diff --git a/.vscode/cspell.json b/.vscode/cspell.json index 31c0b171a04a..8000ae2e0a06 100644 --- a/.vscode/cspell.json +++ b/.vscode/cspell.json @@ -398,6 +398,14 @@ "Phong" ] }, + { + "filename": "tools/azure-sdk-tools/ci_tools/deps.html.j2", + "words": [ + "isfork", + "ISFORK", + "thead" + ] + }, { "filename": "sdk/core/azure-core/tests/test_serialization.py", "words": [ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 67f7438bd425..eafc195fdce5 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -107,7 +107,7 @@ Mypy install and run. ``` #### `sphinx` environment -Generate shpinx doc for this package. +Generate sphinx doc for this package. ``` \> tox -e sphinx -c @@ -117,7 +117,7 @@ Generate shpinx doc for this package. `tox` supports custom arguments, and the defined pytest environments within the common `tox.ini` also allow these. Essentially, separate the arguments you want passed to `pytest` by a `--` in your tox invocation. -[Tox Documentation on Positional Arguments](https://tox.readthedocs.io/en/latest/example/general.html#interactively-passing-positional-arguments) +[Tox Documentation on Positional Arguments](https://tox.wiki/en/latest/config.html#substitutions-for-positional-arguments-in-commands) **Example: Invoke tox, breaking into the debugger on failure** `tox -e whl -c ../../../eng/tox/tox.ini -- --pdb` @@ -155,6 +155,26 @@ b. run tox environment devtest This tox test( devtest) will fail if installed dependent packages are not dev build version. +## Samples + +### Third-party dependencies + +Third party libraries should only be included in samples when necessary to demonstrate usage of an Azure SDK package; they should not be suggested or endorsed as alternatives to the Azure SDK. + +When code samples take dependencies, readers should be able to use the material without significant license burden or research on terms. This goal requires restricting dependencies to certain types of open source or commercial licenses. + +Samples may take the following categories of dependencies: + +- **Open-source** : Open source offerings that use an [Open Source Initiative (OSI) approved license](https://opensource.org/licenses). Any component whose license isn't OSI-approved is considered a commercial offering. Prefer OSS projects that are members of any of the [OSS foundations that Microsoft is part of](https://opensource.microsoft.com/ecosystem/). Prefer permissive licenses for libraries, like [MIT](https://opensource.org/licenses/MIT) and [Apache 2](https://opensource.org/licenses/Apache-2.0). Copy-left licenses like [GPL](https://opensource.org/licenses/gpl-license) are acceptable for tools, and OSs. [Kubernetes](https://github.com/kubernetes/kubernetes), [Linux](https://github.com/torvalds/linux), and [Newtonsoft.Json](https://github.com/JamesNK/Newtonsoft.Json) are examples of this license type. Links to open source components should be to where the source is hosted, including any applicable license, such as a GitHub repository (or similar). + +- **Commercial**: Commercial offerings that enable readers to learn from our content without unnecessary extra costs. Typically, the offering has some form of a community edition, or a free trial sufficient for its use in content. A commercial license may be a form of dual-license, or tiered license. Links to commercial components should be to the commercial site for the software, even if the source software is hosted publicly on GitHub (or similar). + +- **Dual licensed**: Commercial offerings that enable readers to choose either license based on their needs. For example, if the offering has an OSS and commercial license, readers can choose between them. [MySql](https://github.com/mysql/mysql-server) is an example of this license type. + +- **Tiered licensed**: Offerings that enable readers to use the license tier that corresponds to their characteristics. For example, tiers may be available for students, hobbyists, or companies with defined revenue thresholds. For offerings with tiered licenses, strive to limit our use in tutorials to the features available in the lowest tier. This policy enables the widest audience for the article. [Docker](https://www.docker.com/), [IdentityServer](https://duendesoftware.com/products/identityserver), [ImageSharp](https://sixlabors.com/products/imagesharp/), and [Visual Studio](https://visualstudio.com) are examples of this license type. + +In general, we prefer taking dependencies on licensed components in the order of the listed categories. In cases where the category may not be well known, we'll document the category so that readers understand the choice that they're making by using that dependency. + ## Code of Conduct This project's code of conduct can be found in the [CODE_OF_CONDUCT.md file](https://github.com/Azure/azure-sdk-for-python/blob/main/CODE_OF_CONDUCT.md) diff --git a/doc/dev/mgmt/multiapi.md b/doc/dev/mgmt/multiapi.md index 13a9265c21bb..5648adc6bd52 100644 --- a/doc/dev/mgmt/multiapi.md +++ b/doc/dev/mgmt/multiapi.md @@ -1,6 +1,6 @@ # Multi-api packaging and ARM SDK -Several SDKs on this repository are able to support multi-api in a single package. If you're a SDK maintener, this documentation explains the rational of it, and the technical details. +Several SDKs on this repository are able to support multi-api in a single package. If you're a SDK maintainer, this documentation explains the rational of it, and the technical details. ## Overview and rationale @@ -10,7 +10,7 @@ It means a given specific package is able to do calls to several different API v ### Why would I need to call anything else than the latest API version? -Because there is different flavors of Azure that are not necessarly provided with the same set of API versions. For example Azure Governement, Azure Stack usually needs a few months to get the latest available API version. +Because there is different flavors of Azure that are not necessarily provided with the same set of API versions. For example Azure Government, Azure Stack usually needs a few months to get the latest available API version. ### Why a multi-api package? @@ -66,9 +66,9 @@ Main design guidelines: - For people that want a specific API version for a specific need, specifying API version should be possible e.g. `client = ComputeManagementClient(credentials, sub_id, api_version='2018-06-01')` - For people who target a single Azure Profile, specifying it should be be possible - e.g. `client = ComputeManagementClient(credentials, sub_id, profile=KnownProfile.v2018_06_01_bybrid)` + e.g. `client = ComputeManagementClient(credentials, sub_id, profile=KnownProfile.v2018_06_01_hybrid)` -The first condition has impact on models loading, by default they should load the latest API vesion transparently: +The first condition has impact on models loading, by default they should load the latest API version transparently: ```python # Loads the latest version of the model from azure.mgmt.compute.models import VirtualMachineCreateParameter @@ -118,5 +118,3 @@ If this is not the same API version, then we need to bend the rules a little: we ## Possible improvements Current implementation assumes operation group are unique, and as discussed it's not always the case. Also, this limitation has impact on intellisense right now. Example, if a user types `compute_client.virtual_machines.` and hit the intellisense shortcut, users won't see any suggestions. It's because the `virtual_machines` property is dynamic and can change depending of dynamic configuration. - -To improve intellisense and allow operation level profile, the concept would be to make the [operation mixin multi-api concept](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/network/azure-mgmt-network/azure/mgmt/network/_operations_mixin.py) applicable to operation groups as well. I estimate this work to a week of dev-ish. diff --git a/doc/dev/static_type_checking.md b/doc/dev/static_type_checking.md index 6541d2708d85..25a9c7a3a449 100644 --- a/doc/dev/static_type_checking.md +++ b/doc/dev/static_type_checking.md @@ -181,7 +181,7 @@ environment run in CI and brings in the third party stub packages necessary. To ### Run mypy -mypy is currently pinned to version [0.931](https://pypi.org/project/mypy/0.931/). +mypy is currently pinned to version [1.0.0](https://pypi.org/project/mypy/1.0.0/). To run mypy on your library, run the tox mypy env at the package level: @@ -189,7 +189,7 @@ To run mypy on your library, run the tox mypy env at the package level: If you don't want to use `tox` you can also install and run mypy on its own: -`pip install mypy==0.931` +`pip install mypy==1.0.0` `.../azure-sdk-for-python/sdk/textanalytics/azure-ai-textanalytics>mypy azure` diff --git a/doc/dev/test_proxy_troubleshooting.md b/doc/dev/test_proxy_troubleshooting.md index d54e04ac9be0..a8ab0d461dee 100644 --- a/doc/dev/test_proxy_troubleshooting.md +++ b/doc/dev/test_proxy_troubleshooting.md @@ -8,16 +8,18 @@ Documentation of the motivations and goals of the test proxy can be found [here] GitHub repository, and documentation of how to set up and use the proxy can be found [here][detailed_docs]. ## Table of contents -- [General troubleshooting tip](#general-troubleshooting-tip) -- [Test collection failure](#test-collection-failure) -- [Errors in tests using resource preparers](#errors-in-tests-using-resource-preparers) -- [Playback failures from body matching errors](#playback-failures-from-body-matching-errors) -- [Recordings not being produced](#recordings-not-being-produced) -- [KeyError during container startup](#keyerror-during-container-startup) -- [ConnectionError during test startup](#connectionerror-during-test-startup) -- [Different error than expected when using proxy](#different-error-than-expected-when-using-proxy) -- [Test setup failure in test pipeline](#test-setup-failure-in-test-pipeline) -- [Fixture not found error](#fixture-not-found-error) +- [Guide for test proxy troubleshooting](#guide-for-test-proxy-troubleshooting) + - [Table of contents](#table-of-contents) + - [General troubleshooting tip](#general-troubleshooting-tip) + - [Test collection failure](#test-collection-failure) + - [Errors in tests using resource preparers](#errors-in-tests-using-resource-preparers) + - [Playback failures from body matching errors](#playback-failures-from-body-matching-errors) + - [Recordings not being produced](#recordings-not-being-produced) + - [KeyError during container startup](#keyerror-during-container-startup) + - [ConnectionError during test startup](#connectionerror-during-test-startup) + - [Different error than expected when using proxy](#different-error-than-expected-when-using-proxy) + - [Test setup failure in test pipeline](#test-setup-failure-in-test-pipeline) + - [Fixture not found error](#fixture-not-found-error) ## General troubleshooting tip @@ -107,6 +109,7 @@ Tests that aren't recorded should omit the `recorded_by_proxy` decorator. Howeve parameters that are provided by a preparer like the `devtools_testutils` [EnvironmentVariableLoader][env_var_loader], you may see a new test setup error after migrating to the test proxy. For example, imagine a test is decorated with a preparer that provides a Key Vault URL as a `azure_keyvault_url` parameter: + ```python class TestExample(AzureRecordedTestCase): @@ -115,6 +118,7 @@ class TestExample(AzureRecordedTestCase): ``` The above would work in the old test setup, but with the test proxy, running the test will yield + ```text _______ ERROR at setup of TestExample.test_example _______ ... @@ -134,7 +138,7 @@ expected in either case. [detailed_docs]: https://github.com/Azure/azure-sdk-tools/tree/main/tools/test-proxy/Azure.Sdk.Tools.TestProxy/README.md [env_var_loader]: https://github.com/Azure/azure-sdk-for-python/blob/main/tools/azure-sdk-tools/devtools_testutils/envvariable_loader.py [env_var_section]: https://github.com/Azure/azure-sdk-for-python/blob/main/doc/dev/test_proxy_migration_guide.md#fetch-environment-variables -[general_docs]: https://github.com/Azure/azure-sdk-tools/blob/main/tools/test-proxy/README.md +[general_docs]: https://github.com/Azure/azure-sdk-tools/blob/main/tools/test-proxy/documentation/test-proxy/initial-investigation.md [mgmt_recorded_test_case]: https://github.com/Azure/azure-sdk-for-python/blob/main/tools/azure-sdk-tools/devtools_testutils/mgmt_recorded_testcase.py [migration_guide]: https://github.com/Azure/azure-sdk-for-python/blob/main/doc/dev/test_proxy_migration_guide.md [proxy_pipelines]: https://github.com/Azure/azure-sdk-for-python/blob/main/doc/dev/test_proxy_migration_guide.md#enable-the-test-proxy-in-pipelines diff --git a/doc/dev/tests-advanced.md b/doc/dev/tests-advanced.md index 6c201f3ee23e..eb74828a3071 100644 --- a/doc/dev/tests-advanced.md +++ b/doc/dev/tests-advanced.md @@ -1,10 +1,13 @@ # Setup Python Development Environment - Advanced In this document we will provide additional information about the test environments: -- [Test Mixin Classes](#test-mixin-classes) -- [Resource Preparers](#preparers) -- [Examples with Preparers](#examples-with-preparers) -- [mgmt_settings_real.py](#mgmt_settings_real-file) +- [Setup Python Development Environment - Advanced](#setup-python-development-environment---advanced) + - [Test Mixin Classes](#test-mixin-classes) + - [Preparers](#preparers) + - [Examples with Preparers](#examples-with-preparers) + - [Example 2: Basic Preparer Usage with Storage](#example-2-basic-preparer-usage-with-storage) + - [Example 3: Cached Preparer Usage](#example-3-cached-preparer-usage) + - [mgmt\_settings\_real file](#mgmt_settings_real-file) ## Test Mixin Classes Many of our test suites use a mixin class to reduce re-writing code in multiple test files. For example, in the Tables test suite there is a `_shared` directory containing two of these mixin classes, a [sync one](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/tables/azure-data-tables/tests/_shared/testcase.py) and an [async version](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/tables/azure-data-tables/tests/_shared/asynctestcase.py). These classes will often have ways to create connection strings from an account name and key, formulate the account url, configure logging, or validate service responses. In order for these mixin classes to be used by both the functional and unit tests they should inherit from `object`. For example: @@ -74,8 +77,8 @@ class TestTablesUnit(TablesTestMixin): assert client.account_url == "https://{}.tables.core.windows.net/".format(account) ``` - ## Preparers + The Azure SDK team has created some in house tools to help with easier testing. These additional tools are located in the `devtools_testutils` package that was installed with your `dev_requirements.txt`. In this package are the preparers that will be commonly used throughout the repository to test various resources. A preparer is a way to programmatically create fresh resources to run our tests against and then deleting them after running a test suite. These help guarantee standardized behavior by starting each test group from a fresh resource and account. If this situation is a requirement for your tests, you can opt to create a new preparer for your service from the management plane library for a service. There are already a few preparers built in the [devtools_testutils](https://github.com/Azure/azure-sdk-for-python/tree/main/tools/azure-sdk-tools/devtools_testutils). Most prepares will start with the [`ResourceGroupPreparer`](https://github.com/Azure/azure-sdk-for-python/blob/main/tools/azure-sdk-tools/devtools_testutils/resource_testcase.py#L29-L99) to first create a resource group for your service. @@ -86,8 +89,6 @@ To build your own preparer you will need to use the management plane library to |-|-|-| | Resource Group | [link](https://github.com/Azure/azure-sdk-for-python/blob/main/tools/azure-sdk-tools/devtools_testutils/resource_testcase.py#L57-L85) | [link](https://github.com/Azure/azure-sdk-for-python/blob/main/tools/azure-sdk-tools/devtools_testutils/resource_testcase.py#L87-L99) | | Storage Account | [link](https://github.com/Azure/azure-sdk-for-python/blob/main/tools/azure-sdk-tools/devtools_testutils/storage_testcase.py#L53-L102) | [link](https://github.com/Azure/azure-sdk-for-python/blob/main/tools/azure-sdk-tools/devtools_testutils/storage_testcase.py#L104-L107) | -| KeyVault | [link](https://github.com/Azure/azure-sdk-for-python/blob/main/tools/azure-sdk-tools/devtools_testutils/keyvault_preparer.py#L84-L131) | [link](https://github.com/Azure/azure-sdk-for-python/blob/main/tools/azure-sdk-tools/devtools_testutils/keyvault_preparer.py#L133-L138) | - ## Examples with Preparers @@ -107,7 +108,7 @@ from devtools_testutils import ( class ExampleStorageTestCase(AzureTestCase): @ResourceGroupPreparer() - @StorageAcountPreparer() + @StorageAccountPreparer() def test_create_table(self, resource_group, location, storage_account, storage_account_key): account_url = self.account_url(storage_account, "table") client = self.create_client_from_credential(TableServiceClient, storage_account_key, account_url=account_url) @@ -141,7 +142,7 @@ from devtools_testutils import ( class ExampleStorageTestCase(AzureTestCase): @CachedResourceGroupPreparer(name_prefix="storagetest") - @CachedStorageAcountPreparer(name_prefix="storagetest") + @CachedStorageAccountPreparer(name_prefix="storagetest") def test_create_table(self, resource_group, location, storage_account, storage_account_key): account_url = self.account_url(storage_account, "table") client = self.create_client_from_credential(TableServiceClient, storage_account_key, account_url=account_url) @@ -152,7 +153,7 @@ class ExampleStorageTestCase(AzureTestCase): assert valid_table_name == table.table_name @CachedResourceGroupPreparer(name_prefix="storagetest") - @CachedStorageAcountPreparer(name_prefix="storagetest") + @CachedStorageAccountPreparer(name_prefix="storagetest") def test_create_table_if_exists (self, resource_group, location, storage_account, storage_account_key): account_url = self.account_url(storage_account, "table") client = self.create_client_from_credential(TableServiceClient, storage_account_key, account_url=account_url) diff --git a/doc/dev/tests.md b/doc/dev/tests.md index b1acc50e7b5f..5514e2dd1bf2 100644 --- a/doc/dev/tests.md +++ b/doc/dev/tests.md @@ -264,12 +264,13 @@ ServicePreparer = functools.partial( ``` The parameters for the `functools.partial` method are: -* The EnvironmentVariableLoader class -* The service folder that holds your code (in this example, `sdk/testservice`). This value is used to search your + +- The EnvironmentVariableLoader class +- The service folder that holds your code (in this example, `sdk/testservice`). This value is used to search your environment variables for the appropriate values. -* The remaining arguments are key-value kwargs, with the keys being the environment variables needed for the tests, and +- The remaining arguments are key-value kwargs, with the keys being the environment variables needed for the tests, and the value being a fake value to use in recordings. - * These values should have the same formatting as the real values because they are used in playback mode and will need + - These values should have the same formatting as the real values because they are used in playback mode and will need to pass any client side validation. The fake value should also be a unique value to the other key-value pairs. A method that's decorated by the ServicePreparer from the example would be called with `testservice_endpoint` and @@ -733,7 +734,7 @@ Tests that use the Shared Access Signature (SAS) to authenticate a client should [packaging]: https://github.com/Azure/azure-sdk-for-python/blob/main/doc/dev/packaging.md [podman]: https://podman.io/ [proxy_cert_docs]: https://github.com/Azure/azure-sdk-tools/blob/main/tools/test-proxy/documentation/test-proxy/trusting-cert-per-language.md -[proxy_general_docs]: https://github.com/Azure/azure-sdk-tools/blob/main/tools/test-proxy/README.md +[proxy_general_docs]: https://github.com/Azure/azure-sdk-tools/blob/main/tools/test-proxy/Azure.Sdk.Tools.TestProxy/README.md [proxy_migration_guide]: https://github.com/Azure/azure-sdk-for-python/blob/main/doc/dev/test_proxy_migration_guide.md [py_sanitizers]: https://github.com/Azure/azure-sdk-for-python/blob/main/tools/azure-sdk-tools/devtools_testutils/sanitizers.py [pytest_invocation]: https://pytest.org/latest/how-to/usage.html diff --git a/doc/eng_sys_checks.md b/doc/eng_sys_checks.md index fe3fcb88032f..c22c12e4d76c 100644 --- a/doc/eng_sys_checks.md +++ b/doc/eng_sys_checks.md @@ -97,6 +97,10 @@ This is the most useful skip, but the following skip variables are also supporte - Omit `bandit` checks in `analyze` job. - `Skip.Pylint` - Omit linting checks in `analyze` job. +- `Skip.VerifyTypes` + - Omit `VerifyTypes` check in `analyze` job. +- `Skip.Pyright` + - Omit `Pyright` check in `analyze` job. - `Skip.BreakingChanges` - Don't verify if a changeset includes breaking changes. - `Skip.MyPy` diff --git a/eng/ci_tools.txt b/eng/ci_tools.txt index 702cb4997055..6a0e97ffb274 100644 --- a/eng/ci_tools.txt +++ b/eng/ci_tools.txt @@ -1,7 +1,7 @@ # requirements leveraged by ci tools cryptography<4 setuptools==44.1.0; python_version == '2.7' -setuptools==46.4.0; python_version >= '3.5' +setuptools==67.6.0; python_version >= '3.5' virtualenv==20.13.2 wheel==0.37.0 Jinja2==2.11.2 diff --git a/eng/common/scripts/Test-SampleMetadata.ps1 b/eng/common/scripts/Test-SampleMetadata.ps1 index 71c8972a8a36..c20396b0a96b 100644 --- a/eng/common/scripts/Test-SampleMetadata.ps1 +++ b/eng/common/scripts/Test-SampleMetadata.ps1 @@ -202,6 +202,7 @@ begin { "azure-genomics", "azure-hdinsight", "azure-hdinsight-rserver", + "azure-health-insights", "azure-hpc-cache", "azure-immersive-reader", "azure-information-protection", diff --git a/eng/common/scripts/TypeSpec-Project-Generate.ps1 b/eng/common/scripts/TypeSpec-Project-Generate.ps1 new file mode 100644 index 000000000000..feba00d37ed8 --- /dev/null +++ b/eng/common/scripts/TypeSpec-Project-Generate.ps1 @@ -0,0 +1,101 @@ +# For details see https://github.com/Azure/azure-sdk-tools/blob/main/doc/common/TypeSpec-Project-Scripts.md + +[CmdletBinding()] +param ( + [Parameter(Position=0)] + [ValidateNotNullOrEmpty()] + [string] $ProjectDirectory, + [Parameter(Position=1)] + [string] $typespecAdditionalOptions ## addtional typespec emitter options, separated by semicolon if more than one, e.g. option1=value1;option2=value2 +) + +$ErrorActionPreference = "Stop" +. $PSScriptRoot/Helpers/PSModule-Helpers.ps1 +. $PSScriptRoot/common.ps1 +Install-ModuleIfNotInstalled "powershell-yaml" "0.4.1" | Import-Module + +function NpmInstallForProject([string]$workingDirectory) { + Push-Location $workingDirectory + try { + $currentDur = Resolve-Path "." + Write-Host "Generating from $currentDur" + + if (Test-Path "package.json") { + Remove-Item -Path "package.json" -Force + } + + if (Test-Path ".npmrc") { + Remove-Item -Path ".npmrc" -Force + } + + if (Test-Path "node_modules") { + Remove-Item -Path "node_modules" -Force -Recurse + } + + if (Test-Path "package-lock.json") { + Remove-Item -Path "package-lock.json" -Force + } + + #default to root/eng/emitter-package.json but you can override by writing + #Get-${Language}-EmitterPackageJsonPath in your Language-Settings.ps1 + $replacementPackageJson = "$PSScriptRoot/../../emitter-package.json" + if (Test-Path "Function:$GetEmitterPackageJsonPathFn") { + $replacementPackageJson = &$GetEmitterPackageJsonPathFn + } + + Write-Host("Copying package.json from $replacementPackageJson") + Copy-Item -Path $replacementPackageJson -Destination "package.json" -Force + npm install --no-lock-file + if ($LASTEXITCODE) { exit $LASTEXITCODE } + } + finally { + Pop-Location + } +} + +$resolvedProjectDirectory = Resolve-Path $ProjectDirectory +$emitterName = &$GetEmitterNameFn +$typespecConfigurationFile = Resolve-Path "$ProjectDirectory/tsp-location.yaml" + +Write-Host "Reading configuration from $typespecConfigurationFile" +$configuration = Get-Content -Path $typespecConfigurationFile -Raw | ConvertFrom-Yaml + +$specSubDirectory = $configuration["directory"] +$innerFolder = Split-Path $specSubDirectory -Leaf + +$tempFolder = "$ProjectDirectory/TempTypeSpecFiles" +$npmWorkingDir = Resolve-Path $tempFolder/$innerFolder +$mainTypeSpecFile = If (Test-Path "$npmWorkingDir/client.*") { Resolve-Path "$npmWorkingDir/client.*" } Else { Resolve-Path "$npmWorkingDir/main.*"} + +try { + Push-Location $npmWorkingDir + NpmInstallForProject $npmWorkingDir + + if ($LASTEXITCODE) { exit $LASTEXITCODE } + + if (Test-Path "Function:$GetEmitterAdditionalOptionsFn") { + $emitterAdditionalOptions = &$GetEmitterAdditionalOptionsFn $resolvedProjectDirectory + if ($emitterAdditionalOptions.Length -gt 0) { + $emitterAdditionalOptions = " $emitterAdditionalOptions" + } + } + $typespecCompileCommand = "npx tsp compile $mainTypeSpecFile --emit $emitterName$emitterAdditionalOptions" + if ($typespecAdditionalOptions) { + $options = $typespecAdditionalOptions.Split(";"); + foreach ($option in $options) { + $typespecCompileCommand += " --option $emitterName.$option" + } + } + Write-Host($typespecCompileCommand) + Invoke-Expression $typespecCompileCommand + + if ($LASTEXITCODE) { exit $LASTEXITCODE } +} +finally { + Pop-Location +} + +$shouldCleanUp = $configuration["cleanup"] ?? $true +if ($shouldCleanUp) { + Remove-Item $tempFolder -Recurse -Force +} diff --git a/eng/common/scripts/TypeSpec-Project-Sync.ps1 b/eng/common/scripts/TypeSpec-Project-Sync.ps1 new file mode 100644 index 000000000000..f8656bc1d608 --- /dev/null +++ b/eng/common/scripts/TypeSpec-Project-Sync.ps1 @@ -0,0 +1,127 @@ +# For details see https://github.com/Azure/azure-sdk-tools/blob/main/doc/common/TypeSpec-Project-Scripts.md + +[CmdletBinding()] +param ( + [Parameter(Position=0)] + [ValidateNotNullOrEmpty()] + [string] $ProjectDirectory +) + +$ErrorActionPreference = "Stop" +. $PSScriptRoot/Helpers/PSModule-Helpers.ps1 +Install-ModuleIfNotInstalled "powershell-yaml" "0.4.1" | Import-Module +$sparseCheckoutFile = ".git/info/sparse-checkout" + +function AddSparseCheckoutPath([string]$subDirectory) { + if (!(Test-Path $sparseCheckoutFile) -or !((Get-Content $sparseCheckoutFile).Contains($subDirectory))) { + Write-Output $subDirectory >> .git/info/sparse-checkout + } +} + +function CopySpecToProjectIfNeeded([string]$specCloneRoot, [string]$mainSpecDir, [string]$dest, [string[]]$specAdditionalSubDirectories) { + $source = "$specCloneRoot/$mainSpecDir" + Copy-Item -Path $source -Destination $dest -Recurse -Force + Write-Host "Copying spec from $source to $dest" + + foreach ($additionalDir in $specAdditionalSubDirectories) { + $source = "$specCloneRoot/$additionalDir" + Write-Host "Copying spec from $source to $dest" + Copy-Item -Path $source -Destination $dest -Recurse -Force + } +} + +function UpdateSparseCheckoutFile([string]$mainSpecDir, [string[]]$specAdditionalSubDirectories) { + AddSparseCheckoutPath $mainSpecDir + foreach ($subDir in $specAdditionalSubDirectories) { + AddSparseCheckoutPath $subDir + } +} + +function GetGitRemoteValue([string]$repo) { + Push-Location $ProjectDirectory + $result = "" + try { + $gitRemotes = (git remote -v) + foreach ($remote in $gitRemotes) { + if ($remote.StartsWith("origin")) { + if ($remote -match 'https://github.com/\S+') { + $result = "https://github.com/$repo.git" + break + } elseif ($remote -match "git@github.com:\S+"){ + $result = "git@github.com:$repo.git" + break + } else { + throw "Unknown git remote format found: $remote" + } + } + } + } + finally { + Pop-Location + } + + return $result +} + +function InitializeSparseGitClone([string]$repo) { + git clone --no-checkout --filter=tree:0 $repo . + if ($LASTEXITCODE) { exit $LASTEXITCODE } + git sparse-checkout init + if ($LASTEXITCODE) { exit $LASTEXITCODE } + Remove-Item $sparseCheckoutFile -Force +} + +function GetSpecCloneDir([string]$projectName) { + Push-Location $ProjectDirectory + try { + $root = git rev-parse --show-toplevel + } + finally { + Pop-Location + } + + $sparseSpecCloneDir = "$root/../sparse-spec/$projectName" + New-Item $sparseSpecCloneDir -Type Directory -Force | Out-Null + $createResult = Resolve-Path $sparseSpecCloneDir + return $createResult +} + +$typespecConfigurationFile = Resolve-Path "$ProjectDirectory/tsp-location.yaml" +Write-Host "Reading configuration from $typespecConfigurationFile" +$configuration = Get-Content -Path $typespecConfigurationFile -Raw | ConvertFrom-Yaml + +$pieces = $typespecConfigurationFile.Path.Replace("\","/").Split("/") +$projectName = $pieces[$pieces.Count - 2] + +$specSubDirectory = $configuration["directory"] + +if ( $configuration["repo"] -and $configuration["commit"]) { + $specCloneDir = GetSpecCloneDir $projectName + $gitRemoteValue = GetGitRemoteValue $configuration["repo"] + + Write-Host "Setting up sparse clone for $projectName at $specCloneDir" + + Push-Location $specCloneDir.Path + try { + if (!(Test-Path ".git")) { + InitializeSparseGitClone $gitRemoteValue + UpdateSparseCheckoutFile $specSubDirectory $configuration["additionalDirectories"] + } + git checkout $configuration["commit"] + if ($LASTEXITCODE) { exit $LASTEXITCODE } + } + finally { + Pop-Location + } +} elseif ( $configuration["spec-root-dir"] ) { + $specCloneDir = $configuration["spec-root-dir"] +} + + +$tempTypeSpecDir = "$ProjectDirectory/TempTypeSpecFiles" +New-Item $tempTypeSpecDir -Type Directory -Force | Out-Null +CopySpecToProjectIfNeeded ` + -specCloneRoot $specCloneDir ` + -mainSpecDir $specSubDirectory ` + -dest $tempTypeSpecDir ` + -specAdditionalSubDirectories $configuration["additionalDirectories"] diff --git a/eng/common/testproxy/override-proxy-version.ps1 b/eng/common/testproxy/override-proxy-version.ps1 new file mode 100644 index 000000000000..d1e6ff5bfa37 --- /dev/null +++ b/eng/common/testproxy/override-proxy-version.ps1 @@ -0,0 +1,25 @@ +<# +.SYNOPSIS +Replaces target test-proxy version present in target_version.txt. + +.PARAMETER TargetVersion +The replacement version. Used in its entirety, so don't exclude parts of the version definition. +#> +[cmdletbinding(SupportsShouldProcess=$True)] +param( + [Parameter(mandatory=$true)] [string] $TargetVersion +) + +$versionFile = Join-Path $PSScriptRoot "target_version.txt" +$existingVersionText = Get-Content -Raw -Path $versionFile +$existingVersion = $existingVersionText.Trim() + +if ($PSCmdLet.ShouldProcess($versionFile)){ + Write-Host "Replacing version `"$existingVersion`" with version `"$TargetVersion`" in $versionFile." + Set-Content -Path $versionFile -Value "$TargetVersion`n" +} +else { + Write-Host "Would replace version `"$existingVersion`" with version `"$TargetVersion`" in $versionFile." +} + + diff --git a/eng/common/testproxy/test-proxy-docker.yml b/eng/common/testproxy/test-proxy-docker.yml index 71a03d1be3b1..6e749801f4de 100644 --- a/eng/common/testproxy/test-proxy-docker.yml +++ b/eng/common/testproxy/test-proxy-docker.yml @@ -10,6 +10,15 @@ steps: displayName: 'Language Specific Certificate Trust' condition: and(succeeded(), ${{ parameters.condition }}) + - task: PowerShell@2 + displayName: 'Override proxy version if necessary' + condition: and(succeeded(), ${{ parameters.condition }}, ne('${{ parameters.targetVersion }}', '')) + inputs: + targetType: filePath + filePath: '${{ parameters.templateRoot }}/eng/common/testproxy/override-proxy-version.ps1' + arguments: '-TargetVersion "${{ parameters.targetVersion }}"' + pwsh: true + - pwsh: | docker info displayName: 'Dump active docker information' diff --git a/eng/common/testproxy/test-proxy-tool.yml b/eng/common/testproxy/test-proxy-tool.yml index ae9d69051537..bffc68309c04 100644 --- a/eng/common/testproxy/test-proxy-tool.yml +++ b/eng/common/testproxy/test-proxy-tool.yml @@ -11,14 +11,17 @@ steps: displayName: 'Language Specific Certificate Trust' condition: and(succeeded(), ${{ parameters.condition }}) + - task: PowerShell@2 + displayName: 'Override proxy version if necessary' + condition: and(succeeded(), ${{ parameters.condition }}, ne('${{ parameters.targetVersion }}', '')) + inputs: + targetType: filePath + filePath: '${{ parameters.templateRoot }}/eng/common/testproxy/override-proxy-version.ps1' + arguments: '-TargetVersion "${{ parameters.targetVersion }}"' + pwsh: true + - pwsh: | $version = $(Get-Content "${{ parameters.templateRoot }}/eng/common/testproxy/target_version.txt" -Raw).Trim() - $overrideVersion = "${{ parameters.targetVersion }}" - - if($overrideVersion) { - Write-Host "Overriding default target proxy version of '$version' with override $overrideVersion." - $version = $overrideVersion - } dotnet tool install azure.sdk.tools.testproxy ` --tool-path $(Build.BinariesDirectory)/test-proxy ` diff --git a/eng/conda_test_requirements.txt b/eng/conda_test_requirements.txt index c3d01d4b1075..fd1dc5b23c58 100644 --- a/eng/conda_test_requirements.txt +++ b/eng/conda_test_requirements.txt @@ -9,7 +9,7 @@ trio typing_extensions>=3.7.2 cryptography adal -setuptools==46.4.0 +setuptools==67.6.0; python_version >= '3.5' pytest-asyncio==0.12.0 -e sdk/core/azure-core/tests/testserver_tests/coretestserver azure-mgmt-storage \ No newline at end of file diff --git a/eng/pipelines/autorest_checks.yml b/eng/pipelines/autorest_checks.yml index 9fa414c1fddc..1ead75a1381e 100644 --- a/eng/pipelines/autorest_checks.yml +++ b/eng/pipelines/autorest_checks.yml @@ -49,16 +49,16 @@ jobs: - script: | cd $(Build.SourcesDirectory)/autorest.python/packages/autorest.python/test/vanilla/legacy - pip install $(Build.SourcesDirectory)/$(source_path_azure_core) - pip install -r requirements.txt + python -m pip install $(Build.SourcesDirectory)/$(source_path_azure_core) + python -m pip install -r requirements.txt pip freeze pytest $(Build.SourcesDirectory)/autorest.python/packages/autorest.python/test/vanilla/legacy displayName: 'Install azure-core and Test Vanilla Legacy' - script: | cd $(Build.SourcesDirectory)/autorest.python/packages/autorest.python/test/azure/legacy - pip install $(Build.SourcesDirectory)/$(source_path_azure_mgmt_core) - pip install -r requirements.txt + python -m pip install $(Build.SourcesDirectory)/$(source_path_azure_mgmt_core) + python -m pip install -r requirements.txt pip freeze pytest $(Build.SourcesDirectory)/autorest.python/packages/autorest.python/test/azure/legacy displayName: 'Install azure-mgmt-core and Test Azure Legacy' \ No newline at end of file diff --git a/eng/pipelines/docindex.yml b/eng/pipelines/docindex.yml index 64dd21328ad3..909afabe5150 100644 --- a/eng/pipelines/docindex.yml +++ b/eng/pipelines/docindex.yml @@ -21,7 +21,7 @@ jobs: versionSpec: '3.9.13' # Docs CI upgrades pip, wheel, and setuptools - - pwsh: pip install --upgrade pip wheel setuptools + - pwsh: python -m pip install --upgrade pip wheel setuptools displayName: Update python tools for package verification # Pull and build the docker image. diff --git a/eng/pipelines/generate-all-docs.yml b/eng/pipelines/generate-all-docs.yml index 9a865424ecf6..8798cfcfb289 100644 --- a/eng/pipelines/generate-all-docs.yml +++ b/eng/pipelines/generate-all-docs.yml @@ -21,7 +21,7 @@ jobs: versionSpec: '$(PythonVersion)' - script: | - pip install -r eng/ci_tools.txt + python -m pip install -r eng/ci_tools.txt displayName: 'Prep Environment' - task: PythonScript@0 diff --git a/eng/pipelines/templates/jobs/ci.yml b/eng/pipelines/templates/jobs/ci.yml index 0030ecbbfdad..2fbac9f7af8c 100644 --- a/eng/pipelines/templates/jobs/ci.yml +++ b/eng/pipelines/templates/jobs/ci.yml @@ -61,6 +61,9 @@ parameters: - name: TestProxy type: boolean default: false + - name: GenerateApiReviewForManualOnly + type: boolean + default: false jobs: - job: 'Build' @@ -132,6 +135,7 @@ jobs: Artifacts: ${{ parameters.Artifacts }} VerifyAutorest: ${{ parameters.VerifyAutorest }} ValidateFormatting: ${{ parameters.ValidateFormatting }} + GenerateApiReviewForManualOnly: ${{ parameters.GenerateApiReviewForManualOnly }} - job: Compliance pool: @@ -178,7 +182,7 @@ jobs: GenerateVMJobs: true PreGenerationSteps: - pwsh: | - pip install "./tools/azure-sdk-tools[build]" + python -m pip install "./tools/azure-sdk-tools[build]" displayName: 'Prep Environment' - template: /eng/pipelines/templates/steps/targeting-string-resolve.yml parameters: diff --git a/eng/pipelines/templates/jobs/live.tests.yml b/eng/pipelines/templates/jobs/live.tests.yml index 5677cdc9d907..13427adbe193 100644 --- a/eng/pipelines/templates/jobs/live.tests.yml +++ b/eng/pipelines/templates/jobs/live.tests.yml @@ -2,6 +2,9 @@ parameters: - name: ServiceDirectory type: string default: '' + - name: TestResourceDirectories + type: object + default: - name: PreSteps type: object default: [] @@ -99,12 +102,21 @@ jobs: SubscriptionConfiguration: ${{ parameters.CloudConfig.SubscriptionConfiguration }} SubscriptionConfigurations: ${{ parameters.CloudConfig.SubscriptionConfigurations }} - - template: /eng/common/TestResources/deploy-test-resources.yml - parameters: - Location: ${{ coalesce(parameters.Location, parameters.CloudConfig.Location) }} - ServiceDirectory: '${{ parameters.ServiceDirectory }}' - SubscriptionConfiguration: $(SubscriptionConfiguration) - ArmTemplateParameters: $(ArmTemplateParameters) + - ${{ if parameters.TestResourceDirectories }}: + - ${{ each directory in parameters.TestResourceDirectories }}: + - template: /eng/common/TestResources/deploy-test-resources.yml + parameters: + Location: ${{ coalesce(parameters.Location, parameters.CloudConfig.Location) }} + ServiceDirectory: '${{ directory }}' + SubscriptionConfiguration: $(SubscriptionConfiguration) + ArmTemplateParameters: $(ArmTemplateParameters) + - ${{ if not(parameters.TestResourceDirectories) }}: + - template: /eng/common/TestResources/deploy-test-resources.yml + parameters: + Location: ${{ coalesce(parameters.Location, parameters.CloudConfig.Location) }} + ServiceDirectory: '${{ parameters.ServiceDirectory }}' + SubscriptionConfiguration: $(SubscriptionConfiguration) + ArmTemplateParameters: $(ArmTemplateParameters) - template: ../steps/build-test.yml parameters: @@ -125,7 +137,15 @@ jobs: BuildDocs: ${{ parameters.BuildDocs }} TestProxy: ${{ parameters.TestProxy }} - - template: /eng/common/TestResources/remove-test-resources.yml - parameters: - ServiceDirectory: '${{ parameters.ServiceDirectory }}' - SubscriptionConfiguration: $(SubscriptionConfiguration) + + - ${{ if parameters.TestResourceDirectories }}: + - ${{ each directory in parameters.TestResourceDirectories }}: + - template: /eng/common/TestResources/remove-test-resources.yml + parameters: + ServiceDirectory: '${{ directory }}' + SubscriptionConfiguration: $(SubscriptionConfiguration) + - ${{ if not(parameters.TestResourceDirectories) }}: + - template: /eng/common/TestResources/remove-test-resources.yml + parameters: + ServiceDirectory: '${{ parameters.ServiceDirectory }}' + SubscriptionConfiguration: $(SubscriptionConfiguration) diff --git a/eng/pipelines/templates/jobs/regression.yml b/eng/pipelines/templates/jobs/regression.yml index 58658d10620a..472ad702dbef 100644 --- a/eng/pipelines/templates/jobs/regression.yml +++ b/eng/pipelines/templates/jobs/regression.yml @@ -84,7 +84,7 @@ jobs: - pwsh: | mkdir -p $(TEST_PROXY_FOLDER) - pip install -r eng/regression_tools.txt + python -m pip install -r eng/regression_tools.txt displayName: 'Prep Environment' - template: /eng/common/testproxy/test-proxy-tool.yml diff --git a/eng/pipelines/templates/jobs/run-cli-tests.yml b/eng/pipelines/templates/jobs/run-cli-tests.yml index d15e9ca2d7c8..7de72168a62c 100644 --- a/eng/pipelines/templates/jobs/run-cli-tests.yml +++ b/eng/pipelines/templates/jobs/run-cli-tests.yml @@ -67,14 +67,14 @@ jobs: - bash: | set -ev source env/bin/activate - pip install -e $(Build.SourcesDirectory)/${{ artifact }} + python -m pip install -e $(Build.SourcesDirectory)/${{ artifact }} displayName: Install ${{ artifact }} - ${{ each package_spec in parameters.InjectedPackages }}: - bash: | set -ev source env/bin/activate - pip install -e ${{ package_spec }} + python -m pip install -e ${{ package_spec }} displayName: Install ${{ package_spec }} - bash: | diff --git a/eng/pipelines/templates/jobs/smoke.tests.yml b/eng/pipelines/templates/jobs/smoke.tests.yml index 1c964d069771..724d2c40e881 100644 --- a/eng/pipelines/templates/jobs/smoke.tests.yml +++ b/eng/pipelines/templates/jobs/smoke.tests.yml @@ -192,8 +192,8 @@ jobs: - pwsh: | $ErrorActionPreference = "Continue" while ($retries++ -lt 15) { - Write-Host "pip install -r $(requirements) --no-deps --upgrade --no-cache-dir" - pip install -r "$(requirements)" --no-deps --upgrade --no-cache-dir + Write-Host "python -m pip install -r $(requirements) --no-deps --upgrade --no-cache-dir" + python -m pip install -r "$(requirements)" --no-deps --upgrade --no-cache-dir if ($LASTEXITCODE) { if ($retries -ge 15) { exit $LASTEXITCODE @@ -208,12 +208,12 @@ jobs: - ${{ if eq(parameters.Daily, true) }}: - pwsh: | - pip install -r "$(requirements)" --pre --no-deps --upgrade ` + python -m pip install -r "$(requirements)" --pre --no-deps --upgrade ` --index-url https://pkgs.dev.azure.com/azure-sdk/public/_packaging/azure-sdk-for-python/pypi/simple displayName: Install requirements from dev feed without dependencies - - pwsh: pip install -r $(Build.SourcesDirectory)/common/smoketest/requirements_async.txt + - pwsh: python -m pip install -r $(Build.SourcesDirectory)/common/smoketest/requirements_async.txt displayName: "Install requirements_async.txt" condition: and(succeeded(), ne(variables['SkipAsyncInstall'], true)) @@ -222,10 +222,10 @@ jobs: | Out-File $(Build.SourcesDirectory)/common/smoketest/requirements_dependencies.txt displayName: Create dependency list from installed packages - - script: pip install -r $(Build.SourcesDirectory)/common/smoketest/requirements_dependencies.txt + - script: python -m pip install -r $(Build.SourcesDirectory)/common/smoketest/requirements_dependencies.txt displayName: Install package dependencies from PyPI - - script: pip freeze + - script: python -m pip freeze displayName: Show installed packages (pip freeze) - template: /eng/common/TestResources/deploy-test-resources.yml diff --git a/eng/pipelines/templates/jobs/tests-nightly-python.yml b/eng/pipelines/templates/jobs/tests-nightly-python.yml index 650a9217f21c..ed6406412cd4 100644 --- a/eng/pipelines/templates/jobs/tests-nightly-python.yml +++ b/eng/pipelines/templates/jobs/tests-nightly-python.yml @@ -22,8 +22,8 @@ jobs: - script: | python -m pip freeze python -m pip --version - pip install setuptools==56.0.0 wheel==0.37.0 tox==3.24.3 tox-monorepo==0.1.2 packaging==21.0 requests - pip install $(Build.SourcesDirectory)/tools/azure-sdk-tools[build] + python -m pip install setuptools==67.6.0 wheel==0.37.0 tox==3.24.3 tox-monorepo==0.1.2 packaging==21.0 requests + python -m pip install $(Build.SourcesDirectory)/tools/azure-sdk-tools[build] displayName: Install Dependencies - template: /eng/common/testproxy/test-proxy-tool.yml @@ -67,8 +67,8 @@ jobs: sudo apt-get install build-essential -y python -m pip freeze python -m pip --version - pip install setuptools==56.0.0 wheel==0.37.0 tox==3.24.3 tox-monorepo==0.1.2 packaging==21.0 requests - pip install $(Build.SourcesDirectory)/tools/azure-sdk-tools[build] + python -m pip install setuptools==67.6.0 wheel==0.37.0 tox==3.24.3 tox-monorepo==0.1.2 packaging==21.0 requests + python -m pip install $(Build.SourcesDirectory)/tools/azure-sdk-tools[build] displayName: Install Dependencies - template: /eng/common/testproxy/test-proxy-tool.yml @@ -130,7 +130,7 @@ jobs: export PATH=~/.local/bin:$PATH curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py python3 get-pip.py - python3 -m pip install setuptools wheel + python3 -m pip install setuptools==67.6.0 wheel python3 -m pip install tox tox-monorepo packaging twine codecov beautifulsoup4 python3 --version cd $(Build.SourcesDirectory) diff --git a/eng/pipelines/templates/jobs/trigger-ml-sample-pipeline.yml b/eng/pipelines/templates/jobs/trigger-ml-sample-pipeline.yml index 2f79953106db..b25e5af538f2 100644 --- a/eng/pipelines/templates/jobs/trigger-ml-sample-pipeline.yml +++ b/eng/pipelines/templates/jobs/trigger-ml-sample-pipeline.yml @@ -39,8 +39,8 @@ jobs: versionSpec: $(PythonVersion) - script: | - pip install -r eng/ci_tools.txt - pip install -r eng/ml_sample_tools.txt + python -m pip install -r eng/ci_tools.txt + python -m pip install -r eng/ml_sample_tools.txt displayName: 'Prep Environment' - pwsh: | diff --git a/eng/pipelines/templates/stages/archetype-python-release.yml b/eng/pipelines/templates/stages/archetype-python-release.yml index b1e2fa310d37..3e0747a76b92 100644 --- a/eng/pipelines/templates/stages/archetype-python-release.yml +++ b/eng/pipelines/templates/stages/archetype-python-release.yml @@ -85,8 +85,8 @@ stages: - script: | set -e - pip install -r eng/release_requirements.txt - pip install tools/azure-sdk-tools + python -m pip install -r eng/release_requirements.txt + python -m pip install tools/azure-sdk-tools displayName: Install Release Dependencies - task: PythonScript@0 @@ -206,7 +206,7 @@ stages: - checkout: self - task: UsePythonVersion@0 - script: | - pip install "./tools/azure-sdk-tools[build]" + python -m pip install "./tools/azure-sdk-tools[build]" displayName: Install versioning tool dependencies - pwsh: | sdk_increment_version --package-name ${{ artifact.name }} --service ${{ parameters.ServiceDirectory }} @@ -245,7 +245,7 @@ stages: - task: UsePythonVersion@0 - script: | set -e - pip install twine + python -m pip install twine displayName: Install Twine - template: ../steps/auth-dev-feed.yml diff --git a/eng/pipelines/templates/stages/archetype-sdk-client.yml b/eng/pipelines/templates/stages/archetype-sdk-client.yml index 3b3e37f12231..ebf2259401fd 100644 --- a/eng/pipelines/templates/stages/archetype-sdk-client.yml +++ b/eng/pipelines/templates/stages/archetype-sdk-client.yml @@ -72,6 +72,9 @@ parameters: - name: TestProxy type: boolean default: false +- name: GenerateApiReviewForManualOnly + type: boolean + default: false variables: - template: /eng/pipelines/templates/variables/globals.yml @@ -106,6 +109,7 @@ stages: VerifyAutorest: ${{ parameters.VerifyAutorest }} ValidateFormatting: ${{ parameters.ValidateFormatting }} TestProxy: ${{ parameters.TestProxy }} + GenerateApiReviewForManualOnly: ${{ parameters.GenerateApiReviewForManualOnly }} # The Prerelease and Release stages are conditioned on whether we are building a pull request and the branch. - ${{if and(ne(variables['Build.Reason'], 'PullRequest'), eq(variables['System.TeamProject'], 'internal'))}}: diff --git a/eng/pipelines/templates/stages/archetype-sdk-tests.yml b/eng/pipelines/templates/stages/archetype-sdk-tests.yml index dbb6492de0d3..edba9c745dc1 100644 --- a/eng/pipelines/templates/stages/archetype-sdk-tests.yml +++ b/eng/pipelines/templates/stages/archetype-sdk-tests.yml @@ -2,6 +2,9 @@ parameters: - name: ServiceDirectory type: string default: '' + - name: TestResourceDirectories + type: object + default: - name: PreSteps type: object default: [] @@ -105,6 +108,7 @@ stages: JobTemplatePath: /eng/pipelines/templates/jobs/live.tests.yml AdditionalParameters: ServiceDirectory: ${{ parameters.ServiceDirectory }} + TestResourceDirectories: ${{ parameters.TestResourceDirectories }} PreSteps: - ${{ parameters.PlatformPreSteps }} - ${{ parameters.PreSteps }} @@ -173,4 +177,29 @@ stages: --toxenv="next-pylint" --disablecov --filter-type="Omit_management" - env: ${{ parameters.EnvVars }} \ No newline at end of file + env: ${{ parameters.EnvVars }} + + - task: PythonScript@0 + displayName: 'Run MyPy Next' + continueOnError: true + inputs: + scriptPath: 'scripts/devops_tasks/setup_execute_tests.py' + arguments: >- + "azure*" + --mark_arg="${{ parameters.TestMarkArgument }}" + --service="${{ parameters.ServiceDirectory }}" + --toxenv="next-mypy" + --disablecov + env: ${{ parameters.EnvVars }} + + - task: PythonScript@0 + displayName: 'Run Pyright Next' + continueOnError: true + inputs: + scriptPath: 'scripts/devops_tasks/setup_execute_tests.py' + arguments: >- + "azure*" + --mark_arg="${{ parameters.TestMarkArgument }}" + --service="${{ parameters.ServiceDirectory }}" + --toxenv="next-pyright" + --disablecov diff --git a/eng/pipelines/templates/steps/analyze.yml b/eng/pipelines/templates/steps/analyze.yml index 0ae29c431ae6..69ccabcdcfd8 100644 --- a/eng/pipelines/templates/steps/analyze.yml +++ b/eng/pipelines/templates/steps/analyze.yml @@ -6,6 +6,7 @@ parameters: TestPipeline: false VerifyAutorest: false ValidateFormatting: false + GenerateApiReviewForManualOnly: false # The variable TargetingString is set by template `eng/pipelines/templates/steps/targeting-string-resolve.yml`. This template is invoked from yml files: # eng/pipelines/templates/jobs/ci.tests.yml @@ -39,12 +40,12 @@ steps: ForRelease: false - pwsh: | - pip install -r eng/ci_tools.txt $(if($IsWindows) {"--user" }) + python -m pip install -r eng/ci_tools.txt $(if($IsWindows) {"--user" }) displayName: 'Install Necessary Dependencies' condition: succeededOrFailed() - script: | - pip install "./tools/azure-sdk-tools[build]" -q -I + python -m pip install "./tools/azure-sdk-tools[build]" -q -I sdk_find_invalid_versions --always-succeed --service=${{parameters.ServiceDirectory}} displayName: Find Invalid Versions condition: succeededOrFailed() @@ -140,6 +141,7 @@ steps: - template: /eng/pipelines/templates/steps/create-apireview.yml parameters: Artifacts: ${{ parameters.Artifacts }} + GenerateApiReviewForManualOnly: ${{ parameters.GenerateApiReviewForManualOnly }} - template: /eng/common/pipelines/templates/steps/detect-api-changes.yml parameters: diff --git a/eng/pipelines/templates/steps/analyze_dependency.yml b/eng/pipelines/templates/steps/analyze_dependency.yml index 474b9d13ce66..a59daf8f1d8b 100644 --- a/eng/pipelines/templates/steps/analyze_dependency.yml +++ b/eng/pipelines/templates/steps/analyze_dependency.yml @@ -9,7 +9,7 @@ steps: versionSpec: '$(PythonVersion)' - pwsh: | - python -m pip install -r eng/ci_tools.txt $(if($IsWindows) {"--user" }) + python -m pip install -r eng/ci_tools.txt displayName: 'Install Python Tools' condition: succeededOrFailed() @@ -21,11 +21,9 @@ steps: mkdir "$(Build.ArtifactStagingDirectory)/reports" Copy-Item -Path "$(Build.SourcesDirectory)/eng/common/InterdependencyGraph.html" -Destination "$(Build.ArtifactStagingDirectory)/reports/InterdependencyGraph.html" displayName: 'Populate Reports Staging Folder' - condition: succeededOrFailed() + condition: and(succeededOrFailed(),ne(variables['Skip.AnalyzeDependencies'],'true')) - - task: PythonScript@0 + - pwsh: | + sdk_analyze_deps --verbose --out "$(Build.ArtifactStagingDirectory)/reports/dependencies.html" --dump "$(Build.ArtifactStagingDirectory)/reports" displayName: 'Analyze dependencies' condition: and(succeededOrFailed(),ne(variables['Skip.AnalyzeDependencies'],'true')) - inputs: - scriptPath: 'scripts/analyze_deps.py' - arguments: '--verbose --out "$(Build.ArtifactStagingDirectory)/reports/dependencies.html" --dump "$(Build.ArtifactStagingDirectory)/reports"' \ No newline at end of file diff --git a/eng/pipelines/templates/steps/build-artifacts.yml b/eng/pipelines/templates/steps/build-artifacts.yml index 07f835526406..1e8b06f7fdc5 100644 --- a/eng/pipelines/templates/steps/build-artifacts.yml +++ b/eng/pipelines/templates/steps/build-artifacts.yml @@ -43,7 +43,7 @@ steps: versionSpec: $(PythonVersion) - script: | - pip install -r eng/ci_tools.txt + python -m pip install -r eng/ci_tools.txt displayName: 'Prep Environment' - template: ../steps/set-dev-build.yml diff --git a/eng/pipelines/templates/steps/build-conda-artifacts.yml b/eng/pipelines/templates/steps/build-conda-artifacts.yml index aa6943c53c84..7417525a3e34 100644 --- a/eng/pipelines/templates/steps/build-conda-artifacts.yml +++ b/eng/pipelines/templates/steps/build-conda-artifacts.yml @@ -22,7 +22,7 @@ steps: versionSpec: $(PythonVersion) - script: | - pip install -r eng/ci_tools.txt + python -m pip install -r eng/ci_tools.txt displayName: 'Prep Environment' - pwsh: | diff --git a/eng/pipelines/templates/steps/build-test.yml b/eng/pipelines/templates/steps/build-test.yml index b5d268f70cee..78af4185ef91 100644 --- a/eng/pipelines/templates/steps/build-test.yml +++ b/eng/pipelines/templates/steps/build-test.yml @@ -34,7 +34,7 @@ steps: - script: | python -m pip install pip==20.3.3 python -m pip install wheel==0.37.0 - pip install -r eng/ci_tools.txt + python -m pip install -r eng/ci_tools.txt pip --version pip freeze displayName: 'Prep Environment' diff --git a/eng/pipelines/templates/steps/create-apireview.yml b/eng/pipelines/templates/steps/create-apireview.yml index 22a18bcc47c7..e3637470a7f2 100644 --- a/eng/pipelines/templates/steps/create-apireview.yml +++ b/eng/pipelines/templates/steps/create-apireview.yml @@ -4,34 +4,38 @@ parameters: ConfigFileDir: $(Build.ArtifactStagingDirectory)/PackageInfo Language: 'Python' APIViewUri: 'https://apiview.dev/AutoReview/CreateApiReview' + GenerateApiReviewForManualOnly: false steps: # ideally this should be done as initial step of a job in caller template # We can remove this step later once it is added in caller - template: /eng/common/pipelines/templates/steps/set-default-branch.yml - - - task: Powershell@2 - inputs: - filePath: $(Build.SourcesDirectory)/eng/scripts/Create-ApiReview.ps1 - arguments: > - -ArtifactList ('${{ convertToJson(parameters.Artifacts) }}' | ConvertFrom-Json | Select-Object Name) - -ArtifactPath ${{ parameters.ArtifactPath }} - -APIViewUri ${{ parameters.APIViewUri }} - -APIKey $(azuresdk-apiview-apikey) - -SourceBranch $(Build.SourceBranchName) - -DefaultBranch $(DefaultBranch) - -ConfigFileDir '${{ parameters.ConfigFileDir }}' - -BuildId $(Build.BuildId) - -RepoName $(Build.Repository.Name) - -Language ${{ parameters.Language }} - pwsh: true - workingDirectory: $(Pipeline.Workspace) - displayName: Create Automatic API Review - condition: >- - and( - succeededOrFailed(), - ne(variables['Skip.CreateApiReview'], 'true'), - ne(variables['Build.Reason'],'PullRequest'), - eq(variables['System.TeamProject'], 'internal'), - not(endsWith(variables['Build.Repository.Name'], '-pr')) - ) + + # Automatic API review is generated for a package when pipeline runs irrespective of how pipeline gets triggered. + # Below condition ensures that API review is generated only for manual pipeline runs when flag GenerateApiReviewForManualOnly is set to true. + - ${{ if or(ne(parameters.GenerateApiReviewForManualOnly, true), eq(variables['Build.Reason'], 'Manual')) }}: + - task: Powershell@2 + inputs: + filePath: $(Build.SourcesDirectory)/eng/scripts/Create-ApiReview.ps1 + arguments: > + -ArtifactList ('${{ convertToJson(parameters.Artifacts) }}' | ConvertFrom-Json | Select-Object Name) + -ArtifactPath ${{ parameters.ArtifactPath }} + -APIViewUri ${{ parameters.APIViewUri }} + -APIKey $(azuresdk-apiview-apikey) + -SourceBranch $(Build.SourceBranchName) + -DefaultBranch $(DefaultBranch) + -ConfigFileDir '${{ parameters.ConfigFileDir }}' + -BuildId $(Build.BuildId) + -RepoName $(Build.Repository.Name) + -Language ${{ parameters.Language }} + pwsh: true + workingDirectory: $(Pipeline.Workspace) + displayName: Create Automatic API Review + condition: >- + and( + succeededOrFailed(), + ne(variables['Skip.CreateApiReview'], 'true'), + ne(variables['Build.Reason'],'PullRequest'), + eq(variables['System.TeamProject'], 'internal'), + not(endsWith(variables['Build.Repository.Name'], '-pr')) + ) diff --git a/eng/pipelines/templates/steps/run_apistub.yml b/eng/pipelines/templates/steps/run_apistub.yml index aed6b44099f9..da6d1d744852 100644 --- a/eng/pipelines/templates/steps/run_apistub.yml +++ b/eng/pipelines/templates/steps/run_apistub.yml @@ -15,7 +15,7 @@ steps: condition: and(succeededOrFailed(), ne(variables['Skip.ApiStubGen'],'true')) - script: | - pip install -r eng/ci_tools.txt + python -m pip install -r eng/ci_tools.txt displayName: 'Prep Environment' - task: PythonScript@0 diff --git a/eng/pipelines/templates/steps/run_bandit.yml b/eng/pipelines/templates/steps/run_bandit.yml index 8780d5438553..c34b4b6e3776 100644 --- a/eng/pipelines/templates/steps/run_bandit.yml +++ b/eng/pipelines/templates/steps/run_bandit.yml @@ -11,7 +11,7 @@ parameters: # Please use `$(TargetingString)` to refer to the python packages glob string. This was previously `${{ parameters.BuildTargetingString }}`. steps: - script: | - pip install -r eng/ci_tools.txt + python -m pip install -r eng/ci_tools.txt displayName: 'Prep Environment' condition: and(succeededOrFailed(), ne(variables['Skip.Bandit'],'true')) diff --git a/eng/pipelines/templates/steps/run_black.yml b/eng/pipelines/templates/steps/run_black.yml index 85f2c9a68790..002f80b8279e 100644 --- a/eng/pipelines/templates/steps/run_black.yml +++ b/eng/pipelines/templates/steps/run_black.yml @@ -11,7 +11,7 @@ steps: condition: succeededOrFailed() - script: | - pip install black==22.3.0 tools/azure-sdk-tools["build"] + python -m pip install black==22.3.0 tools/azure-sdk-tools["build"] displayName: 'Prep Environment' condition: succeededOrFailed() diff --git a/eng/pipelines/templates/steps/run_mypy.yml b/eng/pipelines/templates/steps/run_mypy.yml index 4faa14c36a44..6a6b77ad0252 100644 --- a/eng/pipelines/templates/steps/run_mypy.yml +++ b/eng/pipelines/templates/steps/run_mypy.yml @@ -12,9 +12,9 @@ parameters: # Please use `$(TargetingString)` to refer to the python packages glob string. This was previously `${{ parameters.BuildTargetingString }}`. steps: - task: UsePythonVersion@0 - displayName: 'Use Python 3.10' + displayName: 'Use Python 3.7' inputs: - versionSpec: '3.10' + versionSpec: '3.7' condition: and(succeededOrFailed(), ne(variables['Skip.MyPy'],'true')) - script: | diff --git a/eng/pipelines/templates/steps/run_pylint.yml b/eng/pipelines/templates/steps/run_pylint.yml index b3eee4ed9556..94675703ec18 100644 --- a/eng/pipelines/templates/steps/run_pylint.yml +++ b/eng/pipelines/templates/steps/run_pylint.yml @@ -17,7 +17,7 @@ steps: condition: and(succeededOrFailed(), ne(variables['Skip.Pylint'],'true')) - script: | - pip install -r eng/ci_tools.txt + python -m pip install -r eng/ci_tools.txt displayName: 'Prep Environment' condition: and(succeededOrFailed(), ne(variables['Skip.Pylint'],'true')) diff --git a/eng/pipelines/templates/steps/run_pyright.yml b/eng/pipelines/templates/steps/run_pyright.yml index 3315fe422575..71635ff4b031 100644 --- a/eng/pipelines/templates/steps/run_pyright.yml +++ b/eng/pipelines/templates/steps/run_pyright.yml @@ -14,12 +14,12 @@ steps: displayName: 'Use Python 3.7' inputs: versionSpec: '3.7' - condition: and(succeededOrFailed(), ne(variables['Skip.Pyright'],'true')) + condition: and(succeededOrFailed(), or(ne(variables['Skip.Pyright'],'true'), ne(variables['Skip.Verifytypes'],'true'))) - script: | - pip install -r eng/ci_tools.txt + python -m pip install -r eng/ci_tools.txt displayName: 'Prep Environment' - condition: and(succeededOrFailed(), ne(variables['Skip.Pyright'],'true')) + condition: and(succeededOrFailed(), or(ne(variables['Skip.Pyright'],'true'), ne(variables['Skip.Verifytypes'],'true'))) - task: PythonScript@0 displayName: 'Run Pyright' @@ -43,4 +43,4 @@ steps: --service="${{ parameters.ServiceDirectory }}" --toxenv="verifytypes" --disablecov - condition: and(succeededOrFailed(), ne(variables['Skip.Pyright'],'true')) + condition: and(succeededOrFailed(), ne(variables['Skip.Verifytypes'],'true')) diff --git a/eng/pipelines/templates/steps/seed-virtualenv-wheels.yml b/eng/pipelines/templates/steps/seed-virtualenv-wheels.yml index 73e1c91e5497..a3a178ca7a9f 100644 --- a/eng/pipelines/templates/steps/seed-virtualenv-wheels.yml +++ b/eng/pipelines/templates/steps/seed-virtualenv-wheels.yml @@ -5,7 +5,7 @@ parameters: steps: - pwsh: | - pip install virtualenv + python -m pip install virtualenv displayName: Ensure virtualenv installed - pwsh: | diff --git a/eng/pipelines/templates/steps/set-dev-build.yml b/eng/pipelines/templates/steps/set-dev-build.yml index 78adeb941eef..a8b5cc68ecae 100644 --- a/eng/pipelines/templates/steps/set-dev-build.yml +++ b/eng/pipelines/templates/steps/set-dev-build.yml @@ -13,7 +13,7 @@ steps: ServiceDirectory: ${{ parameters.ServiceDirectory }} - pwsh: | - pip install "tools/azure-sdk-tools[build]" + python -m pip install "tools/azure-sdk-tools[build]" sdk_set_dev_version "$(TargetingString)" --service="${{parameters.ServiceDirectory}}" --build-id="$(Build.BuildNumber)" displayName: "Update package versions for dev build" condition: and(succeededOrFailed(), eq(variables['SetDevVersion'],'true')) diff --git a/eng/pipelines/templates/steps/use-python-version.yml b/eng/pipelines/templates/steps/use-python-version.yml index e49f9084d7a1..9520e4f1a8f0 100644 --- a/eng/pipelines/templates/steps/use-python-version.yml +++ b/eng/pipelines/templates/steps/use-python-version.yml @@ -9,7 +9,7 @@ steps: versionSpec: 3.8 - pwsh: | - pip install packaging==20.4 + python -m pip install packaging==20.4 displayName: Prep Environment # select the appropriate version from manifest if present diff --git a/eng/regression_tools.txt b/eng/regression_tools.txt index 87cea579a85b..fc9756657305 100644 --- a/eng/regression_tools.txt +++ b/eng/regression_tools.txt @@ -1,7 +1,7 @@ # requirements leveraged by ci tools cryptography==3.3.2 setuptools==44.1.0; python_version == '2.7' -setuptools==46.4.0; python_version >= '3.5' +setuptools==67.6.0; python_version >= '3.5' virtualenv==20.0.23 wheel==0.34.2 Jinja2==2.11.2 diff --git a/eng/tox/run_mypy.py b/eng/tox/run_mypy.py index 4d1a5b39a8bf..36ec13109727 100644 --- a/eng/tox/run_mypy.py +++ b/eng/tox/run_mypy.py @@ -33,9 +33,16 @@ required=True, ) + parser.add_argument( + "--next", + default=False, + help="Next version of mypy is being tested.", + required=False + ) + args = parser.parse_args() package_name = os.path.basename(os.path.abspath(args.target_package)) - if in_ci(): + if not args.next and in_ci(): if not is_check_enabled(args.target_package, "mypy", True) or is_typing_ignored(package_name): logging.info( f"Package {package_name} opts-out of mypy check. See https://aka.ms/python/typing-guide for information." @@ -47,7 +54,7 @@ "-m", "mypy", "--python-version", - "3.10", + "3.7", "--show-error-codes", "--ignore-missing-imports", ] @@ -62,7 +69,7 @@ except CalledProcessError as src_err: src_code_error = src_err - if in_ci() and not is_check_enabled(args.target_package, "type_check_samples", True): + if not args.next and in_ci() and not is_check_enabled(args.target_package, "type_check_samples", True): logging.info( f"Package {package_name} opts-out of mypy check on samples." ) diff --git a/eng/tox/run_pyright.py b/eng/tox/run_pyright.py index 2e155df90df7..ef6f205ef5d4 100644 --- a/eng/tox/run_pyright.py +++ b/eng/tox/run_pyright.py @@ -33,10 +33,17 @@ required=True, ) + parser.add_argument( + "--next", + default=False, + help="Next version of pyright is being tested.", + required=False + ) + args = parser.parse_args() package_name = os.path.basename(os.path.abspath(args.target_package)) - if in_ci(): + if not args.next and in_ci(): if not is_check_enabled(args.target_package, "pyright") or is_typing_ignored(package_name): logging.info( f"Package {package_name} opts-out of pyright check. See https://aka.ms/python/typing-guide for information." @@ -48,7 +55,7 @@ os.path.join(args.target_package, "samples"), ] - if in_ci(): + if not args.next and in_ci(): if not is_check_enabled(args.target_package, "type_check_samples"): logging.info( f"Package {package_name} opts-out of pyright check on samples." diff --git a/eng/tox/tox.ini b/eng/tox/tox.ini index c374df435445..a8c438310d15 100644 --- a/eng/tox/tox.ini +++ b/eng/tox/tox.ini @@ -62,7 +62,7 @@ setenv = PROXY_URL=http://localhost:5000 VIRTUALENV_WHEEL=0.37.0 VIRTUALENV_PIP=20.3.3 - VIRTUALENV_SETUPTOOLS=59.6.0 + VIRTUALENV_SETUPTOOLS=67.6.0 deps = {[base]deps} changedir = {toxinidir} install_command = python -m pip install {opts} {packages} --cache-dir {toxinidir}/../.tox_pip_cache_{envname} --ignore-installed @@ -125,7 +125,7 @@ setenv = PROXY_URL=http://localhost:5003 deps = {[base]deps} - mypy==0.931 + mypy==1.0.0 types-chardet==4.0.3 types-requests==2.27.9 types-six==1.16.10 @@ -138,6 +138,29 @@ commands = --package-type sdist {envbindir}/python {toxinidir}/../../../eng/tox/run_mypy.py -t {toxinidir} +[testenv:next-mypy] +skipsdist = true +skip_install = true +usedevelop = true +changedir = {toxinidir} +setenv = + {[testenv]setenv} + PROXY_URL=http://localhost:5020 +deps = + {[base]deps} + mypy + types-chardet + types-requests + types-six + types-redis +commands = + {envbindir}/python {toxinidir}/../../../eng/tox/create_package_and_install.py \ + -d {distdir} \ + -p {toxinidir} \ + -w {envtmpdir} \ + --package-type sdist + {envbindir}/python {toxinidir}/../../../eng/tox/run_mypy.py -t {toxinidir} --next=True + [testenv:pyright] skipsdist = true @@ -160,6 +183,29 @@ commands = -p {toxinidir} {envbindir}/python {toxinidir}/../../../eng/tox/run_pyright.py -t {toxinidir} + +[testenv:next-pyright] +skipsdist = true +skip_install = true +usedevelop = true +changedir = {toxinidir} +setenv = + {[testenv]setenv} + PROXY_URL=http://localhost:5021 +deps = + {[base]deps} + pyright +commands = + {envbindir}/python {toxinidir}/../../../eng/tox/create_package_and_install.py \ + -d {distdir} \ + -p {toxinidir} \ + -w {envtmpdir} \ + --package-type sdist + {envbindir}/python {toxinidir}/../../../eng/tox/create_dependencies_and_install.py \ + -p {toxinidir} + {envbindir}/python {toxinidir}/../../../eng/tox/run_pyright.py -t {toxinidir} --next=True + + [testenv:verifytypes] skipsdist = true skip_install = true diff --git a/scripts/analyze_deps.py b/scripts/analyze_deps.py deleted file mode 100755 index 84f3cd17c598..000000000000 --- a/scripts/analyze_deps.py +++ /dev/null @@ -1,420 +0,0 @@ -#!/usr/bin/env python -from __future__ import print_function, unicode_literals -import argparse -import ast -from datetime import datetime -import glob -import io -import json -import os -from pkg_resources import Requirement -import re -import sys -import textwrap - -# Todo: This should use a common omit logic once ci scripts are refactored into ci_tools -skip_pkgs = [ - 'azure-mgmt-documentdb', # deprecated - 'azure-sdk-for-python', # top-level package - 'azure-sdk-tools', # internal tooling for automation - 'azure-servicemanagement-legacy', # legacy (not officially deprecated) - 'azure-common', - 'azure', - 'azure-keyvault', - 'azure-ai-ml' -] - -def report_should_skip_lib(lib_name): - return lib_name in skip_pkgs or lib_name.endswith('-nspkg') - -def dump_should_skip_lib(lib_name): - return report_should_skip_lib(lib_name) or '-mgmt' in lib_name or not lib_name.startswith('azure') - -def locate_libs(base_dir): - packages = [os.path.dirname(p) for p in (glob.glob(os.path.join(base_dir, 'azure*', 'setup.py')) + glob.glob(os.path.join(base_dir, 'sdk/*/azure*', 'setup.py')))] - return sorted(packages) - -def locate_wheels(base_dir): - wheels = glob.glob(os.path.join(base_dir, '*.whl')) - return sorted(wheels) - -def parse_req(req): - try: - req_object = Requirement.parse(req.split(";")[0]) - req_name = req_object.key - spec = str(req_object).replace(req_name, '') - return (req_name, spec) - except: - print('Failed to parse requirement %s' % (req)) - -def record_dep(dependencies, req_name, spec, lib_name): - if not req_name in dependencies: - dependencies[req_name] = {} - if not spec in dependencies[req_name]: - dependencies[req_name][spec] = [] - dependencies[req_name][spec].append(lib_name) - - -def get_lib_deps(base_dir): - packages = {} - dependencies = {} - for lib_dir in locate_libs(base_dir): - try: - setup_path = os.path.join(lib_dir, 'setup.py') - lib_name, version, requires = parse_setup(setup_path) - - packages[lib_name] = { - 'version': version, - 'source': lib_dir, - 'deps': [] - } - - for req in requires: - req_name, spec = parse_req(req) - packages[lib_name]['deps'].append({ - 'name': req_name, - 'version': spec - }) - if not report_should_skip_lib(lib_name): - record_dep(dependencies, req_name, spec, lib_name) - except: - print('Failed to parse %s' % (setup_path)) - return packages, dependencies - -def get_wheel_deps(wheel_dir): - from wheel.pkginfo import read_pkg_info_bytes - from wheel.wheelfile import WheelFile - - packages = {} - dependencies = {} - for whl_path in locate_wheels(wheel_dir): - try: - with WheelFile(whl_path) as whl: - pkg_info = read_pkg_info_bytes(whl.read(whl.dist_info_path + '/METADATA')) - lib_name = pkg_info.get('Name') - - packages[lib_name] = { - 'version': pkg_info.get('Version'), - 'source': whl_path, - 'deps': [] - } - - requires = pkg_info.get_all('Requires-Dist') - for req in requires: - req = req.split(';')[0] # Extras conditions appear after a semicolon - req = re.sub(r'[\s\(\)]', '', req) # Version specifiers appear in parentheses - req_name, spec = parse_req(req) - packages[lib_name]['deps'].append({ - 'name': req_name, - 'version': spec - }) - if not report_should_skip_lib(lib_name): - record_dep(dependencies, req_name, spec, lib_name) - except: - print('Failed to parse METADATA from %s' % (whl_path)) - return packages, dependencies - -def parse_setup(setup_filename): - mock_setup = textwrap.dedent('''\ - def setup(*args, **kwargs): - __setup_calls__.append((args, kwargs)) - ''') - parsed_mock_setup = ast.parse(mock_setup, filename=setup_filename) - with io.open(setup_filename, 'r', encoding='utf-8-sig') as setup_file: - parsed = ast.parse(setup_file.read()) - for index, node in enumerate(parsed.body[:]): - if ( - not isinstance(node, ast.Expr) or - not isinstance(node.value, ast.Call) or - not hasattr(node.value.func, 'id') or - node.value.func.id != 'setup' - ): - continue - parsed.body[index:index] = parsed_mock_setup.body - break - - fixed = ast.fix_missing_locations(parsed) - codeobj = compile(fixed, setup_filename, 'exec') - local_vars = {} - global_vars = {'__setup_calls__': []} - current_dir = os.getcwd() - working_dir = os.path.dirname(setup_filename) - os.chdir(working_dir) - exec(codeobj, global_vars, local_vars) - os.chdir(current_dir) - _, kwargs = global_vars['__setup_calls__'][0] - - version = kwargs['version'] - name = kwargs['name'] - requires = [] - if 'install_requires' in kwargs: - requires += kwargs['install_requires'] - if 'extras_require' in kwargs: - for extra in kwargs['extras_require'].values(): - requires += extra - return name, version, requires - -def dict_compare(d1, d2): - d1_keys = set(d1.keys()) - d2_keys = set(d2.keys()) - intersect_keys = d1_keys.intersection(d2_keys) - added = d1_keys - d2_keys - removed = d2_keys - d1_keys - modified = {o : (d1[o], d2[o]) for o in intersect_keys if d1[o] != d2[o]} - return added, removed, modified - -def render_report(output_path, report_context): - env = Environment( - loader=FileSystemLoader(os.path.dirname(os.path.realpath(__file__))) - ) - template = env.get_template('deps.html.j2') - with io.open(output_path, 'w', encoding='utf-8') as output: - output.write(template.render(report_context)) - -def get_dependent_packages(data_pkgs): - # Get unique set of Azure SDK packages that are added as required package - deps = [] - for v in data_pkgs.values(): - deps.extend([dep['name'] for dep in v['deps'] if not dump_should_skip_lib(dep['name'])]) - return set(deps) - -def dump_packages(data_pkgs): - dump_data = {} - unique_dependent_packages = get_dependent_packages(data_pkgs) - for p_name, p_data in data_pkgs.items(): - p_id = p_name + ':' + p_data['version'] - dep = [p for p in p_data['deps'] if not dump_should_skip_lib(p['name'])] - # Add package if it requires other azure sdk package or if it is added as required by other sdk package - if len(dep) > 0 or p_name in unique_dependent_packages: - dump_data[p_id] = { - 'name': p_name, - 'version': p_data['version'], - 'type': 'internal', - 'deps': dep - } - - return dump_data - -def resolve_lib_deps(dump_data, data_pkgs, pkg_id): - for dep in dump_data[pkg_id]['deps']: - dep_req = Requirement.parse(dep['name'] + dep['version']) - if dep['name'] in data_pkgs and data_pkgs[dep['name']]['version'] in dep_req: - # If the internal package version matches the dependency spec, - # rewrite the dep version to match the internal package version - dep['version'] = data_pkgs[dep['name']]['version'] - else: - dep_id = dep['name'] + ':' + dep['version'] - if not dep_id in dump_data: - dump_data[dep_id] = { - 'name': dep['name'], - 'version': dep['version'], - 'type': 'internalbinary' if dep['name'] in data_pkgs else 'external', - 'deps': [] - } - -if __name__ == '__main__': - base_dir = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) - - parser = argparse.ArgumentParser(description='''\ - Analyze dependencies in Python packages. First, all declared dependencies - and the libraries that declare them will be discovered (visible with - --verbose). Next, all declared dependency version specs will be analyzed to - ensure they are consistent across all libraries. Finally, all declared - dependency version specs will be compared to the frozen version specs in - shared_requirements.txt, or if --freeze is provided, all declared dependency - version specs will be frozen to shared_requirements.txt. - ''') - parser.add_argument('--verbose', help='verbose output', action='store_true') - parser.add_argument('--freeze', help='freeze dependencies after analyzing (otherwise, validate dependencies against frozen list)', action='store_true') - parser.add_argument('--out', metavar='FILE', help='write HTML-formatted report to FILE') - parser.add_argument('--dump', metavar='FILE', help='write JSONP-formatted dependency data to FILE') - parser.add_argument('--wheeldir', metavar='DIR', help='analyze wheels in DIR rather than source packages in this repository') - args = parser.parse_args() - - if args.out: - try: - from jinja2 import Environment, FileSystemLoader - except: - print("Jinja2 is required to render the dependency report. Please install with 'pip install Jinja2' to use this option.") - sys.exit(1) - - if args.wheeldir: - all_packages, dependencies = get_wheel_deps(args.wheeldir) - else: - all_packages, dependencies = get_lib_deps(base_dir) - - packages = {k: v for k,v in all_packages.items() if not report_should_skip_lib(k)} - - if args.verbose: - print('Packages analyzed') - print('=================') - for package in sorted(packages.keys()): - info = packages[package] - print("%s %s" % (package, info['version'])) - print(" from %s" % (info['source'])) - - print('\n\nRequirements discovered') - print('=======================') - for requirement in sorted(dependencies.keys()): - specs = dependencies[requirement] - libs = [] - print('%s' % (requirement)) - for spec in specs.keys(): - print('%s' % (spec if spec else '(empty)')) - for lib in specs[spec]: - print(' * %s' % (lib)) - print('') - - inconsistent = [] - for requirement in sorted(dependencies.keys()): - specs = dependencies[requirement] - num_specs = len(specs) - if num_specs == 1: - continue - - if not inconsistent and args.verbose: - print('\nInconsistencies detected') - print('========================') - - inconsistent.append(requirement) - if args.verbose: - print("Requirement '%s' has %s unique specifiers:" % (requirement, num_specs)) - for spec in sorted(specs.keys()): - libs = specs[spec] - friendly_spec = '(none)' if spec == '' else spec - print(" '%s'" % (friendly_spec)) - print(' ' + ('-' * (len(friendly_spec) + 2))) - for lib in sorted(libs): - print(' * %s' % (lib)) - print('') - - frozen_filename = os.path.join(base_dir, 'shared_requirements.txt') - if args.freeze: - if inconsistent: - print('Unable to freeze requirements due to incompatible dependency versions') - sys.exit(1) - else: - with io.open(frozen_filename, 'w', encoding='utf-8') as frozen_file: - for requirement in sorted(dependencies.keys()): - spec = list(dependencies[requirement].keys())[0] - if spec == '': - print("Requirement '%s' being frozen with no version spec" % requirement) - frozen_file.write(requirement + spec + '\n') - print('Current requirements frozen to %s' % (frozen_filename)) - sys.exit(0) - - frozen = {} - overrides = {} - override_count = 0 - try: - with io.open(frozen_filename, 'r', encoding='utf-8-sig') as frozen_file: - for line in frozen_file: - if line.startswith('#override'): - _, lib_name, req_override = line.split(' ', 2) - req_override_name, override_spec = parse_req(req_override) - record_dep(overrides, req_override_name, override_spec, lib_name) - override_count += 1 - elif not line.startswith('#'): - req_name, spec = parse_req(line) - frozen[req_name] = [spec] - except: - print('Unable to open shared_requirements.txt, shared requirements have not been validated') - - missing_reqs, new_reqs, changed_reqs = {}, {}, {} - non_overridden_reqs_count = 0 - exitcode = 0 - if frozen: - flat_deps = {req: sorted(dependencies[req].keys()) for req in dependencies} - missing_reqs, new_reqs, changed_reqs = dict_compare(frozen, flat_deps) - if args.verbose and len(overrides) > 0: - print('\nThe following requirement overrides are in place:') - for overridden_req in overrides: - for spec in overrides[overridden_req]: - libs = ', '.join(sorted(overrides[overridden_req][spec])) - print(' * %s is allowed for %s' % (overridden_req + spec, libs)) - if args.verbose and len(missing_reqs) > 0: - print('\nThe following requirements are frozen but do not exist in any current library:') - for missing_req in missing_reqs: - [spec] = frozen[missing_req] - print(' * %s' % (missing_req + spec)) - if len(new_reqs) > 0: - exitcode = 1 - if args.verbose: - for new_req in new_reqs: - for spec in dependencies[new_req]: - libs = dependencies[new_req][spec] - print("\nRequirement '%s' is declared in the following libraries but has not been frozen:" % (new_req + spec)) - for lib in libs: - print(" * %s" % (lib)) - if len(changed_reqs) > 0: - for changed_req in changed_reqs: - frozen_specs, current_specs = changed_reqs[changed_req] - unmatched_specs = set(current_specs) - set(frozen_specs) - override_specs = overrides.get(changed_req, []) - - for spec in unmatched_specs: - if spec in override_specs: - non_overridden_libs = set(dependencies[changed_req][spec]) - set(override_specs[spec]) - else: - non_overridden_libs = dependencies[changed_req][spec] - - if len(non_overridden_libs) > 0: - exitcode = 1 - non_overridden_reqs_count += 1 - if args.verbose: - print("\nThe following libraries declare requirement '%s' which does not match the frozen requirement '%s':" % (changed_req + spec, changed_req + frozen_specs[0])) - for lib in non_overridden_libs: - print(" * %s" % (lib)) - if exitcode == 0: - if args.verbose: - print('') - print('All library dependencies validated against frozen requirements') - elif not args.verbose: - print('Library dependencies do not match frozen requirements, run this script with --verbose for details') - elif inconsistent: - exitcode = 1 - - if exitcode == 1: - if not args.verbose: - print('\nIncompatible dependency versions detected in libraries, run this script with --verbose for details') - else: - print('\nAll library dependencies verified, no incompatible versions detected') - - if args.out: - external = [k for k in dependencies if k not in packages and not report_should_skip_lib(k)] - def display_order(k): - if k in inconsistent: - return 'a' + k if k in external else 'b' + k - else: - return 'c' + k if k in external else 'd' + k - - render_report(args.out, { - 'changed_reqs': changed_reqs, - 'curtime': datetime.utcnow(), - 'dependencies': dependencies, - 'env': os.environ, - 'external': external, - 'frozen': frozen, - 'inconsistent': inconsistent, - 'missing_reqs': missing_reqs, - 'new_reqs': new_reqs, - 'non_overridden_reqs_count': non_overridden_reqs_count, - 'ordered_deps': sorted(dependencies.keys(), key=display_order), - 'override_count': override_count, - 'overrides': overrides, - 'packages': packages, - 'repo_name': 'azure-sdk-for-python' - }) - - if args.dump: - data_pkgs = {k: v for k, v in all_packages.items() if not dump_should_skip_lib(k)} - dump_data = dump_packages(data_pkgs) - pkg_ids = [k for k in dump_data.keys()] - for pkg_id in pkg_ids: - resolve_lib_deps(dump_data, data_pkgs, pkg_id) - with io.open(f"{args.dump}/data.js", 'w', encoding='utf-8') as dump_file: - dump_file.write('const data = ' + json.dumps(dump_data) + ';') - with io.open(f"{args.dump}/arcdata.json", 'w', encoding='utf-8') as dump_file: - dump_file.write(json.dumps(dump_data)) - - sys.exit(exitcode) diff --git a/scripts/auto_release/PythonSdkLiveTest.yml b/scripts/auto_release/PythonSdkLiveTest.yml index 0edf376164bc..7e3b543000a9 100644 --- a/scripts/auto_release/PythonSdkLiveTest.yml +++ b/scripts/auto_release/PythonSdkLiveTest.yml @@ -71,7 +71,7 @@ jobs: # create virtual env python -m venv venv-sdk source venv-sdk/bin/activate - pip install -r $script_path/requirement.txt + python -m pip install -r $script_path/requirement.txt # import env variable export AZURE_TEST_RUN_LIVE=$(AZURE_TEST_RUN_LIVE) diff --git a/scripts/auto_release/main.py b/scripts/auto_release/main.py index c499fbeaf574..81cfc7d5d6d6 100644 --- a/scripts/auto_release/main.py +++ b/scripts/auto_release/main.py @@ -398,53 +398,6 @@ def check_changelog_file(self): else: self.edit_changelog() - @staticmethod - def get_need_dependency() -> List[str]: - template_path = Path('tools/azure-sdk-tools/packaging_tools/templates/packaging_files/setup.py') - items = ["msrest>", "azure-mgmt-core", "typing-extensions"] - with open(template_path, 'r') as fr: - content = fr.readlines() - dependencies = [] - for i in range(len(content)): - if "install_requires" not in content[i]: - continue - for j in range(i, len(content)): - for item in items: - if item in content[j]: - dependencies.append(content[j].strip().strip(',').strip('\"')) - break - return dependencies - - @staticmethod - def insert_line_num(content: List[str]) -> int: - start_num = 0 - end_num = len(content) - for i in range(end_num): - if content[i].find("#override azure-mgmt-") > -1: - start_num = i - break - return (int(str(time.time()).split('.')[-1]) % max(end_num - start_num, 1)) + start_num - - def check_ci_file_proc(self, dependency: str): - def edit_ci_file(content: List[str]): - new_line = f'#override azure-mgmt-{self.package_name} {dependency}' - dependency_name = re.compile("[a-zA-Z-]*").findall(dependency)[0] - for i in range(len(content)): - if new_line in content[i]: - return - if f'azure-mgmt-{self.package_name} {dependency_name}' in content[i]: - content[i] = new_line + '\n' - return - content.insert(self.insert_line_num(content), new_line + '\n') - - modify_file(str(Path('shared_requirements.txt')), edit_ci_file) - print_exec('git add shared_requirements.txt') - - def check_ci_file(self): - # eg: 'msrest>=0.6.21', 'azure-mgmt-core>=1.3.0,<2.0.0' - for item in self.get_need_dependency(): - self.check_ci_file_proc(item) - def check_dev_requirement(self): file = Path(f'sdk/{self.sdk_folder}/azure-mgmt-{self.package_name}/dev_requirements.txt') content = [ @@ -462,7 +415,6 @@ def check_file(self): self.check_sdk_readme() self.check_version() self.check_changelog_file() - self.check_ci_file() self.check_dev_requirement() def sdk_code_path(self) -> str: diff --git a/scripts/cadl_refresh_sdk/README.md b/scripts/cadl_refresh_sdk/README.md index 64b9a049adbd..75f38aaeba27 100644 --- a/scripts/cadl_refresh_sdk/README.md +++ b/scripts/cadl_refresh_sdk/README.md @@ -1,12 +1,15 @@ # Overview + The script is to refresh SDK code -# Prerequisites -1. Install [Powershell 7+](https://learn.microsoft.com/en-us/shows/it-ops-talk/how-to-install-powershell-7) +## Prerequisites + +1. Install [Powershell 7+](https://learn.microsoft.com/shows/it-ops-talk/how-to-install-powershell-7) 2. Install [Python 3.7+](https://www.python.org/downloads/release/python-370/) 3. Install [Nodejs](https://nodejs.org/en/download/) -# Usage +## Usage + Step into root folder of this repo and run cmd with sdk folder: ```powershell D:\azure-sdk-for-python> python .\scripts\cadl_refresh_sdk\main.py .\sdk\contosowidgetmanager\azure-contosowidgetmanager diff --git a/scripts/collect_api_version_for_multi_api_sdk/collect_api_version.yml b/scripts/collect_api_version_for_multi_api_sdk/collect_api_version.yml index 8e9264a5e801..475f84fc3ed1 100644 --- a/scripts/collect_api_version_for_multi_api_sdk/collect_api_version.yml +++ b/scripts/collect_api_version_for_multi_api_sdk/collect_api_version.yml @@ -43,7 +43,7 @@ jobs: # create virtual env python -m venv venv-sdk source venv-sdk/bin/activate - pip install -r $script_path/requirement.txt + python -m pip install -r $script_path/requirement.txt # run cd file-storage diff --git a/scripts/devops_tasks/test_run_samples.py b/scripts/devops_tasks/test_run_samples.py index 3bab7862b540..2d660d028eb0 100644 --- a/scripts/devops_tasks/test_run_samples.py +++ b/scripts/devops_tasks/test_run_samples.py @@ -90,11 +90,13 @@ "sample_publish_events_to_a_topic_using_sas_credential_async.py" ], "azure-eventhub": [ + "client_identity_authentication.py", # TODO: remove after fixing issue #29177 "connection_to_custom_endpoint_address.py", "proxy.py", "connection_to_custom_endpoint_address_async.py", "iot_hub_connection_string_receive_async.py", "proxy_async.py", + "send_stream.py", # TODO: remove after fixing issue #29177 ], "azure-eventhub-checkpointstoretable": ["receive_events_using_checkpoint_store.py"], "azure-servicebus": [ diff --git a/scripts/issue_helper/issue_helper.yml b/scripts/issue_helper/issue_helper.yml index d30ff672c6cf..c33f12f06582 100644 --- a/scripts/issue_helper/issue_helper.yml +++ b/scripts/issue_helper/issue_helper.yml @@ -55,7 +55,7 @@ jobs: # create virtual env python -m venv venv-sdk source venv-sdk/bin/activate - pip install -r $script_path/requirement.txt + python -m pip install -r $script_path/requirement.txt # checkout the target branch cd file-storage diff --git a/scripts/release_helper/release_helper.yml b/scripts/release_helper/release_helper.yml index 6f4762a0023a..1903fb810d12 100644 --- a/scripts/release_helper/release_helper.yml +++ b/scripts/release_helper/release_helper.yml @@ -61,7 +61,7 @@ jobs: # create virtual env python -m venv venv-sdk source venv-sdk/bin/activate - pip install -r $script_path/requirement.txt + python -m pip install -r $script_path/requirement.txt # checkout the target branch cd file-storage diff --git a/scripts/release_sdk_status/release_sdk_status.yml b/scripts/release_sdk_status/release_sdk_status.yml index 1d29825bfde1..a0228cb56d4c 100644 --- a/scripts/release_sdk_status/release_sdk_status.yml +++ b/scripts/release_sdk_status/release_sdk_status.yml @@ -65,7 +65,7 @@ jobs: # create virtual env python -m venv venv-sdk source venv-sdk/bin/activate - pip install -r $script_path/requirement.txt + python -m pip install -r $script_path/requirement.txt # checkout the target branch cd file-storage diff --git a/sdk/agrifood/azure-agrifood-farming/CHANGELOG.md b/sdk/agrifood/azure-agrifood-farming/CHANGELOG.md index df23e2d99083..4b009ccbc80f 100644 --- a/sdk/agrifood/azure-agrifood-farming/CHANGELOG.md +++ b/sdk/agrifood/azure-agrifood-farming/CHANGELOG.md @@ -1,5 +1,15 @@ # Release History +## 1.0.0b3 (Unreleased) + +### Features Added + +### Breaking Changes + +### Bugs Fixed + +### Other Changes + ## 1.0.0b2 (2023-02-23) ### Features Added - Adding clients for Sensor Integration which includes crud operations on DeviceDataModels, Devices, SensorDataModels, Sensors, SensorMappings, SensorPartnerIntegration and get Sensor events. diff --git a/sdk/agrifood/azure-agrifood-farming/azure/agrifood/farming/_version.py b/sdk/agrifood/azure-agrifood-farming/azure/agrifood/farming/_version.py index dfa6ee022f15..20971492f129 100644 --- a/sdk/agrifood/azure-agrifood-farming/azure/agrifood/farming/_version.py +++ b/sdk/agrifood/azure-agrifood-farming/azure/agrifood/farming/_version.py @@ -6,4 +6,4 @@ # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- -VERSION = "1.0.0b2" +VERSION = "1.0.0b3" diff --git a/sdk/appconfiguration/azure-appconfiguration-provider/CHANGELOG.md b/sdk/appconfiguration/azure-appconfiguration-provider/CHANGELOG.md index 950e8b47b062..3b9b509a12cd 100644 --- a/sdk/appconfiguration/azure-appconfiguration-provider/CHANGELOG.md +++ b/sdk/appconfiguration/azure-appconfiguration-provider/CHANGELOG.md @@ -1,6 +1,6 @@ # Release History -## 1.0.0b3 (Unreleased) +## 1.0.1 (Unreleased) ### Features Added @@ -10,6 +10,18 @@ ### Other Changes +## 1.0.0 (2023-03-09) + +### Breaking Changes +* Renamed `load_provider` to `load` +* Added `AzureAppConfigurationKeyVaultOptions` to take in a `client_configs` a Mapping of endpoints to client kwargs instead of taking in the whole client. +* Removed `AzureAppConfigurationKeyVaultOptions` `secret_clients`, `client_configs` should be used instead. +* Made key_filter and label_filter kwargs for Setting Selector +* Renamed `trimmed_key_prefixes` to `trim_prefixes` + +### Other Changes +* Made EMPTY_LABEL a constant. i.e. "\0" + ## 1.0.0b2 (2023-02-15) ### Features Added diff --git a/sdk/appconfiguration/azure-appconfiguration-provider/README.md b/sdk/appconfiguration/azure-appconfiguration-provider/README.md index 8c5b08fa250f..72a743e2c669 100644 --- a/sdk/appconfiguration/azure-appconfiguration-provider/README.md +++ b/sdk/appconfiguration/azure-appconfiguration-provider/README.md @@ -21,13 +21,13 @@ Alternatively, get the connection string from the Azure Portal. You can create a client with a connection string: ```python -config = load_provider(connection_string="your-connection-string") +config = load(connection_string="your-connection-string") ``` or with AAD: ```python -config = load_provider(endpoint="your-endpoint", credential=DefaultAzureCredential()) +config = load(endpoint="your-endpoint", credential=DefaultAzureCredential()) ``` these providers will by default load all configurations with `(No Label)` from your configuration store. @@ -60,7 +60,7 @@ You can refine or expand the configurations loaded from your store by using `Set ```python selects = {SettingSelector(key_filter="*", label_filter="\0"), SettingSelector(key_filter="*", label_filter="dev")} -config = load_provider(endpoint=endpoint, credential=DefaultAzureCredential(), selects=selects) +config = load(endpoint=endpoint, credential=DefaultAzureCredential(), selects=selects) ``` In this example all configuration with empty label and the dev label are loaded. Because the dev selector is listed last, any configurations from dev take priority over those with `(No Label)` when duplicates are found. @@ -69,8 +69,8 @@ In this example all configuration with empty label and the dev label are loaded. You can trim the prefix off of keys by providing a list of trimmed key prefixes to the provider. For example, if you have the key(s) like `/application/message` in your configuration store, you could trim `/application/` from them. ```python -trimmed_key_prefixes={"/application/"} -config = load_provider(endpoint=endpoint, credential=DefaultAzureCredential(), trimmed_key_prefixes=trimmed_key_prefixes) +trim_prefixes={"/application/"} +config = load(endpoint=endpoint, credential=DefaultAzureCredential(), trim_prefixes=trim_prefixes) print(config["message"]) ``` @@ -84,7 +84,7 @@ You can provide `AzureAppConfigurationKeyVaultOptions` with a credential and all ```python key_vault_options = AzureAppConfigurationKeyVaultOptions(credential=DefaultAzureCredential()) -config = load_provider(endpoint=endpoint, credential=DefaultAzureCredential(), key_vault_options=key_vault_options) +config = load(endpoint=endpoint, credential=DefaultAzureCredential(), key_vault_options=key_vault_options) ``` ### With Clients @@ -92,9 +92,8 @@ You can provide `AzureAppConfigurationKeyVaultOptions` with a list of `SecretCli ```python key_vault_options = AzureAppConfigurationKeyVaultOptions( - secret_clients={SecretClient( - vault_url=key_vault_uri, credential=DefaultAzureCredential())}) -config = load_provider(endpoint=endpoint, credential=DefaultAzureCredential(), key_vault_options=key_vault_options) + client_configs={key_vault_uri: {'credential': credential}}) +config = load(endpoint=endpoint, credential=DefaultAzureCredential(), key_vault_options=key_vault_options) ``` ### Secret Resolver @@ -107,7 +106,7 @@ def secret_resolver(uri): key_vault_options = AzureAppConfigurationKeyVaultOptions( secret_resolver=secret_resolver) -config = load_provider(endpoint=endpoint, credential=DefaultAzureCredential(), key_vault_options=key_vault_options) +config = load(endpoint=endpoint, credential=DefaultAzureCredential(), key_vault_options=key_vault_options) ``` ## Key concepts @@ -116,6 +115,12 @@ config = load_provider(endpoint=endpoint, credential=DefaultAzureCredential(), k ## Next steps +Check out our Django and Flask examples to see how to use the provider in a web application. + +### [Django](https://github.com/Azure/AppConfiguration/tree/main/examples/Python/python-django-webapp-sample) + +### [Flask](https://github.com/Azure/AppConfiguration/tree/main/examples/Python/python-flask-webapp-sample) + ## Contributing This project welcomes contributions and suggestions. Most contributions require diff --git a/sdk/appconfiguration/azure-appconfiguration-provider/azure/appconfiguration/provider/__init__.py b/sdk/appconfiguration/azure-appconfiguration-provider/azure/appconfiguration/provider/__init__.py index a6044d7c6a86..5fb1f75adc33 100644 --- a/sdk/appconfiguration/azure-appconfiguration-provider/azure/appconfiguration/provider/__init__.py +++ b/sdk/appconfiguration/azure-appconfiguration-provider/azure/appconfiguration/provider/__init__.py @@ -4,14 +4,14 @@ # license information. # ------------------------------------------------------------------------- -from ._azureappconfigurationprovider import load_provider, AzureAppConfigurationProvider +from ._azureappconfigurationprovider import load, AzureAppConfigurationProvider from ._models import AzureAppConfigurationKeyVaultOptions, SettingSelector from ._version import VERSION __version__ = VERSION __all__ = [ - "load_provider", + "load", "AzureAppConfigurationProvider", "AzureAppConfigurationKeyVaultOptions", "SettingSelector" diff --git a/sdk/appconfiguration/azure-appconfiguration-provider/azure/appconfiguration/provider/_azureappconfigurationprovider.py b/sdk/appconfiguration/azure-appconfiguration-provider/azure/appconfiguration/provider/_azureappconfigurationprovider.py index 7b68c4609216..67dab9627411 100644 --- a/sdk/appconfiguration/azure-appconfiguration-provider/azure/appconfiguration/provider/_azureappconfigurationprovider.py +++ b/sdk/appconfiguration/azure-appconfiguration-provider/azure/appconfiguration/provider/_azureappconfigurationprovider.py @@ -5,7 +5,7 @@ # ------------------------------------------------------------------------- import os import json -from typing import Any, Dict, Iterable, Mapping, Optional, overload, List, Tuple, TYPE_CHECKING +from typing import Any, Dict, Iterable, Mapping, Optional, overload, List, Tuple, TYPE_CHECKING, Union from azure.appconfiguration import ( AzureAppConfigurationClient, FeatureFlagConfigurationSetting, @@ -20,7 +20,8 @@ AzureFunctionEnvironmentVariable, AzureWebAppEnvironmentVariable, ContainerAppEnvironmentVariable, - KubernetesEnvironmentVariable + KubernetesEnvironmentVariable, + EMPTY_LABEL ) from ._user_agent import USER_AGENT @@ -28,14 +29,15 @@ if TYPE_CHECKING: from azure.core.credentials import TokenCredential +JSON = Union[str, Mapping[str, Any]] # pylint: disable=unsubscriptable-object @overload -def load_provider( +def load( endpoint: str, credential: "TokenCredential", *, selects: Optional[List[SettingSelector]] = None, - trimmed_key_prefixes: Optional[List[str]] = None, + trim_prefixes: Optional[List[str]] = None, key_vault_options: Optional[AzureAppConfigurationKeyVaultOptions] = None, **kwargs ) -> "AzureAppConfigurationProvider": @@ -47,19 +49,19 @@ def load_provider( :type credential: ~azure.core.credentials.TokenCredential :keyword selects: List of setting selectors to filter configuration settings :paramtype selects: Optional[List[~azure.appconfiguration.provider.SettingSelector]] - :keyword trimmed_key_prefixes: List of prefixes to trim from configuration keys - :paramtype trimmed_key_prefixes: Optional[List[str]] + :keyword trim_prefixes: List of prefixes to trim from configuration keys + :paramtype trim_prefixes: Optional[List[str]] :keyword key_vault_options: Options for resolving Key Vault references :paramtype key_vault_options: ~azure.appconfiguration.provider.AzureAppConfigurationKeyVaultOptions """ ... @overload -def load_provider( +def load( *, connection_string: str, selects: Optional[List[SettingSelector]] = None, - trimmed_key_prefixes: Optional[List[str]] = None, + trim_prefixes: Optional[List[str]] = None, key_vault_options: Optional[AzureAppConfigurationKeyVaultOptions] = None, **kwargs ) -> "AzureAppConfigurationProvider": @@ -69,14 +71,14 @@ def load_provider( :keyword str connection_string: Connection string for App Configuration resource. :keyword selects: List of setting selectors to filter configuration settings :paramtype selects: Optional[List[~azure.appconfiguration.provider.SettingSelector]] - :keyword trimmed_key_prefixes: List of prefixes to trim from configuration keys - :paramtype trimmed_key_prefixes: Optional[List[str]] + :keyword trim_prefixes: List of prefixes to trim from configuration keys + :paramtype trim_prefixes: Optional[List[str]] :keyword key_vault_options: Options for resolving Key Vault references :paramtype key_vault_options: ~azure.appconfiguration.provider.AzureAppConfigurationKeyVaultOptions """ ... -def load_provider(*args, **kwargs) -> "AzureAppConfigurationProvider": +def load(*args, **kwargs) -> "AzureAppConfigurationProvider": #pylint:disable=protected-access # Start by parsing kwargs @@ -84,8 +86,8 @@ def load_provider(*args, **kwargs) -> "AzureAppConfigurationProvider": credential: Optional["TokenCredential"] = kwargs.pop("credential", None) connection_string: Optional[str] = kwargs.pop("connection_string", None) key_vault_options: Optional[AzureAppConfigurationKeyVaultOptions] = kwargs.pop("key_vault_options", None) - selects: List[SettingSelector] = kwargs.pop("selects", [SettingSelector("*", "\0")]) - trim_prefixes : List[str] = kwargs.pop("trimmed_key_prefixes", []) + selects: List[SettingSelector] = kwargs.pop("selects", [SettingSelector(key_filter="*", label_filter=EMPTY_LABEL)]) + trim_prefixes : List[str] = kwargs.pop("trim_prefixes", []) # Update endpoint and credential if specified positionally. if len(args) > 2: @@ -108,10 +110,6 @@ def load_provider(*args, **kwargs) -> "AzureAppConfigurationProvider": provider = _buildprovider(connection_string, endpoint, credential, key_vault_options, **kwargs) provider._trim_prefixes = sorted(trim_prefixes, key=len, reverse=True) - if key_vault_options is not None and len(key_vault_options.secret_clients) > 0: - for secret_client in key_vault_options.secret_clients: - provider._secret_clients[secret_client.vault_url] = secret_client - for select in selects: configurations = provider._client.list_configuration_settings( key_filter=select.key_filter, label_filter=select.label_filter @@ -151,7 +149,7 @@ def load_provider(*args, **kwargs) -> "AzureAppConfigurationProvider": def _get_correlation_context(key_vault_options: Optional[AzureAppConfigurationKeyVaultOptions]) -> str: correlation_context = "RequestType=Startup" if key_vault_options and ( - key_vault_options.credential or key_vault_options.secret_clients or key_vault_options.secret_resolver + key_vault_options.credential or key_vault_options.client_configs or key_vault_options.secret_resolver ): correlation_context += ",UsesKeyVault" host_type = "" @@ -207,14 +205,19 @@ def _resolve_keyvault_reference( key_vault_identifier = KeyVaultSecretIdentifier(config.secret_id) + vault_url = key_vault_identifier.vault_url + "/" + #pylint:disable=protected-access - referenced_client = provider._secret_clients.get(key_vault_identifier.vault_url, None) + referenced_client = provider._secret_clients.get(vault_url, None) + + vault_config = key_vault_options.client_configs.get(vault_url, {}) + credential = vault_config.pop("credential", key_vault_options.credential) - if referenced_client is None and key_vault_options.credential is not None: + if referenced_client is None and credential is not None: referenced_client = SecretClient( - vault_url=key_vault_identifier.vault_url, credential=key_vault_options.credential + vault_url=vault_url, credential=credential, **vault_config ) - provider._secret_clients[key_vault_identifier.vault_url] = referenced_client + provider._secret_clients[vault_url] = referenced_client if referenced_client: return referenced_client.get_secret(key_vault_identifier.name, version=key_vault_identifier.version).value @@ -223,7 +226,7 @@ def _resolve_keyvault_reference( return key_vault_options.secret_resolver(config.secret_id) raise ValueError( - "No Secret Client found for Key Vault reference %s" % (key_vault_identifier.vault_url) + "No Secret Client found for Key Vault reference %s" % (vault_url) ) @@ -249,7 +252,7 @@ def _is_json_content_type(content_type: str) -> bool: return False -class AzureAppConfigurationProvider(Mapping[str, str]): +class AzureAppConfigurationProvider(Mapping[str, Union[str, JSON]]): """ Provides a dictionary-like interface to Azure App Configuration settings. Enables loading of sets of configuration settings from Azure App Configuration into a Python application. Enables trimming of prefixes from configuration diff --git a/sdk/appconfiguration/azure-appconfiguration-provider/azure/appconfiguration/provider/_constants.py b/sdk/appconfiguration/azure-appconfiguration-provider/azure/appconfiguration/provider/_constants.py index 9e2552086a5e..a09406770d51 100644 --- a/sdk/appconfiguration/azure-appconfiguration-provider/azure/appconfiguration/provider/_constants.py +++ b/sdk/appconfiguration/azure-appconfiguration-provider/azure/appconfiguration/provider/_constants.py @@ -7,9 +7,11 @@ FEATURE_MANAGEMENT_KEY = "FeatureManagementFeatureFlags" FEATURE_FLAG_PREFIX = ".appconfig.featureflag/" +EMPTY_LABEL = "\0" + RequestTracingDisabledEnvironmentVariable = "AZURE_APP_CONFIGURATION_TRACING_DISABLED" AzureFunctionEnvironmentVariable = "FUNCTIONS_EXTENSION_VERSION" AzureWebAppEnvironmentVariable = "WEBSITE_SITE_NAME" ContainerAppEnvironmentVariable = "CONTAINER_APP_NAME" KubernetesEnvironmentVariable = "KUBERNETES_PORT" -ServiceFabricEnvironmentVariable = "Fabric_NvodeName" # cspell:disable-line +ServiceFabricEnvironmentVariable = "Fabric_NodeName" # cspell:disable-line diff --git a/sdk/appconfiguration/azure-appconfiguration-provider/azure/appconfiguration/provider/_models.py b/sdk/appconfiguration/azure-appconfiguration-provider/azure/appconfiguration/provider/_models.py index 5f8a60369590..1893e7293b90 100644 --- a/sdk/appconfiguration/azure-appconfiguration-provider/azure/appconfiguration/provider/_models.py +++ b/sdk/appconfiguration/azure-appconfiguration-provider/azure/appconfiguration/provider/_models.py @@ -3,13 +3,12 @@ # Licensed under the MIT License. See License.txt in the project root for # license information. # ------------------------------------------------------------------------- -from typing import List, Optional, Callable, TYPE_CHECKING, Union, Awaitable +from typing import Optional, Callable, TYPE_CHECKING, Union, Awaitable, Mapping, Any +from ._constants import EMPTY_LABEL if TYPE_CHECKING: from azure.core.credentials import TokenCredential from azure.core.credentials_async import AsyncTokenCredential - from azure.keyvault.secrets import SecretClient - from azure.keyvault.secrets.aio import SecretClient as AsyncSecretClient class AzureAppConfigurationKeyVaultOptions: @@ -17,7 +16,7 @@ def __init__( self, *, credential: Optional[Union["TokenCredential", "AsyncTokenCredential"]] = None, - secret_clients: Optional[Union[List["SecretClient"], List["AsyncSecretClient"]]] = None, + client_configs: Optional[Mapping[str, Mapping[str, Any]]] = None, secret_resolver: Optional[Union[Callable[[str], str], Callable[[str], Awaitable[str]]]] = None ): """ @@ -26,14 +25,15 @@ def __init__( :keyword credential: A credential for authenticating with the key vault. This is optional if secret_clients is provided. :paramtype credential: ~azure.core.credentials.TokenCredential - :keyword secret_clients: A list of SecretClient from azure-keyvault-secrets. This is optional if credential is - provided. - :paramtype secret_clients: list[~azure.keyvault.secrets.SecretClient] + :keyword client_configs: A Mapping of SecretClient endpoints to client configurations from + azure-keyvault-secrets. This is optional if credential is provided. If a credential isn't provided a + credential will need to be in each set for each. + :paramtype client_configs: Mapping[Url, Mapping] :keyword secret_resolver: A function that takes a URI and returns a value. :paramtype secret_resolver: Callable[[str], str] """ self.credential = credential - self.secret_clients = secret_clients or [] + self.client_configs = client_configs or {} self.secret_resolver = secret_resolver if self.credential is not None and self.secret_resolver is not None: raise ValueError("credential and secret_resolver can't both be configured.") @@ -43,12 +43,13 @@ class SettingSelector: """ Selects a set of configuration settings from Azure App Configuration. - :param key_filter: A filter to select configuration settings based on their keys. + :keyword key_filter: A filter to select configuration settings based on their keys. :type key_filter: str - :param label_filter: A filter to select configuration settings based on their labels. Default is value is '\0' - :type label_filter: str + :keyword label_filter: A filter to select configuration settings based on their labels. Default is value is + EMPTY_LABEL i.e. (No Label) as seen in the portal. + :type label_filter: Optional[str] """ - def __init__(self, key_filter: str, label_filter: str = "\0"): + def __init__(self, *, key_filter: str, label_filter: Optional[str] = EMPTY_LABEL): self.key_filter = key_filter self.label_filter = label_filter diff --git a/sdk/appconfiguration/azure-appconfiguration-provider/azure/appconfiguration/provider/_version.py b/sdk/appconfiguration/azure-appconfiguration-provider/azure/appconfiguration/provider/_version.py index b8d043b247c1..9825929bcbb2 100644 --- a/sdk/appconfiguration/azure-appconfiguration-provider/azure/appconfiguration/provider/_version.py +++ b/sdk/appconfiguration/azure-appconfiguration-provider/azure/appconfiguration/provider/_version.py @@ -4,4 +4,4 @@ # license information. # ------------------------------------------------------------------------- -VERSION = "1.0.0b3" +VERSION = "1.0.1" diff --git a/sdk/appconfiguration/azure-appconfiguration-provider/azure/appconfiguration/provider/aio/__init__.py b/sdk/appconfiguration/azure-appconfiguration-provider/azure/appconfiguration/provider/aio/__init__.py index 5a6311f8407e..6c166951e2ac 100644 --- a/sdk/appconfiguration/azure-appconfiguration-provider/azure/appconfiguration/provider/aio/__init__.py +++ b/sdk/appconfiguration/azure-appconfiguration-provider/azure/appconfiguration/provider/aio/__init__.py @@ -4,9 +4,9 @@ # license information. # ------------------------------------------------------------------------- -from ._azureappconfigurationproviderasync import load_provider, AzureAppConfigurationProvider +from ._azureappconfigurationproviderasync import load, AzureAppConfigurationProvider __all__ = [ - "load_provider", + "load", "AzureAppConfigurationProvider", ] diff --git a/sdk/appconfiguration/azure-appconfiguration-provider/azure/appconfiguration/provider/aio/_azureappconfigurationproviderasync.py b/sdk/appconfiguration/azure-appconfiguration-provider/azure/appconfiguration/provider/aio/_azureappconfigurationproviderasync.py index a9bd83aeb5c2..cb8cdf914b17 100644 --- a/sdk/appconfiguration/azure-appconfiguration-provider/azure/appconfiguration/provider/aio/_azureappconfigurationproviderasync.py +++ b/sdk/appconfiguration/azure-appconfiguration-provider/azure/appconfiguration/provider/aio/_azureappconfigurationproviderasync.py @@ -4,7 +4,7 @@ # license information. # ------------------------------------------------------------------------- import json -from typing import Any, Dict, Iterable, Mapping, Optional, overload, List, Tuple, TYPE_CHECKING +from typing import Any, Dict, Iterable, Mapping, Optional, overload, List, Tuple, TYPE_CHECKING, Union from azure.appconfiguration import FeatureFlagConfigurationSetting, SecretReferenceConfigurationSetting from azure.appconfiguration.aio import AzureAppConfigurationClient @@ -12,21 +12,22 @@ from azure.keyvault.secrets import KeyVaultSecretIdentifier from .._models import AzureAppConfigurationKeyVaultOptions, SettingSelector -from .._constants import FEATURE_MANAGEMENT_KEY, FEATURE_FLAG_PREFIX +from .._constants import FEATURE_MANAGEMENT_KEY, FEATURE_FLAG_PREFIX, EMPTY_LABEL from .._azureappconfigurationprovider import _is_json_content_type, _get_correlation_context from .._user_agent import USER_AGENT if TYPE_CHECKING: from azure.core.credentials_async import AsyncTokenCredential +JSON = Union[str, Mapping[str, Any]] # pylint: disable=unsubscriptable-object @overload -async def load_provider( +async def load( endpoint: str, credential: "AsyncTokenCredential", *, selects: Optional[List[SettingSelector]] = None, - trimmed_key_prefixes: Optional[List[str]] = None, + trim_prefixes: Optional[List[str]] = None, key_vault_options: Optional[AzureAppConfigurationKeyVaultOptions] = None, **kwargs ) -> "AzureAppConfigurationProvider": @@ -38,19 +39,19 @@ async def load_provider( :type credential: ~azure.core.credentials.TokenCredential :keyword selects: List of setting selectors to filter configuration settings :paramtype selects: Optional[List[~azure.appconfiguration.provider.SettingSelector]] - :keyword trimmed_key_prefixes: List of prefixes to trim from configuration keys - :paramtype trimmed_key_prefixes: Optional[List[str]] + :keyword trim_prefixes: List of prefixes to trim from configuration keys + :paramtype trim_prefixes: Optional[List[str]] :keyword key_vault_options: Options for resolving Key Vault references :paramtype key_vault_options: ~azure.appconfiguration.provider.AzureAppConfigurationKeyVaultOptions """ ... @overload -async def load_provider( +async def load( *, connection_string: str, selects: Optional[List[SettingSelector]] = None, - trimmed_key_prefixes: Optional[List[str]] = None, + trim_prefixes: Optional[List[str]] = None, key_vault_options: Optional[AzureAppConfigurationKeyVaultOptions] = None, **kwargs ) -> "AzureAppConfigurationProvider": @@ -60,15 +61,15 @@ async def load_provider( :keyword str connection_string: Connection string for App Configuration resource. :keyword selects: List of setting selectors to filter configuration settings :paramtype selects: Optional[List[~azure.appconfiguration.provider.SettingSelector]] - :keyword trimmed_key_prefixes: List of prefixes to trim from configuration keys - :paramtype trimmed_key_prefixes: Optional[List[str]] + :keyword trim_prefixes: List of prefixes to trim from configuration keys + :paramtype trim_prefixes: Optional[List[str]] :keyword key_vault_options: Options for resolving Key Vault references :paramtype key_vault_options: ~azure.appconfiguration.provider.AzureAppConfigurationKeyVaultOptions """ ... -async def load_provider(*args, **kwargs) -> "AzureAppConfigurationProvider": +async def load(*args, **kwargs) -> "AzureAppConfigurationProvider": #pylint:disable=protected-access # Start by parsing kwargs @@ -76,8 +77,8 @@ async def load_provider(*args, **kwargs) -> "AzureAppConfigurationProvider": credential: Optional["AsyncTokenCredential"] = kwargs.pop("credential", None) connection_string: Optional[str] = kwargs.pop("connection_string", None) key_vault_options: Optional[AzureAppConfigurationKeyVaultOptions] = kwargs.pop("key_vault_options", None) - selects: List[SettingSelector] = kwargs.pop("selects", [SettingSelector("*", "\0")]) - trim_prefixes : List[str] = kwargs.pop("trimmed_key_prefixes", []) + selects: List[SettingSelector] = kwargs.pop("selects", [SettingSelector(key_filter="*", label_filter=EMPTY_LABEL)]) + trim_prefixes : List[str] = kwargs.pop("trim_prefixes", []) # Update endpoint and credential if specified positionally. if len(args) > 2: @@ -101,10 +102,6 @@ async def load_provider(*args, **kwargs) -> "AzureAppConfigurationProvider": provider._trim_prefixes = sorted(trim_prefixes, key=len, reverse=True) - if key_vault_options is not None and len(key_vault_options.secret_clients) > 0: - for secret_client in key_vault_options.secret_clients: - provider._secret_clients[secret_client.vault_url] = secret_client - for select in selects: configurations = provider._client.list_configuration_settings( key_filter=select.key_filter, label_filter=select.label_filter @@ -178,14 +175,19 @@ async def _resolve_keyvault_reference( key_vault_identifier = KeyVaultSecretIdentifier(config.secret_id) + vault_url = key_vault_identifier.vault_url + "/" + #pylint:disable=protected-access - referenced_client = provider._secret_clients.get(key_vault_identifier.vault_url, None) + referenced_client = provider._secret_clients.get(vault_url, None) - if referenced_client is None and key_vault_options.credential is not None: + vault_config = key_vault_options.client_configs.get(vault_url, {}) + credential = vault_config.pop("credential", key_vault_options.credential) + + if referenced_client is None and credential is not None: referenced_client = SecretClient( - vault_url=key_vault_identifier.vault_url, credential=key_vault_options.credential + vault_url=vault_url, credential=credential, **vault_config ) - provider._secret_clients[key_vault_identifier.vault_url] = referenced_client + provider._secret_clients[vault_url] = referenced_client if referenced_client: return ( @@ -202,11 +204,10 @@ async def _resolve_keyvault_reference( return resolved raise ValueError( - "No Secret Client found for Key Vault reference %s" % (key_vault_identifier.vault_url) + "No Secret Client found for Key Vault reference %s" % (vault_url) ) - -class AzureAppConfigurationProvider(Mapping[str, str]): +class AzureAppConfigurationProvider(Mapping[str, Union[str, JSON]]): """ Provides a dictionary-like interface to Azure App Configuration settings. Enables loading of sets of configuration settings from Azure App Configuration into a Python application. Enables trimming of prefixes from configuration diff --git a/sdk/appconfiguration/azure-appconfiguration-provider/samples/README.md b/sdk/appconfiguration/azure-appconfiguration-provider/samples/README.md index 6eed2a4059e4..3428f97207ed 100644 --- a/sdk/appconfiguration/azure-appconfiguration-provider/samples/README.md +++ b/sdk/appconfiguration/azure-appconfiguration-provider/samples/README.md @@ -50,7 +50,15 @@ pip install azure.appconfiguration.provider | connection_string_sample.py | demos connecting to app configuration with a Connection String | | key_vault_reference_sample.py | demos resolving key vault references with App Configuration | +## Next steps + +Check out our Django and Flask examples to see how to use the provider in a web application. + +### [Django](https://github.com/Azure/AppConfiguration/tree/main/examples/Python/python-django-webapp-sample) + +### [Flask](https://github.com/Azure/AppConfiguration/tree/main/examples/Python/python-flask-webapp-sample) + [azure_sub]: https://azure.microsoft.com/free/ [azure_cli]: https://docs.microsoft.com/cli/azure -[configuration_store]: https://azure.microsoft.com/services/app-configuration/ \ No newline at end of file +[configuration_store]: https://azure.microsoft.com/services/app-configuration/ diff --git a/sdk/appconfiguration/azure-appconfiguration-provider/samples/aad_sample.py b/sdk/appconfiguration/azure-appconfiguration-provider/samples/aad_sample.py index c616c7ad2af0..581bbf069845 100644 --- a/sdk/appconfiguration/azure-appconfiguration-provider/samples/aad_sample.py +++ b/sdk/appconfiguration/azure-appconfiguration-provider/samples/aad_sample.py @@ -5,7 +5,7 @@ # ------------------------------------------------------------------------- from azure.appconfiguration.provider import ( - load_provider, + load, SettingSelector ) import os @@ -17,19 +17,19 @@ credential = get_credential(authority) # Connecting to Azure App Configuration using AAD -config = load_provider(endpoint=endpoint, credential=credential) +config = load(endpoint=endpoint, credential=credential) print(config["message"]) -# Connecting to Azure App Configuration using AAD and trimmed key prefixes +# Connecting to Azure App Configuration using AAD and trim key prefixes trimmed = {"test."} -config = load_provider(endpoint=endpoint, credential=credential, trimmed_key_prefixes=trimmed) +config = load(endpoint=endpoint, credential=credential, trim_prefixes=trimmed) print(config["message"]) # Connection to Azure App Configuration using SettingSelector -selects = {SettingSelector("message*", "\0")} -config = load_provider(endpoint=endpoint, credential=credential, selects=selects) +selects = {SettingSelector(key_filter="message*")} +config = load(endpoint=endpoint, credential=credential, selects=selects) print("message found: " + str("message" in config)) print("test.message found: " + str("test.message" in config)) diff --git a/sdk/appconfiguration/azure-appconfiguration-provider/samples/async_aad_sample.py b/sdk/appconfiguration/azure-appconfiguration-provider/samples/async_aad_sample.py index 8892275017a3..1ed9bbcf1061 100644 --- a/sdk/appconfiguration/azure-appconfiguration-provider/samples/async_aad_sample.py +++ b/sdk/appconfiguration/azure-appconfiguration-provider/samples/async_aad_sample.py @@ -5,7 +5,7 @@ # ------------------------------------------------------------------------- import asyncio -from azure.appconfiguration.provider.aio import load_provider +from azure.appconfiguration.provider.aio import load from azure.appconfiguration.provider import SettingSelector import os from sample_utilities import get_authority, get_audience, get_credential @@ -16,18 +16,18 @@ async def main(): credential = get_credential(authority, is_async=True) # Connecting to Azure App Configuration using AAD - config = await load_provider(endpoint=endpoint, credential=credential) + config = await load(endpoint=endpoint, credential=credential) print(config["message"]) - # Connecting to Azure App Configuration using AAD and trimmed key prefixes + # Connecting to Azure App Configuration using AAD and trim key prefixes trimmed = {"test."} - config = await load_provider(endpoint=endpoint, credential=credential, trimmed_key_prefixes=trimmed) + config = await load(endpoint=endpoint, credential=credential, trim_prefixes=trimmed) print(config["message"]) # Connection to Azure App Configuration using SettingSelector - selects = {SettingSelector("message*", "\0")} - config = await load_provider(endpoint=endpoint, credential=credential, selects=selects) + selects = {SettingSelector(key_filter="message*")} + config = await load(endpoint=endpoint, credential=credential, selects=selects) print("message found: " + str("message" in config)) print("test.message found: " + str("test.message" in config)) diff --git a/sdk/appconfiguration/azure-appconfiguration-provider/samples/async_connection_string_sample.py b/sdk/appconfiguration/azure-appconfiguration-provider/samples/async_connection_string_sample.py index 8ac139cadf2a..e9d467c325d7 100644 --- a/sdk/appconfiguration/azure-appconfiguration-provider/samples/async_connection_string_sample.py +++ b/sdk/appconfiguration/azure-appconfiguration-provider/samples/async_connection_string_sample.py @@ -4,7 +4,7 @@ # license information. # ------------------------------------------------------------------------- import asyncio -from azure.appconfiguration.provider.aio import load_provider +from azure.appconfiguration.provider.aio import load from azure.appconfiguration.provider import SettingSelector import os @@ -12,20 +12,20 @@ async def main(): connection_string = os.environ.get("AZURE_APPCONFIG_CONNECTION_STRING") # Connecting to Azure App Configuration using connection string - config = await load_provider(connection_string=connection_string) + config = await load(connection_string=connection_string) print(config["message"]) print(config["my_json"]["key"]) # Connecting to Azure App Configuration using connection string and trimmed key prefixes trimmed = {"test."} - config = await load_provider(connection_string=connection_string, trimmed_key_prefixes=trimmed) + config = await load(connection_string=connection_string, trim_prefixes=trimmed) print(config["message"]) # Connection to Azure App Configuration using SettingSelector - selects = {SettingSelector("message*", "\0")} - config = await load_provider(connection_string=connection_string, selects=selects) + selects = {SettingSelector(key_filter="message*")} + config = await load(connection_string=connection_string, selects=selects) print("message found: " + str("message" in config)) print("test.message found: " + str("test.message" in config)) diff --git a/sdk/appconfiguration/azure-appconfiguration-provider/samples/async_key_vault_reference_provided_clients_sample.py b/sdk/appconfiguration/azure-appconfiguration-provider/samples/async_key_vault_reference_provided_clients_sample.py index 3f46ecd0daf4..992d2e93b940 100644 --- a/sdk/appconfiguration/azure-appconfiguration-provider/samples/async_key_vault_reference_provided_clients_sample.py +++ b/sdk/appconfiguration/azure-appconfiguration-provider/samples/async_key_vault_reference_provided_clients_sample.py @@ -5,7 +5,7 @@ # ------------------------------------------------------------------------- import asyncio -from azure.appconfiguration.provider.aio import load_provider +from azure.appconfiguration.provider.aio import load from azure.appconfiguration.provider import SettingSelector, AzureAppConfigurationKeyVaultOptions from azure.keyvault.secrets.aio import SecretClient import os @@ -20,9 +20,9 @@ async def main(): # Connection to Azure App Configuration using AAD with Provided Client secret_client = SecretClient(vault_url=key_vault_uri, credential=credential) - selects = {SettingSelector("*", "prod")} + selects = {SettingSelector(key_filter="*", label_filter="prod")} key_vault_options = AzureAppConfigurationKeyVaultOptions(secret_clients=[secret_client]) - config = await load_provider(endpoint=endpoint, credential=credential, key_vault_options=key_vault_options, selects=selects) + config = await load(endpoint=endpoint, credential=credential, key_vault_options=key_vault_options, selects=selects) print(config["secret"]) diff --git a/sdk/appconfiguration/azure-appconfiguration-provider/samples/async_key_vault_reference_sample.py b/sdk/appconfiguration/azure-appconfiguration-provider/samples/async_key_vault_reference_sample.py index 50e30cdf4ce9..bc25c4658e02 100644 --- a/sdk/appconfiguration/azure-appconfiguration-provider/samples/async_key_vault_reference_sample.py +++ b/sdk/appconfiguration/azure-appconfiguration-provider/samples/async_key_vault_reference_sample.py @@ -5,7 +5,7 @@ # ------------------------------------------------------------------------- import asyncio -from azure.appconfiguration.provider.aio import load_provider +from azure.appconfiguration.provider.aio import load from azure.appconfiguration.provider import SettingSelector, AzureAppConfigurationKeyVaultOptions import os from sample_utilities import get_authority, get_audience, get_credential @@ -18,9 +18,9 @@ async def main(): # Connection to Azure App Configuration using AAD and Resolving Key Vault References key_vault_options = AzureAppConfigurationKeyVaultOptions(credential=credential) - selects = {SettingSelector("*", "prod")} + selects = {SettingSelector(key_filter="*", label_filter="prod")} - config = await load_provider(endpoint=endpoint, credential=credential, key_vault_options=key_vault_options, selects=selects) + config = await load(endpoint=endpoint, credential=credential, key_vault_options=key_vault_options, selects=selects) print(config["secret"]) diff --git a/sdk/appconfiguration/azure-appconfiguration-provider/samples/connection_string_sample.py b/sdk/appconfiguration/azure-appconfiguration-provider/samples/connection_string_sample.py index ac7dcd59b4cc..a4616cfe726b 100644 --- a/sdk/appconfiguration/azure-appconfiguration-provider/samples/connection_string_sample.py +++ b/sdk/appconfiguration/azure-appconfiguration-provider/samples/connection_string_sample.py @@ -5,7 +5,7 @@ # ------------------------------------------------------------------------- from azure.appconfiguration.provider import ( - load_provider, + load, SettingSelector ) import os @@ -13,20 +13,20 @@ connection_string = os.environ.get("AZURE_APPCONFIG_CONNECTION_STRING") # Connecting to Azure App Configuration using connection string -config = load_provider(connection_string=connection_string) +config = load(connection_string=connection_string) print(config["message"]) print(config["my_json"]["key"]) # Connecting to Azure App Configuration using connection string and trimmed key prefixes trimmed = {"test."} -config = load_provider(connection_string=connection_string, trimmed_key_prefixes=trimmed) +config = load(connection_string=connection_string, trim_prefixes=trimmed) print(config["message"]) # Connection to Azure App Configuration using SettingSelector -selects = {SettingSelector("message*", "\0")} -config = load_provider(connection_string=connection_string, selects=selects) +selects = {SettingSelector(key_filter="message*")} +config = load(connection_string=connection_string, selects=selects) print("message found: " + str("message" in config)) print("test.message found: " + str("test.message" in config)) diff --git a/sdk/appconfiguration/azure-appconfiguration-provider/samples/key_vault_reference_provided_clients_sample.py b/sdk/appconfiguration/azure-appconfiguration-provider/samples/key_vault_reference_customized_clients_sample.py similarity index 67% rename from sdk/appconfiguration/azure-appconfiguration-provider/samples/key_vault_reference_provided_clients_sample.py rename to sdk/appconfiguration/azure-appconfiguration-provider/samples/key_vault_reference_customized_clients_sample.py index 2373222fe8b1..a016e69085b5 100644 --- a/sdk/appconfiguration/azure-appconfiguration-provider/samples/key_vault_reference_provided_clients_sample.py +++ b/sdk/appconfiguration/azure-appconfiguration-provider/samples/key_vault_reference_customized_clients_sample.py @@ -5,11 +5,10 @@ # ------------------------------------------------------------------------- from azure.appconfiguration.provider import ( - load_provider, + load, AzureAppConfigurationKeyVaultOptions, SettingSelector ) -from azure.keyvault.secrets import SecretClient import os from sample_utilities import get_authority, get_audience, get_credential @@ -20,9 +19,10 @@ credential = get_credential(authority) # Connection to Azure App Configuration using AAD with Provided Client -secret_client = SecretClient(vault_url=key_vault_uri, credential=credential) -selects = {SettingSelector("*", "prod")} -key_vault_options = AzureAppConfigurationKeyVaultOptions(secret_clients=[secret_client]) -config = load_provider(endpoint=endpoint, credential=credential, key_vault_options=key_vault_options, selects=selects) +client_configs = {key_vault_uri: {'credential': credential}} +selects = {SettingSelector(key_filter="*", label_filter="prod")} +key_vault_options = AzureAppConfigurationKeyVaultOptions(client_configs=client_configs) +config = load(endpoint=endpoint, credential=credential, key_vault_options=key_vault_options, selects=selects) print(config["secret"]) +print(config["secondSecret"]) diff --git a/sdk/appconfiguration/azure-appconfiguration-provider/samples/key_vault_reference_sample.py b/sdk/appconfiguration/azure-appconfiguration-provider/samples/key_vault_reference_sample.py index 2a44fa87900a..9af9af80a78f 100644 --- a/sdk/appconfiguration/azure-appconfiguration-provider/samples/key_vault_reference_sample.py +++ b/sdk/appconfiguration/azure-appconfiguration-provider/samples/key_vault_reference_sample.py @@ -5,7 +5,7 @@ # ------------------------------------------------------------------------- from azure.appconfiguration.provider import ( - load_provider, + load, AzureAppConfigurationKeyVaultOptions, SettingSelector ) @@ -19,8 +19,8 @@ # Connection to Azure App Configuration using AAD and Resolving Key Vault References key_vault_options = AzureAppConfigurationKeyVaultOptions(credential=credential) -selects = {SettingSelector("*", "prod")} +selects = {SettingSelector(key_filter="*", label_filter="prod")} -config = load_provider(endpoint=endpoint, credential=credential, key_vault_options=key_vault_options, selects=selects) +config = load(endpoint=endpoint, credential=credential, key_vault_options=key_vault_options, selects=selects) print(config["secret"]) diff --git a/sdk/appconfiguration/azure-appconfiguration-provider/sdk_packaging.toml b/sdk/appconfiguration/azure-appconfiguration-provider/sdk_packaging.toml index 7d93f77a90ba..dc5c4e6191b8 100644 --- a/sdk/appconfiguration/azure-appconfiguration-provider/sdk_packaging.toml +++ b/sdk/appconfiguration/azure-appconfiguration-provider/sdk_packaging.toml @@ -6,4 +6,4 @@ package_doc_id = "" is_stable = false is_arm = false need_msrestazure = false -auto_update = false \ No newline at end of file +auto_update = false diff --git a/sdk/appconfiguration/azure-appconfiguration-provider/setup.py b/sdk/appconfiguration/azure-appconfiguration-provider/setup.py index da8f066ccc45..ccfc03f0fc25 100644 --- a/sdk/appconfiguration/azure-appconfiguration-provider/setup.py +++ b/sdk/appconfiguration/azure-appconfiguration-provider/setup.py @@ -58,7 +58,7 @@ author_email="azpysdkhelp@microsoft.com", url="https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/appconfiguration/azure-appconfiguration-provider", classifiers=[ - "Development Status :: 4 - Beta", + "Development Status :: 5 - Production/Stable", "Programming Language :: Python", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3", diff --git a/sdk/appconfiguration/azure-appconfiguration-provider/tests/recordings/test_async_provider.pyTestAppConfigurationProvidertest_provider_trimmed_key_prefixes.json b/sdk/appconfiguration/azure-appconfiguration-provider/tests/recordings/test_async_provider.pyTestAppConfigurationProvidertest_provider_trim_prefixes.json similarity index 100% rename from sdk/appconfiguration/azure-appconfiguration-provider/tests/recordings/test_async_provider.pyTestAppConfigurationProvidertest_provider_trimmed_key_prefixes.json rename to sdk/appconfiguration/azure-appconfiguration-provider/tests/recordings/test_async_provider.pyTestAppConfigurationProvidertest_provider_trim_prefixes.json diff --git a/sdk/appconfiguration/azure-appconfiguration-provider/tests/recordings/test_async_provider_aad.pyTestAppConfigurationProvidertest_provider_trimmed_key_prefixes.json b/sdk/appconfiguration/azure-appconfiguration-provider/tests/recordings/test_async_provider_aad.pyTestAppConfigurationProvidertest_provider_trim_prefixes.json similarity index 100% rename from sdk/appconfiguration/azure-appconfiguration-provider/tests/recordings/test_async_provider_aad.pyTestAppConfigurationProvidertest_provider_trimmed_key_prefixes.json rename to sdk/appconfiguration/azure-appconfiguration-provider/tests/recordings/test_async_provider_aad.pyTestAppConfigurationProvidertest_provider_trim_prefixes.json diff --git a/sdk/appconfiguration/azure-appconfiguration-provider/tests/recordings/test_provider.pyTestAppConfigurationProvidertest_provider_trimmed_key_prefixes.json b/sdk/appconfiguration/azure-appconfiguration-provider/tests/recordings/test_provider.pyTestAppConfigurationProvidertest_provider_trim_prefixes.json similarity index 100% rename from sdk/appconfiguration/azure-appconfiguration-provider/tests/recordings/test_provider.pyTestAppConfigurationProvidertest_provider_trimmed_key_prefixes.json rename to sdk/appconfiguration/azure-appconfiguration-provider/tests/recordings/test_provider.pyTestAppConfigurationProvidertest_provider_trim_prefixes.json diff --git a/sdk/appconfiguration/azure-appconfiguration-provider/tests/recordings/test_provider_aad.pyTestAppConfigurationProvidertest_provider_trimmed_key_prefixes.json b/sdk/appconfiguration/azure-appconfiguration-provider/tests/recordings/test_provider_aad.pyTestAppConfigurationProvidertest_provider_trim_prefixes.json similarity index 100% rename from sdk/appconfiguration/azure-appconfiguration-provider/tests/recordings/test_provider_aad.pyTestAppConfigurationProvidertest_provider_trimmed_key_prefixes.json rename to sdk/appconfiguration/azure-appconfiguration-provider/tests/recordings/test_provider_aad.pyTestAppConfigurationProvidertest_provider_trim_prefixes.json diff --git a/sdk/appconfiguration/azure-appconfiguration-provider/tests/test_async_provider.py b/sdk/appconfiguration/azure-appconfiguration-provider/tests/test_async_provider.py index 0ec459960931..082aaba3866d 100644 --- a/sdk/appconfiguration/azure-appconfiguration-provider/tests/test_async_provider.py +++ b/sdk/appconfiguration/azure-appconfiguration-provider/tests/test_async_provider.py @@ -3,7 +3,7 @@ # Licensed under the MIT License. See License.txt in the project root for # license information. # -------------------------------------------------------------------------- -from azure.appconfiguration.provider.aio import load_provider +from azure.appconfiguration.provider.aio import load from azure.appconfiguration.provider import SettingSelector from devtools_testutils import AzureRecordedTestCase from devtools_testutils.aio import recorded_by_proxy_async @@ -11,8 +11,8 @@ class TestAppConfigurationProvider(AzureRecordedTestCase): - async def build_provider(self, connection_string, trimmed_key_prefixes=[], selects={SettingSelector("*", "\0")}): - return await load_provider(connection_string=connection_string, trimmed_key_prefixes=trimmed_key_prefixes, selects=selects) + async def build_provider(self, connection_string, trim_prefixes=[], selects={SettingSelector(key_filter="*", label_filter="\0")}): + return await load(connection_string=connection_string, trim_prefixes=trim_prefixes, selects=selects) # method: provider_creation @app_config_decorator_async @@ -23,12 +23,12 @@ async def test_provider_creation(self, appconfiguration_connection_string): assert client["my_json"]["key"] == "value" assert client["FeatureManagementFeatureFlags"]["Alpha"] == '{\"enabled\": false, \"conditions\": {\"client_filters\": []}}' - # method: provider_trimmed_key_prefixes + # method: provider_trim_prefixes @app_config_decorator_async @recorded_by_proxy_async - async def test_provider_trimmed_key_prefixes(self, appconfiguration_connection_string): + async def test_provider_trim_prefixes(self, appconfiguration_connection_string): trimmed = {"test."} - async with await self.build_provider(appconfiguration_connection_string, trimmed_key_prefixes=trimmed) as client: + async with await self.build_provider(appconfiguration_connection_string, trim_prefixes=trimmed) as client: assert client["message"] == "hi" assert client["my_json"]["key"] == "value" assert client["trimmed"] == "key" @@ -39,7 +39,7 @@ async def test_provider_trimmed_key_prefixes(self, appconfiguration_connection_s @app_config_decorator_async @recorded_by_proxy_async async def test_provider_selectors(self, appconfiguration_connection_string): - selects = {SettingSelector("message*", "dev")} + selects = {SettingSelector(key_filter="message*",label_filter="dev")} async with await self.build_provider(appconfiguration_connection_string, selects=selects) as client: assert client["message"] == "test" assert "test.trimmed" not in client diff --git a/sdk/appconfiguration/azure-appconfiguration-provider/tests/test_async_provider_aad.py b/sdk/appconfiguration/azure-appconfiguration-provider/tests/test_async_provider_aad.py index e4e30f2aa536..1cb33b454d7f 100644 --- a/sdk/appconfiguration/azure-appconfiguration-provider/tests/test_async_provider_aad.py +++ b/sdk/appconfiguration/azure-appconfiguration-provider/tests/test_async_provider_aad.py @@ -3,7 +3,7 @@ # Licensed under the MIT License. See License.txt in the project root for # license information. # -------------------------------------------------------------------------- -from azure.appconfiguration.provider.aio import load_provider +from azure.appconfiguration.provider.aio import load from azure.appconfiguration.provider import SettingSelector from devtools_testutils import AzureRecordedTestCase from devtools_testutils.aio import recorded_by_proxy_async @@ -12,9 +12,9 @@ class TestAppConfigurationProvider(AzureRecordedTestCase): - async def build_provider_aad(self, endpoint, trimmed_key_prefixes=[], selects={SettingSelector("*", "\0")}): + async def build_provider_aad(self, endpoint, trim_prefixes=[], selects={SettingSelector(key_filter="*", label_filter="\0")}): cred = self.get_credential(AzureAppConfigurationClient, is_async=True) - return await load_provider(credential=cred, endpoint=endpoint, trimmed_key_prefixes=trimmed_key_prefixes, selects=selects) + return await load(credential=cred, endpoint=endpoint, trim_prefixes=trim_prefixes, selects=selects) # method: provider_creation_aad @app_config_decorator_async @@ -25,12 +25,12 @@ async def test_provider_creation_aad(self, appconfiguration_endpoint_string): assert client["my_json"]["key"] == "value" assert client["FeatureManagementFeatureFlags"]["Alpha"] == '{\"enabled\": false, \"conditions\": {\"client_filters\": []}}' - # method: provider_trimmed_key_prefixes + # method: provider_trim_prefixes @app_config_decorator_async @recorded_by_proxy_async - async def test_provider_trimmed_key_prefixes(self, appconfiguration_endpoint_string): + async def test_provider_trim_prefixes(self, appconfiguration_endpoint_string): trimmed = {"test."} - async with await self.build_provider_aad(appconfiguration_endpoint_string, trimmed_key_prefixes=trimmed) as client: + async with await self.build_provider_aad(appconfiguration_endpoint_string, trim_prefixes=trimmed) as client: assert client["message"] == "hi" assert client["my_json"]["key"] == "value" assert client["trimmed"] == "key" @@ -41,7 +41,7 @@ async def test_provider_trimmed_key_prefixes(self, appconfiguration_endpoint_str @app_config_decorator_async @recorded_by_proxy_async async def test_provider_selectors(self, appconfiguration_endpoint_string): - selects = {SettingSelector("message*", "dev")} + selects = {SettingSelector(key_filter="message*",label_filter="dev")} async with await self.build_provider_aad(appconfiguration_endpoint_string, selects=selects) as client: assert client["message"] == "test" assert "test.trimmed" not in client diff --git a/sdk/appconfiguration/azure-appconfiguration-provider/tests/test_provider.py b/sdk/appconfiguration/azure-appconfiguration-provider/tests/test_provider.py index 9839afb4542e..f7347e6a2b24 100644 --- a/sdk/appconfiguration/azure-appconfiguration-provider/tests/test_provider.py +++ b/sdk/appconfiguration/azure-appconfiguration-provider/tests/test_provider.py @@ -4,20 +4,19 @@ # license information. # -------------------------------------------------------------------------- from azure.appconfiguration.provider import ( - load_provider, + load, SettingSelector ) from devtools_testutils import ( AzureRecordedTestCase, recorded_by_proxy ) -from azure.appconfiguration import AzureAppConfigurationClient from preparers import app_config_decorator class TestAppConfigurationProvider(AzureRecordedTestCase): - def build_provider(self, connection_string, trimmed_key_prefixes=[], selects={SettingSelector("*", "\0")}): - return load_provider(connection_string=connection_string, trimmed_key_prefixes=trimmed_key_prefixes, selects=selects) + def build_provider(self, connection_string, trim_prefixes=[], selects={SettingSelector(key_filter="*", label_filter="\0")}): + return load(connection_string=connection_string, trim_prefixes=trim_prefixes, selects=selects) # method: provider_creation @recorded_by_proxy @@ -28,12 +27,12 @@ def test_provider_creation(self, appconfiguration_connection_string): assert client["my_json"]["key"] == "value" assert client["FeatureManagementFeatureFlags"]["Alpha"] == '{\"enabled\": false, \"conditions\": {\"client_filters\": []}}' - # method: provider_trimmed_key_prefixes + # method: provider_trim_prefixes @recorded_by_proxy @app_config_decorator - def test_provider_trimmed_key_prefixes(self, appconfiguration_connection_string): + def test_provider_trim_prefixes(self, appconfiguration_connection_string): trimmed = {"test."} - client = self.build_provider(appconfiguration_connection_string, trimmed_key_prefixes=trimmed) + client = self.build_provider(appconfiguration_connection_string, trim_prefixes=trimmed) assert client["message"] == "hi" assert client["my_json"]["key"] == "value" assert client["trimmed"] == "key" @@ -44,7 +43,7 @@ def test_provider_trimmed_key_prefixes(self, appconfiguration_connection_string) @recorded_by_proxy @app_config_decorator def test_provider_selectors(self, appconfiguration_connection_string): - selects = {SettingSelector("message*", "dev")} + selects = {SettingSelector(key_filter="message*", label_filter="dev")} client = self.build_provider(appconfiguration_connection_string, selects=selects) assert client["message"] == "test" assert "test.trimmed" not in client diff --git a/sdk/appconfiguration/azure-appconfiguration-provider/tests/test_provider_aad.py b/sdk/appconfiguration/azure-appconfiguration-provider/tests/test_provider_aad.py index 80c22d01ca58..82aa913a9584 100644 --- a/sdk/appconfiguration/azure-appconfiguration-provider/tests/test_provider_aad.py +++ b/sdk/appconfiguration/azure-appconfiguration-provider/tests/test_provider_aad.py @@ -4,7 +4,7 @@ # license information. # -------------------------------------------------------------------------- from azure.appconfiguration.provider import ( - load_provider, + load, SettingSelector ) from devtools_testutils import ( @@ -16,9 +16,9 @@ class TestAppConfigurationProvider(AzureRecordedTestCase): - def build_provider_aad(self, endpoint, trimmed_key_prefixes=[], selects={SettingSelector("*", "\0")}): + def build_provider_aad(self, endpoint, trim_prefixes=[], selects={SettingSelector(key_filter="*", label_filter="\0")}): cred = self.get_credential(AzureAppConfigurationClient) - return load_provider(credential=cred, endpoint=endpoint, trimmed_key_prefixes=trimmed_key_prefixes, selects=selects) + return load(credential=cred, endpoint=endpoint, trim_prefixes=trim_prefixes, selects=selects) # method: provider_creation_aad @recorded_by_proxy @@ -29,12 +29,12 @@ def test_provider_creation_aad(self, appconfiguration_endpoint_string): assert client["my_json"]["key"] == "value" assert client["FeatureManagementFeatureFlags"]["Alpha"] == '{\"enabled\": false, \"conditions\": {\"client_filters\": []}}' - # method: provider_trimmed_key_prefixes + # method: provider_trim_prefixes @recorded_by_proxy @app_config_decorator_aad - def test_provider_trimmed_key_prefixes(self, appconfiguration_endpoint_string): + def test_provider_trim_prefixes(self, appconfiguration_endpoint_string): trimmed = {"test."} - client = self.build_provider_aad(appconfiguration_endpoint_string, trimmed_key_prefixes=trimmed) + client = self.build_provider_aad(appconfiguration_endpoint_string, trim_prefixes=trimmed) assert client["message"] == "hi" assert client["my_json"]["key"] == "value" assert client["trimmed"] == "key" @@ -45,7 +45,7 @@ def test_provider_trimmed_key_prefixes(self, appconfiguration_endpoint_string): @recorded_by_proxy @app_config_decorator_aad def test_provider_selectors(self, appconfiguration_endpoint_string): - selects = {SettingSelector("message*", "dev")} + selects = {SettingSelector(key_filter="message*",label_filter="dev")} client = self.build_provider_aad(appconfiguration_endpoint_string, selects=selects) assert client["message"] == "test" assert "test.trimmed" not in client diff --git a/sdk/appconfiguration/azure-appconfiguration/README.md b/sdk/appconfiguration/azure-appconfiguration/README.md index c0db43ee7d0c..cd126f431d26 100644 --- a/sdk/appconfiguration/azure-appconfiguration/README.md +++ b/sdk/appconfiguration/azure-appconfiguration/README.md @@ -6,7 +6,11 @@ Modern programs, especially programs running in a cloud, generally have many com Use the client library for App Configuration to create and manage application configuration settings. -[Source code](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/appconfiguration/azure-appconfiguration) | [Package (Pypi)][package] | [API reference documentation](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/appconfiguration/azure-appconfiguration) | [Product documentation][appconfig_docs] +[Source code](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/appconfiguration/azure-appconfiguration) +| [Package (Pypi)][package] +| [Package (Conda)](https://anaconda.org/microsoft/azure-appconfiguration/) +| [API reference documentation](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/appconfiguration/azure-appconfiguration) +| [Product documentation][appconfig_docs] ## _Disclaimer_ @@ -59,6 +63,7 @@ Alternatively, get the connection string from the Azure Portal. Once you have the value of the connection string, you can create the AzureAppConfigurationClient: + ```python import os from azure.appconfiguration import AzureAppConfigurationClient @@ -67,6 +72,7 @@ CONNECTION_STRING = os.environ['APPCONFIGURATION_CONNECTION_STRING'] # Create app config client client = AzureAppConfigurationClient.from_connection_string(CONNECTION_STRING) ``` + #### Use AAD token @@ -167,6 +173,7 @@ There are two ways to store a Configuration Setting: - add_configuration_setting creates a setting only if the setting does not already exist in the store. + ```python config_setting = ConfigurationSetting( key="MyKey", @@ -177,16 +184,19 @@ config_setting = ConfigurationSetting( ) added_config_setting = client.add_configuration_setting(config_setting) ``` + - set_configuration_setting creates a setting if it doesn't exist or overrides an existing setting. + ```python added_config_setting.value = "new value" added_config_setting.content_type = "new content type" updated_config_setting = client.set_configuration_setting(config_setting) ``` + ### Get a Configuration Setting @@ -194,11 +204,13 @@ updated_config_setting = client.set_configuration_setting(config_setting) Get a previously stored Configuration Setting. + ```python fetched_config_setting = client.get_configuration_setting( key="MyKey" ) ``` + ### Delete a Configuration Setting @@ -206,12 +218,14 @@ fetched_config_setting = client.get_configuration_setting( Delete an existing Configuration Setting. + ```python client.delete_configuration_setting( key="MyKey", label="MyLabel", ) ``` + ### List Configuration Settings @@ -219,11 +233,13 @@ client.delete_configuration_setting( List all configuration settings filtered with label_filter and/or key_filter. + ```python config_settings = client.list_configuration_settings(label_filter="MyLabel") for item in config_settings: print_configuration_setting(item) ``` + ### Async APIs @@ -232,6 +248,7 @@ Async client is supported. To use the async client library, import the AzureAppConfigurationClient from package azure.appconfiguration.aio instead of azure.appconfiguration + ```python import os from azure.appconfiguration.aio import AzureAppConfigurationClient @@ -240,27 +257,32 @@ CONNECTION_STRING = os.environ['APPCONFIGURATION_CONNECTION_STRING'] # Create app config client client = AzureAppConfigurationClient.from_connection_string(CONNECTION_STRING) ``` + This async AzureAppConfigurationClient has the same method signatures as the sync ones except that they're async. For instance, to retrieve a Configuration Setting asynchronously, async_client can be used: + ```python fetched_config_setting = await client.get_configuration_setting( key="MyKey" ) ``` + To use list_configuration_settings, call it synchronously and iterate over the returned async iterator asynchronously + ```python config_settings = client.list_configuration_settings(label_filter="MyLabel") async for item in config_settings: print_configuration_setting(item) ``` + ## Troubleshooting diff --git a/sdk/attestation/azure-security-attestation/README.md b/sdk/attestation/azure-security-attestation/README.md index 1b9512733736..c9afe097ac4a 100644 --- a/sdk/attestation/azure-security-attestation/README.md +++ b/sdk/attestation/azure-security-attestation/README.md @@ -12,7 +12,11 @@ This package has been tested with Python 3.6+. For a more complete view of Azure libraries, see the [Azure SDK for Python release page](https://aka.ms/azsdk/python/all). -[Source code][source_code] | [Package (PyPI)][Attestation_pypi] | [API reference documentation][API_reference] | [Product documentation](https://docs.microsoft.com/azure/attestation/) +[Source code][source_code] +| [Package (PyPI)][Attestation_pypi] +| [Package (Conda)](https://anaconda.org/microsoft/azure-security-attestation/) +| [API reference documentation][API_reference] +| [Product documentation](https://docs.microsoft.com/azure/attestation/) ## Getting started diff --git a/sdk/cognitivelanguage/azure-ai-language-conversations/README.md b/sdk/cognitivelanguage/azure-ai-language-conversations/README.md index 4713479dd6a4..82f8eeecc9e6 100644 --- a/sdk/cognitivelanguage/azure-ai-language-conversations/README.md +++ b/sdk/cognitivelanguage/azure-ai-language-conversations/README.md @@ -8,7 +8,14 @@ Conversational Language Understanding - aka **CLU** for short - is a cloud-based - Conversational PII: Used to extract and redact personally-identifiable information (PII) - Conversational Sentiment Analysis: Used to analyze the sentiment of conversations -[Source code][conversationallanguage_client_src] | [Package (PyPI)][conversationallanguage_pypi_package] | [API reference documentation][api_reference_documentation] | [Samples][conversationallanguage_samples] | [Product documentation][conversationallanguage_docs] | [Analysis REST API documentation][conversationanalysis_restdocs] | [Authoring REST API documentation][conversationanalysis_restdocs_authoring] +[Source code][conversationallanguage_client_src] +| [Package (PyPI)][conversationallanguage_pypi_package] +| [Package (Conda)](https://anaconda.org/microsoft/azure-ai-language-conversations/) +| [API reference documentation][api_reference_documentation] +| [Samples][conversationallanguage_samples] +| [Product documentation][conversationallanguage_docs] +| [Analysis REST API documentation][conversationanalysis_restdocs] +| [Authoring REST API documentation][conversationanalysis_restdocs_authoring] ## Getting started diff --git a/sdk/cognitivelanguage/azure-ai-language-questionanswering/README.md b/sdk/cognitivelanguage/azure-ai-language-questionanswering/README.md index fd684a22aeec..092f33e18c6e 100644 --- a/sdk/cognitivelanguage/azure-ai-language-questionanswering/README.md +++ b/sdk/cognitivelanguage/azure-ai-language-questionanswering/README.md @@ -2,7 +2,14 @@ Question Answering is a cloud-based API service that lets you create a conversational question-and-answer layer over your existing data. Use it to build a knowledge base by extracting questions and answers from your semi-structured content, including FAQ, manuals, and documents. Answer users’ questions with the best answers from the QnAs in your knowledge base—automatically. Your knowledge base gets smarter, too, as it continually learns from users' behavior. -[Source code][questionanswering_client_src] | [Package (PyPI)][questionanswering_pypi_package] | [API reference documentation][questionanswering_refdocs] | [Product documentation][questionanswering_docs] | [Samples][questionanswering_samples] | [Analysis REST API documentation][questionanswering_rest_docs] | [Authoring REST API documentation][questionanswering_rest_docs_authoring] +[Source code][questionanswering_client_src] +| [Package (PyPI)][questionanswering_pypi_package] +| [Package (Conda)](https://anaconda.org/microsoft/azure-ai-language-questionanswering/) +| [API reference documentation][questionanswering_refdocs] +| [Product documentation][questionanswering_docs] +| [Samples][questionanswering_samples] +| [Analysis REST API documentation][questionanswering_rest_docs] +| [Authoring REST API documentation][questionanswering_rest_docs_authoring] ## _Disclaimer_ diff --git a/sdk/communication/CONTRIBUTING.md b/sdk/communication/CONTRIBUTING.md index 560d45645f67..6effc4c65403 100644 --- a/sdk/communication/CONTRIBUTING.md +++ b/sdk/communication/CONTRIBUTING.md @@ -32,7 +32,7 @@ If the tests are successful, we can proceed to run the tests in LIVE mode. Because in LIVE mode we are hitting an actual resource, we must set the appropriate environment variable to make sure the code tests against the resource we want. Set up an env variable called `COMMUNICATION_LIVETEST_STATIC_CONNECTION_STRING` (just needed for SMS and Phone Numbers SDKs) and set it to the connection string of the resource you want to test against. -Depending on which package you are testing, it may need special environment variables to test succesfully. The names of these variables can be found inside each test file in the `setUp()` function. Make sure to set these variables before running the tests themselves. You may need to restart your development environment after creating or updating these environment variables. +Depending on which package you are testing, it may need special environment variables to test successfully. The names of these variables can be found inside each test file in the `setUp()` function. Make sure to set these variables before running the tests themselves. You may need to restart your development environment after creating or updating these environment variables. You can run the `pytest .` command after setting the `AZURE_TEST_RUN_LIVE` variable to `true`. @@ -50,6 +50,10 @@ If you are testing against a personal resource, you can check the [Managed Ident For a more in-depth look on how to authenticate using managed identity, refer to the [Azure Identity client library for Python](https://docs.microsoft.com/python/api/overview/azure/identity-readme?view=azure-python) documentation. This document also has more ways for you to authenticate using the DefaultAzureCredential object besides the ones we discussed in this contributing file. +### Running the New-TestResources and Remove-TestResources Scripts + +You may want to run the `New-TestResources.ps1` or `Remove-TestResources.ps1` scripts to test resource deployments in the SDK Live Test pipelines locally. You will need to add the additional `-TestResourceDirectories` parameter when running these scripts. If you are using the shared `test-resources.json` you can point to `communication/test-resources/`. If you are using a custom `test-resources.json`, you can point to `communication//test-resources.json`. + ## Submitting a Pull Request The easiest way for you to test and not worry about any breaking changes you may cause is to create a fork from the [Python Azure SDK repo](https://github.com/Azure/azure-sdk-for-python). After downloading your repo, make sure to add the original repo as an upstream. To do this, use the `git remote add upstream` command followed by the repo's URL. diff --git a/sdk/communication/azure-communication-callautomation/CHANGELOG.md b/sdk/communication/azure-communication-callautomation/CHANGELOG.md new file mode 100644 index 000000000000..f894388cdfc4 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/CHANGELOG.md @@ -0,0 +1,17 @@ +# Release History + +## 1.0.0b1 (Unreleased) +Call Automation enables developers to build call workflows. Personalise customer interactions by listening to call events and take actions based on your business logic. + +### Features Added +- Create outbound calls to an Azure Communication Service user or a phone number. +- Answer/Redirect/Reject incoming call from an Azure Communication Service user or a phone number. +- Transfer the call to another participant. +- List, add or remove participants from the call. +- Hangup or terminate the call. +- Play audio files to one or more participants in the call. +- Recognize incoming DTMF in the call. +- Record calls with option to start/resume/stop. +- Record mixed and unmixed audio recordings. +- Download recordings. +- Parse various events happening in the call, such as CallConnected and PlayCompleted event. diff --git a/sdk/communication/azure-communication-callautomation/LICENSE b/sdk/communication/azure-communication-callautomation/LICENSE new file mode 100644 index 000000000000..63447fd8bbbf --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/LICENSE @@ -0,0 +1,21 @@ +Copyright (c) Microsoft Corporation. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/sdk/communication/azure-communication-callautomation/MANIFEST.in b/sdk/communication/azure-communication-callautomation/MANIFEST.in new file mode 100644 index 000000000000..e1b40cab44d6 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/MANIFEST.in @@ -0,0 +1,7 @@ +include *.md +include azure/__init__.py +include azure/communication/__init__.py +include LICENSE +recursive-include tests *.py +recursive-include samples *.py *.md +include azure/communication/callautomation/py.typed diff --git a/sdk/communication/azure-communication-callautomation/README.md b/sdk/communication/azure-communication-callautomation/README.md new file mode 100644 index 000000000000..146257c16234 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/README.md @@ -0,0 +1,118 @@ +# Azure Communication Call Automation client library for Python + +This package contains a Python SDK for Azure Communication Call Automation. Call Automation provides developers the ability to build server-based, intelligent call workflows, and call recording for voice and PSTN channels. + +[Overview of Call Automation][overview] | [Product documentation][product_docs] + +## _Disclaimer_ +_Azure SDK Python packages support for Python 2.7 has ended 01 January 2022. For more information and questions, please +refer to https://github.com/Azure/azure-sdk-for-python/issues/20691_ + +## Getting started +### Prerequisites +- Python 3.7 or later is required to use this package. +- You need an [Azure subscription][azure_sub] to use this package. +- A deployed Communication Services resource. You can use the [Azure Portal][azure_portal] or the [Azure PowerShell][azure_powershell] to set it up. + +### Installing +Install the Azure Communication Service Call Automation SDK. + +```bash +pip install azure-communication-callautomation +``` + +## Key concepts +| Name | Description | +| -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| CallAutomationClient | `CallAutomationClient` is the primary interface for developers using this client library. It can be used to initiate calls by `createCall` or `answerCall`. | +| CallConnectionClient | `CallConnectionClient` represents a ongoing call. Once the call is established with `createCall` or `answerCall`, further actions can be performed for the call, such as `transfer` or `addParticipant`. | +| CallMediaClient | `CallMediaClient` can be used to do media related actions, such as `play`, to play media file. This can be retrieved from established `CallConnectionClient`. | +| CallRecordingClient | `CallRecordingClient` can be used to do recording related actions, such as `startRecording`. This can be retrieved from `CallAutomationClient`. | +| Callback Events | Callback events are events sent back during duration of the call. It gives information and state of the call, such as `CallConnected`. `CallbackUrl` must be provided during `createCall` and `answerCall`, and callback events will be sent to this url. You can use `callAutomationEventParser` to parse these events when it arrives. | +| Incoming Call Event | When incoming call happens (that can be answered with `answerCall`), incoming call eventgrid event will be sent. This is different from Callback events above, and should be setup on Azure portal. See [Incoming Call][incomingcall] for detail. | + +## Examples +### Initialize CallAutomationClient +```Python +from azure.communication.callautomation import (CallAutomationClient) + +# Your unique Azure Communication service endpoint +endpoint_url = '' +client = new CallAutomationClient.from_connection_string(endpoint_url) +``` + +### Create Call +```Python +from azure.communication.callautomation import ( + CallAutomationClient, + CallInvite, + CommunicationUserIdentifier +) + +# target endpoint for ACS User +user = CommunicationUserIdentifier("8:acs:...") + +# make invitation +call_invite = CallInvite(target=user) + +# callback url to receive callback events +callback_url = "https:///events" + +# send out the invitation, creating call +response = client.create_call(call_invite, callback_url) +``` + +### Play Media +```Python +# from callconnection of response above, play media of media file +my_file = FileSource(uri="https:///.wav") +const response = call_connection.get_call_media().play_to_all(my_file) +``` + +## Troubleshooting +## Next steps +- [Call Automation Overview][overview] +- [Incoming Call Concept][incomingcall] +- [Build a customer interaction workflow using Call Automation][build1] +- [Redirect inbound telephony calls with Call Automation][build2] +- [Quickstart: Play action][build3] +- [Quickstart: Recognize action][build4] +- [Read more about Call Recording in Azure Communication Services][recording1] +- [Record and download calls with Event Grid][recording2] + +## Provide Feedback + +If you encounter any bugs or have suggestions, please file an issue in the [Issues](https://github.com/Azure/azure-sdk-for-python/issues) section of the project + +## Contributing + +This project welcomes contributions and suggestions. Most contributions require +you to agree to a Contributor License Agreement (CLA) declaring that you have +the right to, and actually do, grant us the rights to use your contribution. +For details, visit https://cla.microsoft.com. + +When you submit a pull request, a CLA-bot will automatically determine whether +you need to provide a CLA and decorate the PR appropriately (e.g., label, +comment). Simply follow the instructions provided by the bot. You will only +need to do this once across all repos using our CLA. + +This project has adopted the +[Microsoft Open Source Code of Conduct][code_of_conduct]. For more information, +see the Code of Conduct FAQ or contact opencode@microsoft.com with any +additional questions or comments. + + +[overview]: https://learn.microsoft.com/azure/communication-services/concepts/voice-video-calling/call-automation +[product_docs]: https://docs.microsoft.com/azure/communication-services/overview +[azure_cli]: https://docs.microsoft.com/cli/azure +[azure_sub]: https://azure.microsoft.com/free/ +[azure_portal]: https://portal.azure.com +[azure_powershell]: https://docs.microsoft.com/powershell/module/az.communication/new-azcommunicationservice +[build_doc]: https://aka.ms/AzureSDKBundling +[incomingcall]: https://learn.microsoft.com/azure/communication-services/concepts/voice-video-calling/incoming-call-notification +[build1]: https://learn.microsoft.com/azure/communication-services/quickstarts/voice-video-calling/callflows-for-customer-interactions?pivots=programming-language-csha +[build2]: https://learn.microsoft.com/azure/communication-services/how-tos/call-automation-sdk/redirect-inbound-telephony-calls?pivots=programming-language-csharp +[build3]: https://learn.microsoft.com/azure/communication-services/quickstarts/voice-video-calling/play-action?pivots=programming-language-csharp +[build4]: https://learn.microsoft.com/azure/communication-services/quickstarts/voice-video-calling/recognize-action?pivots=programming-language-csharp +[recording1]: https://learn.microsoft.com/azure/communication-services/concepts/voice-video-calling/call-recording +[recording2]: https://learn.microsoft.com/azure/communication-services/quickstarts/voice-video-calling/get-started-call-recording?pivots=programming-language-csharp diff --git a/sdk/communication/azure-communication-callautomation/azure/__init__.py b/sdk/communication/azure-communication-callautomation/azure/__init__.py new file mode 100644 index 000000000000..69e3be50dac4 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/azure/__init__.py @@ -0,0 +1 @@ +__path__ = __import__('pkgutil').extend_path(__path__, __name__) diff --git a/sdk/communication/azure-communication-callautomation/azure/communication/__init__.py b/sdk/communication/azure-communication-callautomation/azure/communication/__init__.py new file mode 100644 index 000000000000..69e3be50dac4 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/azure/communication/__init__.py @@ -0,0 +1 @@ +__path__ = __import__('pkgutil').extend_path(__path__, __name__) diff --git a/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/__init__.py b/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/__init__.py new file mode 100644 index 000000000000..5dda514d4b1a --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/__init__.py @@ -0,0 +1,111 @@ +from ._version import VERSION +from ._call_connection_client import CallConnectionClient +from ._call_media_client import CallMediaClient +from ._call_recording_client import CallRecordingClient +from ._call_automation_client import ( + CallAutomationClient, + AnswerCallResult, + CreateCallResult +) +from ._call_automation_event_parser import CallAutomationEventParser +from ._models import ( + RecordingStateResponse, + StartRecordingOptions, + ServerCallLocator, + GroupCallLocator, + CallInvite, + RecordingFormat, + RecordingContent, + RecordingStorage, + RecordingChannel, + PlaySource, + FileSource, + CallMediaRecognizeOptions, + CallConnectionProperties, + CallParticipant, + CallMediaRecognizeDtmfOptions, + Gender, + DtmfTone, + CallRejectReason +) +from ._shared.models import ( + CommunicationIdentifier, + PhoneNumberIdentifier, + MicrosoftTeamsUserIdentifier, + CommunicationUserIdentifier +) +from ._events import ( + AddParticipantSucceeded, + AddParticipantFailed, + CallConnected, + CallDisconnected, + CallTransferAccepted, + CallTransferFailed, + ParticipantsUpdated, + RecordingStateChanged, + PlayCompleted, + PlayFailed, + PlayCanceled, + RecognizeCompleted, + RecognizeCanceled, + RecognizeFailed +) +from ._generated.models import ( + GetParticipantsResponse, + TransferCallResponse, + AddParticipantResponse, + CustomContext, + RemoveParticipantResponse +) + +__all__ = [ + 'CallAutomationClient', + 'RecordingFormat', + 'RecordingContent', + 'RecordingStorage', + 'RecordingChannel', + 'CallConnectionClient', + 'CallMediaClient', + 'CallRecordingClient', + "StartRecordingOptions", + "RecordingStateResponse", + "ServerCallLocator", + "GroupCallLocator", + "CallAutomationEventParser", + "AddParticipantSucceeded", + "AddParticipantFailed", + "CallConnected", + "CallDisconnected", + "CallTransferAccepted", + "CallTransferFailed", + "ParticipantsUpdated", + "RecordingStateChanged", + "PlayCompleted", + "PlayFailed", + "PlayCanceled", + "RecognizeCompleted", + "RecognizeCanceled", + "RecognizeFailed", + "CallInvite", + "CommunicationIdentifier", + "CommunicationUserIdentifier", + "PhoneNumberIdentifier", + "MicrosoftTeamsUserIdentifier", + "PlaySource", + "FileSource", + "CallMediaRecognizeOptions", + "CallMediaRecognizeDtmfOptions", + "AnswerCallResult", + "CreateCallResult", + "CallConnectionProperties", + "CallParticipant", + "GetParticipantsResponse", + "TransferCallResponse", + "AddParticipantResponse", + "CustomContext", + "RemoveParticipantResponse", + "Gender", + "DtmfTone", + "CallRejectReason" +] +__version__ = VERSION diff --git a/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_api_versions.py b/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_api_versions.py new file mode 100644 index 000000000000..8960eec937ea --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_api_versions.py @@ -0,0 +1,12 @@ +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ + +from enum import Enum +from azure.core import CaseInsensitiveEnumMeta + +class ApiVersion(str, Enum, metaclass=CaseInsensitiveEnumMeta): + V2023_01_15_PREVIEW = "2023-01-15-preview" + +DEFAULT_VERSION = ApiVersion.V2023_01_15_PREVIEW diff --git a/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_call_automation_client.py b/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_call_automation_client.py new file mode 100644 index 000000000000..c557a02c8e99 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_call_automation_client.py @@ -0,0 +1,439 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- + +from typing import Any, List # pylint: disable=unused-import +from urllib.parse import urlparse +from azure.core.credentials import TokenCredential + +from ._version import SDK_MONIKER +from ._api_versions import DEFAULT_VERSION +from ._call_connection_client import CallConnectionClient +from ._call_recording_client import CallRecordingClient +from ._generated._client import AzureCommunicationCallAutomationService +from ._shared.models import CommunicationIdentifier +from ._communication_identifier_serializer import serialize_phone_identifier, serialize_identifier +from ._shared.utils import get_authentication_policy, parse_connection_str +from ._generated.models import ( + CreateCallRequest, AnswerCallRequest, RedirectCallRequest, RejectCallRequest) +from ._models import (CallInvite, CallConnectionProperties) + + +class CallResult(object): + def __init__( + self, + *, + call_connection: CallConnectionClient, + call_connection_properties: CallConnectionProperties, + **kwargs: Any + ) -> None: + """ + :keyword call_connection: Call connection. Required. + :type call_connection: CallConnectionClient + :keyword call_connection_properties: Properties of the call connection + :type call_connection_properties: CallConnectionProperties + """ + super().__init__(**kwargs) + self.call_connection = call_connection + self.call_connection_properties = call_connection_properties + + +class CreateCallResult(CallResult): + pass + + +class AnswerCallResult(CallResult): + pass + + +class CallAutomationClient(object): + """A client to interact with the AzureCommunicationService CallAutomation service. + + Call Automation provides developers the ability to build server-based, + intelligent call workflows, and call recording for voice and PSTN channels. + + :param str endpoint: + The endpoint of the Azure Communication resource. + :param ~azure.core.credentials.TokenCredential credential: + The credentials with which to authenticate + + :keyword api_version: Azure Communication Call Automation API version. + Default value is "2023-01-15-preview". + Note that overriding this default value may result in unsupported behavior. + :paramtype api_version: str + """ + + def __init__( + self, + endpoint: str, + credential: TokenCredential, + **kwargs + ) -> None: + if not credential: + raise ValueError("credential can not be None") + + try: + if not endpoint.lower().startswith('http'): + endpoint = "https://" + endpoint + except AttributeError: + raise ValueError("Host URL must be a string") + + parsed_url = urlparse(endpoint.rstrip('/')) + if not parsed_url.netloc: + raise ValueError(f"Invalid URL: {format(endpoint)}") + + self._endpoint = endpoint + self._api_version = kwargs.pop("api_version", DEFAULT_VERSION) + self._credential = credential + + self._client = AzureCommunicationCallAutomationService( + self._endpoint, + api_version=self._api_version, + authentication_policy=get_authentication_policy( + endpoint, credential), + sdk_moniker=SDK_MONIKER, + **kwargs) + + self._call_connection_client = self._client.call_connection + self._call_media = self._client.call_media + self._call_recording_client = self._client.call_recording + self.source_identity = kwargs.pop("source_identity", None) + + @classmethod + def from_connection_string( + cls, + conn_str: str, + **kwargs + ) -> 'CallAutomationClient': + """Create CallAutomation from a Connection String. + + :param str conn_str: + A connection string to an Azure Communication Service resource. + + :return: Instance of CallAutomationClient. + :rtype: CallAutomationClient + """ + endpoint, access_key = parse_connection_str(conn_str) + + return cls(endpoint, access_key, **kwargs) + + def get_call_connection( + self, + call_connection_id: str, + **kwargs + ) -> CallConnectionClient: + """Get CallConnectionClient object. + Only use when you already know CallConnectionId for an ongoing call. + + :param str call_connection_id: + CallConnectionId of ongoing call. + + :return: Instance of CallConnectionClient. + :rtype: ~azure.communication.callautomation.CallConnectionClient + """ + if not call_connection_id: + raise ValueError("call_connection_id can not be None") + + return CallConnectionClient( + call_connection_id, + self._call_connection_client, + self._call_media, + **kwargs + ) + + def get_call_recording( + self, + **kwargs + ) -> CallRecordingClient: + """Get CallRecordingClient object. + For any recording related action, use this to perform actions. + + :return: Instance of CallRecordingClient. + :rtype: ~azure.communication.callautomation.CallRecordingClient + """ + return CallRecordingClient( + self._call_recording_client, + **kwargs + ) + + def create_call( + self, + target: CallInvite, + callback_uri: str, + **kwargs + ) -> CreateCallResult: + """ + Create a call connection request from a source identity to a target identity. + + :param target: Required. Call invitee's information. + :type target: CallInvite + :param callback_uri: Required. The call back uri for receiving events. + :type callback_uri: str + :param source_caller_id_number: The source caller Id, a phone number, + that's shown to the PSTN participant being invited. + Required only when calling a PSTN callee. + :type source_caller_id_number: PhoneNumberIdentifier + :param source_display_name: Display name of the call if dialing out to a pstn number. + :type source_display_name: str + :param source_identity: The identifier of the source of the call. + :type source_identity: CommunicationIdentifier + :param operation_context: A customer set value used to track the answering of a call. + :type operation_context: str + :param media_streaming_configuration: Media Streaming Configuration. + :type media_streaming_configuration: MediaStreamingConfiguration + :param azure_cognitive_services_endpoint_url: The identifier of the Cognitive Service resource + assigned to this call. + :type azure_cognitive_services_endpoint_url: str + :return: Instance of CreateCallResult. + :rtype: CreateCallResult + """ + + if not target: + raise ValueError('target cannot be None.') + if not callback_uri: + raise ValueError('callback_uri cannot be None.') + + media_streaming_config = kwargs.pop( + "media_streaming_configuration", None) + create_call_request = CreateCallRequest( + targets=[serialize_identifier(target.target)], + callback_uri=callback_uri, + source_caller_id_number=serialize_phone_identifier( + target.sourceCallIdNumber) if target.sourceCallIdNumber else None, + source_display_name=target.sourceDisplayName, + source_identity=serialize_identifier( + self.source_identity) if self.source_identity else None, + operation_context=kwargs.pop("operation_context", None), + media_streaming_configuration=media_streaming_config.to_generated( + ) if media_streaming_config else None, + azure_cognitive_services_endpoint_url=kwargs.pop( + "azure_cognitive_services_endpoint_url", None), + ) + repeatability_request_id = kwargs.pop("repeatability_request_id", None) + repeatability_first_sent = kwargs.pop("repeatability_first_sent", None) + + result = self._client.create_call( + create_call_request=create_call_request, + repeatability_first_sent=repeatability_first_sent, + repeatability_request_id=repeatability_request_id, + **kwargs) + + return CreateCallResult( + call_connection=self.get_call_connection( + result.call_connection_id), + call_connection_properties=CallConnectionProperties._from_generated( # pylint:disable=protected-access + result)) + + def create_group_call( + self, + targets: List[CommunicationIdentifier], + callback_uri: str, + **kwargs + ) -> CreateCallResult: + """ + Create a call connection request from a source identity to a list of target identities. + + :param targets: Required. A list of targets. + :type targets: list[CommunicationIdentifier] + :param callback_uri: Required. The call back uri for receiving events. + :type callback_uri: str + :param source_caller_id_number: The source caller Id, a phone number, + that's shown to the PSTN participant being invited. + Required only when calling a PSTN callee. + :type source_caller_id_number: PhoneNumberIdentifier + :param source_display_name: Display name of the call if dialing out to a pstn number. + :type source_display_name: str + :param source_identity: The identifier of the source of the call. + :type source_identity: CommunicationIdentifier + :param operation_context: A customer set value used to track the answering of a call. + :type operation_context: str + :param media_streaming_configuration: Media Streaming Configuration. + :type media_streaming_configuration: MediaStreamingConfiguration + :param azure_cognitive_services_endpoint_url: The identifier of the Cognitive Service resource + assigned to this call. + :type azure_cognitive_services_endpoint_url: str + :return: Instance of CreateCallResult. + :rtype: CreateCallResult + """ + + if not targets: + raise ValueError('targets cannot be None.') + if not callback_uri: + raise ValueError('callback_uri cannot be None.') + + caller_id_number = kwargs.pop("source_caller_id_number", None) + media_streaming_config = kwargs.pop( + "media_streaming_configuration", None) + + create_call_request = CreateCallRequest( + targets=[serialize_identifier(identifier) + for identifier in targets], + callback_uri=callback_uri, + source_caller_id_number=serialize_phone_identifier( + caller_id_number) if caller_id_number else None, + source_display_name=kwargs.pop("source_display_name", None), + source_identity=serialize_identifier( + self.source_identity) if self.source_identity else None, + operation_context=kwargs.pop("operation_context", None), + media_streaming_configuration=media_streaming_config.to_generated( + ) if media_streaming_config else None, + azure_cognitive_services_endpoint_url=kwargs.pop( + "azure_cognitive_services_endpoint_url", None), + ) + + repeatability_request_id = kwargs.pop("repeatability_request_id", None) + repeatability_first_sent = kwargs.pop("repeatability_first_sent", None) + + result = self._client.create_call( + create_call_request=create_call_request, + repeatability_first_sent=repeatability_first_sent, + repeatability_request_id=repeatability_request_id, + **kwargs) + + return CreateCallResult( + call_connection=self.get_call_connection( + result.call_connection_id), + call_connection_properties=CallConnectionProperties._from_generated( # pylint:disable=protected-access + result)) + + def answer_call( + self, + incoming_call_context: str, + callback_uri: str, + **kwargs + ) -> AnswerCallResult: + """ + Create a call connection request from a source identity to a list of target identities. + + :param incoming_call_context: Required. The incoming call context. + :type incoming_call_context: str + :param callback_uri: Required. The call back uri for receiving events. + :type callback_uri: str + :param media_streaming_configuration: Media Streaming Configuration. + :type media_streaming_configuration: MediaStreamingConfiguration + :param azure_cognitive_services_endpoint_url: The endpoint uri of + the Azure Cognitive Services resource attached. + :type azure_cognitive_services_endpoint_url: str + :param repeatability_request_id: If specified, the client directs that the request is + repeatable; that is, that the client can make the request multiple times + with the same Repeatability-Request-Id and get back an appropriate response + without the server executing the request multiple times. The value of the + Repeatability-Request-Id is an opaque string representing a client-generated + unique identifier for the request. It is a version 4 (random) + UUID. Default value is None. + :type repeatability_request_id: str + :param repeatability_first_sent: If Repeatability-Request-ID header is specified, + then Repeatability-First-Sent header must also be specified. The value should be + the date and time at which the request was first created, expressed using the + IMF-fixdate form of HTTP-date. + Example: Sun, 06 Nov 1994 08:49:37 GMT. Default value is None. + :type repeatability_first_sent: str + :return: Instance of AnswerCallResult. + :rtype: AnswerCallResult + """ + + if not incoming_call_context: + raise ValueError('incoming_call_context cannot be None.') + if not callback_uri: + raise ValueError('callback_uri cannot be None.') + + media_streaming_config = kwargs.pop( + "media_streaming_configuration", None) + + answer_call_request = AnswerCallRequest( + incoming_call_context=incoming_call_context, + callback_uri=callback_uri, + media_streaming_configuration=media_streaming_config.to_generated( + ) if media_streaming_config else None, + azure_cognitive_services_endpoint_url=kwargs.pop( + "azure_cognitive_services_endpoint_url", None), + answered_by_identifier=serialize_identifier( + self.source_identity) if self.source_identity else None + ) + + repeatability_request_id = kwargs.pop("repeatability_request_id", None) + repeatability_first_sent = kwargs.pop("repeatability_first_sent", None) + + result = self._client.answer_call( + answer_call_request=answer_call_request, + repeatability_first_sent=repeatability_first_sent, + repeatability_request_id=repeatability_request_id, + **kwargs) + + return AnswerCallResult( + call_connection=self.get_call_connection( + result.call_connection_id), + call_connection_properties=CallConnectionProperties._from_generated( # pylint:disable=protected-access + result)) + + def redirect_call( + self, + incoming_call_context: str, + target: CallInvite, + **kwargs + ) -> None: + """ + Redirect a call to a specific target. + + :param incoming_call_context: Required. The incoming call context. + :type incoming_call_context: str + :param target: The target identity to redirect the call to. Required. + :type target: CallInvite + :return: None + :rtype: None + """ + + if not incoming_call_context: + raise ValueError('incoming_call_context cannot be None.') + if not target: + raise ValueError('target cannot be None.') + + redirect_call_request = RedirectCallRequest( + incoming_call_context=incoming_call_context, + target=serialize_identifier(target.target) + ) + + repeatability_request_id = kwargs.pop("repeatability_request_id", None) + repeatability_first_sent = kwargs.pop("repeatability_first_sent", None) + + self._client.redirect_call( + redirect_call_request=redirect_call_request, + repeatability_first_sent=repeatability_first_sent, + repeatability_request_id=repeatability_request_id, + **kwargs) + + def reject_call( + self, + incoming_call_context: str, + **kwargs + ) -> None: + """ + Reject the call. + + :param incoming_call_context: Required. The incoming call context. + :type incoming_call_context: str + :param call_reject_reason: The rejection reason. + Known values are: "none", "busy", and "forbidden". + :type call_reject_reason: str or CallRejectReason + :return: None + :rtype: None + """ + + if not incoming_call_context: + raise ValueError('incoming_call_context cannot be None.') + + reject_call_request = RejectCallRequest( + incoming_call_context=incoming_call_context, + call_reject_reason=kwargs.pop("call_reject_reason", None) + ) + + repeatability_request_id = kwargs.pop("repeatability_request_id", None) + repeatability_first_sent = kwargs.pop("repeatability_first_sent", None) + + self._client.reject_call( + reject_call_request=reject_call_request, + repeatability_first_sent=repeatability_first_sent, + repeatability_request_id=repeatability_request_id, + **kwargs) diff --git a/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_call_automation_event_parser.py b/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_call_automation_event_parser.py new file mode 100644 index 000000000000..0137658b9123 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_call_automation_event_parser.py @@ -0,0 +1,45 @@ +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ + +import json +from azure.communication.callautomation._generated._serialization import Deserializer +from azure.communication.callautomation._generated import models as _models +from ._events_mapping import get_mapping + +class CallAutomationEventParser(object): + + _client_models = {k: v for k, v in _models.__dict__.items() if isinstance(v, type)} + _deserializer = Deserializer(_client_models) + + def __init__( + self + ): + pass + + @classmethod + def parse(cls, parse_string): + + parsed = json.loads(parse_string) + if isinstance(parsed, list): + # If JSON object is an array, extract the first element + parsed = parsed[0] + + event_type = "" + if parsed['type']: + event_type = parsed['type'].split(".")[-1] + + event_mapping = get_mapping() + + if event_type in event_mapping: + event_data = parsed['data'] + event_class = event_mapping[event_type] + + # deserialize event + deserialized = cls._deserializer(event_type, event_data) + + # create public event class with given AutoRest deserialized event + return event_class(deserialized) + + raise ValueError('Unknown event type:', event_type) diff --git a/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_call_connection_client.py b/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_call_connection_client.py new file mode 100644 index 000000000000..6ed369ff2197 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_call_connection_client.py @@ -0,0 +1,267 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- + +from typing import TYPE_CHECKING, Any, Optional # pylint: disable=unused-import + +from ._call_media_client import CallMediaClient + +from ._models import ( + CallConnectionProperties, + CallParticipant, + GetParticipantsResponse, + CallInvite, + AddParticipantResponse +) + +from ._shared.models import CommunicationIdentifier + +from ._communication_identifier_serializer import ( + serialize_phone_identifier, + serialize_identifier +) + +from ._generated.models import ( + TransferCallResponse, + TransferToParticipantRequest, + CustomContext, + AddParticipantRequest, + RemoveParticipantResponse, + RemoveParticipantRequest +) + +if TYPE_CHECKING: + from ._generated.operations import CallConnectionOperations, CallMediaOperations + + +class CallConnectionClient(object): # pylint: disable=client-accepts-api-version-keyword + """A client to interact with media of ongoing call. + + :param str call_connection_id: + Call Connection Id of ongoing call. + :param ~azure.communication.callautomation._generated.operations.CallConnectionOperations call_connection_client: + The REST version of call connection client. + :param ~azure.communication.callautomation._generated.operations.CallMediaOperations call_media_operations: + The REST version of media client. + """ + def __init__(# pylint: disable=missing-client-constructor-parameter-credential, missing-client-constructor-parameter-kwargs + self, + call_connection_id: str, + call_connection_client, # type: CallConnectionOperations + call_media_operations, # type: CallMediaOperations + ) -> None: + + self.call_connection_id = call_connection_id + self._call_connection_client = call_connection_client + self._call_media_operations = call_media_operations + + def get_call_media( + self, + **kwargs # type: Any + ) -> CallMediaClient: + """ + Initializes an instance of the CallMediaClient. + + :return: CallMediaClient + :type: CallMediaClient + """ + return CallMediaClient( + self.call_connection_id, + self._call_media_operations, + **kwargs + ) + + def get_call_properties(self, **kwargs) -> CallConnectionProperties: + """Get call connection. + + Get call connection. + + :return: CallConnectionProperties + :type: CallConnectionProperties + """ + return CallConnectionProperties._from_generated( # pylint:disable=protected-access + self._call_connection_client.get_call(call_connection_id=self.call_connection_id, **kwargs)) + + def hang_up(self, is_for_everyone: bool, **kwargs) -> None: + """Hangup the call. + + Hangup the call. + + :param is_for_everyone: Determine if the call is handed up for all participants. + :type is_for_everyone: bool + :param repeatability_request_id: If specified, the client directs that the request is + repeatable; that is, that the client can make the request multiple times with the same + Repeatability-Request-Id and get back an appropriate response without the server executing the + request multiple times. The value of the Repeatability-Request-Id is an opaque string + representing a client-generated unique identifier for the request. It is a version 4 (random) + UUID. Default value is None. + :type repeatability_request_id: str + :param repeatability_first_sent: If Repeatability-Request-ID header is specified, then + Repeatability-First-Sent header must also be specified. The value should be the date and time + at which the request was first created, expressed using the IMF-fixdate form of HTTP-date. + Example: Sun, 06 Nov 1994 08:49:37 GMT. Default value is None. + :type repeatability_first_sent: str + :return: None + :type: None + """ + + repeatability_request_id = kwargs.pop("repeatability_request_id", None) + repeatability_first_sent = kwargs.pop("repeatability_first_sent", None) + + if is_for_everyone: + self._call_connection_client.terminate_call( + self.call_connection_id, repeatability_first_sent=repeatability_first_sent, + repeatability_request_id=repeatability_request_id, + **kwargs) + else: + self._call_connection_client.hangup_call( + self.call_connection_id, **kwargs) + + def get_participant(self, participantMri: str, **kwargs) -> CallParticipant: + """Get a participant from a call. + + Get a participant from a call. + + :param call_connection_id: The call connection Id. Required. + :type call_connection_id: str + :param participant_raw_id: Raw id of the participant to retrieve. Required. + :type participant_raw_id: str + :return: CallParticipant + """ + return CallParticipant._from_generated( # pylint:disable=protected-access + self._call_connection_client.get_participant(self.call_connection_id, participantMri, **kwargs)) + + def list_participants(self, **kwargs) -> GetParticipantsResponse: + """Get participants from a call. + + Get participants from a call. + + :param call_connection_id: The call connection Id. Required. + :type call_connection_id: str + :param participant_raw_id: Raw id of the participant to retrieve. Required. + :type participant_raw_id: str + :return: GetParticipantsResponse + """ + return GetParticipantsResponse._from_generated( # pylint:disable=protected-access + self._call_connection_client.get_participants(self.call_connection_id, **kwargs)) + + def transfer_call_to_participant(self, target: CallInvite, **kwargs: Any) -> TransferCallResponse: + """ + Transfer the call to a participant. + + :param target: The transfer target. Required. + :type transfer_to_participant_request: CallInvite + :keyword operation_context: The operation context provided by client. + :type operation_context: str + :keyword repeatability_request_id: If specified, the client directs that the request is + repeatable; that is, that the client can make the request multiple times with the same + Repeatability-Request-Id and get back an appropriate response without the server executing the + request multiple times. The value of the Repeatability-Request-Id is an opaque string + representing a client-generated unique identifier for the request. It is a version 4 (random) + UUID. Default value is None. + :type repeatability_request_id: str + :keyword repeatability_first_sent: If Repeatability-Request-ID header is specified, then + Repeatability-First-Sent header must also be specified. The value should be the date and time + at which the request was first created, expressed using the IMF-fixdate form of HTTP-date. + Example: Sun, 06 Nov 1994 08:49:37 GMT. Default value is None. + :type repeatability_first_sent: str + :return: TransferCallResponse + """ + user_custom_context = CustomContext( + voip_headers=target.voipHeaders, sip_headers=target.sipHeaders) + request = TransferToParticipantRequest( + target_participant=serialize_identifier(target.target), + transferee_caller_id=serialize_identifier( + target.sourceCallIdNumber) if target.sourceCallIdNumber else None, + custom_context=user_custom_context, operation_context=kwargs.pop("operation_context", None)) + repeatability_request_id = kwargs.pop("repeatability_request_id", None) + repeatability_first_sent = kwargs.pop("repeatability_first_sent", None) + + return self._call_connection_client.transfer_to_participant( + self.call_connection_id, request, repeatability_first_sent=repeatability_first_sent, + repeatability_request_id=repeatability_request_id, + **kwargs) + + def add_participant(self, participant: CallInvite, **kwargs: Any) -> AddParticipantResponse: + """ + Add a participant to the call. + + :param participant: The participant being added. Required. + :type participant: CallInvite + :keyword invitation_timeout_in_seconds: Gets or sets the timeout to wait for the invited + participant to pickup. + The maximum value of this is 180 seconds. + :type invitation_timeout_in_seconds: int + :keyword operation_context: Used by customers when calling mid-call actions to correlate the + request to the response event. + :type operation_context: str + :keyword repeatability_request_id: If specified, the client directs that the request is + repeatable; that is, that the client can make the request multiple times with the same + Repeatability-Request-Id and get back an appropriate response without the server executing the + request multiple times. The value of the Repeatability-Request-Id is an opaque string + representing a client-generated unique identifier for the request. It is a version 4 (random) + UUID. Default value is None. + :type repeatability_request_id: str + :keyword repeatability_first_sent: If Repeatability-Request-ID header is specified, then + Repeatability-First-Sent header must also be specified. The value should be the date and time + at which the request was first created, expressed using the IMF-fixdate form of HTTP-date. + Example: Sun, 06 Nov 1994 08:49:37 GMT. Default value is None. + :type repeatability_first_sent: str + :return: AddParticipantResponse + """ + user_custom_context = CustomContext( + voip_headers=participant.voipHeaders, sip_headers=participant.sipHeaders) + add_participant_request = AddParticipantRequest( + participant_to_add=serialize_identifier(participant.target), + source_caller_id_number=serialize_phone_identifier( + participant.sourceCallIdNumber) if participant.sourceCallIdNumber else None, + source_display_name=participant.sourceDisplayName, + custom_context=user_custom_context, + invitation_timeout_in_seconds=kwargs.pop( + "invitation_timeout_in_seconds", None), + operation_context=kwargs.pop("operation_context", None)) + repeatability_request_id = kwargs.pop("repeatability_request_id", None) + repeatability_first_sent = kwargs.pop("repeatability_first_sent", None) + + return AddParticipantResponse._from_generated( # pylint:disable=protected-access + self._call_connection_client.add_participant( + self.call_connection_id, + add_participant_request, + repeatability_first_sent=repeatability_first_sent, + repeatability_request_id=repeatability_request_id)) + + def remove_participant(self, participant: CommunicationIdentifier, **kwargs: Any) -> RemoveParticipantResponse: + """ + Remove a participant from the call. + + :param participant: The participant being removed. Required. + :type participant: CallInvite + :keyword operation_context: Used by customers when calling mid-call actions to correlate the + request to the response event. + :type operation_context: str + :keyword repeatability_request_id: If specified, the client directs that the request is + repeatable; that is, that the client can make the request multiple times with the same + Repeatability-Request-Id and get back an appropriate response without the server executing the + request multiple times. The value of the Repeatability-Request-Id is an opaque string + representing a client-generated unique identifier for the request. It is a version 4 (random) + UUID. Default value is None. + :type repeatability_request_id: str + :keyword repeatability_first_sent: If Repeatability-Request-ID header is specified, then + Repeatability-First-Sent header must also be specified. The value should be the date and time + at which the request was first created, expressed using the IMF-fixdate form of HTTP-date. + Example: Sun, 06 Nov 1994 08:49:37 GMT. Default value is None. + :type repeatability_first_sent: str + :return: AddParticipantResponse + """ + + remove_participant_request = RemoveParticipantRequest(participant_to_remove=serialize_identifier(participant), + operation_context=kwargs.pop("operation_context", None)) + repeatability_request_id = kwargs.pop("repeatability_request_id", None) + repeatability_first_sent = kwargs.pop("repeatability_first_sent", None) + + return self._call_connection_client.remove_participant(self.call_connection_id, + remove_participant_request, + repeatability_first_sent=repeatability_first_sent, + repeatability_request_id=repeatability_request_id) diff --git a/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_call_media_client.py b/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_call_media_client.py new file mode 100644 index 000000000000..67ab7609d417 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_call_media_client.py @@ -0,0 +1,167 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- + +from typing import List, TYPE_CHECKING # pylint: disable=unused-import + +from ._api_versions import DEFAULT_VERSION + +from ._generated.models._models import ( + PlayRequest, RecognizeRequest, RecognizeOptions, DtmfOptions, PlayOptions, + PlaySource as PlaySourceInternal, FileSource as FileSourceInternal +) + +from ._generated.models import PlaySourceType +from ._models import ( + CallMediaRecognizeOptions, CallMediaRecognizeDtmfOptions, + PlaySource, FileSource +) + +from ._shared.models import CommunicationIdentifier + +from ._communication_identifier_serializer import serialize_identifier + +if TYPE_CHECKING: + from ._generated.operations import CallMediaOperations + + +class CallMediaClient(object): + """A client to interact with media of ongoing call. + + :param str call_connection_id: + Call Connection Id of ongoing call. + :param ~azure.communication.callautomation._generated.operations.CallMediaOperations call_media_operations: + The REST version of media client. + + :keyword api_version: Azure Communication Call Automation API version. + Default value is "2023-01-15-preview". + Note that overriding this default value may result in unsupported behavior. + :paramtype api_version: str + """ + def __init__(# pylint:disable=missing-client-constructor-parameter-credential + self, + call_connection_id: str, + call_media_operations, # type: CallMediaOperations + **kwargs + ) -> None: + self._api_version = kwargs.pop("api_version", DEFAULT_VERSION) + + self.call_connection_id = call_connection_id + self._call_media_operations = call_media_operations + + @staticmethod + def _create_play_source_internal(play_source): + if isinstance(play_source, FileSource): + file_source = FileSourceInternal(uri=play_source.uri) + return PlaySourceInternal( + source_type=PlaySourceType.FILE, + file_source=file_source, + play_source_id=play_source.play_source_id + ) + return None + + def play_to_all( + self, + play_source: PlaySource, + **kwargs + ) -> None: + """ + Play to all participants. + + :param play_source: A PlaySource representing the source to play. + :type play_source: ~azure.communication.callautomation.PlaySource + + :return: None + :type: None + """ + if not play_source: + raise ValueError('play_source cannot be None.') + + self.play(play_source=play_source, play_to=[], **kwargs) + + def play( + self, + play_source: PlaySource, + play_to: List[CommunicationIdentifier], + **kwargs + ) -> None: + """ + Play. + + :param play_source: Required. A PlaySource representing the source to play. + :type play_source: PlaySource + :param play_to: Required. The targets to play to. + :type play_to: list[~azure.communication.callautomation.models.CommunicationIdentifier] + + :return: None + :type: None + """ + + if not play_source: + raise ValueError('play_source cannot be None.') + + play_request = PlayRequest( + play_source_info=self._create_play_source_internal(play_source), + play_to=[serialize_identifier(identifier) + for identifier in play_to], + play_options=PlayOptions(loop=kwargs.get('loop', False)) + ) + self._call_media_operations.play(self.call_connection_id, play_request) + + def start_recognizing( + self, + recognize_options: CallMediaRecognizeOptions + ) -> None: + """ + Recognize tones. + + :param recognize_options: Different attributes for recognize. + :type recognize_options: ~azure.communication.callautomation.CallMediaRecognizeOptions + + :return: None + :rtype: None + """ + + if not recognize_options: + raise ValueError('recognize_options cannot be None.') + + options = RecognizeOptions( + target_participant=serialize_identifier( + recognize_options.target_participant), + interrupt_prompt=recognize_options.interrupt_prompt, + initial_silence_timeout_in_seconds=recognize_options.initial_silence_timeout + ) + + if isinstance(recognize_options, CallMediaRecognizeDtmfOptions): + options.dtmf_options = DtmfOptions( + inter_tone_timeout_in_seconds=recognize_options.inter_tone_timeout, + max_tones_to_collect=recognize_options.max_tones_to_collect, + stop_tones=recognize_options.stop_dtmf_tones + ) + + play_source = recognize_options.play_prompt + + recognize_request = RecognizeRequest( + recognize_input_type=recognize_options.input_type, + play_prompt=self._create_play_source_internal(play_source), + interrupt_call_media_operation=recognize_options.interrupt_call_media_operation, + operation_context=recognize_options.operation_context, + recognize_options=options + ) + + self._call_media_operations.recognize( + self.call_connection_id, recognize_request) + + def cancel_all_media_operations( + self + ) -> None: + """ + Cancels all the queued media operations. + + :return: None + :type: None + """ + self._call_media_operations.cancel_all_media_operations( + self.call_connection_id) diff --git a/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_call_recording_client.py b/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_call_recording_client.py new file mode 100644 index 000000000000..68398c57afce --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_call_recording_client.py @@ -0,0 +1,128 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- + +from typing import TYPE_CHECKING # pylint: disable=unused-import +from ._models import RecordingStateResponse, StartRecordingOptions + +from ._generated.operations import CallRecordingOperations + +class CallRecordingClient(object): # pylint: disable=client-accepts-api-version-keyword + """A client to interact with recording of ongoing call. + + :param ~azure.communication.callautomation._generated.operations.CallRecordingOperations call_recording_client: + The REST version of recording client. + """ + def __init__(# pylint: disable=missing-client-constructor-parameter-credential, missing-client-constructor-parameter-kwargs + self, + call_recording_client: CallRecordingOperations + ) -> None: + self._call_recording_client = call_recording_client + + def start_recording( + self, + start_recording_options: StartRecordingOptions, + **kwargs + ) -> RecordingStateResponse: + """Start recording the call. + + :param start_recording_options: Required. + :type content: StartRecordingOptions + :keyword repeatability_request_id: If specified, the client directs that the request is + repeatable; that is, that the client can make the request multiple times with the same + Repeatability-Request-Id and get back an appropriate response without the server executing the + request multiple times. The value of the Repeatability-Request-Id is an opaque string + representing a client-generated unique identifier for the request. It is a version 4 (random) + UUID. Default value is None. + :paramtype repeatability_request_id: str + :keyword repeatability_first_sent: If Repeatability-Request-ID header is specified, then + Repeatability-First-Sent header must also be specified. The value should be the date and time + at which the request was first created, expressed using the IMF-fixdate form of HTTP-date. + Example: Sun, 06 Nov 1994 08:49:37 GMT. Default value is None. + :paramtype repeatability_first_sent: str + :keyword content_type: Body Parameter content-type. Content type parameter for binary body. + Default value is "application/json". + :paramtype content_type: str + :return: RecordingStateResponse + :rtype: ~azure.communication.callautomation.models.RecordingStateResponse #todo-itk create + this model, test kwargs + :raises ~azure.core.exceptions.HttpResponseError: + """ + + repeatability_request_id = kwargs.pop("repeatability_request_id", None) + repeatability_first_sent = kwargs.pop("repeatability_first_sent", None) + + recording_state_response = self._call_recording_client.start_recording( + start_call_recording = start_recording_options._to_generated(# pylint:disable=protected-access + ), + repeatability_first_sent = repeatability_first_sent, + repeatability_request_id = repeatability_request_id, + **kwargs) + + return RecordingStateResponse._from_generated(# pylint:disable=protected-access + recording_state_response) + + def stop_recording( + self, + recording_id: str, + **kwargs + ) -> None: + """Stop recording the call. + + :param recording_id: The recording id. Required. + :type recording_id: str + :return: None + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + self._call_recording_client.stop_recording(recording_id = recording_id, **kwargs) + + def pause_recording( + self, + recording_id: str, + **kwargs + ) -> None: + """Pause recording the call. + + :param recording_id: The recording id. Required. + :type recording_id: str + :return: None + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + self._call_recording_client.pause_recording(recording_id = recording_id, **kwargs) + + def resume_recording( + self, + recording_id: str, + **kwargs + ) -> None: + """Resume recording the call. + + :param recording_id: The recording id. Required. + :type recording_id: str + :return: None + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + self._call_recording_client.resume_recording(recording_id = recording_id, **kwargs) + + def get_recording_properties( + self, + recording_id: str, + **kwargs + ) -> RecordingStateResponse: + """Get call recording properties. + + :param recording_id: The recording id. Required. + :type recording_id: str + :return: RecordingStateResponse + :rtype: ~azure.communication.callautomation.models.RecordingStateResponse + :raises ~azure.core.exceptions.HttpResponseError: + """ + recording_state_response = self._call_recording_client.get_recording_properties( + recording_id = recording_id, **kwargs) + return RecordingStateResponse._from_generated(# pylint:disable=protected-access + recording_state_response) diff --git a/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_communication_identifier_serializer.py b/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_communication_identifier_serializer.py new file mode 100644 index 000000000000..0d5460dd490e --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_communication_identifier_serializer.py @@ -0,0 +1,91 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +from typing import Dict, Any, Union + +from ._shared.models import ( + CommunicationIdentifier, + CommunicationUserIdentifier, + PhoneNumberIdentifier, + MicrosoftTeamsUserIdentifier, + UnknownIdentifier, + CommunicationIdentifierKind +) + +from ._generated.models import ( + CommunicationIdentifierModel, + PhoneNumberIdentifierModel +) + +def serialize_identifier(identifier): + # type: (CommunicationIdentifier) -> Dict[str, Any] + """Serialize the Communication identifier into CommunicationIdentifierModel + + :param identifier: Identifier object + :type identifier: CommunicationIdentifier + :return: CommunicationIdentifierModel + """ + try: + request_model = {'raw_id': identifier.raw_id} + + if identifier.kind and identifier.kind != CommunicationIdentifierKind.UNKNOWN: + request_model[identifier.kind] = dict(identifier.properties) + return request_model + except AttributeError: + raise TypeError("Unsupported identifier type " + + identifier.__class__.__name__) + +def serialize_phone_identifier(identifier): + # type: (PhoneNumberIdentifier) -> PhoneNumberIdentifierModel + """Serialize the Communication identifier into CommunicationIdentifierModel + + :param identifier: PhoneNumberIdentifier + :type identifier: PhoneNumberIdentifier + :return: PhoneNumberIdentifierModel + """ + try: + if identifier.kind and identifier.kind == CommunicationIdentifierKind.PHONE_NUMBER: + request_model = PhoneNumberIdentifierModel(value=identifier.properties['value']) + return request_model + raise AttributeError + except AttributeError: + raise TypeError("Unsupported identifier type " + + identifier.__class__.__name__) + +def deserialize_identifier(identifier_model): + # type: (CommunicationIdentifierModel) -> CommunicationIdentifier + """ + Deserialize the CommunicationIdentifierModel into Communication Identifier + + :param identifier_model: CommunicationIdentifierModel + :type identifier_model: CommunicationIdentifierModel + :return: CommunicationIdentifier + """ + raw_id = identifier_model.raw_id + + if identifier_model.communication_user: + return CommunicationUserIdentifier(raw_id, raw_id=raw_id) + if identifier_model.phone_number: + return PhoneNumberIdentifier(identifier_model.phone_number.value, raw_id=raw_id) + if identifier_model.microsoft_teams_user: + return MicrosoftTeamsUserIdentifier( + raw_id=raw_id, + user_id=identifier_model.microsoft_teams_user.user_id, + is_anonymous=identifier_model.microsoft_teams_user.is_anonymous, + cloud=identifier_model.microsoft_teams_user.cloud + ) + return UnknownIdentifier(raw_id) + +def deserialize_phone_identifier(identifier_model) -> Union[PhoneNumberIdentifier, None]: + """ + Deserialize the PhoneNumberIdentifierModel into PhoneNumberIdentifier + + :param identifier_model: PhoneNumberIdentifierModel + :type identifier_model: PhoneNumberIdentifierModel + :return: PhoneNumberIdentifier + """ + if identifier_model: + return PhoneNumberIdentifier(identifier_model.value) + return None diff --git a/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_events.py b/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_events.py new file mode 100644 index 000000000000..b2eb68ef506f --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_events.py @@ -0,0 +1,404 @@ +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ + +from ._generated.models import ( + AddParticipantSucceeded as AddParticipantSucceededRest, + AddParticipantFailed as AddParticipantFailedRest, + CallConnected as CallConnectedRest, + CallDisconnected as CallDisconnectedRest, + CallTransferAccepted as CallTransferAcceptedRest, + CallTransferFailed as CallTransferFailedRest, + ParticipantsUpdated as ParticipantsUpdatedRest, + RecordingStateChanged as RecordingStateChangedRest, + PlayCompleted as PlayCompletedRest, + PlayFailed as PlayFailedRest, + PlayCanceled as PlayCanceledRest, + RecognizeCompleted as RecognizeCompletedRest, + RecognizeCanceled as RecognizeCanceledRest, + RecognizeFailed as RecognizeFailedRest, + CallParticipant +) + +from ._communication_identifier_serializer import deserialize_identifier + +class AddParticipantSucceeded(AddParticipantSucceededRest): + """Event sent when the participant was successfully added to the call. + + :ivar call_connection_id: Call connection ID. + :vartype call_connection_id: str + :ivar server_call_id: Server call ID. + :vartype server_call_id: str + :ivar correlation_id: Correlation ID for event to call correlation. Also Called Skype-Chain-Id. + :vartype correlation_id: str + :ivar operation_context: Used by customers when calling mid-call actions to correlate the + request to the response event. + :vartype operation_context: str + :ivar result_information: Result information of the event. Contains detail information of the outcome. + :vartype result_information: ~azure.communication.callautomation.models.ResultInformation + :ivar participant: participant that was added to the call. + :vartype participant: ~azure.communication.callautomation.models.CommunicationIdentifier + :ivar kind: This event kind. + :vartype kind: str + """ + def __init__(self, parent: AddParticipantSucceededRest, *args, **kwargs): + super().__init__(*args, **kwargs) + self.call_connection_id = parent.call_connection_id + self.server_call_id = parent.server_call_id + self.correlation_id = parent.correlation_id + self.operation_context = parent.operation_context + self.result_information = parent.result_information + self.participant = deserialize_identifier(parent.participant) + self.kind = "AddParticipantSucceeded" + + +class AddParticipantFailed(AddParticipantFailedRest): + """Event sent when the participant was not added successfully to the call. + + :ivar call_connection_id: Call connection ID. + :vartype call_connection_id: str + :ivar server_call_id: Server call ID. + :vartype server_call_id: str + :ivar correlation_id: Correlation ID for event to call correlation. Also Called Skype-Chain-Id. + :vartype correlation_id: str + :ivar operation_context: Used by customers when calling mid-call actions to correlate the + request to the response event. + :vartype operation_context: str + :ivar result_information: Result information of the event. Contains detail information of the outcome. + :vartype result_information: ~azure.communication.callautomation.models.ResultInformation + :ivar participant: participant that was added to the call. + :vartype participant: ~azure.communication.callautomation.models.CommunicationIdentifier + :ivar kind: This event kind. + :vartype kind: str + """ + def __init__(self, parent: AddParticipantFailedRest, *args, **kwargs): + super().__init__(*args, **kwargs) + self.call_connection_id = parent.call_connection_id + self.server_call_id = parent.server_call_id + self.correlation_id = parent.correlation_id + self.operation_context = parent.operation_context + self.result_information = parent.result_information + self.participant = deserialize_identifier(parent.participant) + self.kind = "AddParticipantFailed" + + +class CallConnected(CallConnectedRest): + """Event sent when the call is established. + + :ivar call_connection_id: Call connection ID. + :vartype call_connection_id: str + :ivar server_call_id: Server call ID. + :vartype server_call_id: str + :ivar correlation_id: Correlation ID for event to call correlation. Also Called Skype-Chain-Id. + :vartype correlation_id: str + :ivar operation_context: Used by customers when calling mid-call actions to correlate the + request to the response event. + :vartype operation_context: str + :ivar kind: This event kind. + :vartype kind: str + """ + def __init__(self, parent: CallConnectedRest, *args, **kwargs): + super().__init__(*args, **kwargs) + self.call_connection_id = parent.call_connection_id + self.server_call_id = parent.server_call_id + self.correlation_id = parent.correlation_id + self.operation_context = parent.operation_context + self.kind = "CallConnected" + + +class CallDisconnected(CallDisconnectedRest): + """Event sent when the call is terminated. + + :ivar call_connection_id: Call connection ID. + :vartype call_connection_id: str + :ivar server_call_id: Server call ID. + :vartype server_call_id: str + :ivar correlation_id: Correlation ID for event to call correlation. Also Called Skype-Chain-Id. + :vartype correlation_id: str + :ivar operation_context: Used by customers when calling mid-call actions to correlate the + request to the response event. + :vartype operation_context: str + :ivar kind: This event kind. + :vartype kind: str + """ + def __init__(self, parent: CallDisconnectedRest, *args, **kwargs): + super().__init__(*args, **kwargs) + self.call_connection_id = parent.call_connection_id + self.server_call_id = parent.server_call_id + self.correlation_id = parent.correlation_id + self.operation_context = parent.operation_context + self.kind = "CallDisconnected" + + +class CallTransferAccepted(CallTransferAcceptedRest): + """Event sent when transfer of the call was successful. + + :ivar call_connection_id: Call connection ID. + :vartype call_connection_id: str + :ivar server_call_id: Server call ID. + :vartype server_call_id: str + :ivar correlation_id: Correlation ID for event to call correlation. Also Called Skype-Chain-Id. + :vartype correlation_id: str + :ivar operation_context: Used by customers when calling mid-call actions to correlate the + request to the response event. + :vartype operation_context: str + :ivar result_information: Result information of the event. Contains detail information of the outcome. + :vartype result_information: ~azure.communication.callautomation.models.ResultInformation + :ivar kind: This event kind. + :vartype kind: str + """ + def __init__(self, parent: CallTransferAcceptedRest, *args, **kwargs): + super().__init__(*args, **kwargs) + self.call_connection_id = parent.call_connection_id + self.server_call_id = parent.server_call_id + self.correlation_id = parent.correlation_id + self.operation_context = parent.operation_context + self.result_information = parent.result_information + self.kind = "CallTransferAccepted" + + +class CallTransferFailed(CallTransferFailedRest): + """Event sent when transfer of the call was not successful. + + :ivar call_connection_id: Call connection ID. + :vartype call_connection_id: str + :ivar server_call_id: Server call ID. + :vartype server_call_id: str + :ivar correlation_id: Correlation ID for event to call correlation. Also Called Skype-Chain-Id. + :vartype correlation_id: str + :ivar operation_context: Used by customers when calling mid-call actions to correlate the + request to the response event. + :vartype operation_context: str + :ivar result_information: Result information of the event. Contains detail information of the outcome. + :vartype result_information: ~azure.communication.callautomation.models.ResultInformation + :ivar kind: This event kind. + :vartype kind: str + """ + def __init__(self, parent: CallTransferFailedRest, *args, **kwargs): + super().__init__(*args, **kwargs) + self.call_connection_id = parent.call_connection_id + self.server_call_id = parent.server_call_id + self.correlation_id = parent.correlation_id + self.operation_context = parent.operation_context + self.result_information = parent.result_information + self.kind = "CallTransferFailed" + + +class ParticipantsUpdated(ParticipantsUpdatedRest): + """Event sent when a participant joins, leaves, muted or unmuted. + + :ivar call_connection_id: Call connection ID. + :vartype call_connection_id: str + :ivar server_call_id: Server call ID. + :vartype server_call_id: str + :ivar correlation_id: Correlation ID for event to call correlation. Also Called Skype-Chain-Id. + :vartype correlation_id: str + :vartype operation_context: str + :ivar participants: List of participants in the call. + :vartype participants: [~azure.communication.callautomation.models.CallParticipant] + :ivar kind: This event kind. + :vartype kind: str + """ + def __init__(self, parent: ParticipantsUpdatedRest, *args, **kwargs): + super().__init__(*args, **kwargs) + self.call_connection_id = parent.call_connection_id + self.server_call_id = parent.server_call_id + self.correlation_id = parent.correlation_id + self.participants = [CallParticipant(identifier=deserialize_identifier( + participant.identifier), is_muted=participant.is_muted) for participant in parent.participants] + self.kind = "ParticipantsUpdated" + + +class RecordingStateChanged(RecordingStateChangedRest): + """Event sent when recording state changes. + + :ivar call_connection_id: Call connection ID. + :vartype call_connection_id: str + :ivar server_call_id: Server call ID. + :vartype server_call_id: str + :ivar correlation_id: Correlation ID for event to call correlation. Also Called Skype-Chain-Id. + :vartype correlation_id: str + :ivar recording_id: recording id to be used for recording actions. + :vartype recording_id: str + :ivar state: state of the call recording. + :vartype state: RecordingState + :ivar start_date_time: time the call recording started. + :vartype start_date_time: startDateTime + :ivar kind: This event kind. + :vartype kind: str + """ + def __init__(self, parent: RecordingStateChangedRest, *args, **kwargs): + super().__init__(*args, **kwargs) + self.call_connection_id = parent.call_connection_id + self.server_call_id = parent.server_call_id + self.correlation_id = parent.correlation_id + self.recording_id = parent.recording_id + self.state = parent.state + self.start_date_time = parent.start_date_time + self.kind = "RecordingStateChanged" + + +class PlayCompleted(PlayCompletedRest): + """Event sent when media play is completed successfully. + + :ivar call_connection_id: Call connection ID. + :vartype call_connection_id: str + :ivar server_call_id: Server call ID. + :vartype server_call_id: str + :ivar correlation_id: Correlation ID for event to call correlation. Also Called Skype-Chain-Id. + :vartype correlation_id: str + :ivar operation_context: Used by customers when calling mid-call actions to correlate the + request to the response event. + :vartype operation_context: str + :ivar result_information: Result information of the event. Contains detail information of the outcome. + :vartype result_information: ~azure.communication.callautomation.models.ResultInformation + :ivar kind: This event kind. + :vartype kind: str + """ + def __init__(self, parent: PlayCompletedRest, *args, **kwargs): + super().__init__(*args, **kwargs) + self.call_connection_id = parent.call_connection_id + self.server_call_id = parent.server_call_id + self.correlation_id = parent.correlation_id + self.operation_context = parent.operation_context + self.result_information = parent.result_information + self.kind = "PlayCompleted" + + +class PlayFailed(PlayFailedRest): + """Event sent when media play failed. + + :ivar call_connection_id: Call connection ID. + :vartype call_connection_id: str + :ivar server_call_id: Server call ID. + :vartype server_call_id: str + :ivar correlation_id: Correlation ID for event to call correlation. Also Called Skype-Chain-Id. + :vartype correlation_id: str + :ivar operation_context: Used by customers when calling mid-call actions to correlate the + request to the response event. + :vartype operation_context: str + :ivar result_information: Result information of the event. Contains detail information of the outcome. + :vartype result_information: ~azure.communication.callautomation.models.ResultInformation + :ivar kind: This event kind. + :vartype kind: str + """ + def __init__(self, parent: PlayFailedRest, *args, **kwargs): + super().__init__(*args, **kwargs) + self.call_connection_id = parent.call_connection_id + self.server_call_id = parent.server_call_id + self.correlation_id = parent.correlation_id + self.operation_context = parent.operation_context + self.result_information = parent.result_information + self.kind = "PlayFailed" + + +class PlayCanceled(PlayCanceledRest): + """Event sent when media play is cancelled. + + :ivar call_connection_id: Call connection ID. + :vartype call_connection_id: str + :ivar server_call_id: Server call ID. + :vartype server_call_id: str + :ivar correlation_id: Correlation ID for event to call correlation. Also Called Skype-Chain-Id. + :vartype correlation_id: str + :ivar operation_context: Used by customers when calling mid-call actions to correlate the + request to the response event. + :vartype operation_context: str + :ivar kind: This event kind. + :vartype kind: str + """ + def __init__(self, parent: PlayCanceledRest, *args, **kwargs): + super().__init__(*args, **kwargs) + self.call_connection_id = parent.call_connection_id + self.server_call_id = parent.server_call_id + self.correlation_id = parent.correlation_id + self.operation_context = parent.operation_context + self.kind = "PlayCanceled" + + +class RecognizeCompleted(RecognizeCompletedRest): + """Event sent when recognize is completed successfully. + + :ivar call_connection_id: Call connection ID. + :vartype call_connection_id: str + :ivar server_call_id: Server call ID. + :vartype server_call_id: str + :ivar correlation_id: Correlation ID for event to call correlation. Also called ChainId for + skype chain ID. + :vartype correlation_id: str + :ivar operation_context: Used by customers when calling mid-call actions to correlate the + request to the response event. + :vartype operation_context: str + :ivar result_information: Result information of the event. Contains detail information of the outcome. + :vartype result_information: ~azure.communication.callautomation.models.ResultInformation + :ivar recognition_type: Determines the sub-type of the recognize operation. + In case of cancel operation the this field is not set and is returned empty. Known values are: + "dtmf" and "choices". + :vartype recognition_type: str or ~azure.communication.callautomation.models.RecognitionType + :ivar collect_tones_result: Defines the result for RecognitionType = Dtmf. + :vartype collect_tones_result: ~azure.communication.callautomation.models.CollectTonesResult + :ivar choice_result: Defines the result for RecognitionType = Choices. + :vartype choice_result: ~azure.communication.callautomation.models.ChoiceResult + :ivar kind: This event kind. + :vartype kind: str + """ + def __init__(self, parent: RecognizeCompletedRest, *args, **kwargs): + super().__init__(*args, **kwargs) + self.call_connection_id = parent.call_connection_id + self.server_call_id = parent.server_call_id + self.correlation_id = parent.correlation_id + self.operation_context = parent.operation_context + self.result_information = parent.result_information + self.recognition_type = parent.recognition_type + self.collect_tones_result = parent.collect_tones_result + self.choice_result = parent.choice_result + self.kind = "RecognizeCompleted" + + +class RecognizeFailed(RecognizeFailedRest): + """Event sent when recognize action failed. + + :ivar call_connection_id: Call connection ID. + :vartype call_connection_id: str + :ivar server_call_id: Server call ID. + :vartype server_call_id: str + :ivar correlation_id: Correlation ID for event to call correlation. Also Called Skype-Chain-Id. + :vartype correlation_id: str + :ivar operation_context: Used by customers when calling mid-call actions to correlate the + request to the response event. + :vartype operation_context: str + :ivar kind: This event kind. + :vartype kind: str + """ + def __init__(self, parent: RecognizeFailedRest, *args, **kwargs): + super().__init__(*args, **kwargs) + self.call_connection_id = parent.call_connection_id + self.server_call_id = parent.server_call_id + self.correlation_id = parent.correlation_id + self.operation_context = parent.operation_context + self.kind = "RecognizeFailed" + + +class RecognizeCanceled(RecognizeCanceledRest): + """Event sent when recognize is cancelled. + + :ivar call_connection_id: Call connection ID. + :vartype call_connection_id: str + :ivar server_call_id: Server call ID. + :vartype server_call_id: str + :ivar correlation_id: Correlation ID for event to call correlation. Also Called Skype-Chain-Id. + :vartype correlation_id: str + :ivar operation_context: Used by customers when calling mid-call actions to correlate the + request to the response event. + :vartype operation_context: str + :ivar kind: This event kind. + :vartype kind: str + """ + def __init__(self, parent: RecognizeCanceledRest, *args, **kwargs): + super().__init__(*args, **kwargs) + self.call_connection_id = parent.call_connection_id + self.server_call_id = parent.server_call_id + self.correlation_id = parent.correlation_id + self.operation_context = parent.operation_context + self.kind = "RecognizeCanceled" diff --git a/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_events_mapping.py b/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_events_mapping.py new file mode 100644 index 000000000000..b892794efc53 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_events_mapping.py @@ -0,0 +1,41 @@ +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ + +from ._events import ( + AddParticipantSucceeded, + AddParticipantFailed, + CallConnected, + CallDisconnected, + CallTransferAccepted, + CallTransferFailed, + ParticipantsUpdated, + RecordingStateChanged, + PlayCompleted, + PlayFailed, + PlayCanceled, + RecognizeCompleted, + RecognizeCanceled, + RecognizeFailed +) + +_call_automation_event_mapping = { + "AddParticipantSucceeded": AddParticipantSucceeded, + "AddParticipantFailed": AddParticipantFailed, + "CallConnected": CallConnected, + "CallDisconnected": CallDisconnected, + "CallTransferAccepted": CallTransferAccepted, + "CallTransferFailed": CallTransferFailed, + "ParticipantsUpdated": ParticipantsUpdated, + "RecordingStateChanged": RecordingStateChanged, + "PlayCompleted": PlayCompleted, + "PlayFailed": PlayFailed, + "PlayCanceled": PlayCanceled, + "RecognizeCompleted": RecognizeCompleted, + "RecognizeCanceled": RecognizeCanceled, + "RecognizeFailed": RecognizeFailed +} + +def get_mapping(): + return _call_automation_event_mapping diff --git a/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_generated/__init__.py b/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_generated/__init__.py new file mode 100644 index 000000000000..bd660b0173b5 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_generated/__init__.py @@ -0,0 +1,23 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from ._client import AzureCommunicationCallAutomationService + +try: + from ._patch import __all__ as _patch_all + from ._patch import * # pylint: disable=unused-wildcard-import +except ImportError: + _patch_all = [] +from ._patch import patch_sdk as _patch_sdk + +__all__ = [ + "AzureCommunicationCallAutomationService", +] +__all__.extend([p for p in _patch_all if p not in __all__]) + +_patch_sdk() diff --git a/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_generated/_client.py b/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_generated/_client.py new file mode 100644 index 000000000000..8518d9d49af4 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_generated/_client.py @@ -0,0 +1,94 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from copy import deepcopy +from typing import Any + +from azure.core import PipelineClient +from azure.core.rest import HttpRequest, HttpResponse + +from . import models as _models +from ._configuration import AzureCommunicationCallAutomationServiceConfiguration +from ._serialization import Deserializer, Serializer +from .operations import ( + AzureCommunicationCallAutomationServiceOperationsMixin, + CallConnectionOperations, + CallMediaOperations, + CallRecordingOperations, +) + + +class AzureCommunicationCallAutomationService( + AzureCommunicationCallAutomationServiceOperationsMixin +): # pylint: disable=client-accepts-api-version-keyword + """Azure Communication Service Call Automation APIs. + + :ivar call_connection: CallConnectionOperations operations + :vartype call_connection: + azure.communication.callautomation.operations.CallConnectionOperations + :ivar call_media: CallMediaOperations operations + :vartype call_media: azure.communication.callautomation.operations.CallMediaOperations + :ivar call_recording: CallRecordingOperations operations + :vartype call_recording: azure.communication.callautomation.operations.CallRecordingOperations + :param endpoint: The endpoint of the Azure Communication resource. Required. + :type endpoint: str + :keyword api_version: Api Version. Default value is "2023-01-15-preview". Note that overriding + this default value may result in unsupported behavior. + :paramtype api_version: str + """ + + def __init__( # pylint: disable=missing-client-constructor-parameter-credential + self, endpoint: str, **kwargs: Any + ) -> None: + _endpoint = "{endpoint}" + self._config = AzureCommunicationCallAutomationServiceConfiguration(endpoint=endpoint, **kwargs) + self._client = PipelineClient(base_url=_endpoint, config=self._config, **kwargs) + + client_models = {k: v for k, v in _models.__dict__.items() if isinstance(v, type)} + self._serialize = Serializer(client_models) + self._deserialize = Deserializer(client_models) + self._serialize.client_side_validation = False + self.call_connection = CallConnectionOperations(self._client, self._config, self._serialize, self._deserialize) + self.call_media = CallMediaOperations(self._client, self._config, self._serialize, self._deserialize) + self.call_recording = CallRecordingOperations(self._client, self._config, self._serialize, self._deserialize) + + def send_request(self, request: HttpRequest, **kwargs: Any) -> HttpResponse: + """Runs the network request through the client's chained policies. + + >>> from azure.core.rest import HttpRequest + >>> request = HttpRequest("GET", "https://www.example.org/") + + >>> response = client.send_request(request) + + + For more information on this code flow, see https://aka.ms/azsdk/dpcodegen/python/send_request + + :param request: The network request you want to make. Required. + :type request: ~azure.core.rest.HttpRequest + :keyword bool stream: Whether the response payload will be streamed. Defaults to False. + :return: The response of your network call. Does not do error handling on your response. + :rtype: ~azure.core.rest.HttpResponse + """ + + request_copy = deepcopy(request) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + + request_copy.url = self._client.format_url(request_copy.url, **path_format_arguments) + return self._client.send_request(request_copy, **kwargs) + + def close(self) -> None: + self._client.close() + + def __enter__(self) -> "AzureCommunicationCallAutomationService": + self._client.__enter__() + return self + + def __exit__(self, *exc_details: Any) -> None: + self._client.__exit__(*exc_details) diff --git a/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_generated/_configuration.py b/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_generated/_configuration.py new file mode 100644 index 000000000000..0e2c07fa53c2 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_generated/_configuration.py @@ -0,0 +1,59 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +import sys +from typing import Any + +from azure.core.configuration import Configuration +from azure.core.pipeline import policies + +if sys.version_info >= (3, 8): + from typing import Literal # pylint: disable=no-name-in-module, ungrouped-imports +else: + from typing_extensions import Literal # type: ignore # pylint: disable=ungrouped-imports + +VERSION = "unknown" + + +class AzureCommunicationCallAutomationServiceConfiguration( + Configuration +): # pylint: disable=too-many-instance-attributes + """Configuration for AzureCommunicationCallAutomationService. + + Note that all parameters used to create this instance are saved as instance + attributes. + + :param endpoint: The endpoint of the Azure Communication resource. Required. + :type endpoint: str + :keyword api_version: Api Version. Default value is "2023-01-15-preview". Note that overriding + this default value may result in unsupported behavior. + :paramtype api_version: str + """ + + def __init__(self, endpoint: str, **kwargs: Any) -> None: + super(AzureCommunicationCallAutomationServiceConfiguration, self).__init__(**kwargs) + api_version: Literal["2023-01-15-preview"] = kwargs.pop("api_version", "2023-01-15-preview") + + if endpoint is None: + raise ValueError("Parameter 'endpoint' must not be None.") + + self.endpoint = endpoint + self.api_version = api_version + kwargs.setdefault("sdk_moniker", "communication-callautomation/{}".format(VERSION)) + self._configure(**kwargs) + + def _configure(self, **kwargs: Any) -> None: + self.user_agent_policy = kwargs.get("user_agent_policy") or policies.UserAgentPolicy(**kwargs) + self.headers_policy = kwargs.get("headers_policy") or policies.HeadersPolicy(**kwargs) + self.proxy_policy = kwargs.get("proxy_policy") or policies.ProxyPolicy(**kwargs) + self.logging_policy = kwargs.get("logging_policy") or policies.NetworkTraceLoggingPolicy(**kwargs) + self.http_logging_policy = kwargs.get("http_logging_policy") or policies.HttpLoggingPolicy(**kwargs) + self.retry_policy = kwargs.get("retry_policy") or policies.RetryPolicy(**kwargs) + self.custom_hook_policy = kwargs.get("custom_hook_policy") or policies.CustomHookPolicy(**kwargs) + self.redirect_policy = kwargs.get("redirect_policy") or policies.RedirectPolicy(**kwargs) + self.authentication_policy = kwargs.get("authentication_policy") diff --git a/sdk/keyvault/azure-keyvault-administration/azure/keyvault/administration/_generated/v7_4_preview_1/_patch.py b/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_generated/_patch.py similarity index 100% rename from sdk/keyvault/azure-keyvault-administration/azure/keyvault/administration/_generated/v7_4_preview_1/_patch.py rename to sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_generated/_patch.py diff --git a/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_generated/_serialization.py b/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_generated/_serialization.py new file mode 100644 index 000000000000..f17c068e833e --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_generated/_serialization.py @@ -0,0 +1,1996 @@ +# -------------------------------------------------------------------------- +# +# Copyright (c) Microsoft Corporation. All rights reserved. +# +# The MIT License (MIT) +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the ""Software""), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +# IN THE SOFTWARE. +# +# -------------------------------------------------------------------------- + +# pylint: skip-file +# pyright: reportUnnecessaryTypeIgnoreComment=false + +from base64 import b64decode, b64encode +import calendar +import datetime +import decimal +import email +from enum import Enum +import json +import logging +import re +import sys +import codecs +from typing import ( + Dict, + Any, + cast, + Optional, + Union, + AnyStr, + IO, + Mapping, + Callable, + TypeVar, + MutableMapping, + Type, + List, + Mapping, +) + +try: + from urllib import quote # type: ignore +except ImportError: + from urllib.parse import quote +import xml.etree.ElementTree as ET + +import isodate # type: ignore + +from azure.core.exceptions import DeserializationError, SerializationError, raise_with_traceback +from azure.core.serialization import NULL as AzureCoreNull + +_BOM = codecs.BOM_UTF8.decode(encoding="utf-8") + +ModelType = TypeVar("ModelType", bound="Model") +JSON = MutableMapping[str, Any] + + +class RawDeserializer: + + # Accept "text" because we're open minded people... + JSON_REGEXP = re.compile(r"^(application|text)/([a-z+.]+\+)?json$") + + # Name used in context + CONTEXT_NAME = "deserialized_data" + + @classmethod + def deserialize_from_text(cls, data: Optional[Union[AnyStr, IO]], content_type: Optional[str] = None) -> Any: + """Decode data according to content-type. + + Accept a stream of data as well, but will be load at once in memory for now. + + If no content-type, will return the string version (not bytes, not stream) + + :param data: Input, could be bytes or stream (will be decoded with UTF8) or text + :type data: str or bytes or IO + :param str content_type: The content type. + """ + if hasattr(data, "read"): + # Assume a stream + data = cast(IO, data).read() + + if isinstance(data, bytes): + data_as_str = data.decode(encoding="utf-8-sig") + else: + # Explain to mypy the correct type. + data_as_str = cast(str, data) + + # Remove Byte Order Mark if present in string + data_as_str = data_as_str.lstrip(_BOM) + + if content_type is None: + return data + + if cls.JSON_REGEXP.match(content_type): + try: + return json.loads(data_as_str) + except ValueError as err: + raise DeserializationError("JSON is invalid: {}".format(err), err) + elif "xml" in (content_type or []): + try: + + try: + if isinstance(data, unicode): # type: ignore + # If I'm Python 2.7 and unicode XML will scream if I try a "fromstring" on unicode string + data_as_str = data_as_str.encode(encoding="utf-8") # type: ignore + except NameError: + pass + + return ET.fromstring(data_as_str) # nosec + except ET.ParseError: + # It might be because the server has an issue, and returned JSON with + # content-type XML.... + # So let's try a JSON load, and if it's still broken + # let's flow the initial exception + def _json_attemp(data): + try: + return True, json.loads(data) + except ValueError: + return False, None # Don't care about this one + + success, json_result = _json_attemp(data) + if success: + return json_result + # If i'm here, it's not JSON, it's not XML, let's scream + # and raise the last context in this block (the XML exception) + # The function hack is because Py2.7 messes up with exception + # context otherwise. + _LOGGER.critical("Wasn't XML not JSON, failing") + raise_with_traceback(DeserializationError, "XML is invalid") + raise DeserializationError("Cannot deserialize content-type: {}".format(content_type)) + + @classmethod + def deserialize_from_http_generics(cls, body_bytes: Optional[Union[AnyStr, IO]], headers: Mapping) -> Any: + """Deserialize from HTTP response. + + Use bytes and headers to NOT use any requests/aiohttp or whatever + specific implementation. + Headers will tested for "content-type" + """ + # Try to use content-type from headers if available + content_type = None + if "content-type" in headers: + content_type = headers["content-type"].split(";")[0].strip().lower() + # Ouch, this server did not declare what it sent... + # Let's guess it's JSON... + # Also, since Autorest was considering that an empty body was a valid JSON, + # need that test as well.... + else: + content_type = "application/json" + + if body_bytes: + return cls.deserialize_from_text(body_bytes, content_type) + return None + + +try: + basestring # type: ignore + unicode_str = unicode # type: ignore +except NameError: + basestring = str + unicode_str = str + +_LOGGER = logging.getLogger(__name__) + +try: + _long_type = long # type: ignore +except NameError: + _long_type = int + + +class UTC(datetime.tzinfo): + """Time Zone info for handling UTC""" + + def utcoffset(self, dt): + """UTF offset for UTC is 0.""" + return datetime.timedelta(0) + + def tzname(self, dt): + """Timestamp representation.""" + return "Z" + + def dst(self, dt): + """No daylight saving for UTC.""" + return datetime.timedelta(hours=1) + + +try: + from datetime import timezone as _FixedOffset # type: ignore +except ImportError: # Python 2.7 + + class _FixedOffset(datetime.tzinfo): # type: ignore + """Fixed offset in minutes east from UTC. + Copy/pasted from Python doc + :param datetime.timedelta offset: offset in timedelta format + """ + + def __init__(self, offset): + self.__offset = offset + + def utcoffset(self, dt): + return self.__offset + + def tzname(self, dt): + return str(self.__offset.total_seconds() / 3600) + + def __repr__(self): + return "".format(self.tzname(None)) + + def dst(self, dt): + return datetime.timedelta(0) + + def __getinitargs__(self): + return (self.__offset,) + + +try: + from datetime import timezone + + TZ_UTC = timezone.utc +except ImportError: + TZ_UTC = UTC() # type: ignore + +_FLATTEN = re.compile(r"(? None: + self.additional_properties: Dict[str, Any] = {} + for k in kwargs: + if k not in self._attribute_map: + _LOGGER.warning("%s is not a known attribute of class %s and will be ignored", k, self.__class__) + elif k in self._validation and self._validation[k].get("readonly", False): + _LOGGER.warning("Readonly attribute %s will be ignored in class %s", k, self.__class__) + else: + setattr(self, k, kwargs[k]) + + def __eq__(self, other: Any) -> bool: + """Compare objects by comparing all attributes.""" + if isinstance(other, self.__class__): + return self.__dict__ == other.__dict__ + return False + + def __ne__(self, other: Any) -> bool: + """Compare objects by comparing all attributes.""" + return not self.__eq__(other) + + def __str__(self) -> str: + return str(self.__dict__) + + @classmethod + def enable_additional_properties_sending(cls) -> None: + cls._attribute_map["additional_properties"] = {"key": "", "type": "{object}"} + + @classmethod + def is_xml_model(cls) -> bool: + try: + cls._xml_map # type: ignore + except AttributeError: + return False + return True + + @classmethod + def _create_xml_node(cls): + """Create XML node.""" + try: + xml_map = cls._xml_map # type: ignore + except AttributeError: + xml_map = {} + + return _create_xml_node(xml_map.get("name", cls.__name__), xml_map.get("prefix", None), xml_map.get("ns", None)) + + def serialize(self, keep_readonly: bool = False, **kwargs: Any) -> JSON: + """Return the JSON that would be sent to azure from this model. + + This is an alias to `as_dict(full_restapi_key_transformer, keep_readonly=False)`. + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize(self, keep_readonly=keep_readonly, **kwargs) + + def as_dict( + self, + keep_readonly: bool = True, + key_transformer: Callable[[str, Dict[str, Any], Any], Any] = attribute_transformer, + **kwargs: Any + ) -> JSON: + """Return a dict that can be serialized using json.dump. + + Advanced usage might optionally use a callback as parameter: + + .. code::python + + def my_key_transformer(key, attr_desc, value): + return key + + Key is the attribute name used in Python. Attr_desc + is a dict of metadata. Currently contains 'type' with the + msrest type and 'key' with the RestAPI encoded key. + Value is the current value in this object. + + The string returned will be used to serialize the key. + If the return type is a list, this is considered hierarchical + result dict. + + See the three examples in this file: + + - attribute_transformer + - full_restapi_key_transformer + - last_restapi_key_transformer + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param function key_transformer: A key transformer function. + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize(self, key_transformer=key_transformer, keep_readonly=keep_readonly, **kwargs) + + @classmethod + def _infer_class_models(cls): + try: + str_models = cls.__module__.rsplit(".", 1)[0] + models = sys.modules[str_models] + client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)} + if cls.__name__ not in client_models: + raise ValueError("Not Autorest generated code") + except Exception: + # Assume it's not Autorest generated (tests?). Add ourselves as dependencies. + client_models = {cls.__name__: cls} + return client_models + + @classmethod + def deserialize(cls: Type[ModelType], data: Any, content_type: Optional[str] = None) -> ModelType: + """Parse a str using the RestAPI syntax and return a model. + + :param str data: A str using RestAPI structure. JSON by default. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises: DeserializationError if something went wrong + """ + deserializer = Deserializer(cls._infer_class_models()) + return deserializer(cls.__name__, data, content_type=content_type) + + @classmethod + def from_dict( + cls: Type[ModelType], + data: Any, + key_extractors: Optional[Callable[[str, Dict[str, Any], Any], Any]] = None, + content_type: Optional[str] = None, + ) -> ModelType: + """Parse a dict using given key extractor return a model. + + By default consider key + extractors (rest_key_case_insensitive_extractor, attribute_key_case_insensitive_extractor + and last_rest_key_case_insensitive_extractor) + + :param dict data: A dict using RestAPI structure + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises: DeserializationError if something went wrong + """ + deserializer = Deserializer(cls._infer_class_models()) + deserializer.key_extractors = ( # type: ignore + [ # type: ignore + attribute_key_case_insensitive_extractor, + rest_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + if key_extractors is None + else key_extractors + ) + return deserializer(cls.__name__, data, content_type=content_type) + + @classmethod + def _flatten_subtype(cls, key, objects): + if "_subtype_map" not in cls.__dict__: + return {} + result = dict(cls._subtype_map[key]) + for valuetype in cls._subtype_map[key].values(): + result.update(objects[valuetype]._flatten_subtype(key, objects)) + return result + + @classmethod + def _classify(cls, response, objects): + """Check the class _subtype_map for any child classes. + We want to ignore any inherited _subtype_maps. + Remove the polymorphic key from the initial data. + """ + for subtype_key in cls.__dict__.get("_subtype_map", {}).keys(): + subtype_value = None + + if not isinstance(response, ET.Element): + rest_api_response_key = cls._get_rest_key_parts(subtype_key)[-1] + subtype_value = response.pop(rest_api_response_key, None) or response.pop(subtype_key, None) + else: + subtype_value = xml_key_extractor(subtype_key, cls._attribute_map[subtype_key], response) + if subtype_value: + # Try to match base class. Can be class name only + # (bug to fix in Autorest to support x-ms-discriminator-name) + if cls.__name__ == subtype_value: + return cls + flatten_mapping_type = cls._flatten_subtype(subtype_key, objects) + try: + return objects[flatten_mapping_type[subtype_value]] # type: ignore + except KeyError: + _LOGGER.warning( + "Subtype value %s has no mapping, use base class %s.", + subtype_value, + cls.__name__, + ) + break + else: + _LOGGER.warning("Discriminator %s is absent or null, use base class %s.", subtype_key, cls.__name__) + break + return cls + + @classmethod + def _get_rest_key_parts(cls, attr_key): + """Get the RestAPI key of this attr, split it and decode part + :param str attr_key: Attribute key must be in attribute_map. + :returns: A list of RestAPI part + :rtype: list + """ + rest_split_key = _FLATTEN.split(cls._attribute_map[attr_key]["key"]) + return [_decode_attribute_map_key(key_part) for key_part in rest_split_key] + + +def _decode_attribute_map_key(key): + """This decode a key in an _attribute_map to the actual key we want to look at + inside the received data. + + :param str key: A key string from the generated code + """ + return key.replace("\\.", ".") + + +class Serializer(object): + """Request object model serializer.""" + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + _xml_basic_types_serializers = {"bool": lambda x: str(x).lower()} + days = {0: "Mon", 1: "Tue", 2: "Wed", 3: "Thu", 4: "Fri", 5: "Sat", 6: "Sun"} + months = { + 1: "Jan", + 2: "Feb", + 3: "Mar", + 4: "Apr", + 5: "May", + 6: "Jun", + 7: "Jul", + 8: "Aug", + 9: "Sep", + 10: "Oct", + 11: "Nov", + 12: "Dec", + } + validation = { + "min_length": lambda x, y: len(x) < y, + "max_length": lambda x, y: len(x) > y, + "minimum": lambda x, y: x < y, + "maximum": lambda x, y: x > y, + "minimum_ex": lambda x, y: x <= y, + "maximum_ex": lambda x, y: x >= y, + "min_items": lambda x, y: len(x) < y, + "max_items": lambda x, y: len(x) > y, + "pattern": lambda x, y: not re.match(y, x, re.UNICODE), + "unique": lambda x, y: len(x) != len(set(x)), + "multiple": lambda x, y: x % y != 0, + } + + def __init__(self, classes: Optional[Mapping[str, Type[ModelType]]] = None): + self.serialize_type = { + "iso-8601": Serializer.serialize_iso, + "rfc-1123": Serializer.serialize_rfc, + "unix-time": Serializer.serialize_unix, + "duration": Serializer.serialize_duration, + "date": Serializer.serialize_date, + "time": Serializer.serialize_time, + "decimal": Serializer.serialize_decimal, + "long": Serializer.serialize_long, + "bytearray": Serializer.serialize_bytearray, + "base64": Serializer.serialize_base64, + "object": self.serialize_object, + "[]": self.serialize_iter, + "{}": self.serialize_dict, + } + self.dependencies: Dict[str, Type[ModelType]] = dict(classes) if classes else {} + self.key_transformer = full_restapi_key_transformer + self.client_side_validation = True + + def _serialize(self, target_obj, data_type=None, **kwargs): + """Serialize data into a string according to type. + + :param target_obj: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, dict + :raises: SerializationError if serialization fails. + """ + key_transformer = kwargs.get("key_transformer", self.key_transformer) + keep_readonly = kwargs.get("keep_readonly", False) + if target_obj is None: + return None + + attr_name = None + class_name = target_obj.__class__.__name__ + + if data_type: + return self.serialize_data(target_obj, data_type, **kwargs) + + if not hasattr(target_obj, "_attribute_map"): + data_type = type(target_obj).__name__ + if data_type in self.basic_types.values(): + return self.serialize_data(target_obj, data_type, **kwargs) + + # Force "is_xml" kwargs if we detect a XML model + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + is_xml_model_serialization = kwargs.setdefault("is_xml", target_obj.is_xml_model()) + + serialized = {} + if is_xml_model_serialization: + serialized = target_obj._create_xml_node() + try: + attributes = target_obj._attribute_map + for attr, attr_desc in attributes.items(): + attr_name = attr + if not keep_readonly and target_obj._validation.get(attr_name, {}).get("readonly", False): + continue + + if attr_name == "additional_properties" and attr_desc["key"] == "": + if target_obj.additional_properties is not None: + serialized.update(target_obj.additional_properties) + continue + try: + + orig_attr = getattr(target_obj, attr) + if is_xml_model_serialization: + pass # Don't provide "transformer" for XML for now. Keep "orig_attr" + else: # JSON + keys, orig_attr = key_transformer(attr, attr_desc.copy(), orig_attr) + keys = keys if isinstance(keys, list) else [keys] + + kwargs["serialization_ctxt"] = attr_desc + new_attr = self.serialize_data(orig_attr, attr_desc["type"], **kwargs) + + if is_xml_model_serialization: + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + xml_prefix = xml_desc.get("prefix", None) + xml_ns = xml_desc.get("ns", None) + if xml_desc.get("attr", False): + if xml_ns: + ET.register_namespace(xml_prefix, xml_ns) + xml_name = "{}{}".format(xml_ns, xml_name) + serialized.set(xml_name, new_attr) # type: ignore + continue + if xml_desc.get("text", False): + serialized.text = new_attr # type: ignore + continue + if isinstance(new_attr, list): + serialized.extend(new_attr) # type: ignore + elif isinstance(new_attr, ET.Element): + # If the down XML has no XML/Name, we MUST replace the tag with the local tag. But keeping the namespaces. + if "name" not in getattr(orig_attr, "_xml_map", {}): + splitted_tag = new_attr.tag.split("}") + if len(splitted_tag) == 2: # Namespace + new_attr.tag = "}".join([splitted_tag[0], xml_name]) + else: + new_attr.tag = xml_name + serialized.append(new_attr) # type: ignore + else: # That's a basic type + # Integrate namespace if necessary + local_node = _create_xml_node(xml_name, xml_prefix, xml_ns) + local_node.text = unicode_str(new_attr) + serialized.append(local_node) # type: ignore + else: # JSON + for k in reversed(keys): # type: ignore + new_attr = {k: new_attr} + + _new_attr = new_attr + _serialized = serialized + for k in keys: # type: ignore + if k not in _serialized: + _serialized.update(_new_attr) # type: ignore + _new_attr = _new_attr[k] # type: ignore + _serialized = _serialized[k] + except ValueError: + continue + + except (AttributeError, KeyError, TypeError) as err: + msg = "Attribute {} in object {} cannot be serialized.\n{}".format(attr_name, class_name, str(target_obj)) + raise_with_traceback(SerializationError, msg, err) + else: + return serialized + + def body(self, data, data_type, **kwargs): + """Serialize data intended for a request body. + + :param data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: dict + :raises: SerializationError if serialization fails. + :raises: ValueError if data is None + """ + + # Just in case this is a dict + internal_data_type_str = data_type.strip("[]{}") + internal_data_type = self.dependencies.get(internal_data_type_str, None) + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + if internal_data_type and issubclass(internal_data_type, Model): + is_xml_model_serialization = kwargs.setdefault("is_xml", internal_data_type.is_xml_model()) + else: + is_xml_model_serialization = False + if internal_data_type and not isinstance(internal_data_type, Enum): + try: + deserializer = Deserializer(self.dependencies) + # Since it's on serialization, it's almost sure that format is not JSON REST + # We're not able to deal with additional properties for now. + deserializer.additional_properties_detection = False + if is_xml_model_serialization: + deserializer.key_extractors = [ # type: ignore + attribute_key_case_insensitive_extractor, + ] + else: + deserializer.key_extractors = [ + rest_key_case_insensitive_extractor, + attribute_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + data = deserializer._deserialize(data_type, data) + except DeserializationError as err: + raise_with_traceback(SerializationError, "Unable to build a model: " + str(err), err) + + return self._serialize(data, data_type, **kwargs) + + def url(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL path. + + :param data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :raises: TypeError if serialization fails. + :raises: ValueError if data is None + """ + try: + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + + if kwargs.get("skip_quote") is True: + output = str(output) + else: + output = quote(str(output), safe="") + except SerializationError: + raise TypeError("{} must be type {}.".format(name, data_type)) + else: + return output + + def query(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL query. + + :param data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :raises: TypeError if serialization fails. + :raises: ValueError if data is None + """ + try: + # Treat the list aside, since we don't want to encode the div separator + if data_type.startswith("["): + internal_data_type = data_type[1:-1] + data = [self.serialize_data(d, internal_data_type, **kwargs) if d is not None else "" for d in data] + if not kwargs.get("skip_quote", False): + data = [quote(str(d), safe="") for d in data] + return str(self.serialize_iter(data, internal_data_type, **kwargs)) + + # Not a list, regular serialization + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + if kwargs.get("skip_quote") is True: + output = str(output) + else: + output = quote(str(output), safe="") + except SerializationError: + raise TypeError("{} must be type {}.".format(name, data_type)) + else: + return str(output) + + def header(self, name, data, data_type, **kwargs): + """Serialize data intended for a request header. + + :param data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :raises: TypeError if serialization fails. + :raises: ValueError if data is None + """ + try: + if data_type in ["[str]"]: + data = ["" if d is None else d for d in data] + + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + except SerializationError: + raise TypeError("{} must be type {}.".format(name, data_type)) + else: + return str(output) + + def serialize_data(self, data, data_type, **kwargs): + """Serialize generic data according to supplied data type. + + :param data: The data to be serialized. + :param str data_type: The type to be serialized from. + :param bool required: Whether it's essential that the data not be + empty or None + :raises: AttributeError if required data is None. + :raises: ValueError if data is None + :raises: SerializationError if serialization fails. + """ + if data is None: + raise ValueError("No value for given attribute") + + try: + if data is AzureCoreNull: + return None + if data_type in self.basic_types.values(): + return self.serialize_basic(data, data_type, **kwargs) + + elif data_type in self.serialize_type: + return self.serialize_type[data_type](data, **kwargs) + + # If dependencies is empty, try with current data class + # It has to be a subclass of Enum anyway + enum_type = self.dependencies.get(data_type, data.__class__) + if issubclass(enum_type, Enum): + return Serializer.serialize_enum(data, enum_obj=enum_type) + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.serialize_type: + return self.serialize_type[iter_type](data, data_type[1:-1], **kwargs) + + except (ValueError, TypeError) as err: + msg = "Unable to serialize value: {!r} as type: {!r}." + raise_with_traceback(SerializationError, msg.format(data, data_type), err) + else: + return self._serialize(data, **kwargs) + + @classmethod + def _get_custom_serializers(cls, data_type, **kwargs): + custom_serializer = kwargs.get("basic_types_serializers", {}).get(data_type) + if custom_serializer: + return custom_serializer + if kwargs.get("is_xml", False): + return cls._xml_basic_types_serializers.get(data_type) + + @classmethod + def serialize_basic(cls, data, data_type, **kwargs): + """Serialize basic builting data type. + Serializes objects to str, int, float or bool. + + Possible kwargs: + - basic_types_serializers dict[str, callable] : If set, use the callable as serializer + - is_xml bool : If set, use xml_basic_types_serializers + + :param data: Object to be serialized. + :param str data_type: Type of object in the iterable. + """ + custom_serializer = cls._get_custom_serializers(data_type, **kwargs) + if custom_serializer: + return custom_serializer(data) + if data_type == "str": + return cls.serialize_unicode(data) + return eval(data_type)(data) # nosec + + @classmethod + def serialize_unicode(cls, data): + """Special handling for serializing unicode strings in Py2. + Encode to UTF-8 if unicode, otherwise handle as a str. + + :param data: Object to be serialized. + :rtype: str + """ + try: # If I received an enum, return its value + return data.value + except AttributeError: + pass + + try: + if isinstance(data, unicode): # type: ignore + # Don't change it, JSON and XML ElementTree are totally able + # to serialize correctly u'' strings + return data + except NameError: + return str(data) + else: + return str(data) + + def serialize_iter(self, data, iter_type, div=None, **kwargs): + """Serialize iterable. + + Supported kwargs: + - serialization_ctxt dict : The current entry of _attribute_map, or same format. + serialization_ctxt['type'] should be same as data_type. + - is_xml bool : If set, serialize as XML + + :param list attr: Object to be serialized. + :param str iter_type: Type of object in the iterable. + :param bool required: Whether the objects in the iterable must + not be None or empty. + :param str div: If set, this str will be used to combine the elements + in the iterable into a combined string. Default is 'None'. + :rtype: list, str + """ + if isinstance(data, str): + raise SerializationError("Refuse str type as a valid iter type.") + + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + is_xml = kwargs.get("is_xml", False) + + serialized = [] + for d in data: + try: + serialized.append(self.serialize_data(d, iter_type, **kwargs)) + except ValueError: + serialized.append(None) + + if div: + serialized = ["" if s is None else str(s) for s in serialized] + serialized = div.join(serialized) + + if "xml" in serialization_ctxt or is_xml: + # XML serialization is more complicated + xml_desc = serialization_ctxt.get("xml", {}) + xml_name = xml_desc.get("name") + if not xml_name: + xml_name = serialization_ctxt["key"] + + # Create a wrap node if necessary (use the fact that Element and list have "append") + is_wrapped = xml_desc.get("wrapped", False) + node_name = xml_desc.get("itemsName", xml_name) + if is_wrapped: + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + else: + final_result = [] + # All list elements to "local_node" + for el in serialized: + if isinstance(el, ET.Element): + el_node = el + else: + el_node = _create_xml_node(node_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + if el is not None: # Otherwise it writes "None" :-p + el_node.text = str(el) + final_result.append(el_node) + return final_result + return serialized + + def serialize_dict(self, attr, dict_type, **kwargs): + """Serialize a dictionary of objects. + + :param dict attr: Object to be serialized. + :param str dict_type: Type of object in the dictionary. + :param bool required: Whether the objects in the dictionary must + not be None or empty. + :rtype: dict + """ + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_data(value, dict_type, **kwargs) + except ValueError: + serialized[self.serialize_unicode(key)] = None + + if "xml" in serialization_ctxt: + # XML serialization is more complicated + xml_desc = serialization_ctxt["xml"] + xml_name = xml_desc["name"] + + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + for key, value in serialized.items(): + ET.SubElement(final_result, key).text = value + return final_result + + return serialized + + def serialize_object(self, attr, **kwargs): + """Serialize a generic object. + This will be handled as a dictionary. If object passed in is not + a basic type (str, int, float, dict, list) it will simply be + cast to str. + + :param dict attr: Object to be serialized. + :rtype: dict or str + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + return attr + obj_type = type(attr) + if obj_type in self.basic_types: + return self.serialize_basic(attr, self.basic_types[obj_type], **kwargs) + if obj_type is _long_type: + return self.serialize_long(attr) + if obj_type is unicode_str: + return self.serialize_unicode(attr) + if obj_type is datetime.datetime: + return self.serialize_iso(attr) + if obj_type is datetime.date: + return self.serialize_date(attr) + if obj_type is datetime.time: + return self.serialize_time(attr) + if obj_type is datetime.timedelta: + return self.serialize_duration(attr) + if obj_type is decimal.Decimal: + return self.serialize_decimal(attr) + + # If it's a model or I know this dependency, serialize as a Model + elif obj_type in self.dependencies.values() or isinstance(attr, Model): + return self._serialize(attr) + + if obj_type == dict: + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_object(value, **kwargs) + except ValueError: + serialized[self.serialize_unicode(key)] = None + return serialized + + if obj_type == list: + serialized = [] + for obj in attr: + try: + serialized.append(self.serialize_object(obj, **kwargs)) + except ValueError: + pass + return serialized + return str(attr) + + @staticmethod + def serialize_enum(attr, enum_obj=None): + try: + result = attr.value + except AttributeError: + result = attr + try: + enum_obj(result) # type: ignore + return result + except ValueError: + for enum_value in enum_obj: # type: ignore + if enum_value.value.lower() == str(attr).lower(): + return enum_value.value + error = "{!r} is not valid value for enum {!r}" + raise SerializationError(error.format(attr, enum_obj)) + + @staticmethod + def serialize_bytearray(attr, **kwargs): + """Serialize bytearray into base-64 string. + + :param attr: Object to be serialized. + :rtype: str + """ + return b64encode(attr).decode() + + @staticmethod + def serialize_base64(attr, **kwargs): + """Serialize str into base-64 string. + + :param attr: Object to be serialized. + :rtype: str + """ + encoded = b64encode(attr).decode("ascii") + return encoded.strip("=").replace("+", "-").replace("/", "_") + + @staticmethod + def serialize_decimal(attr, **kwargs): + """Serialize Decimal object to float. + + :param attr: Object to be serialized. + :rtype: float + """ + return float(attr) + + @staticmethod + def serialize_long(attr, **kwargs): + """Serialize long (Py2) or int (Py3). + + :param attr: Object to be serialized. + :rtype: int/long + """ + return _long_type(attr) + + @staticmethod + def serialize_date(attr, **kwargs): + """Serialize Date object into ISO-8601 formatted string. + + :param Date attr: Object to be serialized. + :rtype: str + """ + if isinstance(attr, str): + attr = isodate.parse_date(attr) + t = "{:04}-{:02}-{:02}".format(attr.year, attr.month, attr.day) + return t + + @staticmethod + def serialize_time(attr, **kwargs): + """Serialize Time object into ISO-8601 formatted string. + + :param datetime.time attr: Object to be serialized. + :rtype: str + """ + if isinstance(attr, str): + attr = isodate.parse_time(attr) + t = "{:02}:{:02}:{:02}".format(attr.hour, attr.minute, attr.second) + if attr.microsecond: + t += ".{:02}".format(attr.microsecond) + return t + + @staticmethod + def serialize_duration(attr, **kwargs): + """Serialize TimeDelta object into ISO-8601 formatted string. + + :param TimeDelta attr: Object to be serialized. + :rtype: str + """ + if isinstance(attr, str): + attr = isodate.parse_duration(attr) + return isodate.duration_isoformat(attr) + + @staticmethod + def serialize_rfc(attr, **kwargs): + """Serialize Datetime object into RFC-1123 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises: TypeError if format invalid. + """ + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + except AttributeError: + raise TypeError("RFC1123 object must be valid Datetime object.") + + return "{}, {:02} {} {:04} {:02}:{:02}:{:02} GMT".format( + Serializer.days[utc.tm_wday], + utc.tm_mday, + Serializer.months[utc.tm_mon], + utc.tm_year, + utc.tm_hour, + utc.tm_min, + utc.tm_sec, + ) + + @staticmethod + def serialize_iso(attr, **kwargs): + """Serialize Datetime object into ISO-8601 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises: SerializationError if format invalid. + """ + if isinstance(attr, str): + attr = isodate.parse_datetime(attr) + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + if utc.tm_year > 9999 or utc.tm_year < 1: + raise OverflowError("Hit max or min date") + + microseconds = str(attr.microsecond).rjust(6, "0").rstrip("0").ljust(3, "0") + if microseconds: + microseconds = "." + microseconds + date = "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}".format( + utc.tm_year, utc.tm_mon, utc.tm_mday, utc.tm_hour, utc.tm_min, utc.tm_sec + ) + return date + microseconds + "Z" + except (ValueError, OverflowError) as err: + msg = "Unable to serialize datetime object." + raise_with_traceback(SerializationError, msg, err) + except AttributeError as err: + msg = "ISO-8601 object must be valid Datetime object." + raise_with_traceback(TypeError, msg, err) + + @staticmethod + def serialize_unix(attr, **kwargs): + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param Datetime attr: Object to be serialized. + :rtype: int + :raises: SerializationError if format invalid + """ + if isinstance(attr, int): + return attr + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + return int(calendar.timegm(attr.utctimetuple())) + except AttributeError: + raise TypeError("Unix time object must be valid Datetime object.") + + +def rest_key_extractor(attr, attr_desc, data): + key = attr_desc["key"] + working_data = data + + while "." in key: + # Need the cast, as for some reasons "split" is typed as list[str | Any] + dict_keys = cast(List[str], _FLATTEN.split(key)) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = working_data.get(working_key, data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + # https://github.com/Azure/msrest-for-python/issues/197 + return None + key = ".".join(dict_keys[1:]) + + return working_data.get(key) + + +def rest_key_case_insensitive_extractor(attr, attr_desc, data): + key = attr_desc["key"] + working_data = data + + while "." in key: + dict_keys = _FLATTEN.split(key) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = attribute_key_case_insensitive_extractor(working_key, None, working_data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + # https://github.com/Azure/msrest-for-python/issues/197 + return None + key = ".".join(dict_keys[1:]) + + if working_data: + return attribute_key_case_insensitive_extractor(key, None, working_data) + + +def last_rest_key_extractor(attr, attr_desc, data): + """Extract the attribute in "data" based on the last part of the JSON path key.""" + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_extractor(dict_keys[-1], None, data) + + +def last_rest_key_case_insensitive_extractor(attr, attr_desc, data): + """Extract the attribute in "data" based on the last part of the JSON path key. + + This is the case insensitive version of "last_rest_key_extractor" + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_case_insensitive_extractor(dict_keys[-1], None, data) + + +def attribute_key_extractor(attr, _, data): + return data.get(attr) + + +def attribute_key_case_insensitive_extractor(attr, _, data): + found_key = None + lower_attr = attr.lower() + for key in data: + if lower_attr == key.lower(): + found_key = key + break + + return data.get(found_key) + + +def _extract_name_from_internal_type(internal_type): + """Given an internal type XML description, extract correct XML name with namespace. + + :param dict internal_type: An model type + :rtype: tuple + :returns: A tuple XML name + namespace dict + """ + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + xml_name = internal_type_xml_map.get("name", internal_type.__name__) + xml_ns = internal_type_xml_map.get("ns", None) + if xml_ns: + xml_name = "{}{}".format(xml_ns, xml_name) + return xml_name + + +def xml_key_extractor(attr, attr_desc, data): + if isinstance(data, dict): + return None + + # Test if this model is XML ready first + if not isinstance(data, ET.Element): + return None + + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + + # Look for a children + is_iter_type = attr_desc["type"].startswith("[") + is_wrapped = xml_desc.get("wrapped", False) + internal_type = attr_desc.get("internalType", None) + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + + # Integrate namespace if necessary + xml_ns = xml_desc.get("ns", internal_type_xml_map.get("ns", None)) + if xml_ns: + xml_name = "{}{}".format(xml_ns, xml_name) + + # If it's an attribute, that's simple + if xml_desc.get("attr", False): + return data.get(xml_name) + + # If it's x-ms-text, that's simple too + if xml_desc.get("text", False): + return data.text + + # Scenario where I take the local name: + # - Wrapped node + # - Internal type is an enum (considered basic types) + # - Internal type has no XML/Name node + if is_wrapped or (internal_type and (issubclass(internal_type, Enum) or "name" not in internal_type_xml_map)): + children = data.findall(xml_name) + # If internal type has a local name and it's not a list, I use that name + elif not is_iter_type and internal_type and "name" in internal_type_xml_map: + xml_name = _extract_name_from_internal_type(internal_type) + children = data.findall(xml_name) + # That's an array + else: + if internal_type: # Complex type, ignore itemsName and use the complex type name + items_name = _extract_name_from_internal_type(internal_type) + else: + items_name = xml_desc.get("itemsName", xml_name) + children = data.findall(items_name) + + if len(children) == 0: + if is_iter_type: + if is_wrapped: + return None # is_wrapped no node, we want None + else: + return [] # not wrapped, assume empty list + return None # Assume it's not there, maybe an optional node. + + # If is_iter_type and not wrapped, return all found children + if is_iter_type: + if not is_wrapped: + return children + else: # Iter and wrapped, should have found one node only (the wrap one) + if len(children) != 1: + raise DeserializationError( + "Tried to deserialize an array not wrapped, and found several nodes '{}'. Maybe you should declare this array as wrapped?".format( + xml_name + ) + ) + return list(children[0]) # Might be empty list and that's ok. + + # Here it's not a itertype, we should have found one element only or empty + if len(children) > 1: + raise DeserializationError("Find several XML '{}' where it was not expected".format(xml_name)) + return children[0] + + +class Deserializer(object): + """Response object model deserializer. + + :param dict classes: Class type dictionary for deserializing complex types. + :ivar list key_extractors: Ordered list of extractors to be used by this deserializer. + """ + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + valid_date = re.compile(r"\d{4}[-]\d{2}[-]\d{2}T\d{2}:\d{2}:\d{2}" r"\.?\d*Z?[-+]?[\d{2}]?:?[\d{2}]?") + + def __init__(self, classes: Optional[Mapping[str, Type[ModelType]]] = None): + self.deserialize_type = { + "iso-8601": Deserializer.deserialize_iso, + "rfc-1123": Deserializer.deserialize_rfc, + "unix-time": Deserializer.deserialize_unix, + "duration": Deserializer.deserialize_duration, + "date": Deserializer.deserialize_date, + "time": Deserializer.deserialize_time, + "decimal": Deserializer.deserialize_decimal, + "long": Deserializer.deserialize_long, + "bytearray": Deserializer.deserialize_bytearray, + "base64": Deserializer.deserialize_base64, + "object": self.deserialize_object, + "[]": self.deserialize_iter, + "{}": self.deserialize_dict, + } + self.deserialize_expected_types = { + "duration": (isodate.Duration, datetime.timedelta), + "iso-8601": (datetime.datetime), + } + self.dependencies: Dict[str, Type[ModelType]] = dict(classes) if classes else {} + self.key_extractors = [rest_key_extractor, xml_key_extractor] + # Additional properties only works if the "rest_key_extractor" is used to + # extract the keys. Making it to work whatever the key extractor is too much + # complicated, with no real scenario for now. + # So adding a flag to disable additional properties detection. This flag should be + # used if your expect the deserialization to NOT come from a JSON REST syntax. + # Otherwise, result are unexpected + self.additional_properties_detection = True + + def __call__(self, target_obj, response_data, content_type=None): + """Call the deserializer to process a REST response. + + :param str target_obj: Target data type to deserialize to. + :param requests.Response response_data: REST response object. + :param str content_type: Swagger "produces" if available. + :raises: DeserializationError if deserialization fails. + :return: Deserialized object. + """ + data = self._unpack_content(response_data, content_type) + return self._deserialize(target_obj, data) + + def _deserialize(self, target_obj, data): + """Call the deserializer on a model. + + Data needs to be already deserialized as JSON or XML ElementTree + + :param str target_obj: Target data type to deserialize to. + :param object data: Object to deserialize. + :raises: DeserializationError if deserialization fails. + :return: Deserialized object. + """ + # This is already a model, go recursive just in case + if hasattr(data, "_attribute_map"): + constants = [name for name, config in getattr(data, "_validation", {}).items() if config.get("constant")] + try: + for attr, mapconfig in data._attribute_map.items(): + if attr in constants: + continue + value = getattr(data, attr) + if value is None: + continue + local_type = mapconfig["type"] + internal_data_type = local_type.strip("[]{}") + if internal_data_type not in self.dependencies or isinstance(internal_data_type, Enum): + continue + setattr(data, attr, self._deserialize(local_type, value)) + return data + except AttributeError: + return + + response, class_name = self._classify_target(target_obj, data) + + if isinstance(response, basestring): + return self.deserialize_data(data, response) + elif isinstance(response, type) and issubclass(response, Enum): + return self.deserialize_enum(data, response) + + if data is None: + return data + try: + attributes = response._attribute_map # type: ignore + d_attrs = {} + for attr, attr_desc in attributes.items(): + # Check empty string. If it's not empty, someone has a real "additionalProperties"... + if attr == "additional_properties" and attr_desc["key"] == "": + continue + raw_value = None + # Enhance attr_desc with some dynamic data + attr_desc = attr_desc.copy() # Do a copy, do not change the real one + internal_data_type = attr_desc["type"].strip("[]{}") + if internal_data_type in self.dependencies: + attr_desc["internalType"] = self.dependencies[internal_data_type] + + for key_extractor in self.key_extractors: + found_value = key_extractor(attr, attr_desc, data) + if found_value is not None: + if raw_value is not None and raw_value != found_value: + msg = ( + "Ignoring extracted value '%s' from %s for key '%s'" + " (duplicate extraction, follow extractors order)" + ) + _LOGGER.warning(msg, found_value, key_extractor, attr) + continue + raw_value = found_value + + value = self.deserialize_data(raw_value, attr_desc["type"]) + d_attrs[attr] = value + except (AttributeError, TypeError, KeyError) as err: + msg = "Unable to deserialize to object: " + class_name # type: ignore + raise_with_traceback(DeserializationError, msg, err) + else: + additional_properties = self._build_additional_properties(attributes, data) + return self._instantiate_model(response, d_attrs, additional_properties) + + def _build_additional_properties(self, attribute_map, data): + if not self.additional_properties_detection: + return None + if "additional_properties" in attribute_map and attribute_map.get("additional_properties", {}).get("key") != "": + # Check empty string. If it's not empty, someone has a real "additionalProperties" + return None + if isinstance(data, ET.Element): + data = {el.tag: el.text for el in data} + + known_keys = { + _decode_attribute_map_key(_FLATTEN.split(desc["key"])[0]) + for desc in attribute_map.values() + if desc["key"] != "" + } + present_keys = set(data.keys()) + missing_keys = present_keys - known_keys + return {key: data[key] for key in missing_keys} + + def _classify_target(self, target, data): + """Check to see whether the deserialization target object can + be classified into a subclass. + Once classification has been determined, initialize object. + + :param str target: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + """ + if target is None: + return None, None + + if isinstance(target, basestring): + try: + target = self.dependencies[target] + except KeyError: + return target, target + + try: + target = target._classify(data, self.dependencies) + except AttributeError: + pass # Target is not a Model, no classify + return target, target.__class__.__name__ # type: ignore + + def failsafe_deserialize(self, target_obj, data, content_type=None): + """Ignores any errors encountered in deserialization, + and falls back to not deserializing the object. Recommended + for use in error deserialization, as we want to return the + HttpResponseError to users, and not have them deal with + a deserialization error. + + :param str target_obj: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :param str content_type: Swagger "produces" if available. + """ + try: + return self(target_obj, data, content_type=content_type) + except: + _LOGGER.debug( + "Ran into a deserialization error. Ignoring since this is failsafe deserialization", exc_info=True + ) + return None + + @staticmethod + def _unpack_content(raw_data, content_type=None): + """Extract the correct structure for deserialization. + + If raw_data is a PipelineResponse, try to extract the result of RawDeserializer. + if we can't, raise. Your Pipeline should have a RawDeserializer. + + If not a pipeline response and raw_data is bytes or string, use content-type + to decode it. If no content-type, try JSON. + + If raw_data is something else, bypass all logic and return it directly. + + :param raw_data: Data to be processed. + :param content_type: How to parse if raw_data is a string/bytes. + :raises JSONDecodeError: If JSON is requested and parsing is impossible. + :raises UnicodeDecodeError: If bytes is not UTF8 + """ + # Assume this is enough to detect a Pipeline Response without importing it + context = getattr(raw_data, "context", {}) + if context: + if RawDeserializer.CONTEXT_NAME in context: + return context[RawDeserializer.CONTEXT_NAME] + raise ValueError("This pipeline didn't have the RawDeserializer policy; can't deserialize") + + # Assume this is enough to recognize universal_http.ClientResponse without importing it + if hasattr(raw_data, "body"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text(), raw_data.headers) + + # Assume this enough to recognize requests.Response without importing it. + if hasattr(raw_data, "_content_consumed"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text, raw_data.headers) + + if isinstance(raw_data, (basestring, bytes)) or hasattr(raw_data, "read"): + return RawDeserializer.deserialize_from_text(raw_data, content_type) # type: ignore + return raw_data + + def _instantiate_model(self, response, attrs, additional_properties=None): + """Instantiate a response model passing in deserialized args. + + :param response: The response model class. + :param d_attrs: The deserialized response attributes. + """ + if callable(response): + subtype = getattr(response, "_subtype_map", {}) + try: + readonly = [k for k, v in response._validation.items() if v.get("readonly")] + const = [k for k, v in response._validation.items() if v.get("constant")] + kwargs = {k: v for k, v in attrs.items() if k not in subtype and k not in readonly + const} + response_obj = response(**kwargs) + for attr in readonly: + setattr(response_obj, attr, attrs.get(attr)) + if additional_properties: + response_obj.additional_properties = additional_properties + return response_obj + except TypeError as err: + msg = "Unable to deserialize {} into model {}. ".format(kwargs, response) # type: ignore + raise DeserializationError(msg + str(err)) + else: + try: + for attr, value in attrs.items(): + setattr(response, attr, value) + return response + except Exception as exp: + msg = "Unable to populate response model. " + msg += "Type: {}, Error: {}".format(type(response), exp) + raise DeserializationError(msg) + + def deserialize_data(self, data, data_type): + """Process data for deserialization according to data type. + + :param str data: The response string to be deserialized. + :param str data_type: The type to deserialize to. + :raises: DeserializationError if deserialization fails. + :return: Deserialized object. + """ + if data is None: + return data + + try: + if not data_type: + return data + if data_type in self.basic_types.values(): + return self.deserialize_basic(data, data_type) + if data_type in self.deserialize_type: + if isinstance(data, self.deserialize_expected_types.get(data_type, tuple())): + return data + + is_a_text_parsing_type = lambda x: x not in ["object", "[]", r"{}"] + if isinstance(data, ET.Element) and is_a_text_parsing_type(data_type) and not data.text: + return None + data_val = self.deserialize_type[data_type](data) + return data_val + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.deserialize_type: + return self.deserialize_type[iter_type](data, data_type[1:-1]) + + obj_type = self.dependencies[data_type] + if issubclass(obj_type, Enum): + if isinstance(data, ET.Element): + data = data.text + return self.deserialize_enum(data, obj_type) + + except (ValueError, TypeError, AttributeError) as err: + msg = "Unable to deserialize response data." + msg += " Data: {}, {}".format(data, data_type) + raise_with_traceback(DeserializationError, msg, err) + else: + return self._deserialize(obj_type, data) + + def deserialize_iter(self, attr, iter_type): + """Deserialize an iterable. + + :param list attr: Iterable to be deserialized. + :param str iter_type: The type of object in the iterable. + :rtype: list + """ + if attr is None: + return None + if isinstance(attr, ET.Element): # If I receive an element here, get the children + attr = list(attr) + if not isinstance(attr, (list, set)): + raise DeserializationError("Cannot deserialize as [{}] an object of type {}".format(iter_type, type(attr))) + return [self.deserialize_data(a, iter_type) for a in attr] + + def deserialize_dict(self, attr, dict_type): + """Deserialize a dictionary. + + :param dict/list attr: Dictionary to be deserialized. Also accepts + a list of key, value pairs. + :param str dict_type: The object type of the items in the dictionary. + :rtype: dict + """ + if isinstance(attr, list): + return {x["key"]: self.deserialize_data(x["value"], dict_type) for x in attr} + + if isinstance(attr, ET.Element): + # Transform value into {"Key": "value"} + attr = {el.tag: el.text for el in attr} + return {k: self.deserialize_data(v, dict_type) for k, v in attr.items()} + + def deserialize_object(self, attr, **kwargs): + """Deserialize a generic object. + This will be handled as a dictionary. + + :param dict attr: Dictionary to be deserialized. + :rtype: dict + :raises: TypeError if non-builtin datatype encountered. + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + # Do no recurse on XML, just return the tree as-is + return attr + if isinstance(attr, basestring): + return self.deserialize_basic(attr, "str") + obj_type = type(attr) + if obj_type in self.basic_types: + return self.deserialize_basic(attr, self.basic_types[obj_type]) + if obj_type is _long_type: + return self.deserialize_long(attr) + + if obj_type == dict: + deserialized = {} + for key, value in attr.items(): + try: + deserialized[key] = self.deserialize_object(value, **kwargs) + except ValueError: + deserialized[key] = None + return deserialized + + if obj_type == list: + deserialized = [] + for obj in attr: + try: + deserialized.append(self.deserialize_object(obj, **kwargs)) + except ValueError: + pass + return deserialized + + else: + error = "Cannot deserialize generic object with type: " + raise TypeError(error + str(obj_type)) + + def deserialize_basic(self, attr, data_type): + """Deserialize basic builtin data type from string. + Will attempt to convert to str, int, float and bool. + This function will also accept '1', '0', 'true' and 'false' as + valid bool values. + + :param str attr: response string to be deserialized. + :param str data_type: deserialization data type. + :rtype: str, int, float or bool + :raises: TypeError if string format is not valid. + """ + # If we're here, data is supposed to be a basic type. + # If it's still an XML node, take the text + if isinstance(attr, ET.Element): + attr = attr.text + if not attr: + if data_type == "str": + # None or '', node is empty string. + return "" + else: + # None or '', node with a strong type is None. + # Don't try to model "empty bool" or "empty int" + return None + + if data_type == "bool": + if attr in [True, False, 1, 0]: + return bool(attr) + elif isinstance(attr, basestring): + if attr.lower() in ["true", "1"]: + return True + elif attr.lower() in ["false", "0"]: + return False + raise TypeError("Invalid boolean value: {}".format(attr)) + + if data_type == "str": + return self.deserialize_unicode(attr) + return eval(data_type)(attr) # nosec + + @staticmethod + def deserialize_unicode(data): + """Preserve unicode objects in Python 2, otherwise return data + as a string. + + :param str data: response string to be deserialized. + :rtype: str or unicode + """ + # We might be here because we have an enum modeled as string, + # and we try to deserialize a partial dict with enum inside + if isinstance(data, Enum): + return data + + # Consider this is real string + try: + if isinstance(data, unicode): # type: ignore + return data + except NameError: + return str(data) + else: + return str(data) + + @staticmethod + def deserialize_enum(data, enum_obj): + """Deserialize string into enum object. + + If the string is not a valid enum value it will be returned as-is + and a warning will be logged. + + :param str data: Response string to be deserialized. If this value is + None or invalid it will be returned as-is. + :param Enum enum_obj: Enum object to deserialize to. + :rtype: Enum + """ + if isinstance(data, enum_obj) or data is None: + return data + if isinstance(data, Enum): + data = data.value + if isinstance(data, int): + # Workaround. We might consider remove it in the future. + # https://github.com/Azure/azure-rest-api-specs/issues/141 + try: + return list(enum_obj.__members__.values())[data] + except IndexError: + error = "{!r} is not a valid index for enum {!r}" + raise DeserializationError(error.format(data, enum_obj)) + try: + return enum_obj(str(data)) + except ValueError: + for enum_value in enum_obj: + if enum_value.value.lower() == str(data).lower(): + return enum_value + # We don't fail anymore for unknown value, we deserialize as a string + _LOGGER.warning("Deserializer is not able to find %s as valid enum in %s", data, enum_obj) + return Deserializer.deserialize_unicode(data) + + @staticmethod + def deserialize_bytearray(attr): + """Deserialize string into bytearray. + + :param str attr: response string to be deserialized. + :rtype: bytearray + :raises: TypeError if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return bytearray(b64decode(attr)) # type: ignore + + @staticmethod + def deserialize_base64(attr): + """Deserialize base64 encoded string into string. + + :param str attr: response string to be deserialized. + :rtype: bytearray + :raises: TypeError if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + padding = "=" * (3 - (len(attr) + 3) % 4) # type: ignore + attr = attr + padding # type: ignore + encoded = attr.replace("-", "+").replace("_", "/") + return b64decode(encoded) + + @staticmethod + def deserialize_decimal(attr): + """Deserialize string into Decimal object. + + :param str attr: response string to be deserialized. + :rtype: Decimal + :raises: DeserializationError if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + return decimal.Decimal(attr) # type: ignore + except decimal.DecimalException as err: + msg = "Invalid decimal {}".format(attr) + raise_with_traceback(DeserializationError, msg, err) + + @staticmethod + def deserialize_long(attr): + """Deserialize string into long (Py2) or int (Py3). + + :param str attr: response string to be deserialized. + :rtype: long or int + :raises: ValueError if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return _long_type(attr) # type: ignore + + @staticmethod + def deserialize_duration(attr): + """Deserialize ISO-8601 formatted string into TimeDelta object. + + :param str attr: response string to be deserialized. + :rtype: TimeDelta + :raises: DeserializationError if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + duration = isodate.parse_duration(attr) + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize duration object." + raise_with_traceback(DeserializationError, msg, err) + else: + return duration + + @staticmethod + def deserialize_date(attr): + """Deserialize ISO-8601 formatted string into Date object. + + :param str attr: response string to be deserialized. + :rtype: Date + :raises: DeserializationError if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + # This must NOT use defaultmonth/defaultday. Using None ensure this raises an exception. + return isodate.parse_date(attr, defaultmonth=None, defaultday=None) + + @staticmethod + def deserialize_time(attr): + """Deserialize ISO-8601 formatted string into time object. + + :param str attr: response string to be deserialized. + :rtype: datetime.time + :raises: DeserializationError if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + return isodate.parse_time(attr) + + @staticmethod + def deserialize_rfc(attr): + """Deserialize RFC-1123 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :rtype: Datetime + :raises: DeserializationError if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + parsed_date = email.utils.parsedate_tz(attr) # type: ignore + date_obj = datetime.datetime( + *parsed_date[:6], tzinfo=_FixedOffset(datetime.timedelta(minutes=(parsed_date[9] or 0) / 60)) + ) + if not date_obj.tzinfo: + date_obj = date_obj.astimezone(tz=TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to rfc datetime object." + raise_with_traceback(DeserializationError, msg, err) + else: + return date_obj + + @staticmethod + def deserialize_iso(attr): + """Deserialize ISO-8601 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :rtype: Datetime + :raises: DeserializationError if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + attr = attr.upper() # type: ignore + match = Deserializer.valid_date.match(attr) + if not match: + raise ValueError("Invalid datetime string: " + attr) + + check_decimal = attr.split(".") + if len(check_decimal) > 1: + decimal_str = "" + for digit in check_decimal[1]: + if digit.isdigit(): + decimal_str += digit + else: + break + if len(decimal_str) > 6: + attr = attr.replace(decimal_str, decimal_str[0:6]) + + date_obj = isodate.parse_datetime(attr) + test_utc = date_obj.utctimetuple() + if test_utc.tm_year > 9999 or test_utc.tm_year < 1: + raise OverflowError("Hit max or min date") + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize datetime object." + raise_with_traceback(DeserializationError, msg, err) + else: + return date_obj + + @staticmethod + def deserialize_unix(attr): + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param int attr: Object to be serialized. + :rtype: Datetime + :raises: DeserializationError if format invalid + """ + if isinstance(attr, ET.Element): + attr = int(attr.text) # type: ignore + try: + date_obj = datetime.datetime.fromtimestamp(attr, TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to unix datetime object." + raise_with_traceback(DeserializationError, msg, err) + else: + return date_obj diff --git a/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_generated/_vendor.py b/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_generated/_vendor.py new file mode 100644 index 000000000000..c414500d99bf --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_generated/_vendor.py @@ -0,0 +1,38 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import List, TYPE_CHECKING, cast + +from ._configuration import AzureCommunicationCallAutomationServiceConfiguration + +if TYPE_CHECKING: + # pylint: disable=unused-import,ungrouped-imports + from azure.core import PipelineClient + + from ._serialization import Deserializer, Serializer + + +def _format_url_section(template, **kwargs): + components = template.split("/") + while components: + try: + return template.format(**kwargs) + except KeyError as key: + # Need the cast, as for some reasons "split" is typed as list[str | Any] + formatted_components = cast(List[str], template.split("/")) + components = [c for c in formatted_components if "{}".format(key.args[0]) not in c] + template = "/".join(components) + + +class AzureCommunicationCallAutomationServiceMixinABC(ABC): + """DO NOT use this class. It is for internal typing use only.""" + + _client: "PipelineClient" + _config: AzureCommunicationCallAutomationServiceConfiguration + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_generated/aio/__init__.py b/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_generated/aio/__init__.py new file mode 100644 index 000000000000..bd660b0173b5 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_generated/aio/__init__.py @@ -0,0 +1,23 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from ._client import AzureCommunicationCallAutomationService + +try: + from ._patch import __all__ as _patch_all + from ._patch import * # pylint: disable=unused-wildcard-import +except ImportError: + _patch_all = [] +from ._patch import patch_sdk as _patch_sdk + +__all__ = [ + "AzureCommunicationCallAutomationService", +] +__all__.extend([p for p in _patch_all if p not in __all__]) + +_patch_sdk() diff --git a/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_generated/aio/_client.py b/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_generated/aio/_client.py new file mode 100644 index 000000000000..82186a5fc39a --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_generated/aio/_client.py @@ -0,0 +1,95 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from copy import deepcopy +from typing import Any, Awaitable + +from azure.core import AsyncPipelineClient +from azure.core.rest import AsyncHttpResponse, HttpRequest + +from .. import models as _models +from .._serialization import Deserializer, Serializer +from ._configuration import AzureCommunicationCallAutomationServiceConfiguration +from .operations import ( + AzureCommunicationCallAutomationServiceOperationsMixin, + CallConnectionOperations, + CallMediaOperations, + CallRecordingOperations, +) + + +class AzureCommunicationCallAutomationService( + AzureCommunicationCallAutomationServiceOperationsMixin +): # pylint: disable=client-accepts-api-version-keyword + """Azure Communication Service Call Automation APIs. + + :ivar call_connection: CallConnectionOperations operations + :vartype call_connection: + azure.communication.callautomation.aio.operations.CallConnectionOperations + :ivar call_media: CallMediaOperations operations + :vartype call_media: azure.communication.callautomation.aio.operations.CallMediaOperations + :ivar call_recording: CallRecordingOperations operations + :vartype call_recording: + azure.communication.callautomation.aio.operations.CallRecordingOperations + :param endpoint: The endpoint of the Azure Communication resource. Required. + :type endpoint: str + :keyword api_version: Api Version. Default value is "2023-01-15-preview". Note that overriding + this default value may result in unsupported behavior. + :paramtype api_version: str + """ + + def __init__( # pylint: disable=missing-client-constructor-parameter-credential + self, endpoint: str, **kwargs: Any + ) -> None: + _endpoint = "{endpoint}" + self._config = AzureCommunicationCallAutomationServiceConfiguration(endpoint=endpoint, **kwargs) + self._client = AsyncPipelineClient(base_url=_endpoint, config=self._config, **kwargs) + + client_models = {k: v for k, v in _models.__dict__.items() if isinstance(v, type)} + self._serialize = Serializer(client_models) + self._deserialize = Deserializer(client_models) + self._serialize.client_side_validation = False + self.call_connection = CallConnectionOperations(self._client, self._config, self._serialize, self._deserialize) + self.call_media = CallMediaOperations(self._client, self._config, self._serialize, self._deserialize) + self.call_recording = CallRecordingOperations(self._client, self._config, self._serialize, self._deserialize) + + def send_request(self, request: HttpRequest, **kwargs: Any) -> Awaitable[AsyncHttpResponse]: + """Runs the network request through the client's chained policies. + + >>> from azure.core.rest import HttpRequest + >>> request = HttpRequest("GET", "https://www.example.org/") + + >>> response = await client.send_request(request) + + + For more information on this code flow, see https://aka.ms/azsdk/dpcodegen/python/send_request + + :param request: The network request you want to make. Required. + :type request: ~azure.core.rest.HttpRequest + :keyword bool stream: Whether the response payload will be streamed. Defaults to False. + :return: The response of your network call. Does not do error handling on your response. + :rtype: ~azure.core.rest.AsyncHttpResponse + """ + + request_copy = deepcopy(request) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + + request_copy.url = self._client.format_url(request_copy.url, **path_format_arguments) + return self._client.send_request(request_copy, **kwargs) + + async def close(self) -> None: + await self._client.close() + + async def __aenter__(self) -> "AzureCommunicationCallAutomationService": + await self._client.__aenter__() + return self + + async def __aexit__(self, *exc_details: Any) -> None: + await self._client.__aexit__(*exc_details) diff --git a/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_generated/aio/_configuration.py b/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_generated/aio/_configuration.py new file mode 100644 index 000000000000..59257e12a1e7 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_generated/aio/_configuration.py @@ -0,0 +1,59 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +import sys +from typing import Any + +from azure.core.configuration import Configuration +from azure.core.pipeline import policies + +if sys.version_info >= (3, 8): + from typing import Literal # pylint: disable=no-name-in-module, ungrouped-imports +else: + from typing_extensions import Literal # type: ignore # pylint: disable=ungrouped-imports + +VERSION = "unknown" + + +class AzureCommunicationCallAutomationServiceConfiguration( + Configuration +): # pylint: disable=too-many-instance-attributes + """Configuration for AzureCommunicationCallAutomationService. + + Note that all parameters used to create this instance are saved as instance + attributes. + + :param endpoint: The endpoint of the Azure Communication resource. Required. + :type endpoint: str + :keyword api_version: Api Version. Default value is "2023-01-15-preview". Note that overriding + this default value may result in unsupported behavior. + :paramtype api_version: str + """ + + def __init__(self, endpoint: str, **kwargs: Any) -> None: + super(AzureCommunicationCallAutomationServiceConfiguration, self).__init__(**kwargs) + api_version: Literal["2023-01-15-preview"] = kwargs.pop("api_version", "2023-01-15-preview") + + if endpoint is None: + raise ValueError("Parameter 'endpoint' must not be None.") + + self.endpoint = endpoint + self.api_version = api_version + kwargs.setdefault("sdk_moniker", "communication-callautomation/{}".format(VERSION)) + self._configure(**kwargs) + + def _configure(self, **kwargs: Any) -> None: + self.user_agent_policy = kwargs.get("user_agent_policy") or policies.UserAgentPolicy(**kwargs) + self.headers_policy = kwargs.get("headers_policy") or policies.HeadersPolicy(**kwargs) + self.proxy_policy = kwargs.get("proxy_policy") or policies.ProxyPolicy(**kwargs) + self.logging_policy = kwargs.get("logging_policy") or policies.NetworkTraceLoggingPolicy(**kwargs) + self.http_logging_policy = kwargs.get("http_logging_policy") or policies.HttpLoggingPolicy(**kwargs) + self.retry_policy = kwargs.get("retry_policy") or policies.AsyncRetryPolicy(**kwargs) + self.custom_hook_policy = kwargs.get("custom_hook_policy") or policies.CustomHookPolicy(**kwargs) + self.redirect_policy = kwargs.get("redirect_policy") or policies.AsyncRedirectPolicy(**kwargs) + self.authentication_policy = kwargs.get("authentication_policy") diff --git a/sdk/keyvault/azure-keyvault-administration/azure/keyvault/administration/_generated/v7_4_preview_1/aio/_patch.py b/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_generated/aio/_patch.py similarity index 100% rename from sdk/keyvault/azure-keyvault-administration/azure/keyvault/administration/_generated/v7_4_preview_1/aio/_patch.py rename to sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_generated/aio/_patch.py diff --git a/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_generated/aio/_vendor.py b/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_generated/aio/_vendor.py new file mode 100644 index 000000000000..95c68c99690d --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_generated/aio/_vendor.py @@ -0,0 +1,26 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import TYPE_CHECKING + +from ._configuration import AzureCommunicationCallAutomationServiceConfiguration + +if TYPE_CHECKING: + # pylint: disable=unused-import,ungrouped-imports + from azure.core import AsyncPipelineClient + + from .._serialization import Deserializer, Serializer + + +class AzureCommunicationCallAutomationServiceMixinABC(ABC): + """DO NOT use this class. It is for internal typing use only.""" + + _client: "AsyncPipelineClient" + _config: AzureCommunicationCallAutomationServiceConfiguration + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_generated/aio/operations/__init__.py b/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_generated/aio/operations/__init__.py new file mode 100644 index 000000000000..5a21927092cc --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_generated/aio/operations/__init__.py @@ -0,0 +1,25 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from ._operations import AzureCommunicationCallAutomationServiceOperationsMixin +from ._operations import CallConnectionOperations +from ._operations import CallMediaOperations +from ._operations import CallRecordingOperations + +from ._patch import __all__ as _patch_all +from ._patch import * # pylint: disable=unused-wildcard-import +from ._patch import patch_sdk as _patch_sdk + +__all__ = [ + "AzureCommunicationCallAutomationServiceOperationsMixin", + "CallConnectionOperations", + "CallMediaOperations", + "CallRecordingOperations", +] +__all__.extend([p for p in _patch_all if p not in __all__]) +_patch_sdk() diff --git a/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_generated/aio/operations/_operations.py b/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_generated/aio/operations/_operations.py new file mode 100644 index 000000000000..b26c3f95c07d --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_generated/aio/operations/_operations.py @@ -0,0 +1,2569 @@ +# pylint: disable=too-many-lines +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +from typing import Any, Callable, Dict, IO, Optional, TypeVar, Union, overload + +from azure.core.exceptions import ( + ClientAuthenticationError, + HttpResponseError, + ResourceExistsError, + ResourceNotFoundError, + ResourceNotModifiedError, + map_error, +) +from azure.core.pipeline import PipelineResponse +from azure.core.pipeline.transport import AsyncHttpResponse +from azure.core.rest import HttpRequest +from azure.core.tracing.decorator_async import distributed_trace_async +from azure.core.utils import case_insensitive_dict + +from ... import models as _models +from ...operations._operations import ( + build_azure_communication_call_automation_service_answer_call_request, + build_azure_communication_call_automation_service_create_call_request, + build_azure_communication_call_automation_service_redirect_call_request, + build_azure_communication_call_automation_service_reject_call_request, + build_call_connection_add_participant_request, + build_call_connection_get_call_request, + build_call_connection_get_participant_request, + build_call_connection_get_participants_request, + build_call_connection_hangup_call_request, + build_call_connection_mute_request, + build_call_connection_remove_participant_request, + build_call_connection_terminate_call_request, + build_call_connection_transfer_to_participant_request, + build_call_connection_unmute_request, + build_call_media_cancel_all_media_operations_request, + build_call_media_play_request, + build_call_media_recognize_request, + build_call_recording_get_recording_properties_request, + build_call_recording_pause_recording_request, + build_call_recording_resume_recording_request, + build_call_recording_start_recording_request, + build_call_recording_stop_recording_request, +) +from .._vendor import AzureCommunicationCallAutomationServiceMixinABC + +T = TypeVar("T") +ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] + + +class AzureCommunicationCallAutomationServiceOperationsMixin(AzureCommunicationCallAutomationServiceMixinABC): + @overload + async def create_call( + self, + create_call_request: _models.CreateCallRequest, + *, + repeatability_request_id: Optional[str] = None, + repeatability_first_sent: Optional[str] = None, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.CallConnectionProperties: + """Create an outbound call. + + Create an outbound call. + + :param create_call_request: The create call request. Required. + :type create_call_request: ~azure.communication.callautomation.models.CreateCallRequest + :keyword repeatability_request_id: If specified, the client directs that the request is + repeatable; that is, that the client can make the request multiple times with the same + Repeatability-Request-Id and get back an appropriate response without the server executing the + request multiple times. The value of the Repeatability-Request-Id is an opaque string + representing a client-generated unique identifier for the request. It is a version 4 (random) + UUID. Default value is None. + :paramtype repeatability_request_id: str + :keyword repeatability_first_sent: If Repeatability-Request-ID header is specified, then + Repeatability-First-Sent header must also be specified. The value should be the date and time + at which the request was first created, expressed using the IMF-fixdate form of HTTP-date. + Example: Sun, 06 Nov 1994 08:49:37 GMT. Default value is None. + :paramtype repeatability_first_sent: str + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: CallConnectionProperties + :rtype: ~azure.communication.callautomation.models.CallConnectionProperties + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + async def create_call( + self, + create_call_request: IO, + *, + repeatability_request_id: Optional[str] = None, + repeatability_first_sent: Optional[str] = None, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.CallConnectionProperties: + """Create an outbound call. + + Create an outbound call. + + :param create_call_request: The create call request. Required. + :type create_call_request: IO + :keyword repeatability_request_id: If specified, the client directs that the request is + repeatable; that is, that the client can make the request multiple times with the same + Repeatability-Request-Id and get back an appropriate response without the server executing the + request multiple times. The value of the Repeatability-Request-Id is an opaque string + representing a client-generated unique identifier for the request. It is a version 4 (random) + UUID. Default value is None. + :paramtype repeatability_request_id: str + :keyword repeatability_first_sent: If Repeatability-Request-ID header is specified, then + Repeatability-First-Sent header must also be specified. The value should be the date and time + at which the request was first created, expressed using the IMF-fixdate form of HTTP-date. + Example: Sun, 06 Nov 1994 08:49:37 GMT. Default value is None. + :paramtype repeatability_first_sent: str + :keyword content_type: Body Parameter content-type. Content type parameter for binary body. + Default value is "application/json". + :paramtype content_type: str + :return: CallConnectionProperties + :rtype: ~azure.communication.callautomation.models.CallConnectionProperties + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @distributed_trace_async + async def create_call( + self, + create_call_request: Union[_models.CreateCallRequest, IO], + *, + repeatability_request_id: Optional[str] = None, + repeatability_first_sent: Optional[str] = None, + **kwargs: Any + ) -> _models.CallConnectionProperties: + """Create an outbound call. + + Create an outbound call. + + :param create_call_request: The create call request. Is either a CreateCallRequest type or a IO + type. Required. + :type create_call_request: ~azure.communication.callautomation.models.CreateCallRequest or IO + :keyword repeatability_request_id: If specified, the client directs that the request is + repeatable; that is, that the client can make the request multiple times with the same + Repeatability-Request-Id and get back an appropriate response without the server executing the + request multiple times. The value of the Repeatability-Request-Id is an opaque string + representing a client-generated unique identifier for the request. It is a version 4 (random) + UUID. Default value is None. + :paramtype repeatability_request_id: str + :keyword repeatability_first_sent: If Repeatability-Request-ID header is specified, then + Repeatability-First-Sent header must also be specified. The value should be the date and time + at which the request was first created, expressed using the IMF-fixdate form of HTTP-date. + Example: Sun, 06 Nov 1994 08:49:37 GMT. Default value is None. + :paramtype repeatability_first_sent: str + :keyword content_type: Body Parameter content-type. Known values are: 'application/json'. + Default value is None. + :paramtype content_type: str + :return: CallConnectionProperties + :rtype: ~azure.communication.callautomation.models.CallConnectionProperties + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = kwargs.pop("params", {}) or {} + + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[_models.CallConnectionProperties] = kwargs.pop("cls", None) + + content_type = content_type or "application/json" + _json = None + _content = None + if isinstance(create_call_request, (IO, bytes)): + _content = create_call_request + else: + _json = self._serialize.body(create_call_request, "CreateCallRequest") + + request = build_azure_communication_call_automation_service_create_call_request( + repeatability_request_id=repeatability_request_id, + repeatability_first_sent=repeatability_first_sent, + content_type=content_type, + api_version=self._config.api_version, + json=_json, + content=_content, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + request.url = self._client.format_url(request.url, **path_format_arguments) + + pipeline_response: PipelineResponse = await self._client._pipeline.run( # type: ignore # pylint: disable=protected-access + request, stream=False, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [201]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.CommunicationErrorResponse, pipeline_response) + raise HttpResponseError(response=response, model=error) + + deserialized = self._deserialize("CallConnectionProperties", pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + + @overload + async def answer_call( + self, + answer_call_request: _models.AnswerCallRequest, + *, + repeatability_request_id: Optional[str] = None, + repeatability_first_sent: Optional[str] = None, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.CallConnectionProperties: + """Answer a Call. + + Answer a call using the IncomingCallContext from Event Grid. + + :param answer_call_request: The answer call request. Required. + :type answer_call_request: ~azure.communication.callautomation.models.AnswerCallRequest + :keyword repeatability_request_id: If specified, the client directs that the request is + repeatable; that is, that the client can make the request multiple times with the same + Repeatability-Request-Id and get back an appropriate response without the server executing the + request multiple times. The value of the Repeatability-Request-Id is an opaque string + representing a client-generated unique identifier for the request. It is a version 4 (random) + UUID. Default value is None. + :paramtype repeatability_request_id: str + :keyword repeatability_first_sent: If Repeatability-Request-ID header is specified, then + Repeatability-First-Sent header must also be specified. The value should be the date and time + at which the request was first created, expressed using the IMF-fixdate form of HTTP-date. + Example: Sun, 06 Nov 1994 08:49:37 GMT. Default value is None. + :paramtype repeatability_first_sent: str + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: CallConnectionProperties + :rtype: ~azure.communication.callautomation.models.CallConnectionProperties + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + async def answer_call( + self, + answer_call_request: IO, + *, + repeatability_request_id: Optional[str] = None, + repeatability_first_sent: Optional[str] = None, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.CallConnectionProperties: + """Answer a Call. + + Answer a call using the IncomingCallContext from Event Grid. + + :param answer_call_request: The answer call request. Required. + :type answer_call_request: IO + :keyword repeatability_request_id: If specified, the client directs that the request is + repeatable; that is, that the client can make the request multiple times with the same + Repeatability-Request-Id and get back an appropriate response without the server executing the + request multiple times. The value of the Repeatability-Request-Id is an opaque string + representing a client-generated unique identifier for the request. It is a version 4 (random) + UUID. Default value is None. + :paramtype repeatability_request_id: str + :keyword repeatability_first_sent: If Repeatability-Request-ID header is specified, then + Repeatability-First-Sent header must also be specified. The value should be the date and time + at which the request was first created, expressed using the IMF-fixdate form of HTTP-date. + Example: Sun, 06 Nov 1994 08:49:37 GMT. Default value is None. + :paramtype repeatability_first_sent: str + :keyword content_type: Body Parameter content-type. Content type parameter for binary body. + Default value is "application/json". + :paramtype content_type: str + :return: CallConnectionProperties + :rtype: ~azure.communication.callautomation.models.CallConnectionProperties + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @distributed_trace_async + async def answer_call( + self, + answer_call_request: Union[_models.AnswerCallRequest, IO], + *, + repeatability_request_id: Optional[str] = None, + repeatability_first_sent: Optional[str] = None, + **kwargs: Any + ) -> _models.CallConnectionProperties: + """Answer a Call. + + Answer a call using the IncomingCallContext from Event Grid. + + :param answer_call_request: The answer call request. Is either a AnswerCallRequest type or a IO + type. Required. + :type answer_call_request: ~azure.communication.callautomation.models.AnswerCallRequest or IO + :keyword repeatability_request_id: If specified, the client directs that the request is + repeatable; that is, that the client can make the request multiple times with the same + Repeatability-Request-Id and get back an appropriate response without the server executing the + request multiple times. The value of the Repeatability-Request-Id is an opaque string + representing a client-generated unique identifier for the request. It is a version 4 (random) + UUID. Default value is None. + :paramtype repeatability_request_id: str + :keyword repeatability_first_sent: If Repeatability-Request-ID header is specified, then + Repeatability-First-Sent header must also be specified. The value should be the date and time + at which the request was first created, expressed using the IMF-fixdate form of HTTP-date. + Example: Sun, 06 Nov 1994 08:49:37 GMT. Default value is None. + :paramtype repeatability_first_sent: str + :keyword content_type: Body Parameter content-type. Known values are: 'application/json'. + Default value is None. + :paramtype content_type: str + :return: CallConnectionProperties + :rtype: ~azure.communication.callautomation.models.CallConnectionProperties + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = kwargs.pop("params", {}) or {} + + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[_models.CallConnectionProperties] = kwargs.pop("cls", None) + + content_type = content_type or "application/json" + _json = None + _content = None + if isinstance(answer_call_request, (IO, bytes)): + _content = answer_call_request + else: + _json = self._serialize.body(answer_call_request, "AnswerCallRequest") + + request = build_azure_communication_call_automation_service_answer_call_request( + repeatability_request_id=repeatability_request_id, + repeatability_first_sent=repeatability_first_sent, + content_type=content_type, + api_version=self._config.api_version, + json=_json, + content=_content, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + request.url = self._client.format_url(request.url, **path_format_arguments) + + pipeline_response: PipelineResponse = await self._client._pipeline.run( # type: ignore # pylint: disable=protected-access + request, stream=False, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.CommunicationErrorResponse, pipeline_response) + raise HttpResponseError(response=response, model=error) + + deserialized = self._deserialize("CallConnectionProperties", pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + + @overload + async def redirect_call( # pylint: disable=inconsistent-return-statements + self, + redirect_call_request: _models.RedirectCallRequest, + *, + repeatability_request_id: Optional[str] = None, + repeatability_first_sent: Optional[str] = None, + content_type: str = "application/json", + **kwargs: Any + ) -> None: + """Redirect a call. + + Redirect a call. + + :param redirect_call_request: The redirect call request. Required. + :type redirect_call_request: ~azure.communication.callautomation.models.RedirectCallRequest + :keyword repeatability_request_id: If specified, the client directs that the request is + repeatable; that is, that the client can make the request multiple times with the same + Repeatability-Request-Id and get back an appropriate response without the server executing the + request multiple times. The value of the Repeatability-Request-Id is an opaque string + representing a client-generated unique identifier for the request. It is a version 4 (random) + UUID. Default value is None. + :paramtype repeatability_request_id: str + :keyword repeatability_first_sent: If Repeatability-Request-ID header is specified, then + Repeatability-First-Sent header must also be specified. The value should be the date and time + at which the request was first created, expressed using the IMF-fixdate form of HTTP-date. + Example: Sun, 06 Nov 1994 08:49:37 GMT. Default value is None. + :paramtype repeatability_first_sent: str + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: None + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + async def redirect_call( # pylint: disable=inconsistent-return-statements + self, + redirect_call_request: IO, + *, + repeatability_request_id: Optional[str] = None, + repeatability_first_sent: Optional[str] = None, + content_type: str = "application/json", + **kwargs: Any + ) -> None: + """Redirect a call. + + Redirect a call. + + :param redirect_call_request: The redirect call request. Required. + :type redirect_call_request: IO + :keyword repeatability_request_id: If specified, the client directs that the request is + repeatable; that is, that the client can make the request multiple times with the same + Repeatability-Request-Id and get back an appropriate response without the server executing the + request multiple times. The value of the Repeatability-Request-Id is an opaque string + representing a client-generated unique identifier for the request. It is a version 4 (random) + UUID. Default value is None. + :paramtype repeatability_request_id: str + :keyword repeatability_first_sent: If Repeatability-Request-ID header is specified, then + Repeatability-First-Sent header must also be specified. The value should be the date and time + at which the request was first created, expressed using the IMF-fixdate form of HTTP-date. + Example: Sun, 06 Nov 1994 08:49:37 GMT. Default value is None. + :paramtype repeatability_first_sent: str + :keyword content_type: Body Parameter content-type. Content type parameter for binary body. + Default value is "application/json". + :paramtype content_type: str + :return: None + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @distributed_trace_async + async def redirect_call( # pylint: disable=inconsistent-return-statements + self, + redirect_call_request: Union[_models.RedirectCallRequest, IO], + *, + repeatability_request_id: Optional[str] = None, + repeatability_first_sent: Optional[str] = None, + **kwargs: Any + ) -> None: + """Redirect a call. + + Redirect a call. + + :param redirect_call_request: The redirect call request. Is either a RedirectCallRequest type + or a IO type. Required. + :type redirect_call_request: ~azure.communication.callautomation.models.RedirectCallRequest or + IO + :keyword repeatability_request_id: If specified, the client directs that the request is + repeatable; that is, that the client can make the request multiple times with the same + Repeatability-Request-Id and get back an appropriate response without the server executing the + request multiple times. The value of the Repeatability-Request-Id is an opaque string + representing a client-generated unique identifier for the request. It is a version 4 (random) + UUID. Default value is None. + :paramtype repeatability_request_id: str + :keyword repeatability_first_sent: If Repeatability-Request-ID header is specified, then + Repeatability-First-Sent header must also be specified. The value should be the date and time + at which the request was first created, expressed using the IMF-fixdate form of HTTP-date. + Example: Sun, 06 Nov 1994 08:49:37 GMT. Default value is None. + :paramtype repeatability_first_sent: str + :keyword content_type: Body Parameter content-type. Known values are: 'application/json'. + Default value is None. + :paramtype content_type: str + :return: None + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = kwargs.pop("params", {}) or {} + + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[None] = kwargs.pop("cls", None) + + content_type = content_type or "application/json" + _json = None + _content = None + if isinstance(redirect_call_request, (IO, bytes)): + _content = redirect_call_request + else: + _json = self._serialize.body(redirect_call_request, "RedirectCallRequest") + + request = build_azure_communication_call_automation_service_redirect_call_request( + repeatability_request_id=repeatability_request_id, + repeatability_first_sent=repeatability_first_sent, + content_type=content_type, + api_version=self._config.api_version, + json=_json, + content=_content, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + request.url = self._client.format_url(request.url, **path_format_arguments) + + pipeline_response: PipelineResponse = await self._client._pipeline.run( # type: ignore # pylint: disable=protected-access + request, stream=False, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [204]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.CommunicationErrorResponse, pipeline_response) + raise HttpResponseError(response=response, model=error) + + if cls: + return cls(pipeline_response, None, {}) + + @overload + async def reject_call( # pylint: disable=inconsistent-return-statements + self, + reject_call_request: _models.RejectCallRequest, + *, + repeatability_request_id: Optional[str] = None, + repeatability_first_sent: Optional[str] = None, + content_type: str = "application/json", + **kwargs: Any + ) -> None: + """Reject the call. + + Reject the call. + + :param reject_call_request: The reject call request. Required. + :type reject_call_request: ~azure.communication.callautomation.models.RejectCallRequest + :keyword repeatability_request_id: If specified, the client directs that the request is + repeatable; that is, that the client can make the request multiple times with the same + Repeatability-Request-Id and get back an appropriate response without the server executing the + request multiple times. The value of the Repeatability-Request-Id is an opaque string + representing a client-generated unique identifier for the request. It is a version 4 (random) + UUID. Default value is None. + :paramtype repeatability_request_id: str + :keyword repeatability_first_sent: If Repeatability-Request-ID header is specified, then + Repeatability-First-Sent header must also be specified. The value should be the date and time + at which the request was first created, expressed using the IMF-fixdate form of HTTP-date. + Example: Sun, 06 Nov 1994 08:49:37 GMT. Default value is None. + :paramtype repeatability_first_sent: str + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: None + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + async def reject_call( # pylint: disable=inconsistent-return-statements + self, + reject_call_request: IO, + *, + repeatability_request_id: Optional[str] = None, + repeatability_first_sent: Optional[str] = None, + content_type: str = "application/json", + **kwargs: Any + ) -> None: + """Reject the call. + + Reject the call. + + :param reject_call_request: The reject call request. Required. + :type reject_call_request: IO + :keyword repeatability_request_id: If specified, the client directs that the request is + repeatable; that is, that the client can make the request multiple times with the same + Repeatability-Request-Id and get back an appropriate response without the server executing the + request multiple times. The value of the Repeatability-Request-Id is an opaque string + representing a client-generated unique identifier for the request. It is a version 4 (random) + UUID. Default value is None. + :paramtype repeatability_request_id: str + :keyword repeatability_first_sent: If Repeatability-Request-ID header is specified, then + Repeatability-First-Sent header must also be specified. The value should be the date and time + at which the request was first created, expressed using the IMF-fixdate form of HTTP-date. + Example: Sun, 06 Nov 1994 08:49:37 GMT. Default value is None. + :paramtype repeatability_first_sent: str + :keyword content_type: Body Parameter content-type. Content type parameter for binary body. + Default value is "application/json". + :paramtype content_type: str + :return: None + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @distributed_trace_async + async def reject_call( # pylint: disable=inconsistent-return-statements + self, + reject_call_request: Union[_models.RejectCallRequest, IO], + *, + repeatability_request_id: Optional[str] = None, + repeatability_first_sent: Optional[str] = None, + **kwargs: Any + ) -> None: + """Reject the call. + + Reject the call. + + :param reject_call_request: The reject call request. Is either a RejectCallRequest type or a IO + type. Required. + :type reject_call_request: ~azure.communication.callautomation.models.RejectCallRequest or IO + :keyword repeatability_request_id: If specified, the client directs that the request is + repeatable; that is, that the client can make the request multiple times with the same + Repeatability-Request-Id and get back an appropriate response without the server executing the + request multiple times. The value of the Repeatability-Request-Id is an opaque string + representing a client-generated unique identifier for the request. It is a version 4 (random) + UUID. Default value is None. + :paramtype repeatability_request_id: str + :keyword repeatability_first_sent: If Repeatability-Request-ID header is specified, then + Repeatability-First-Sent header must also be specified. The value should be the date and time + at which the request was first created, expressed using the IMF-fixdate form of HTTP-date. + Example: Sun, 06 Nov 1994 08:49:37 GMT. Default value is None. + :paramtype repeatability_first_sent: str + :keyword content_type: Body Parameter content-type. Known values are: 'application/json'. + Default value is None. + :paramtype content_type: str + :return: None + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = kwargs.pop("params", {}) or {} + + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[None] = kwargs.pop("cls", None) + + content_type = content_type or "application/json" + _json = None + _content = None + if isinstance(reject_call_request, (IO, bytes)): + _content = reject_call_request + else: + _json = self._serialize.body(reject_call_request, "RejectCallRequest") + + request = build_azure_communication_call_automation_service_reject_call_request( + repeatability_request_id=repeatability_request_id, + repeatability_first_sent=repeatability_first_sent, + content_type=content_type, + api_version=self._config.api_version, + json=_json, + content=_content, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + request.url = self._client.format_url(request.url, **path_format_arguments) + + pipeline_response: PipelineResponse = await self._client._pipeline.run( # type: ignore # pylint: disable=protected-access + request, stream=False, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [204]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.CommunicationErrorResponse, pipeline_response) + raise HttpResponseError(response=response, model=error) + + if cls: + return cls(pipeline_response, None, {}) + + +class CallConnectionOperations: + """ + .. warning:: + **DO NOT** instantiate this class directly. + + Instead, you should access the following operations through + :class:`~azure.communication.callautomation.aio.AzureCommunicationCallAutomationService`'s + :attr:`call_connection` attribute. + """ + + models = _models + + def __init__(self, *args, **kwargs) -> None: + input_args = list(args) + self._client = input_args.pop(0) if input_args else kwargs.pop("client") + self._config = input_args.pop(0) if input_args else kwargs.pop("config") + self._serialize = input_args.pop(0) if input_args else kwargs.pop("serializer") + self._deserialize = input_args.pop(0) if input_args else kwargs.pop("deserializer") + + @distributed_trace_async + async def get_call(self, call_connection_id: str, **kwargs: Any) -> _models.CallConnectionProperties: + """Get call connection. + + Get call connection. + + :param call_connection_id: The call connection id. Required. + :type call_connection_id: str + :return: CallConnectionProperties + :rtype: ~azure.communication.callautomation.models.CallConnectionProperties + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[_models.CallConnectionProperties] = kwargs.pop("cls", None) + + request = build_call_connection_get_call_request( + call_connection_id=call_connection_id, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + request.url = self._client.format_url(request.url, **path_format_arguments) + + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + request, stream=False, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.CommunicationErrorResponse, pipeline_response) + raise HttpResponseError(response=response, model=error) + + deserialized = self._deserialize("CallConnectionProperties", pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + + @distributed_trace_async + async def hangup_call( # pylint: disable=inconsistent-return-statements + self, call_connection_id: str, **kwargs: Any + ) -> None: + """Hangup the call. + + Hangup the call. + + :param call_connection_id: The call connection id. Required. + :type call_connection_id: str + :return: None + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[None] = kwargs.pop("cls", None) + + request = build_call_connection_hangup_call_request( + call_connection_id=call_connection_id, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + request.url = self._client.format_url(request.url, **path_format_arguments) + + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + request, stream=False, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [204]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.CommunicationErrorResponse, pipeline_response) + raise HttpResponseError(response=response, model=error) + + if cls: + return cls(pipeline_response, None, {}) + + @distributed_trace_async + async def terminate_call( # pylint: disable=inconsistent-return-statements + self, + call_connection_id: str, + *, + repeatability_request_id: Optional[str] = None, + repeatability_first_sent: Optional[str] = None, + **kwargs: Any + ) -> None: + """Terminate a call using CallConnectionId. + + Terminate a call using CallConnectionId. + + :param call_connection_id: The terminate call request. Required. + :type call_connection_id: str + :keyword repeatability_request_id: If specified, the client directs that the request is + repeatable; that is, that the client can make the request multiple times with the same + Repeatability-Request-Id and get back an appropriate response without the server executing the + request multiple times. The value of the Repeatability-Request-Id is an opaque string + representing a client-generated unique identifier for the request. It is a version 4 (random) + UUID. Default value is None. + :paramtype repeatability_request_id: str + :keyword repeatability_first_sent: If Repeatability-Request-ID header is specified, then + Repeatability-First-Sent header must also be specified. The value should be the date and time + at which the request was first created, expressed using the IMF-fixdate form of HTTP-date. + Example: Sun, 06 Nov 1994 08:49:37 GMT. Default value is None. + :paramtype repeatability_first_sent: str + :return: None + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[None] = kwargs.pop("cls", None) + + request = build_call_connection_terminate_call_request( + call_connection_id=call_connection_id, + repeatability_request_id=repeatability_request_id, + repeatability_first_sent=repeatability_first_sent, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + request.url = self._client.format_url(request.url, **path_format_arguments) + + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + request, stream=False, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [204]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.CommunicationErrorResponse, pipeline_response) + raise HttpResponseError(response=response, model=error) + + if cls: + return cls(pipeline_response, None, {}) + + @overload + async def transfer_to_participant( + self, + call_connection_id: str, + transfer_to_participant_request: _models.TransferToParticipantRequest, + *, + repeatability_request_id: Optional[str] = None, + repeatability_first_sent: Optional[str] = None, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.TransferCallResponse: + """Transfer the call to a participant. + + Transfer the call to a participant. + + :param call_connection_id: The call connection id. Required. + :type call_connection_id: str + :param transfer_to_participant_request: The transfer to participant request. Required. + :type transfer_to_participant_request: + ~azure.communication.callautomation.models.TransferToParticipantRequest + :keyword repeatability_request_id: If specified, the client directs that the request is + repeatable; that is, that the client can make the request multiple times with the same + Repeatability-Request-Id and get back an appropriate response without the server executing the + request multiple times. The value of the Repeatability-Request-Id is an opaque string + representing a client-generated unique identifier for the request. It is a version 4 (random) + UUID. Default value is None. + :paramtype repeatability_request_id: str + :keyword repeatability_first_sent: If Repeatability-Request-ID header is specified, then + Repeatability-First-Sent header must also be specified. The value should be the date and time + at which the request was first created, expressed using the IMF-fixdate form of HTTP-date. + Example: Sun, 06 Nov 1994 08:49:37 GMT. Default value is None. + :paramtype repeatability_first_sent: str + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: TransferCallResponse + :rtype: ~azure.communication.callautomation.models.TransferCallResponse + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + async def transfer_to_participant( + self, + call_connection_id: str, + transfer_to_participant_request: IO, + *, + repeatability_request_id: Optional[str] = None, + repeatability_first_sent: Optional[str] = None, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.TransferCallResponse: + """Transfer the call to a participant. + + Transfer the call to a participant. + + :param call_connection_id: The call connection id. Required. + :type call_connection_id: str + :param transfer_to_participant_request: The transfer to participant request. Required. + :type transfer_to_participant_request: IO + :keyword repeatability_request_id: If specified, the client directs that the request is + repeatable; that is, that the client can make the request multiple times with the same + Repeatability-Request-Id and get back an appropriate response without the server executing the + request multiple times. The value of the Repeatability-Request-Id is an opaque string + representing a client-generated unique identifier for the request. It is a version 4 (random) + UUID. Default value is None. + :paramtype repeatability_request_id: str + :keyword repeatability_first_sent: If Repeatability-Request-ID header is specified, then + Repeatability-First-Sent header must also be specified. The value should be the date and time + at which the request was first created, expressed using the IMF-fixdate form of HTTP-date. + Example: Sun, 06 Nov 1994 08:49:37 GMT. Default value is None. + :paramtype repeatability_first_sent: str + :keyword content_type: Body Parameter content-type. Content type parameter for binary body. + Default value is "application/json". + :paramtype content_type: str + :return: TransferCallResponse + :rtype: ~azure.communication.callautomation.models.TransferCallResponse + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @distributed_trace_async + async def transfer_to_participant( + self, + call_connection_id: str, + transfer_to_participant_request: Union[_models.TransferToParticipantRequest, IO], + *, + repeatability_request_id: Optional[str] = None, + repeatability_first_sent: Optional[str] = None, + **kwargs: Any + ) -> _models.TransferCallResponse: + """Transfer the call to a participant. + + Transfer the call to a participant. + + :param call_connection_id: The call connection id. Required. + :type call_connection_id: str + :param transfer_to_participant_request: The transfer to participant request. Is either a + TransferToParticipantRequest type or a IO type. Required. + :type transfer_to_participant_request: + ~azure.communication.callautomation.models.TransferToParticipantRequest or IO + :keyword repeatability_request_id: If specified, the client directs that the request is + repeatable; that is, that the client can make the request multiple times with the same + Repeatability-Request-Id and get back an appropriate response without the server executing the + request multiple times. The value of the Repeatability-Request-Id is an opaque string + representing a client-generated unique identifier for the request. It is a version 4 (random) + UUID. Default value is None. + :paramtype repeatability_request_id: str + :keyword repeatability_first_sent: If Repeatability-Request-ID header is specified, then + Repeatability-First-Sent header must also be specified. The value should be the date and time + at which the request was first created, expressed using the IMF-fixdate form of HTTP-date. + Example: Sun, 06 Nov 1994 08:49:37 GMT. Default value is None. + :paramtype repeatability_first_sent: str + :keyword content_type: Body Parameter content-type. Known values are: 'application/json'. + Default value is None. + :paramtype content_type: str + :return: TransferCallResponse + :rtype: ~azure.communication.callautomation.models.TransferCallResponse + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = kwargs.pop("params", {}) or {} + + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[_models.TransferCallResponse] = kwargs.pop("cls", None) + + content_type = content_type or "application/json" + _json = None + _content = None + if isinstance(transfer_to_participant_request, (IO, bytes)): + _content = transfer_to_participant_request + else: + _json = self._serialize.body(transfer_to_participant_request, "TransferToParticipantRequest") + + request = build_call_connection_transfer_to_participant_request( + call_connection_id=call_connection_id, + repeatability_request_id=repeatability_request_id, + repeatability_first_sent=repeatability_first_sent, + content_type=content_type, + api_version=self._config.api_version, + json=_json, + content=_content, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + request.url = self._client.format_url(request.url, **path_format_arguments) + + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + request, stream=False, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [202]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.CommunicationErrorResponse, pipeline_response) + raise HttpResponseError(response=response, model=error) + + deserialized = self._deserialize("TransferCallResponse", pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + + @distributed_trace_async + async def get_participants(self, call_connection_id: str, **kwargs: Any) -> _models.GetParticipantsResponse: + """Get participants from a call. + + Get participants from a call. + + :param call_connection_id: The call connection Id. Required. + :type call_connection_id: str + :return: GetParticipantsResponse + :rtype: ~azure.communication.callautomation.models.GetParticipantsResponse + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[_models.GetParticipantsResponse] = kwargs.pop("cls", None) + + request = build_call_connection_get_participants_request( + call_connection_id=call_connection_id, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + request.url = self._client.format_url(request.url, **path_format_arguments) + + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + request, stream=False, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.CommunicationErrorResponse, pipeline_response) + raise HttpResponseError(response=response, model=error) + + deserialized = self._deserialize("GetParticipantsResponse", pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + + @overload + async def add_participant( + self, + call_connection_id: str, + add_participant_request: _models.AddParticipantRequest, + *, + repeatability_request_id: Optional[str] = None, + repeatability_first_sent: Optional[str] = None, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.AddParticipantResponse: + """Add participants to the call. + + Add participants to the call. + + :param call_connection_id: The call connection Id. Required. + :type call_connection_id: str + :param add_participant_request: Required. + :type add_participant_request: ~azure.communication.callautomation.models.AddParticipantRequest + :keyword repeatability_request_id: If specified, the client directs that the request is + repeatable; that is, that the client can make the request multiple times with the same + Repeatability-Request-Id and get back an appropriate response without the server executing the + request multiple times. The value of the Repeatability-Request-Id is an opaque string + representing a client-generated unique identifier for the request. It is a version 4 (random) + UUID. Default value is None. + :paramtype repeatability_request_id: str + :keyword repeatability_first_sent: If Repeatability-Request-ID header is specified, then + Repeatability-First-Sent header must also be specified. The value should be the date and time + at which the request was first created, expressed using the IMF-fixdate form of HTTP-date. + Example: Sun, 06 Nov 1994 08:49:37 GMT. Default value is None. + :paramtype repeatability_first_sent: str + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: AddParticipantResponse + :rtype: ~azure.communication.callautomation.models.AddParticipantResponse + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + async def add_participant( + self, + call_connection_id: str, + add_participant_request: IO, + *, + repeatability_request_id: Optional[str] = None, + repeatability_first_sent: Optional[str] = None, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.AddParticipantResponse: + """Add participants to the call. + + Add participants to the call. + + :param call_connection_id: The call connection Id. Required. + :type call_connection_id: str + :param add_participant_request: Required. + :type add_participant_request: IO + :keyword repeatability_request_id: If specified, the client directs that the request is + repeatable; that is, that the client can make the request multiple times with the same + Repeatability-Request-Id and get back an appropriate response without the server executing the + request multiple times. The value of the Repeatability-Request-Id is an opaque string + representing a client-generated unique identifier for the request. It is a version 4 (random) + UUID. Default value is None. + :paramtype repeatability_request_id: str + :keyword repeatability_first_sent: If Repeatability-Request-ID header is specified, then + Repeatability-First-Sent header must also be specified. The value should be the date and time + at which the request was first created, expressed using the IMF-fixdate form of HTTP-date. + Example: Sun, 06 Nov 1994 08:49:37 GMT. Default value is None. + :paramtype repeatability_first_sent: str + :keyword content_type: Body Parameter content-type. Content type parameter for binary body. + Default value is "application/json". + :paramtype content_type: str + :return: AddParticipantResponse + :rtype: ~azure.communication.callautomation.models.AddParticipantResponse + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @distributed_trace_async + async def add_participant( + self, + call_connection_id: str, + add_participant_request: Union[_models.AddParticipantRequest, IO], + *, + repeatability_request_id: Optional[str] = None, + repeatability_first_sent: Optional[str] = None, + **kwargs: Any + ) -> _models.AddParticipantResponse: + """Add participants to the call. + + Add participants to the call. + + :param call_connection_id: The call connection Id. Required. + :type call_connection_id: str + :param add_participant_request: Is either a AddParticipantRequest type or a IO type. Required. + :type add_participant_request: ~azure.communication.callautomation.models.AddParticipantRequest + or IO + :keyword repeatability_request_id: If specified, the client directs that the request is + repeatable; that is, that the client can make the request multiple times with the same + Repeatability-Request-Id and get back an appropriate response without the server executing the + request multiple times. The value of the Repeatability-Request-Id is an opaque string + representing a client-generated unique identifier for the request. It is a version 4 (random) + UUID. Default value is None. + :paramtype repeatability_request_id: str + :keyword repeatability_first_sent: If Repeatability-Request-ID header is specified, then + Repeatability-First-Sent header must also be specified. The value should be the date and time + at which the request was first created, expressed using the IMF-fixdate form of HTTP-date. + Example: Sun, 06 Nov 1994 08:49:37 GMT. Default value is None. + :paramtype repeatability_first_sent: str + :keyword content_type: Body Parameter content-type. Known values are: 'application/json'. + Default value is None. + :paramtype content_type: str + :return: AddParticipantResponse + :rtype: ~azure.communication.callautomation.models.AddParticipantResponse + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = kwargs.pop("params", {}) or {} + + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[_models.AddParticipantResponse] = kwargs.pop("cls", None) + + content_type = content_type or "application/json" + _json = None + _content = None + if isinstance(add_participant_request, (IO, bytes)): + _content = add_participant_request + else: + _json = self._serialize.body(add_participant_request, "AddParticipantRequest") + + request = build_call_connection_add_participant_request( + call_connection_id=call_connection_id, + repeatability_request_id=repeatability_request_id, + repeatability_first_sent=repeatability_first_sent, + content_type=content_type, + api_version=self._config.api_version, + json=_json, + content=_content, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + request.url = self._client.format_url(request.url, **path_format_arguments) + + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + request, stream=False, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [202]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.CommunicationErrorResponse, pipeline_response) + raise HttpResponseError(response=response, model=error) + + deserialized = self._deserialize("AddParticipantResponse", pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + + @overload + async def remove_participant( + self, + call_connection_id: str, + remove_participant_request: _models.RemoveParticipantRequest, + *, + repeatability_request_id: Optional[str] = None, + repeatability_first_sent: Optional[str] = None, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.RemoveParticipantResponse: + """Remove participant from the call using identifier. + + Remove participant from the call using identifier. + + :param call_connection_id: The call connection id. Required. + :type call_connection_id: str + :param remove_participant_request: The participant to be removed from the call. Required. + :type remove_participant_request: + ~azure.communication.callautomation.models.RemoveParticipantRequest + :keyword repeatability_request_id: If specified, the client directs that the request is + repeatable; that is, that the client can make the request multiple times with the same + Repeatability-Request-Id and get back an appropriate response without the server executing the + request multiple times. The value of the Repeatability-Request-Id is an opaque string + representing a client-generated unique identifier for the request. It is a version 4 (random) + UUID. Default value is None. + :paramtype repeatability_request_id: str + :keyword repeatability_first_sent: If Repeatability-Request-ID header is specified, then + Repeatability-First-Sent header must also be specified. The value should be the date and time + at which the request was first created, expressed using the IMF-fixdate form of HTTP-date. + Example: Sun, 06 Nov 1994 08:49:37 GMT. Default value is None. + :paramtype repeatability_first_sent: str + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: RemoveParticipantResponse + :rtype: ~azure.communication.callautomation.models.RemoveParticipantResponse + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + async def remove_participant( + self, + call_connection_id: str, + remove_participant_request: IO, + *, + repeatability_request_id: Optional[str] = None, + repeatability_first_sent: Optional[str] = None, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.RemoveParticipantResponse: + """Remove participant from the call using identifier. + + Remove participant from the call using identifier. + + :param call_connection_id: The call connection id. Required. + :type call_connection_id: str + :param remove_participant_request: The participant to be removed from the call. Required. + :type remove_participant_request: IO + :keyword repeatability_request_id: If specified, the client directs that the request is + repeatable; that is, that the client can make the request multiple times with the same + Repeatability-Request-Id and get back an appropriate response without the server executing the + request multiple times. The value of the Repeatability-Request-Id is an opaque string + representing a client-generated unique identifier for the request. It is a version 4 (random) + UUID. Default value is None. + :paramtype repeatability_request_id: str + :keyword repeatability_first_sent: If Repeatability-Request-ID header is specified, then + Repeatability-First-Sent header must also be specified. The value should be the date and time + at which the request was first created, expressed using the IMF-fixdate form of HTTP-date. + Example: Sun, 06 Nov 1994 08:49:37 GMT. Default value is None. + :paramtype repeatability_first_sent: str + :keyword content_type: Body Parameter content-type. Content type parameter for binary body. + Default value is "application/json". + :paramtype content_type: str + :return: RemoveParticipantResponse + :rtype: ~azure.communication.callautomation.models.RemoveParticipantResponse + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @distributed_trace_async + async def remove_participant( + self, + call_connection_id: str, + remove_participant_request: Union[_models.RemoveParticipantRequest, IO], + *, + repeatability_request_id: Optional[str] = None, + repeatability_first_sent: Optional[str] = None, + **kwargs: Any + ) -> _models.RemoveParticipantResponse: + """Remove participant from the call using identifier. + + Remove participant from the call using identifier. + + :param call_connection_id: The call connection id. Required. + :type call_connection_id: str + :param remove_participant_request: The participant to be removed from the call. Is either a + RemoveParticipantRequest type or a IO type. Required. + :type remove_participant_request: + ~azure.communication.callautomation.models.RemoveParticipantRequest or IO + :keyword repeatability_request_id: If specified, the client directs that the request is + repeatable; that is, that the client can make the request multiple times with the same + Repeatability-Request-Id and get back an appropriate response without the server executing the + request multiple times. The value of the Repeatability-Request-Id is an opaque string + representing a client-generated unique identifier for the request. It is a version 4 (random) + UUID. Default value is None. + :paramtype repeatability_request_id: str + :keyword repeatability_first_sent: If Repeatability-Request-ID header is specified, then + Repeatability-First-Sent header must also be specified. The value should be the date and time + at which the request was first created, expressed using the IMF-fixdate form of HTTP-date. + Example: Sun, 06 Nov 1994 08:49:37 GMT. Default value is None. + :paramtype repeatability_first_sent: str + :keyword content_type: Body Parameter content-type. Known values are: 'application/json'. + Default value is None. + :paramtype content_type: str + :return: RemoveParticipantResponse + :rtype: ~azure.communication.callautomation.models.RemoveParticipantResponse + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = kwargs.pop("params", {}) or {} + + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[_models.RemoveParticipantResponse] = kwargs.pop("cls", None) + + content_type = content_type or "application/json" + _json = None + _content = None + if isinstance(remove_participant_request, (IO, bytes)): + _content = remove_participant_request + else: + _json = self._serialize.body(remove_participant_request, "RemoveParticipantRequest") + + request = build_call_connection_remove_participant_request( + call_connection_id=call_connection_id, + repeatability_request_id=repeatability_request_id, + repeatability_first_sent=repeatability_first_sent, + content_type=content_type, + api_version=self._config.api_version, + json=_json, + content=_content, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + request.url = self._client.format_url(request.url, **path_format_arguments) + + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + request, stream=False, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [202]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.CommunicationErrorResponse, pipeline_response) + raise HttpResponseError(response=response, model=error) + + deserialized = self._deserialize("RemoveParticipantResponse", pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + + @overload + async def mute( + self, + call_connection_id: str, + mute_participants_request: _models.MuteParticipantsRequest, + *, + repeatability_request_id: Optional[str] = None, + repeatability_first_sent: Optional[str] = None, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.MuteParticipantsResponse: + """Mute participants from the call using identifier. + + Mute participants from the call using identifier. + + :param call_connection_id: The call connection id. Required. + :type call_connection_id: str + :param mute_participants_request: The participants to be muted from the call. Required. + :type mute_participants_request: + ~azure.communication.callautomation.models.MuteParticipantsRequest + :keyword repeatability_request_id: If specified, the client directs that the request is + repeatable; that is, that the client can make the request multiple times with the same + Repeatability-Request-Id and get back an appropriate response without the server executing the + request multiple times. The value of the Repeatability-Request-Id is an opaque string + representing a client-generated unique identifier for the request. It is a version 4 (random) + UUID. Default value is None. + :paramtype repeatability_request_id: str + :keyword repeatability_first_sent: If Repeatability-Request-ID header is specified, then + Repeatability-First-Sent header must also be specified. The value should be the date and time + at which the request was first created, expressed using the IMF-fixdate form of HTTP-date. + Example: Sun, 06 Nov 1994 08:49:37 GMT. Default value is None. + :paramtype repeatability_first_sent: str + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: MuteParticipantsResponse + :rtype: ~azure.communication.callautomation.models.MuteParticipantsResponse + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + async def mute( + self, + call_connection_id: str, + mute_participants_request: IO, + *, + repeatability_request_id: Optional[str] = None, + repeatability_first_sent: Optional[str] = None, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.MuteParticipantsResponse: + """Mute participants from the call using identifier. + + Mute participants from the call using identifier. + + :param call_connection_id: The call connection id. Required. + :type call_connection_id: str + :param mute_participants_request: The participants to be muted from the call. Required. + :type mute_participants_request: IO + :keyword repeatability_request_id: If specified, the client directs that the request is + repeatable; that is, that the client can make the request multiple times with the same + Repeatability-Request-Id and get back an appropriate response without the server executing the + request multiple times. The value of the Repeatability-Request-Id is an opaque string + representing a client-generated unique identifier for the request. It is a version 4 (random) + UUID. Default value is None. + :paramtype repeatability_request_id: str + :keyword repeatability_first_sent: If Repeatability-Request-ID header is specified, then + Repeatability-First-Sent header must also be specified. The value should be the date and time + at which the request was first created, expressed using the IMF-fixdate form of HTTP-date. + Example: Sun, 06 Nov 1994 08:49:37 GMT. Default value is None. + :paramtype repeatability_first_sent: str + :keyword content_type: Body Parameter content-type. Content type parameter for binary body. + Default value is "application/json". + :paramtype content_type: str + :return: MuteParticipantsResponse + :rtype: ~azure.communication.callautomation.models.MuteParticipantsResponse + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @distributed_trace_async + async def mute( + self, + call_connection_id: str, + mute_participants_request: Union[_models.MuteParticipantsRequest, IO], + *, + repeatability_request_id: Optional[str] = None, + repeatability_first_sent: Optional[str] = None, + **kwargs: Any + ) -> _models.MuteParticipantsResponse: + """Mute participants from the call using identifier. + + Mute participants from the call using identifier. + + :param call_connection_id: The call connection id. Required. + :type call_connection_id: str + :param mute_participants_request: The participants to be muted from the call. Is either a + MuteParticipantsRequest type or a IO type. Required. + :type mute_participants_request: + ~azure.communication.callautomation.models.MuteParticipantsRequest or IO + :keyword repeatability_request_id: If specified, the client directs that the request is + repeatable; that is, that the client can make the request multiple times with the same + Repeatability-Request-Id and get back an appropriate response without the server executing the + request multiple times. The value of the Repeatability-Request-Id is an opaque string + representing a client-generated unique identifier for the request. It is a version 4 (random) + UUID. Default value is None. + :paramtype repeatability_request_id: str + :keyword repeatability_first_sent: If Repeatability-Request-ID header is specified, then + Repeatability-First-Sent header must also be specified. The value should be the date and time + at which the request was first created, expressed using the IMF-fixdate form of HTTP-date. + Example: Sun, 06 Nov 1994 08:49:37 GMT. Default value is None. + :paramtype repeatability_first_sent: str + :keyword content_type: Body Parameter content-type. Known values are: 'application/json'. + Default value is None. + :paramtype content_type: str + :return: MuteParticipantsResponse + :rtype: ~azure.communication.callautomation.models.MuteParticipantsResponse + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = kwargs.pop("params", {}) or {} + + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[_models.MuteParticipantsResponse] = kwargs.pop("cls", None) + + content_type = content_type or "application/json" + _json = None + _content = None + if isinstance(mute_participants_request, (IO, bytes)): + _content = mute_participants_request + else: + _json = self._serialize.body(mute_participants_request, "MuteParticipantsRequest") + + request = build_call_connection_mute_request( + call_connection_id=call_connection_id, + repeatability_request_id=repeatability_request_id, + repeatability_first_sent=repeatability_first_sent, + content_type=content_type, + api_version=self._config.api_version, + json=_json, + content=_content, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + request.url = self._client.format_url(request.url, **path_format_arguments) + + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + request, stream=False, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [202]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.CommunicationErrorResponse, pipeline_response) + raise HttpResponseError(response=response, model=error) + + deserialized = self._deserialize("MuteParticipantsResponse", pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + + @overload + async def unmute( + self, + call_connection_id: str, + unmute_participants_request: _models.UnmuteParticipantsRequest, + *, + repeatability_request_id: Optional[str] = None, + repeatability_first_sent: Optional[str] = None, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.UnmuteParticipantsResponse: + """Unmute participants from the call using identifier. + + Unmute participants from the call using identifier. + + :param call_connection_id: The call connection id. Required. + :type call_connection_id: str + :param unmute_participants_request: The participants to be unmuted from the call. Required. + :type unmute_participants_request: + ~azure.communication.callautomation.models.UnmuteParticipantsRequest + :keyword repeatability_request_id: If specified, the client directs that the request is + repeatable; that is, that the client can make the request multiple times with the same + Repeatability-Request-Id and get back an appropriate response without the server executing the + request multiple times. The value of the Repeatability-Request-Id is an opaque string + representing a client-generated unique identifier for the request. It is a version 4 (random) + UUID. Default value is None. + :paramtype repeatability_request_id: str + :keyword repeatability_first_sent: If Repeatability-Request-ID header is specified, then + Repeatability-First-Sent header must also be specified. The value should be the date and time + at which the request was first created, expressed using the IMF-fixdate form of HTTP-date. + Example: Sun, 06 Nov 1994 08:49:37 GMT. Default value is None. + :paramtype repeatability_first_sent: str + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: UnmuteParticipantsResponse + :rtype: ~azure.communication.callautomation.models.UnmuteParticipantsResponse + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + async def unmute( + self, + call_connection_id: str, + unmute_participants_request: IO, + *, + repeatability_request_id: Optional[str] = None, + repeatability_first_sent: Optional[str] = None, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.UnmuteParticipantsResponse: + """Unmute participants from the call using identifier. + + Unmute participants from the call using identifier. + + :param call_connection_id: The call connection id. Required. + :type call_connection_id: str + :param unmute_participants_request: The participants to be unmuted from the call. Required. + :type unmute_participants_request: IO + :keyword repeatability_request_id: If specified, the client directs that the request is + repeatable; that is, that the client can make the request multiple times with the same + Repeatability-Request-Id and get back an appropriate response without the server executing the + request multiple times. The value of the Repeatability-Request-Id is an opaque string + representing a client-generated unique identifier for the request. It is a version 4 (random) + UUID. Default value is None. + :paramtype repeatability_request_id: str + :keyword repeatability_first_sent: If Repeatability-Request-ID header is specified, then + Repeatability-First-Sent header must also be specified. The value should be the date and time + at which the request was first created, expressed using the IMF-fixdate form of HTTP-date. + Example: Sun, 06 Nov 1994 08:49:37 GMT. Default value is None. + :paramtype repeatability_first_sent: str + :keyword content_type: Body Parameter content-type. Content type parameter for binary body. + Default value is "application/json". + :paramtype content_type: str + :return: UnmuteParticipantsResponse + :rtype: ~azure.communication.callautomation.models.UnmuteParticipantsResponse + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @distributed_trace_async + async def unmute( + self, + call_connection_id: str, + unmute_participants_request: Union[_models.UnmuteParticipantsRequest, IO], + *, + repeatability_request_id: Optional[str] = None, + repeatability_first_sent: Optional[str] = None, + **kwargs: Any + ) -> _models.UnmuteParticipantsResponse: + """Unmute participants from the call using identifier. + + Unmute participants from the call using identifier. + + :param call_connection_id: The call connection id. Required. + :type call_connection_id: str + :param unmute_participants_request: The participants to be unmuted from the call. Is either a + UnmuteParticipantsRequest type or a IO type. Required. + :type unmute_participants_request: + ~azure.communication.callautomation.models.UnmuteParticipantsRequest or IO + :keyword repeatability_request_id: If specified, the client directs that the request is + repeatable; that is, that the client can make the request multiple times with the same + Repeatability-Request-Id and get back an appropriate response without the server executing the + request multiple times. The value of the Repeatability-Request-Id is an opaque string + representing a client-generated unique identifier for the request. It is a version 4 (random) + UUID. Default value is None. + :paramtype repeatability_request_id: str + :keyword repeatability_first_sent: If Repeatability-Request-ID header is specified, then + Repeatability-First-Sent header must also be specified. The value should be the date and time + at which the request was first created, expressed using the IMF-fixdate form of HTTP-date. + Example: Sun, 06 Nov 1994 08:49:37 GMT. Default value is None. + :paramtype repeatability_first_sent: str + :keyword content_type: Body Parameter content-type. Known values are: 'application/json'. + Default value is None. + :paramtype content_type: str + :return: UnmuteParticipantsResponse + :rtype: ~azure.communication.callautomation.models.UnmuteParticipantsResponse + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = kwargs.pop("params", {}) or {} + + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[_models.UnmuteParticipantsResponse] = kwargs.pop("cls", None) + + content_type = content_type or "application/json" + _json = None + _content = None + if isinstance(unmute_participants_request, (IO, bytes)): + _content = unmute_participants_request + else: + _json = self._serialize.body(unmute_participants_request, "UnmuteParticipantsRequest") + + request = build_call_connection_unmute_request( + call_connection_id=call_connection_id, + repeatability_request_id=repeatability_request_id, + repeatability_first_sent=repeatability_first_sent, + content_type=content_type, + api_version=self._config.api_version, + json=_json, + content=_content, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + request.url = self._client.format_url(request.url, **path_format_arguments) + + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + request, stream=False, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [202]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.CommunicationErrorResponse, pipeline_response) + raise HttpResponseError(response=response, model=error) + + deserialized = self._deserialize("UnmuteParticipantsResponse", pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + + @distributed_trace_async + async def get_participant( + self, call_connection_id: str, participant_raw_id: str, **kwargs: Any + ) -> _models.CallParticipant: + """Get participant from a call. + + Get participant from a call. + + :param call_connection_id: The call connection Id. Required. + :type call_connection_id: str + :param participant_raw_id: Raw id of the participant to retrieve. Required. + :type participant_raw_id: str + :return: CallParticipant + :rtype: ~azure.communication.callautomation.models.CallParticipant + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[_models.CallParticipant] = kwargs.pop("cls", None) + + request = build_call_connection_get_participant_request( + call_connection_id=call_connection_id, + participant_raw_id=participant_raw_id, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + request.url = self._client.format_url(request.url, **path_format_arguments) + + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + request, stream=False, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.CommunicationErrorResponse, pipeline_response) + raise HttpResponseError(response=response, model=error) + + deserialized = self._deserialize("CallParticipant", pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + + +class CallMediaOperations: + """ + .. warning:: + **DO NOT** instantiate this class directly. + + Instead, you should access the following operations through + :class:`~azure.communication.callautomation.aio.AzureCommunicationCallAutomationService`'s + :attr:`call_media` attribute. + """ + + models = _models + + def __init__(self, *args, **kwargs) -> None: + input_args = list(args) + self._client = input_args.pop(0) if input_args else kwargs.pop("client") + self._config = input_args.pop(0) if input_args else kwargs.pop("config") + self._serialize = input_args.pop(0) if input_args else kwargs.pop("serializer") + self._deserialize = input_args.pop(0) if input_args else kwargs.pop("deserializer") + + @overload + async def play( # pylint: disable=inconsistent-return-statements + self, + call_connection_id: str, + play_request: _models.PlayRequest, + *, + content_type: str = "application/json", + **kwargs: Any + ) -> None: + """Plays audio to participants in the call. + + Plays audio to participants in the call. + + :param call_connection_id: The call connection id. Required. + :type call_connection_id: str + :param play_request: play request payload. Required. + :type play_request: ~azure.communication.callautomation.models.PlayRequest + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: None + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + async def play( # pylint: disable=inconsistent-return-statements + self, call_connection_id: str, play_request: IO, *, content_type: str = "application/json", **kwargs: Any + ) -> None: + """Plays audio to participants in the call. + + Plays audio to participants in the call. + + :param call_connection_id: The call connection id. Required. + :type call_connection_id: str + :param play_request: play request payload. Required. + :type play_request: IO + :keyword content_type: Body Parameter content-type. Content type parameter for binary body. + Default value is "application/json". + :paramtype content_type: str + :return: None + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @distributed_trace_async + async def play( # pylint: disable=inconsistent-return-statements + self, call_connection_id: str, play_request: Union[_models.PlayRequest, IO], **kwargs: Any + ) -> None: + """Plays audio to participants in the call. + + Plays audio to participants in the call. + + :param call_connection_id: The call connection id. Required. + :type call_connection_id: str + :param play_request: play request payload. Is either a PlayRequest type or a IO type. Required. + :type play_request: ~azure.communication.callautomation.models.PlayRequest or IO + :keyword content_type: Body Parameter content-type. Known values are: 'application/json'. + Default value is None. + :paramtype content_type: str + :return: None + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = kwargs.pop("params", {}) or {} + + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[None] = kwargs.pop("cls", None) + + content_type = content_type or "application/json" + _json = None + _content = None + if isinstance(play_request, (IO, bytes)): + _content = play_request + else: + _json = self._serialize.body(play_request, "PlayRequest") + + request = build_call_media_play_request( + call_connection_id=call_connection_id, + content_type=content_type, + api_version=self._config.api_version, + json=_json, + content=_content, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + request.url = self._client.format_url(request.url, **path_format_arguments) + + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + request, stream=False, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [202]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.CommunicationErrorResponse, pipeline_response) + raise HttpResponseError(response=response, model=error) + + if cls: + return cls(pipeline_response, None, {}) + + @distributed_trace_async + async def cancel_all_media_operations( # pylint: disable=inconsistent-return-statements + self, call_connection_id: str, **kwargs: Any + ) -> None: + """Cancel all media operations in a call. + + Cancel all media operations in a call. + + :param call_connection_id: The call connection id. Required. + :type call_connection_id: str + :return: None + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[None] = kwargs.pop("cls", None) + + request = build_call_media_cancel_all_media_operations_request( + call_connection_id=call_connection_id, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + request.url = self._client.format_url(request.url, **path_format_arguments) + + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + request, stream=False, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [202]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.CommunicationErrorResponse, pipeline_response) + raise HttpResponseError(response=response, model=error) + + if cls: + return cls(pipeline_response, None, {}) + + @overload + async def recognize( # pylint: disable=inconsistent-return-statements + self, + call_connection_id: str, + recognize_request: _models.RecognizeRequest, + *, + content_type: str = "application/json", + **kwargs: Any + ) -> None: + """Recognize media from call. + + Recognize media from call. + + :param call_connection_id: The call connection id. Required. + :type call_connection_id: str + :param recognize_request: The media recognize request. Required. + :type recognize_request: ~azure.communication.callautomation.models.RecognizeRequest + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: None + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + async def recognize( # pylint: disable=inconsistent-return-statements + self, call_connection_id: str, recognize_request: IO, *, content_type: str = "application/json", **kwargs: Any + ) -> None: + """Recognize media from call. + + Recognize media from call. + + :param call_connection_id: The call connection id. Required. + :type call_connection_id: str + :param recognize_request: The media recognize request. Required. + :type recognize_request: IO + :keyword content_type: Body Parameter content-type. Content type parameter for binary body. + Default value is "application/json". + :paramtype content_type: str + :return: None + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @distributed_trace_async + async def recognize( # pylint: disable=inconsistent-return-statements + self, call_connection_id: str, recognize_request: Union[_models.RecognizeRequest, IO], **kwargs: Any + ) -> None: + """Recognize media from call. + + Recognize media from call. + + :param call_connection_id: The call connection id. Required. + :type call_connection_id: str + :param recognize_request: The media recognize request. Is either a RecognizeRequest type or a + IO type. Required. + :type recognize_request: ~azure.communication.callautomation.models.RecognizeRequest or IO + :keyword content_type: Body Parameter content-type. Known values are: 'application/json'. + Default value is None. + :paramtype content_type: str + :return: None + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = kwargs.pop("params", {}) or {} + + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[None] = kwargs.pop("cls", None) + + content_type = content_type or "application/json" + _json = None + _content = None + if isinstance(recognize_request, (IO, bytes)): + _content = recognize_request + else: + _json = self._serialize.body(recognize_request, "RecognizeRequest") + + request = build_call_media_recognize_request( + call_connection_id=call_connection_id, + content_type=content_type, + api_version=self._config.api_version, + json=_json, + content=_content, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + request.url = self._client.format_url(request.url, **path_format_arguments) + + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + request, stream=False, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [202]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.CommunicationErrorResponse, pipeline_response) + raise HttpResponseError(response=response, model=error) + + if cls: + return cls(pipeline_response, None, {}) + + +class CallRecordingOperations: + """ + .. warning:: + **DO NOT** instantiate this class directly. + + Instead, you should access the following operations through + :class:`~azure.communication.callautomation.aio.AzureCommunicationCallAutomationService`'s + :attr:`call_recording` attribute. + """ + + models = _models + + def __init__(self, *args, **kwargs) -> None: + input_args = list(args) + self._client = input_args.pop(0) if input_args else kwargs.pop("client") + self._config = input_args.pop(0) if input_args else kwargs.pop("config") + self._serialize = input_args.pop(0) if input_args else kwargs.pop("serializer") + self._deserialize = input_args.pop(0) if input_args else kwargs.pop("deserializer") + + @overload + async def start_recording( + self, + start_call_recording: _models.StartCallRecordingRequest, + *, + repeatability_request_id: Optional[str] = None, + repeatability_first_sent: Optional[str] = None, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.RecordingStateResponse: + """Start recording the call. + + Start recording the call. + + :param start_call_recording: The request body of start call recording request. Required. + :type start_call_recording: + ~azure.communication.callautomation.models.StartCallRecordingRequest + :keyword repeatability_request_id: If specified, the client directs that the request is + repeatable; that is, that the client can make the request multiple times with the same + Repeatability-Request-Id and get back an appropriate response without the server executing the + request multiple times. The value of the Repeatability-Request-Id is an opaque string + representing a client-generated unique identifier for the request. It is a version 4 (random) + UUID. Default value is None. + :paramtype repeatability_request_id: str + :keyword repeatability_first_sent: If Repeatability-Request-ID header is specified, then + Repeatability-First-Sent header must also be specified. The value should be the date and time + at which the request was first created, expressed using the IMF-fixdate form of HTTP-date. + Example: Sun, 06 Nov 1994 08:49:37 GMT. Default value is None. + :paramtype repeatability_first_sent: str + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: RecordingStateResponse + :rtype: ~azure.communication.callautomation.models.RecordingStateResponse + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + async def start_recording( + self, + start_call_recording: IO, + *, + repeatability_request_id: Optional[str] = None, + repeatability_first_sent: Optional[str] = None, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.RecordingStateResponse: + """Start recording the call. + + Start recording the call. + + :param start_call_recording: The request body of start call recording request. Required. + :type start_call_recording: IO + :keyword repeatability_request_id: If specified, the client directs that the request is + repeatable; that is, that the client can make the request multiple times with the same + Repeatability-Request-Id and get back an appropriate response without the server executing the + request multiple times. The value of the Repeatability-Request-Id is an opaque string + representing a client-generated unique identifier for the request. It is a version 4 (random) + UUID. Default value is None. + :paramtype repeatability_request_id: str + :keyword repeatability_first_sent: If Repeatability-Request-ID header is specified, then + Repeatability-First-Sent header must also be specified. The value should be the date and time + at which the request was first created, expressed using the IMF-fixdate form of HTTP-date. + Example: Sun, 06 Nov 1994 08:49:37 GMT. Default value is None. + :paramtype repeatability_first_sent: str + :keyword content_type: Body Parameter content-type. Content type parameter for binary body. + Default value is "application/json". + :paramtype content_type: str + :return: RecordingStateResponse + :rtype: ~azure.communication.callautomation.models.RecordingStateResponse + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @distributed_trace_async + async def start_recording( + self, + start_call_recording: Union[_models.StartCallRecordingRequest, IO], + *, + repeatability_request_id: Optional[str] = None, + repeatability_first_sent: Optional[str] = None, + **kwargs: Any + ) -> _models.RecordingStateResponse: + """Start recording the call. + + Start recording the call. + + :param start_call_recording: The request body of start call recording request. Is either a + StartCallRecordingRequest type or a IO type. Required. + :type start_call_recording: + ~azure.communication.callautomation.models.StartCallRecordingRequest or IO + :keyword repeatability_request_id: If specified, the client directs that the request is + repeatable; that is, that the client can make the request multiple times with the same + Repeatability-Request-Id and get back an appropriate response without the server executing the + request multiple times. The value of the Repeatability-Request-Id is an opaque string + representing a client-generated unique identifier for the request. It is a version 4 (random) + UUID. Default value is None. + :paramtype repeatability_request_id: str + :keyword repeatability_first_sent: If Repeatability-Request-ID header is specified, then + Repeatability-First-Sent header must also be specified. The value should be the date and time + at which the request was first created, expressed using the IMF-fixdate form of HTTP-date. + Example: Sun, 06 Nov 1994 08:49:37 GMT. Default value is None. + :paramtype repeatability_first_sent: str + :keyword content_type: Body Parameter content-type. Known values are: 'application/json'. + Default value is None. + :paramtype content_type: str + :return: RecordingStateResponse + :rtype: ~azure.communication.callautomation.models.RecordingStateResponse + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = kwargs.pop("params", {}) or {} + + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[_models.RecordingStateResponse] = kwargs.pop("cls", None) + + content_type = content_type or "application/json" + _json = None + _content = None + if isinstance(start_call_recording, (IO, bytes)): + _content = start_call_recording + else: + _json = self._serialize.body(start_call_recording, "StartCallRecordingRequest") + + request = build_call_recording_start_recording_request( + repeatability_request_id=repeatability_request_id, + repeatability_first_sent=repeatability_first_sent, + content_type=content_type, + api_version=self._config.api_version, + json=_json, + content=_content, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + request.url = self._client.format_url(request.url, **path_format_arguments) + + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + request, stream=False, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.CommunicationErrorResponse, pipeline_response) + raise HttpResponseError(response=response, model=error) + + deserialized = self._deserialize("RecordingStateResponse", pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + + @distributed_trace_async + async def get_recording_properties(self, recording_id: str, **kwargs: Any) -> _models.RecordingStateResponse: + """Get call recording properties. + + Get call recording properties. + + :param recording_id: The recording id. Required. + :type recording_id: str + :return: RecordingStateResponse + :rtype: ~azure.communication.callautomation.models.RecordingStateResponse + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[_models.RecordingStateResponse] = kwargs.pop("cls", None) + + request = build_call_recording_get_recording_properties_request( + recording_id=recording_id, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + request.url = self._client.format_url(request.url, **path_format_arguments) + + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + request, stream=False, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.CommunicationErrorResponse, pipeline_response) + raise HttpResponseError(response=response, model=error) + + deserialized = self._deserialize("RecordingStateResponse", pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + + @distributed_trace_async + async def stop_recording( # pylint: disable=inconsistent-return-statements + self, recording_id: str, **kwargs: Any + ) -> None: + """Stop recording the call. + + Stop recording the call. + + :param recording_id: The recording id. Required. + :type recording_id: str + :return: None + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[None] = kwargs.pop("cls", None) + + request = build_call_recording_stop_recording_request( + recording_id=recording_id, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + request.url = self._client.format_url(request.url, **path_format_arguments) + + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + request, stream=False, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [204]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.CommunicationErrorResponse, pipeline_response) + raise HttpResponseError(response=response, model=error) + + if cls: + return cls(pipeline_response, None, {}) + + @distributed_trace_async + async def pause_recording( # pylint: disable=inconsistent-return-statements + self, recording_id: str, **kwargs: Any + ) -> None: + """Pause recording the call. + + Pause recording the call. + + :param recording_id: The recording id. Required. + :type recording_id: str + :return: None + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[None] = kwargs.pop("cls", None) + + request = build_call_recording_pause_recording_request( + recording_id=recording_id, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + request.url = self._client.format_url(request.url, **path_format_arguments) + + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + request, stream=False, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [202]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.CommunicationErrorResponse, pipeline_response) + raise HttpResponseError(response=response, model=error) + + if cls: + return cls(pipeline_response, None, {}) + + @distributed_trace_async + async def resume_recording( # pylint: disable=inconsistent-return-statements + self, recording_id: str, **kwargs: Any + ) -> None: + """Resume recording the call. + + Resume recording the call. + + :param recording_id: The recording id. Required. + :type recording_id: str + :return: None + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[None] = kwargs.pop("cls", None) + + request = build_call_recording_resume_recording_request( + recording_id=recording_id, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + request.url = self._client.format_url(request.url, **path_format_arguments) + + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + request, stream=False, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [202]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.CommunicationErrorResponse, pipeline_response) + raise HttpResponseError(response=response, model=error) + + if cls: + return cls(pipeline_response, None, {}) diff --git a/sdk/keyvault/azure-keyvault-administration/azure/keyvault/administration/_generated/v7_4_preview_1/aio/operations/_patch.py b/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_generated/aio/operations/_patch.py similarity index 100% rename from sdk/keyvault/azure-keyvault-administration/azure/keyvault/administration/_generated/v7_4_preview_1/aio/operations/_patch.py rename to sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_generated/aio/operations/_patch.py diff --git a/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_generated/models/__init__.py b/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_generated/models/__init__.py new file mode 100644 index 000000000000..b5693d720183 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_generated/models/__init__.py @@ -0,0 +1,161 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from ._models import AddParticipantFailed +from ._models import AddParticipantRequest +from ._models import AddParticipantResponse +from ._models import AddParticipantSucceeded +from ._models import AnswerCallRequest +from ._models import CallConnected +from ._models import CallConnectionProperties +from ._models import CallDisconnected +from ._models import CallLocator +from ._models import CallParticipant +from ._models import CallTransferAccepted +from ._models import CallTransferFailed +from ._models import Choice +from ._models import ChoiceResult +from ._models import CollectTonesResult +from ._models import CommunicationError +from ._models import CommunicationErrorResponse +from ._models import CommunicationIdentifierModel +from ._models import CommunicationUserIdentifierModel +from ._models import CreateCallRequest +from ._models import CustomContext +from ._models import DtmfOptions +from ._models import FileSource +from ._models import GetParticipantsResponse +from ._models import MediaStreamingConfiguration +from ._models import MicrosoftTeamsUserIdentifierModel +from ._models import MuteParticipantsRequest +from ._models import MuteParticipantsResponse +from ._models import ParticipantsUpdated +from ._models import PhoneNumberIdentifierModel +from ._models import PlayCanceled +from ._models import PlayCompleted +from ._models import PlayFailed +from ._models import PlayOptions +from ._models import PlayRequest +from ._models import PlaySource +from ._models import RecognizeCanceled +from ._models import RecognizeCompleted +from ._models import RecognizeFailed +from ._models import RecognizeOptions +from ._models import RecognizeRequest +from ._models import RecordingStateChanged +from ._models import RecordingStateResponse +from ._models import RedirectCallRequest +from ._models import RejectCallRequest +from ._models import RemoveParticipantRequest +from ._models import RemoveParticipantResponse +from ._models import ResultInformation +from ._models import StartCallRecordingRequest +from ._models import TextSource +from ._models import TransferCallResponse +from ._models import TransferToParticipantRequest +from ._models import UnmuteParticipantsRequest +from ._models import UnmuteParticipantsResponse + +from ._enums import CallConnectionStateModel +from ._enums import CallLocatorKind +from ._enums import CallRejectReason +from ._enums import CommunicationCloudEnvironmentModel +from ._enums import CommunicationIdentifierModelKind +from ._enums import Gender +from ._enums import MediaStreamingAudioChannelType +from ._enums import MediaStreamingContentType +from ._enums import MediaStreamingTransportType +from ._enums import PlaySourceType +from ._enums import RecognitionType +from ._enums import RecognizeInputType +from ._enums import RecordingChannelType +from ._enums import RecordingContentType +from ._enums import RecordingFormatType +from ._enums import RecordingState +from ._enums import RecordingStorageType +from ._enums import Tone +from ._patch import __all__ as _patch_all +from ._patch import * # pylint: disable=unused-wildcard-import +from ._patch import patch_sdk as _patch_sdk + +__all__ = [ + "AddParticipantFailed", + "AddParticipantRequest", + "AddParticipantResponse", + "AddParticipantSucceeded", + "AnswerCallRequest", + "CallConnected", + "CallConnectionProperties", + "CallDisconnected", + "CallLocator", + "CallParticipant", + "CallTransferAccepted", + "CallTransferFailed", + "Choice", + "ChoiceResult", + "CollectTonesResult", + "CommunicationError", + "CommunicationErrorResponse", + "CommunicationIdentifierModel", + "CommunicationUserIdentifierModel", + "CreateCallRequest", + "CustomContext", + "DtmfOptions", + "FileSource", + "GetParticipantsResponse", + "MediaStreamingConfiguration", + "MicrosoftTeamsUserIdentifierModel", + "MuteParticipantsRequest", + "MuteParticipantsResponse", + "ParticipantsUpdated", + "PhoneNumberIdentifierModel", + "PlayCanceled", + "PlayCompleted", + "PlayFailed", + "PlayOptions", + "PlayRequest", + "PlaySource", + "RecognizeCanceled", + "RecognizeCompleted", + "RecognizeFailed", + "RecognizeOptions", + "RecognizeRequest", + "RecordingStateChanged", + "RecordingStateResponse", + "RedirectCallRequest", + "RejectCallRequest", + "RemoveParticipantRequest", + "RemoveParticipantResponse", + "ResultInformation", + "StartCallRecordingRequest", + "TextSource", + "TransferCallResponse", + "TransferToParticipantRequest", + "UnmuteParticipantsRequest", + "UnmuteParticipantsResponse", + "CallConnectionStateModel", + "CallLocatorKind", + "CallRejectReason", + "CommunicationCloudEnvironmentModel", + "CommunicationIdentifierModelKind", + "Gender", + "MediaStreamingAudioChannelType", + "MediaStreamingContentType", + "MediaStreamingTransportType", + "PlaySourceType", + "RecognitionType", + "RecognizeInputType", + "RecordingChannelType", + "RecordingContentType", + "RecordingFormatType", + "RecordingState", + "RecordingStorageType", + "Tone", +] +__all__.extend([p for p in _patch_all if p not in __all__]) +_patch_sdk() diff --git a/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_generated/models/_enums.py b/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_generated/models/_enums.py new file mode 100644 index 000000000000..0ef9e7fd6951 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_generated/models/_enums.py @@ -0,0 +1,162 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from enum import Enum +from azure.core import CaseInsensitiveEnumMeta + + +class CallConnectionStateModel(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """The state of the call connection.""" + + UNKNOWN = "unknown" + CONNECTING = "connecting" + CONNECTED = "connected" + TRANSFERRING = "transferring" + TRANSFER_ACCEPTED = "transferAccepted" + DISCONNECTING = "disconnecting" + DISCONNECTED = "disconnected" + + +class CallLocatorKind(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """The call locator kind.""" + + GROUP_CALL_LOCATOR = "groupCallLocator" + SERVER_CALL_LOCATOR = "serverCallLocator" + + +class CallRejectReason(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """The rejection reason.""" + + NONE = "none" + BUSY = "busy" + FORBIDDEN = "forbidden" + + +class CommunicationCloudEnvironmentModel(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """CommunicationCloudEnvironmentModel.""" + + PUBLIC = "public" + DOD = "dod" + GCCH = "gcch" + + +class CommunicationIdentifierModelKind(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """Type of CommunicationIdentifierModel.""" + + UNKNOWN = "unknown" + COMMUNICATION_USER = "communicationUser" + PHONE_NUMBER = "phoneNumber" + MICROSOFT_TEAMS_USER = "microsoftTeamsUser" + + +class Gender(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """Voice gender type.""" + + MALE = "male" + FEMALE = "female" + + +class MediaStreamingAudioChannelType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """Audio channel type to stream, eg. unmixed audio, mixed audio.""" + + MIXED = "mixed" + UNMIXED = "unmixed" + + +class MediaStreamingContentType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """Content type to stream, eg. audio, audio/video.""" + + AUDIO = "audio" + + +class MediaStreamingTransportType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """The type of transport to be used for media streaming, eg. Websocket.""" + + WEBSOCKET = "websocket" + + +class PlaySourceType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """Defines the type of the play source.""" + + FILE = "file" + TEXT = "text" + + +class RecognitionType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """Determines the sub-type of the recognize operation. + In case of cancel operation the this field is not set and is returned empty. + """ + + DTMF = "dtmf" + CHOICES = "choices" + + +class RecognizeInputType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """Determines the type of the recognition.""" + + DTMF = "dtmf" + CHOICES = "choices" + + +class RecordingChannelType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """The channel type of call recording.""" + + MIXED = "mixed" + UNMIXED = "unmixed" + + +class RecordingContentType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """The content type of call recording.""" + + AUDIO = "audio" + AUDIO_VIDEO = "audioVideo" + + +class RecordingFormatType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """The format type of call recording.""" + + WAV = "wav" + MP3 = "mp3" + MP4 = "mp4" + + +class RecordingState(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """RecordingState.""" + + ACTIVE = "active" + INACTIVE = "inactive" + + +class RecordingStorageType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """Recording storage mode. When set to 'BlobStorage', specify required parameter + 'ExternalStorageLocation', to export recording to your own blob container. + """ + + ACS = "acs" + BLOB_STORAGE = "blobStorage" + + +class Tone(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """Tone.""" + + ZERO = "zero" + ONE = "one" + TWO = "two" + THREE = "three" + FOUR = "four" + FIVE = "five" + SIX = "six" + SEVEN = "seven" + EIGHT = "eight" + NINE = "nine" + A = "a" + B = "b" + C = "c" + D = "d" + POUND = "pound" + ASTERISK = "asterisk" diff --git a/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_generated/models/_models.py b/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_generated/models/_models.py new file mode 100644 index 000000000000..33e2d35c3c62 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_generated/models/_models.py @@ -0,0 +1,2685 @@ +# coding=utf-8 +# pylint: disable=too-many-lines +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from typing import Any, Dict, List, Optional, TYPE_CHECKING, Union + +from .. import _serialization + +if TYPE_CHECKING: + # pylint: disable=unused-import,ungrouped-imports + from .. import models as _models + + +class AddParticipantFailed(_serialization.Model): + """The failed to add participants event. + + :ivar call_connection_id: Call connection ID. + :vartype call_connection_id: str + :ivar server_call_id: Server call ID. + :vartype server_call_id: str + :ivar correlation_id: Correlation ID for event to call correlation. Also called ChainId for + skype chain ID. + :vartype correlation_id: str + :ivar operation_context: Used by customers when calling mid-call actions to correlate the + request to the response event. + :vartype operation_context: str + :ivar result_information: Contains the resulting SIP code/sub-code and message from NGC + services. + :vartype result_information: ~azure.communication.callautomation.models.ResultInformation + :ivar participant: Participant. + :vartype participant: ~azure.communication.callautomation.models.CommunicationIdentifierModel + """ + + _attribute_map = { + "call_connection_id": {"key": "callConnectionId", "type": "str"}, + "server_call_id": {"key": "serverCallId", "type": "str"}, + "correlation_id": {"key": "correlationId", "type": "str"}, + "operation_context": {"key": "operationContext", "type": "str"}, + "result_information": {"key": "resultInformation", "type": "ResultInformation"}, + "participant": {"key": "participant", "type": "CommunicationIdentifierModel"}, + } + + def __init__( + self, + *, + call_connection_id: Optional[str] = None, + server_call_id: Optional[str] = None, + correlation_id: Optional[str] = None, + operation_context: Optional[str] = None, + result_information: Optional["_models.ResultInformation"] = None, + participant: Optional["_models.CommunicationIdentifierModel"] = None, + **kwargs: Any + ) -> None: + """ + :keyword call_connection_id: Call connection ID. + :paramtype call_connection_id: str + :keyword server_call_id: Server call ID. + :paramtype server_call_id: str + :keyword correlation_id: Correlation ID for event to call correlation. Also called ChainId for + skype chain ID. + :paramtype correlation_id: str + :keyword operation_context: Used by customers when calling mid-call actions to correlate the + request to the response event. + :paramtype operation_context: str + :keyword result_information: Contains the resulting SIP code/sub-code and message from NGC + services. + :paramtype result_information: ~azure.communication.callautomation.models.ResultInformation + :keyword participant: Participant. + :paramtype participant: ~azure.communication.callautomation.models.CommunicationIdentifierModel + """ + super().__init__(**kwargs) + self.call_connection_id = call_connection_id + self.server_call_id = server_call_id + self.correlation_id = correlation_id + self.operation_context = operation_context + self.result_information = result_information + self.participant = participant + + +class AddParticipantRequest(_serialization.Model): + """The request payload for adding participant to the call. + + All required parameters must be populated in order to send to Azure. + + :ivar source_caller_id_number: The source caller Id, a phone number, that's shown to the PSTN + participant being invited. + Required only when inviting a PSTN participant. + :vartype source_caller_id_number: + ~azure.communication.callautomation.models.PhoneNumberIdentifierModel + :ivar source_display_name: (Optional) The display name of the source that is associated with + this invite operation when + adding a PSTN participant or teams user. Note: Will not update the display name in the + roster. + :vartype source_display_name: str + :ivar participant_to_add: The participant to invite. Required. + :vartype participant_to_add: + ~azure.communication.callautomation.models.CommunicationIdentifierModel + :ivar invitation_timeout_in_seconds: Gets or sets the timeout to wait for the invited + participant to pickup. + The maximum value of this is 180 seconds. + :vartype invitation_timeout_in_seconds: int + :ivar operation_context: Used by customers when calling mid-call actions to correlate the + request to the response event. + :vartype operation_context: str + :ivar custom_context: Used by customer to send custom context to targets. + :vartype custom_context: ~azure.communication.callautomation.models.CustomContext + """ + + _validation = { + "participant_to_add": {"required": True}, + "invitation_timeout_in_seconds": {"maximum": 180, "minimum": 0}, + } + + _attribute_map = { + "source_caller_id_number": {"key": "sourceCallerIdNumber", "type": "PhoneNumberIdentifierModel"}, + "source_display_name": {"key": "sourceDisplayName", "type": "str"}, + "participant_to_add": {"key": "participantToAdd", "type": "CommunicationIdentifierModel"}, + "invitation_timeout_in_seconds": {"key": "invitationTimeoutInSeconds", "type": "int"}, + "operation_context": {"key": "operationContext", "type": "str"}, + "custom_context": {"key": "customContext", "type": "CustomContext"}, + } + + def __init__( + self, + *, + participant_to_add: "_models.CommunicationIdentifierModel", + source_caller_id_number: Optional["_models.PhoneNumberIdentifierModel"] = None, + source_display_name: Optional[str] = None, + invitation_timeout_in_seconds: Optional[int] = None, + operation_context: Optional[str] = None, + custom_context: Optional["_models.CustomContext"] = None, + **kwargs: Any + ) -> None: + """ + :keyword source_caller_id_number: The source caller Id, a phone number, that's shown to the + PSTN participant being invited. + Required only when inviting a PSTN participant. + :paramtype source_caller_id_number: + ~azure.communication.callautomation.models.PhoneNumberIdentifierModel + :keyword source_display_name: (Optional) The display name of the source that is associated with + this invite operation when + adding a PSTN participant or teams user. Note: Will not update the display name in the + roster. + :paramtype source_display_name: str + :keyword participant_to_add: The participant to invite. Required. + :paramtype participant_to_add: + ~azure.communication.callautomation.models.CommunicationIdentifierModel + :keyword invitation_timeout_in_seconds: Gets or sets the timeout to wait for the invited + participant to pickup. + The maximum value of this is 180 seconds. + :paramtype invitation_timeout_in_seconds: int + :keyword operation_context: Used by customers when calling mid-call actions to correlate the + request to the response event. + :paramtype operation_context: str + :keyword custom_context: Used by customer to send custom context to targets. + :paramtype custom_context: ~azure.communication.callautomation.models.CustomContext + """ + super().__init__(**kwargs) + self.source_caller_id_number = source_caller_id_number + self.source_display_name = source_display_name + self.participant_to_add = participant_to_add + self.invitation_timeout_in_seconds = invitation_timeout_in_seconds + self.operation_context = operation_context + self.custom_context = custom_context + + +class AddParticipantResponse(_serialization.Model): + """The response payload for adding participants to the call. + + :ivar participant: List of current participants in the call. + :vartype participant: ~azure.communication.callautomation.models.CallParticipant + :ivar operation_context: The operation context provided by client. + :vartype operation_context: str + """ + + _attribute_map = { + "participant": {"key": "participant", "type": "CallParticipant"}, + "operation_context": {"key": "operationContext", "type": "str"}, + } + + def __init__( + self, + *, + participant: Optional["_models.CallParticipant"] = None, + operation_context: Optional[str] = None, + **kwargs: Any + ) -> None: + """ + :keyword participant: List of current participants in the call. + :paramtype participant: ~azure.communication.callautomation.models.CallParticipant + :keyword operation_context: The operation context provided by client. + :paramtype operation_context: str + """ + super().__init__(**kwargs) + self.participant = participant + self.operation_context = operation_context + + +class AddParticipantSucceeded(_serialization.Model): + """The participants successfully added event. + + :ivar call_connection_id: Call connection ID. + :vartype call_connection_id: str + :ivar server_call_id: Server call ID. + :vartype server_call_id: str + :ivar correlation_id: Correlation ID for event to call correlation. Also called ChainId for + skype chain ID. + :vartype correlation_id: str + :ivar operation_context: Used by customers when calling mid-call actions to correlate the + request to the response event. + :vartype operation_context: str + :ivar result_information: Contains the resulting SIP code/sub-code and message from NGC + services. + :vartype result_information: ~azure.communication.callautomation.models.ResultInformation + :ivar participant: Participant. + :vartype participant: ~azure.communication.callautomation.models.CommunicationIdentifierModel + """ + + _attribute_map = { + "call_connection_id": {"key": "callConnectionId", "type": "str"}, + "server_call_id": {"key": "serverCallId", "type": "str"}, + "correlation_id": {"key": "correlationId", "type": "str"}, + "operation_context": {"key": "operationContext", "type": "str"}, + "result_information": {"key": "resultInformation", "type": "ResultInformation"}, + "participant": {"key": "participant", "type": "CommunicationIdentifierModel"}, + } + + def __init__( + self, + *, + call_connection_id: Optional[str] = None, + server_call_id: Optional[str] = None, + correlation_id: Optional[str] = None, + operation_context: Optional[str] = None, + result_information: Optional["_models.ResultInformation"] = None, + participant: Optional["_models.CommunicationIdentifierModel"] = None, + **kwargs: Any + ) -> None: + """ + :keyword call_connection_id: Call connection ID. + :paramtype call_connection_id: str + :keyword server_call_id: Server call ID. + :paramtype server_call_id: str + :keyword correlation_id: Correlation ID for event to call correlation. Also called ChainId for + skype chain ID. + :paramtype correlation_id: str + :keyword operation_context: Used by customers when calling mid-call actions to correlate the + request to the response event. + :paramtype operation_context: str + :keyword result_information: Contains the resulting SIP code/sub-code and message from NGC + services. + :paramtype result_information: ~azure.communication.callautomation.models.ResultInformation + :keyword participant: Participant. + :paramtype participant: ~azure.communication.callautomation.models.CommunicationIdentifierModel + """ + super().__init__(**kwargs) + self.call_connection_id = call_connection_id + self.server_call_id = server_call_id + self.correlation_id = correlation_id + self.operation_context = operation_context + self.result_information = result_information + self.participant = participant + + +class AnswerCallRequest(_serialization.Model): + """The request payload for answering the call. + + All required parameters must be populated in order to send to Azure. + + :ivar incoming_call_context: The context associated with the call. Required. + :vartype incoming_call_context: str + :ivar callback_uri: The callback uri. Required. + :vartype callback_uri: str + :ivar media_streaming_configuration: Media Streaming Configuration. + :vartype media_streaming_configuration: + ~azure.communication.callautomation.models.MediaStreamingConfiguration + :ivar azure_cognitive_services_endpoint_url: The endpoint URL of the Azure Cognitive Services + resource attached. + :vartype azure_cognitive_services_endpoint_url: str + :ivar answered_by_identifier: The identifier of the contoso app which answers the call. + :vartype answered_by_identifier: + ~azure.communication.callautomation.models.CommunicationIdentifierModel + """ + + _validation = { + "incoming_call_context": {"required": True}, + "callback_uri": {"required": True}, + } + + _attribute_map = { + "incoming_call_context": {"key": "incomingCallContext", "type": "str"}, + "callback_uri": {"key": "callbackUri", "type": "str"}, + "media_streaming_configuration": {"key": "mediaStreamingConfiguration", "type": "MediaStreamingConfiguration"}, + "azure_cognitive_services_endpoint_url": {"key": "azureCognitiveServicesEndpointUrl", "type": "str"}, + "answered_by_identifier": {"key": "answeredByIdentifier", "type": "CommunicationIdentifierModel"}, + } + + def __init__( + self, + *, + incoming_call_context: str, + callback_uri: str, + media_streaming_configuration: Optional["_models.MediaStreamingConfiguration"] = None, + azure_cognitive_services_endpoint_url: Optional[str] = None, + answered_by_identifier: Optional["_models.CommunicationIdentifierModel"] = None, + **kwargs: Any + ) -> None: + """ + :keyword incoming_call_context: The context associated with the call. Required. + :paramtype incoming_call_context: str + :keyword callback_uri: The callback uri. Required. + :paramtype callback_uri: str + :keyword media_streaming_configuration: Media Streaming Configuration. + :paramtype media_streaming_configuration: + ~azure.communication.callautomation.models.MediaStreamingConfiguration + :keyword azure_cognitive_services_endpoint_url: The endpoint URL of the Azure Cognitive + Services resource attached. + :paramtype azure_cognitive_services_endpoint_url: str + :keyword answered_by_identifier: The identifier of the contoso app which answers the call. + :paramtype answered_by_identifier: + ~azure.communication.callautomation.models.CommunicationIdentifierModel + """ + super().__init__(**kwargs) + self.incoming_call_context = incoming_call_context + self.callback_uri = callback_uri + self.media_streaming_configuration = media_streaming_configuration + self.azure_cognitive_services_endpoint_url = azure_cognitive_services_endpoint_url + self.answered_by_identifier = answered_by_identifier + + +class CallConnected(_serialization.Model): + """The call connected event. + + :ivar call_connection_id: Call connection ID. + :vartype call_connection_id: str + :ivar server_call_id: Server call ID. + :vartype server_call_id: str + :ivar correlation_id: Correlation ID for event to call correlation. Also called ChainId for + skype chain ID. + :vartype correlation_id: str + :ivar operation_context: Used by customers to set the context for creating a new call. This + property will be null for answering a call. + :vartype operation_context: str + """ + + _attribute_map = { + "call_connection_id": {"key": "callConnectionId", "type": "str"}, + "server_call_id": {"key": "serverCallId", "type": "str"}, + "correlation_id": {"key": "correlationId", "type": "str"}, + "operation_context": {"key": "operationContext", "type": "str"}, + } + + def __init__( + self, + *, + call_connection_id: Optional[str] = None, + server_call_id: Optional[str] = None, + correlation_id: Optional[str] = None, + operation_context: Optional[str] = None, + **kwargs: Any + ) -> None: + """ + :keyword call_connection_id: Call connection ID. + :paramtype call_connection_id: str + :keyword server_call_id: Server call ID. + :paramtype server_call_id: str + :keyword correlation_id: Correlation ID for event to call correlation. Also called ChainId for + skype chain ID. + :paramtype correlation_id: str + :keyword operation_context: Used by customers to set the context for creating a new call. This + property will be null for answering a call. + :paramtype operation_context: str + """ + super().__init__(**kwargs) + self.call_connection_id = call_connection_id + self.server_call_id = server_call_id + self.correlation_id = correlation_id + self.operation_context = operation_context + + +class CallConnectionProperties(_serialization.Model): + """Properties of a call connection. + + :ivar call_connection_id: The call connection id. + :vartype call_connection_id: str + :ivar server_call_id: The server call id. + :vartype server_call_id: str + :ivar targets: The targets of the call. + :vartype targets: list[~azure.communication.callautomation.models.CommunicationIdentifierModel] + :ivar call_connection_state: The state of the call connection. Known values are: "unknown", + "connecting", "connected", "transferring", "transferAccepted", "disconnecting", and + "disconnected". + :vartype call_connection_state: str or + ~azure.communication.callautomation.models.CallConnectionStateModel + :ivar callback_uri: The callback URI. + :vartype callback_uri: str + :ivar media_subscription_id: SubscriptionId for media streaming. + :vartype media_subscription_id: str + :ivar source_caller_id_number: The source caller Id, a phone number, that's shown to the PSTN + participant being invited. + Required only when calling a PSTN callee. + :vartype source_caller_id_number: + ~azure.communication.callautomation.models.PhoneNumberIdentifierModel + :ivar source_display_name: Display name of the call if dialing out to a pstn number. + :vartype source_display_name: str + :ivar source_identity: Source identity. + :vartype source_identity: + ~azure.communication.callautomation.models.CommunicationIdentifierModel + """ + + _attribute_map = { + "call_connection_id": {"key": "callConnectionId", "type": "str"}, + "server_call_id": {"key": "serverCallId", "type": "str"}, + "targets": {"key": "targets", "type": "[CommunicationIdentifierModel]"}, + "call_connection_state": {"key": "callConnectionState", "type": "str"}, + "callback_uri": {"key": "callbackUri", "type": "str"}, + "media_subscription_id": {"key": "mediaSubscriptionId", "type": "str"}, + "source_caller_id_number": {"key": "sourceCallerIdNumber", "type": "PhoneNumberIdentifierModel"}, + "source_display_name": {"key": "sourceDisplayName", "type": "str"}, + "source_identity": {"key": "sourceIdentity", "type": "CommunicationIdentifierModel"}, + } + + def __init__( + self, + *, + call_connection_id: Optional[str] = None, + server_call_id: Optional[str] = None, + targets: Optional[List["_models.CommunicationIdentifierModel"]] = None, + call_connection_state: Optional[Union[str, "_models.CallConnectionStateModel"]] = None, + callback_uri: Optional[str] = None, + media_subscription_id: Optional[str] = None, + source_caller_id_number: Optional["_models.PhoneNumberIdentifierModel"] = None, + source_display_name: Optional[str] = None, + source_identity: Optional["_models.CommunicationIdentifierModel"] = None, + **kwargs: Any + ) -> None: + """ + :keyword call_connection_id: The call connection id. + :paramtype call_connection_id: str + :keyword server_call_id: The server call id. + :paramtype server_call_id: str + :keyword targets: The targets of the call. + :paramtype targets: + list[~azure.communication.callautomation.models.CommunicationIdentifierModel] + :keyword call_connection_state: The state of the call connection. Known values are: "unknown", + "connecting", "connected", "transferring", "transferAccepted", "disconnecting", and + "disconnected". + :paramtype call_connection_state: str or + ~azure.communication.callautomation.models.CallConnectionStateModel + :keyword callback_uri: The callback URI. + :paramtype callback_uri: str + :keyword media_subscription_id: SubscriptionId for media streaming. + :paramtype media_subscription_id: str + :keyword source_caller_id_number: The source caller Id, a phone number, that's shown to the + PSTN participant being invited. + Required only when calling a PSTN callee. + :paramtype source_caller_id_number: + ~azure.communication.callautomation.models.PhoneNumberIdentifierModel + :keyword source_display_name: Display name of the call if dialing out to a pstn number. + :paramtype source_display_name: str + :keyword source_identity: Source identity. + :paramtype source_identity: + ~azure.communication.callautomation.models.CommunicationIdentifierModel + """ + super().__init__(**kwargs) + self.call_connection_id = call_connection_id + self.server_call_id = server_call_id + self.targets = targets + self.call_connection_state = call_connection_state + self.callback_uri = callback_uri + self.media_subscription_id = media_subscription_id + self.source_caller_id_number = source_caller_id_number + self.source_display_name = source_display_name + self.source_identity = source_identity + + +class CallDisconnected(_serialization.Model): + """The call disconnected event. + + :ivar call_connection_id: Call connection ID. + :vartype call_connection_id: str + :ivar server_call_id: Server call ID. + :vartype server_call_id: str + :ivar correlation_id: Correlation ID for event to call correlation. Also called ChainId for + skype chain ID. + :vartype correlation_id: str + :ivar operation_context: Used by customers to set the context for creating a new call. This + property will be null for answering a call. + :vartype operation_context: str + """ + + _attribute_map = { + "call_connection_id": {"key": "callConnectionId", "type": "str"}, + "server_call_id": {"key": "serverCallId", "type": "str"}, + "correlation_id": {"key": "correlationId", "type": "str"}, + "operation_context": {"key": "operationContext", "type": "str"}, + } + + def __init__( + self, + *, + call_connection_id: Optional[str] = None, + server_call_id: Optional[str] = None, + correlation_id: Optional[str] = None, + operation_context: Optional[str] = None, + **kwargs: Any + ) -> None: + """ + :keyword call_connection_id: Call connection ID. + :paramtype call_connection_id: str + :keyword server_call_id: Server call ID. + :paramtype server_call_id: str + :keyword correlation_id: Correlation ID for event to call correlation. Also called ChainId for + skype chain ID. + :paramtype correlation_id: str + :keyword operation_context: Used by customers to set the context for creating a new call. This + property will be null for answering a call. + :paramtype operation_context: str + """ + super().__init__(**kwargs) + self.call_connection_id = call_connection_id + self.server_call_id = server_call_id + self.correlation_id = correlation_id + self.operation_context = operation_context + + +class CallLocator(_serialization.Model): + """The locator used for joining or taking action on a call. + + :ivar group_call_id: The group call id. + :vartype group_call_id: str + :ivar server_call_id: The server call id. + :vartype server_call_id: str + :ivar kind: The call locator kind. Known values are: "groupCallLocator" and + "serverCallLocator". + :vartype kind: str or ~azure.communication.callautomation.models.CallLocatorKind + """ + + _attribute_map = { + "group_call_id": {"key": "groupCallId", "type": "str"}, + "server_call_id": {"key": "serverCallId", "type": "str"}, + "kind": {"key": "kind", "type": "str"}, + } + + def __init__( + self, + *, + group_call_id: Optional[str] = None, + server_call_id: Optional[str] = None, + kind: Optional[Union[str, "_models.CallLocatorKind"]] = None, + **kwargs: Any + ) -> None: + """ + :keyword group_call_id: The group call id. + :paramtype group_call_id: str + :keyword server_call_id: The server call id. + :paramtype server_call_id: str + :keyword kind: The call locator kind. Known values are: "groupCallLocator" and + "serverCallLocator". + :paramtype kind: str or ~azure.communication.callautomation.models.CallLocatorKind + """ + super().__init__(**kwargs) + self.group_call_id = group_call_id + self.server_call_id = server_call_id + self.kind = kind + + +class CallParticipant(_serialization.Model): + """Contract model of an ACS call participant. + + :ivar identifier: Communication identifier of the participant. + :vartype identifier: ~azure.communication.callautomation.models.CommunicationIdentifierModel + :ivar is_muted: Is participant muted. + :vartype is_muted: bool + """ + + _attribute_map = { + "identifier": {"key": "identifier", "type": "CommunicationIdentifierModel"}, + "is_muted": {"key": "isMuted", "type": "bool"}, + } + + def __init__( + self, + *, + identifier: Optional["_models.CommunicationIdentifierModel"] = None, + is_muted: Optional[bool] = None, + **kwargs: Any + ) -> None: + """ + :keyword identifier: Communication identifier of the participant. + :paramtype identifier: ~azure.communication.callautomation.models.CommunicationIdentifierModel + :keyword is_muted: Is participant muted. + :paramtype is_muted: bool + """ + super().__init__(**kwargs) + self.identifier = identifier + self.is_muted = is_muted + + +class CallTransferAccepted(_serialization.Model): + """The call transfer accepted event. + + :ivar call_connection_id: Call connection ID. + :vartype call_connection_id: str + :ivar server_call_id: Server call ID. + :vartype server_call_id: str + :ivar correlation_id: Correlation ID for event to call correlation. Also called ChainId for + skype chain ID. + :vartype correlation_id: str + :ivar operation_context: Used by customers when calling mid-call actions to correlate the + request to the response event. + :vartype operation_context: str + :ivar result_information: Contains the resulting SIP code/sub-code and message from NGC + services. + :vartype result_information: ~azure.communication.callautomation.models.ResultInformation + """ + + _attribute_map = { + "call_connection_id": {"key": "callConnectionId", "type": "str"}, + "server_call_id": {"key": "serverCallId", "type": "str"}, + "correlation_id": {"key": "correlationId", "type": "str"}, + "operation_context": {"key": "operationContext", "type": "str"}, + "result_information": {"key": "resultInformation", "type": "ResultInformation"}, + } + + def __init__( + self, + *, + call_connection_id: Optional[str] = None, + server_call_id: Optional[str] = None, + correlation_id: Optional[str] = None, + operation_context: Optional[str] = None, + result_information: Optional["_models.ResultInformation"] = None, + **kwargs: Any + ) -> None: + """ + :keyword call_connection_id: Call connection ID. + :paramtype call_connection_id: str + :keyword server_call_id: Server call ID. + :paramtype server_call_id: str + :keyword correlation_id: Correlation ID for event to call correlation. Also called ChainId for + skype chain ID. + :paramtype correlation_id: str + :keyword operation_context: Used by customers when calling mid-call actions to correlate the + request to the response event. + :paramtype operation_context: str + :keyword result_information: Contains the resulting SIP code/sub-code and message from NGC + services. + :paramtype result_information: ~azure.communication.callautomation.models.ResultInformation + """ + super().__init__(**kwargs) + self.call_connection_id = call_connection_id + self.server_call_id = server_call_id + self.correlation_id = correlation_id + self.operation_context = operation_context + self.result_information = result_information + + +class CallTransferFailed(_serialization.Model): + """The call transfer failed event. + + :ivar call_connection_id: Call connection ID. + :vartype call_connection_id: str + :ivar server_call_id: Server call ID. + :vartype server_call_id: str + :ivar correlation_id: Correlation ID for event to call correlation. Also called ChainId for + skype chain ID. + :vartype correlation_id: str + :ivar operation_context: Used by customers when calling mid-call actions to correlate the + request to the response event. + :vartype operation_context: str + :ivar result_information: Contains the resulting SIP code/sub-code and message from NGC + services. + :vartype result_information: ~azure.communication.callautomation.models.ResultInformation + """ + + _attribute_map = { + "call_connection_id": {"key": "callConnectionId", "type": "str"}, + "server_call_id": {"key": "serverCallId", "type": "str"}, + "correlation_id": {"key": "correlationId", "type": "str"}, + "operation_context": {"key": "operationContext", "type": "str"}, + "result_information": {"key": "resultInformation", "type": "ResultInformation"}, + } + + def __init__( + self, + *, + call_connection_id: Optional[str] = None, + server_call_id: Optional[str] = None, + correlation_id: Optional[str] = None, + operation_context: Optional[str] = None, + result_information: Optional["_models.ResultInformation"] = None, + **kwargs: Any + ) -> None: + """ + :keyword call_connection_id: Call connection ID. + :paramtype call_connection_id: str + :keyword server_call_id: Server call ID. + :paramtype server_call_id: str + :keyword correlation_id: Correlation ID for event to call correlation. Also called ChainId for + skype chain ID. + :paramtype correlation_id: str + :keyword operation_context: Used by customers when calling mid-call actions to correlate the + request to the response event. + :paramtype operation_context: str + :keyword result_information: Contains the resulting SIP code/sub-code and message from NGC + services. + :paramtype result_information: ~azure.communication.callautomation.models.ResultInformation + """ + super().__init__(**kwargs) + self.call_connection_id = call_connection_id + self.server_call_id = server_call_id + self.correlation_id = correlation_id + self.operation_context = operation_context + self.result_information = result_information + + +class Choice(_serialization.Model): + """Choice. + + All required parameters must be populated in order to send to Azure. + + :ivar label: Identifier for a given choice. Required. + :vartype label: str + :ivar phrases: List of phrases to recognize. Required. + :vartype phrases: list[str] + :ivar tone: Known values are: "zero", "one", "two", "three", "four", "five", "six", "seven", + "eight", "nine", "a", "b", "c", "d", "pound", and "asterisk". + :vartype tone: str or ~azure.communication.callautomation.models.Tone + """ + + _validation = { + "label": {"required": True}, + "phrases": {"required": True}, + } + + _attribute_map = { + "label": {"key": "label", "type": "str"}, + "phrases": {"key": "phrases", "type": "[str]"}, + "tone": {"key": "tone", "type": "str"}, + } + + def __init__( + self, *, label: str, phrases: List[str], tone: Optional[Union[str, "_models.Tone"]] = None, **kwargs: Any + ) -> None: + """ + :keyword label: Identifier for a given choice. Required. + :paramtype label: str + :keyword phrases: List of phrases to recognize. Required. + :paramtype phrases: list[str] + :keyword tone: Known values are: "zero", "one", "two", "three", "four", "five", "six", "seven", + "eight", "nine", "a", "b", "c", "d", "pound", and "asterisk". + :paramtype tone: str or ~azure.communication.callautomation.models.Tone + """ + super().__init__(**kwargs) + self.label = label + self.phrases = phrases + self.tone = tone + + +class ChoiceResult(_serialization.Model): + """ChoiceResult. + + :ivar label: Label is the primary identifier for the choice detected. + :vartype label: str + :ivar recognized_phrase: Phrases are set to the value if choice is selected via phrase + detection. + If Dtmf input is recognized, then Label will be the identifier for the choice detected and + phrases will be set to null. + :vartype recognized_phrase: str + """ + + _attribute_map = { + "label": {"key": "label", "type": "str"}, + "recognized_phrase": {"key": "recognizedPhrase", "type": "str"}, + } + + def __init__(self, *, label: Optional[str] = None, recognized_phrase: Optional[str] = None, **kwargs: Any) -> None: + """ + :keyword label: Label is the primary identifier for the choice detected. + :paramtype label: str + :keyword recognized_phrase: Phrases are set to the value if choice is selected via phrase + detection. + If Dtmf input is recognized, then Label will be the identifier for the choice detected and + phrases will be set to null. + :paramtype recognized_phrase: str + """ + super().__init__(**kwargs) + self.label = label + self.recognized_phrase = recognized_phrase + + +class CollectTonesResult(_serialization.Model): + """CollectTonesResult. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar tones: + :vartype tones: list[str or ~azure.communication.callautomation.models.Tone] + """ + + _validation = { + "tones": {"readonly": True}, + } + + _attribute_map = { + "tones": {"key": "tones", "type": "[str]"}, + } + + def __init__(self, **kwargs: Any) -> None: + """ """ + super().__init__(**kwargs) + self.tones = None + + +class CommunicationError(_serialization.Model): + """CommunicationError. + + :ivar code: + :vartype code: str + :ivar message: + :vartype message: str + :ivar target: + :vartype target: str + :ivar details: + :vartype details: list[~azure.communication.callautomation.models.CommunicationError] + :ivar innererror: + :vartype innererror: ~azure.communication.callautomation.models.CommunicationError + """ + + _attribute_map = { + "code": {"key": "code", "type": "str"}, + "message": {"key": "message", "type": "str"}, + "target": {"key": "target", "type": "str"}, + "details": {"key": "details", "type": "[CommunicationError]"}, + "innererror": {"key": "innererror", "type": "CommunicationError"}, + } + + def __init__( + self, + *, + code: Optional[str] = None, + message: Optional[str] = None, + target: Optional[str] = None, + details: Optional[List["_models.CommunicationError"]] = None, + innererror: Optional["_models.CommunicationError"] = None, + **kwargs: Any + ) -> None: + """ + :keyword code: + :paramtype code: str + :keyword message: + :paramtype message: str + :keyword target: + :paramtype target: str + :keyword details: + :paramtype details: list[~azure.communication.callautomation.models.CommunicationError] + :keyword innererror: + :paramtype innererror: ~azure.communication.callautomation.models.CommunicationError + """ + super().__init__(**kwargs) + self.code = code + self.message = message + self.target = target + self.details = details + self.innererror = innererror + + +class CommunicationErrorResponse(_serialization.Model): + """The Communication Services error response. + + All required parameters must be populated in order to send to Azure. + + :ivar error: Required. + :vartype error: ~azure.communication.callautomation.models.CommunicationError + """ + + _validation = { + "error": {"required": True}, + } + + _attribute_map = { + "error": {"key": "error", "type": "CommunicationError"}, + } + + def __init__(self, *, error: "_models.CommunicationError", **kwargs: Any) -> None: + """ + :keyword error: Required. + :paramtype error: ~azure.communication.callautomation.models.CommunicationError + """ + super().__init__(**kwargs) + self.error = error + + +class CommunicationIdentifierModel(_serialization.Model): + """CommunicationIdentifierModel. + + :ivar raw_id: Full ID of the identifier. + :vartype raw_id: str + :ivar kind: Type of CommunicationIdentifierModel. Known values are: "unknown", + "communicationUser", "phoneNumber", and "microsoftTeamsUser". + :vartype kind: str or + ~azure.communication.callautomation.models.CommunicationIdentifierModelKind + :ivar communication_user: The communication user. + :vartype communication_user: + ~azure.communication.callautomation.models.CommunicationUserIdentifierModel + :ivar phone_number: The phone number. + :vartype phone_number: ~azure.communication.callautomation.models.PhoneNumberIdentifierModel + :ivar microsoft_teams_user: The Microsoft Teams user. + :vartype microsoft_teams_user: + ~azure.communication.callautomation.models.MicrosoftTeamsUserIdentifierModel + """ + + _attribute_map = { + "raw_id": {"key": "rawId", "type": "str"}, + "kind": {"key": "kind", "type": "str"}, + "communication_user": {"key": "communicationUser", "type": "CommunicationUserIdentifierModel"}, + "phone_number": {"key": "phoneNumber", "type": "PhoneNumberIdentifierModel"}, + "microsoft_teams_user": {"key": "microsoftTeamsUser", "type": "MicrosoftTeamsUserIdentifierModel"}, + } + + def __init__( + self, + *, + raw_id: Optional[str] = None, + kind: Optional[Union[str, "_models.CommunicationIdentifierModelKind"]] = None, + communication_user: Optional["_models.CommunicationUserIdentifierModel"] = None, + phone_number: Optional["_models.PhoneNumberIdentifierModel"] = None, + microsoft_teams_user: Optional["_models.MicrosoftTeamsUserIdentifierModel"] = None, + **kwargs: Any + ) -> None: + """ + :keyword raw_id: Full ID of the identifier. + :paramtype raw_id: str + :keyword kind: Type of CommunicationIdentifierModel. Known values are: "unknown", + "communicationUser", "phoneNumber", and "microsoftTeamsUser". + :paramtype kind: str or + ~azure.communication.callautomation.models.CommunicationIdentifierModelKind + :keyword communication_user: The communication user. + :paramtype communication_user: + ~azure.communication.callautomation.models.CommunicationUserIdentifierModel + :keyword phone_number: The phone number. + :paramtype phone_number: ~azure.communication.callautomation.models.PhoneNumberIdentifierModel + :keyword microsoft_teams_user: The Microsoft Teams user. + :paramtype microsoft_teams_user: + ~azure.communication.callautomation.models.MicrosoftTeamsUserIdentifierModel + """ + super().__init__(**kwargs) + self.raw_id = raw_id + self.kind = kind + self.communication_user = communication_user + self.phone_number = phone_number + self.microsoft_teams_user = microsoft_teams_user + + +class CommunicationUserIdentifierModel(_serialization.Model): + """CommunicationUserIdentifierModel. + + All required parameters must be populated in order to send to Azure. + + :ivar id: Required. + :vartype id: str + """ + + _validation = { + "id": {"required": True}, + } + + _attribute_map = { + "id": {"key": "id", "type": "str"}, + } + + def __init__(self, *, id: str, **kwargs: Any) -> None: # pylint: disable=redefined-builtin + """ + :keyword id: Required. + :paramtype id: str + """ + super().__init__(**kwargs) + self.id = id + + +class CreateCallRequest(_serialization.Model): + """The request payload for creating the call. + + All required parameters must be populated in order to send to Azure. + + :ivar targets: The targets of the call. Required. + :vartype targets: list[~azure.communication.callautomation.models.CommunicationIdentifierModel] + :ivar source_caller_id_number: The source caller Id, a phone number, that's shown to the PSTN + participant being invited. + Required only when calling a PSTN callee. + :vartype source_caller_id_number: + ~azure.communication.callautomation.models.PhoneNumberIdentifierModel + :ivar source_display_name: Display name of the call if dialing out to a pstn number. + :vartype source_display_name: str + :ivar source_identity: The identifier of the source of the call. + :vartype source_identity: + ~azure.communication.callautomation.models.CommunicationIdentifierModel + :ivar operation_context: A customer set value used to track the answering of a call. + :vartype operation_context: str + :ivar callback_uri: The callback URI. Required. + :vartype callback_uri: str + :ivar media_streaming_configuration: Media Streaming Configuration. + :vartype media_streaming_configuration: + ~azure.communication.callautomation.models.MediaStreamingConfiguration + :ivar azure_cognitive_services_endpoint_url: The identifier of the Cognitive Service resource + assigned to this call. + :vartype azure_cognitive_services_endpoint_url: str + """ + + _validation = { + "targets": {"required": True}, + "callback_uri": {"required": True}, + } + + _attribute_map = { + "targets": {"key": "targets", "type": "[CommunicationIdentifierModel]"}, + "source_caller_id_number": {"key": "sourceCallerIdNumber", "type": "PhoneNumberIdentifierModel"}, + "source_display_name": {"key": "sourceDisplayName", "type": "str"}, + "source_identity": {"key": "sourceIdentity", "type": "CommunicationIdentifierModel"}, + "operation_context": {"key": "operationContext", "type": "str"}, + "callback_uri": {"key": "callbackUri", "type": "str"}, + "media_streaming_configuration": {"key": "mediaStreamingConfiguration", "type": "MediaStreamingConfiguration"}, + "azure_cognitive_services_endpoint_url": {"key": "azureCognitiveServicesEndpointUrl", "type": "str"}, + } + + def __init__( + self, + *, + targets: List["_models.CommunicationIdentifierModel"], + callback_uri: str, + source_caller_id_number: Optional["_models.PhoneNumberIdentifierModel"] = None, + source_display_name: Optional[str] = None, + source_identity: Optional["_models.CommunicationIdentifierModel"] = None, + operation_context: Optional[str] = None, + media_streaming_configuration: Optional["_models.MediaStreamingConfiguration"] = None, + azure_cognitive_services_endpoint_url: Optional[str] = None, + **kwargs: Any + ) -> None: + """ + :keyword targets: The targets of the call. Required. + :paramtype targets: + list[~azure.communication.callautomation.models.CommunicationIdentifierModel] + :keyword source_caller_id_number: The source caller Id, a phone number, that's shown to the + PSTN participant being invited. + Required only when calling a PSTN callee. + :paramtype source_caller_id_number: + ~azure.communication.callautomation.models.PhoneNumberIdentifierModel + :keyword source_display_name: Display name of the call if dialing out to a pstn number. + :paramtype source_display_name: str + :keyword source_identity: The identifier of the source of the call. + :paramtype source_identity: + ~azure.communication.callautomation.models.CommunicationIdentifierModel + :keyword operation_context: A customer set value used to track the answering of a call. + :paramtype operation_context: str + :keyword callback_uri: The callback URI. Required. + :paramtype callback_uri: str + :keyword media_streaming_configuration: Media Streaming Configuration. + :paramtype media_streaming_configuration: + ~azure.communication.callautomation.models.MediaStreamingConfiguration + :keyword azure_cognitive_services_endpoint_url: The identifier of the Cognitive Service + resource assigned to this call. + :paramtype azure_cognitive_services_endpoint_url: str + """ + super().__init__(**kwargs) + self.targets = targets + self.source_caller_id_number = source_caller_id_number + self.source_display_name = source_display_name + self.source_identity = source_identity + self.operation_context = operation_context + self.callback_uri = callback_uri + self.media_streaming_configuration = media_streaming_configuration + self.azure_cognitive_services_endpoint_url = azure_cognitive_services_endpoint_url + + +class CustomContext(_serialization.Model): + """CustomContext. + + :ivar voip_headers: Dictionary of :code:``. + :vartype voip_headers: dict[str, str] + :ivar sip_headers: Dictionary of :code:``. + :vartype sip_headers: dict[str, str] + """ + + _attribute_map = { + "voip_headers": {"key": "voipHeaders", "type": "{str}"}, + "sip_headers": {"key": "sipHeaders", "type": "{str}"}, + } + + def __init__( + self, + *, + voip_headers: Optional[Dict[str, str]] = None, + sip_headers: Optional[Dict[str, str]] = None, + **kwargs: Any + ) -> None: + """ + :keyword voip_headers: Dictionary of :code:``. + :paramtype voip_headers: dict[str, str] + :keyword sip_headers: Dictionary of :code:``. + :paramtype sip_headers: dict[str, str] + """ + super().__init__(**kwargs) + self.voip_headers = voip_headers + self.sip_headers = sip_headers + + +class DtmfOptions(_serialization.Model): + """Options for DTMF recognition. + + :ivar inter_tone_timeout_in_seconds: Time to wait between DTMF inputs to stop recognizing. + :vartype inter_tone_timeout_in_seconds: int + :ivar max_tones_to_collect: Maximum number of DTMF tones to be collected. + :vartype max_tones_to_collect: int + :ivar stop_tones: List of tones that will stop recognizing. + :vartype stop_tones: list[str or ~azure.communication.callautomation.models.Tone] + """ + + _validation = { + "inter_tone_timeout_in_seconds": {"maximum": 60, "minimum": 1}, + } + + _attribute_map = { + "inter_tone_timeout_in_seconds": {"key": "interToneTimeoutInSeconds", "type": "int"}, + "max_tones_to_collect": {"key": "maxTonesToCollect", "type": "int"}, + "stop_tones": {"key": "stopTones", "type": "[str]"}, + } + + def __init__( + self, + *, + inter_tone_timeout_in_seconds: Optional[int] = None, + max_tones_to_collect: Optional[int] = None, + stop_tones: Optional[List[Union[str, "_models.Tone"]]] = None, + **kwargs: Any + ) -> None: + """ + :keyword inter_tone_timeout_in_seconds: Time to wait between DTMF inputs to stop recognizing. + :paramtype inter_tone_timeout_in_seconds: int + :keyword max_tones_to_collect: Maximum number of DTMF tones to be collected. + :paramtype max_tones_to_collect: int + :keyword stop_tones: List of tones that will stop recognizing. + :paramtype stop_tones: list[str or ~azure.communication.callautomation.models.Tone] + """ + super().__init__(**kwargs) + self.inter_tone_timeout_in_seconds = inter_tone_timeout_in_seconds + self.max_tones_to_collect = max_tones_to_collect + self.stop_tones = stop_tones + + +class FileSource(_serialization.Model): + """FileSource. + + All required parameters must be populated in order to send to Azure. + + :ivar uri: Uri for the audio file to be played. Required. + :vartype uri: str + """ + + _validation = { + "uri": {"required": True}, + } + + _attribute_map = { + "uri": {"key": "uri", "type": "str"}, + } + + def __init__(self, *, uri: str, **kwargs: Any) -> None: + """ + :keyword uri: Uri for the audio file to be played. Required. + :paramtype uri: str + """ + super().__init__(**kwargs) + self.uri = uri + + +class GetParticipantsResponse(_serialization.Model): + """The response payload for getting participants of the call. + + :ivar values: List of the current participants in the call. + :vartype values: list[~azure.communication.callautomation.models.CallParticipant] + :ivar next_link: Continue of the list of participants. + :vartype next_link: str + """ + + _attribute_map = { + "values": {"key": "values", "type": "[CallParticipant]"}, + "next_link": {"key": "nextLink", "type": "str"}, + } + + def __init__( + self, + *, + values: Optional[List["_models.CallParticipant"]] = None, + next_link: Optional[str] = None, + **kwargs: Any + ) -> None: + """ + :keyword values: List of the current participants in the call. + :paramtype values: list[~azure.communication.callautomation.models.CallParticipant] + :keyword next_link: Continue of the list of participants. + :paramtype next_link: str + """ + super().__init__(**kwargs) + self.values = values + self.next_link = next_link + + +class MediaStreamingConfiguration(_serialization.Model): + """Configuration of Media streaming. + + All required parameters must be populated in order to send to Azure. + + :ivar transport_url: Transport URL for media streaming. Required. + :vartype transport_url: str + :ivar transport_type: The type of transport to be used for media streaming, eg. Websocket. + Required. "websocket" + :vartype transport_type: str or + ~azure.communication.callautomation.models.MediaStreamingTransportType + :ivar content_type: Content type to stream, eg. audio, audio/video. Required. "audio" + :vartype content_type: str or + ~azure.communication.callautomation.models.MediaStreamingContentType + :ivar audio_channel_type: Audio channel type to stream, eg. unmixed audio, mixed audio. + Required. Known values are: "mixed" and "unmixed". + :vartype audio_channel_type: str or + ~azure.communication.callautomation.models.MediaStreamingAudioChannelType + """ + + _validation = { + "transport_url": {"required": True}, + "transport_type": {"required": True}, + "content_type": {"required": True}, + "audio_channel_type": {"required": True}, + } + + _attribute_map = { + "transport_url": {"key": "transportUrl", "type": "str"}, + "transport_type": {"key": "transportType", "type": "str"}, + "content_type": {"key": "contentType", "type": "str"}, + "audio_channel_type": {"key": "audioChannelType", "type": "str"}, + } + + def __init__( + self, + *, + transport_url: str, + transport_type: Union[str, "_models.MediaStreamingTransportType"], + content_type: Union[str, "_models.MediaStreamingContentType"], + audio_channel_type: Union[str, "_models.MediaStreamingAudioChannelType"], + **kwargs: Any + ) -> None: + """ + :keyword transport_url: Transport URL for media streaming. Required. + :paramtype transport_url: str + :keyword transport_type: The type of transport to be used for media streaming, eg. Websocket. + Required. "websocket" + :paramtype transport_type: str or + ~azure.communication.callautomation.models.MediaStreamingTransportType + :keyword content_type: Content type to stream, eg. audio, audio/video. Required. "audio" + :paramtype content_type: str or + ~azure.communication.callautomation.models.MediaStreamingContentType + :keyword audio_channel_type: Audio channel type to stream, eg. unmixed audio, mixed audio. + Required. Known values are: "mixed" and "unmixed". + :paramtype audio_channel_type: str or + ~azure.communication.callautomation.models.MediaStreamingAudioChannelType + """ + super().__init__(**kwargs) + self.transport_url = transport_url + self.transport_type = transport_type + self.content_type = content_type + self.audio_channel_type = audio_channel_type + + +class MicrosoftTeamsUserIdentifierModel(_serialization.Model): + """MicrosoftTeamsUserIdentifierModel. + + All required parameters must be populated in order to send to Azure. + + :ivar user_id: Required. + :vartype user_id: str + :ivar is_anonymous: + :vartype is_anonymous: bool + :ivar cloud: Known values are: "public", "dod", and "gcch". + :vartype cloud: str or + ~azure.communication.callautomation.models.CommunicationCloudEnvironmentModel + """ + + _validation = { + "user_id": {"required": True}, + } + + _attribute_map = { + "user_id": {"key": "userId", "type": "str"}, + "is_anonymous": {"key": "isAnonymous", "type": "bool"}, + "cloud": {"key": "cloud", "type": "str"}, + } + + def __init__( + self, + *, + user_id: str, + is_anonymous: Optional[bool] = None, + cloud: Optional[Union[str, "_models.CommunicationCloudEnvironmentModel"]] = None, + **kwargs: Any + ) -> None: + """ + :keyword user_id: Required. + :paramtype user_id: str + :keyword is_anonymous: + :paramtype is_anonymous: bool + :keyword cloud: Known values are: "public", "dod", and "gcch". + :paramtype cloud: str or + ~azure.communication.callautomation.models.CommunicationCloudEnvironmentModel + """ + super().__init__(**kwargs) + self.user_id = user_id + self.is_anonymous = is_anonymous + self.cloud = cloud + + +class MuteParticipantsRequest(_serialization.Model): + """The request payload for muting participants from the call. + + All required parameters must be populated in order to send to Azure. + + :ivar target_participants: Participants to be muted from the call. + Only ACS Users are supported. Required. + :vartype target_participants: + list[~azure.communication.callautomation.models.CommunicationIdentifierModel] + :ivar operation_context: Used by customers when calling mid-call actions to correlate the + request to the response event. + :vartype operation_context: str + """ + + _validation = { + "target_participants": {"required": True}, + } + + _attribute_map = { + "target_participants": {"key": "targetParticipants", "type": "[CommunicationIdentifierModel]"}, + "operation_context": {"key": "operationContext", "type": "str"}, + } + + def __init__( + self, + *, + target_participants: List["_models.CommunicationIdentifierModel"], + operation_context: Optional[str] = None, + **kwargs: Any + ) -> None: + """ + :keyword target_participants: Participants to be muted from the call. + Only ACS Users are supported. Required. + :paramtype target_participants: + list[~azure.communication.callautomation.models.CommunicationIdentifierModel] + :keyword operation_context: Used by customers when calling mid-call actions to correlate the + request to the response event. + :paramtype operation_context: str + """ + super().__init__(**kwargs) + self.target_participants = target_participants + self.operation_context = operation_context + + +class MuteParticipantsResponse(_serialization.Model): + """The response payload for muting participants from the call. + + :ivar operation_context: The operation context provided by client. + :vartype operation_context: str + """ + + _attribute_map = { + "operation_context": {"key": "operationContext", "type": "str"}, + } + + def __init__(self, *, operation_context: Optional[str] = None, **kwargs: Any) -> None: + """ + :keyword operation_context: The operation context provided by client. + :paramtype operation_context: str + """ + super().__init__(**kwargs) + self.operation_context = operation_context + + +class ParticipantsUpdated(_serialization.Model): + """The participants updated in a call event. + + :ivar call_connection_id: Call connection ID. + :vartype call_connection_id: str + :ivar server_call_id: Server call ID. + :vartype server_call_id: str + :ivar correlation_id: Correlation ID for event to call correlation. Also called ChainId for + skype chain ID. + :vartype correlation_id: str + :ivar participants: The list of participants in the call. + :vartype participants: list[~azure.communication.callautomation.models.CallParticipant] + """ + + _attribute_map = { + "call_connection_id": {"key": "callConnectionId", "type": "str"}, + "server_call_id": {"key": "serverCallId", "type": "str"}, + "correlation_id": {"key": "correlationId", "type": "str"}, + "participants": {"key": "participants", "type": "[CallParticipant]"}, + } + + def __init__( + self, + *, + call_connection_id: Optional[str] = None, + server_call_id: Optional[str] = None, + correlation_id: Optional[str] = None, + participants: Optional[List["_models.CallParticipant"]] = None, + **kwargs: Any + ) -> None: + """ + :keyword call_connection_id: Call connection ID. + :paramtype call_connection_id: str + :keyword server_call_id: Server call ID. + :paramtype server_call_id: str + :keyword correlation_id: Correlation ID for event to call correlation. Also called ChainId for + skype chain ID. + :paramtype correlation_id: str + :keyword participants: The list of participants in the call. + :paramtype participants: list[~azure.communication.callautomation.models.CallParticipant] + """ + super().__init__(**kwargs) + self.call_connection_id = call_connection_id + self.server_call_id = server_call_id + self.correlation_id = correlation_id + self.participants = participants + + +class PhoneNumberIdentifierModel(_serialization.Model): + """PhoneNumberIdentifierModel. + + All required parameters must be populated in order to send to Azure. + + :ivar value: Required. + :vartype value: str + """ + + _validation = { + "value": {"required": True}, + } + + _attribute_map = { + "value": {"key": "value", "type": "str"}, + } + + def __init__(self, *, value: str, **kwargs: Any) -> None: + """ + :keyword value: Required. + :paramtype value: str + """ + super().__init__(**kwargs) + self.value = value + + +class PlayCanceled(_serialization.Model): + """PlayCanceled. + + :ivar call_connection_id: Call connection ID. + :vartype call_connection_id: str + :ivar server_call_id: Server call ID. + :vartype server_call_id: str + :ivar correlation_id: Correlation ID for event to call correlation. Also called ChainId for + skype chain ID. + :vartype correlation_id: str + :ivar operation_context: Used by customers when calling mid-call actions to correlate the + request to the response event. + :vartype operation_context: str + """ + + _attribute_map = { + "call_connection_id": {"key": "callConnectionId", "type": "str"}, + "server_call_id": {"key": "serverCallId", "type": "str"}, + "correlation_id": {"key": "correlationId", "type": "str"}, + "operation_context": {"key": "operationContext", "type": "str"}, + } + + def __init__( + self, + *, + call_connection_id: Optional[str] = None, + server_call_id: Optional[str] = None, + correlation_id: Optional[str] = None, + operation_context: Optional[str] = None, + **kwargs: Any + ) -> None: + """ + :keyword call_connection_id: Call connection ID. + :paramtype call_connection_id: str + :keyword server_call_id: Server call ID. + :paramtype server_call_id: str + :keyword correlation_id: Correlation ID for event to call correlation. Also called ChainId for + skype chain ID. + :paramtype correlation_id: str + :keyword operation_context: Used by customers when calling mid-call actions to correlate the + request to the response event. + :paramtype operation_context: str + """ + super().__init__(**kwargs) + self.call_connection_id = call_connection_id + self.server_call_id = server_call_id + self.correlation_id = correlation_id + self.operation_context = operation_context + + +class PlayCompleted(_serialization.Model): + """PlayCompleted. + + :ivar call_connection_id: Call connection ID. + :vartype call_connection_id: str + :ivar server_call_id: Server call ID. + :vartype server_call_id: str + :ivar correlation_id: Correlation ID for event to call correlation. Also called ChainId for + skype chain ID. + :vartype correlation_id: str + :ivar operation_context: Used by customers when calling mid-call actions to correlate the + request to the response event. + :vartype operation_context: str + :ivar result_information: Contains the resulting SIP code/sub-code and message from NGC + services. + :vartype result_information: ~azure.communication.callautomation.models.ResultInformation + """ + + _attribute_map = { + "call_connection_id": {"key": "callConnectionId", "type": "str"}, + "server_call_id": {"key": "serverCallId", "type": "str"}, + "correlation_id": {"key": "correlationId", "type": "str"}, + "operation_context": {"key": "operationContext", "type": "str"}, + "result_information": {"key": "resultInformation", "type": "ResultInformation"}, + } + + def __init__( + self, + *, + call_connection_id: Optional[str] = None, + server_call_id: Optional[str] = None, + correlation_id: Optional[str] = None, + operation_context: Optional[str] = None, + result_information: Optional["_models.ResultInformation"] = None, + **kwargs: Any + ) -> None: + """ + :keyword call_connection_id: Call connection ID. + :paramtype call_connection_id: str + :keyword server_call_id: Server call ID. + :paramtype server_call_id: str + :keyword correlation_id: Correlation ID for event to call correlation. Also called ChainId for + skype chain ID. + :paramtype correlation_id: str + :keyword operation_context: Used by customers when calling mid-call actions to correlate the + request to the response event. + :paramtype operation_context: str + :keyword result_information: Contains the resulting SIP code/sub-code and message from NGC + services. + :paramtype result_information: ~azure.communication.callautomation.models.ResultInformation + """ + super().__init__(**kwargs) + self.call_connection_id = call_connection_id + self.server_call_id = server_call_id + self.correlation_id = correlation_id + self.operation_context = operation_context + self.result_information = result_information + + +class PlayFailed(_serialization.Model): + """PlayFailed. + + :ivar call_connection_id: Call connection ID. + :vartype call_connection_id: str + :ivar server_call_id: Server call ID. + :vartype server_call_id: str + :ivar correlation_id: Correlation ID for event to call correlation. Also called ChainId for + skype chain ID. + :vartype correlation_id: str + :ivar operation_context: Used by customers when calling mid-call actions to correlate the + request to the response event. + :vartype operation_context: str + :ivar result_information: Contains the resulting SIP code/sub-code and message from NGC + services. + :vartype result_information: ~azure.communication.callautomation.models.ResultInformation + """ + + _attribute_map = { + "call_connection_id": {"key": "callConnectionId", "type": "str"}, + "server_call_id": {"key": "serverCallId", "type": "str"}, + "correlation_id": {"key": "correlationId", "type": "str"}, + "operation_context": {"key": "operationContext", "type": "str"}, + "result_information": {"key": "resultInformation", "type": "ResultInformation"}, + } + + def __init__( + self, + *, + call_connection_id: Optional[str] = None, + server_call_id: Optional[str] = None, + correlation_id: Optional[str] = None, + operation_context: Optional[str] = None, + result_information: Optional["_models.ResultInformation"] = None, + **kwargs: Any + ) -> None: + """ + :keyword call_connection_id: Call connection ID. + :paramtype call_connection_id: str + :keyword server_call_id: Server call ID. + :paramtype server_call_id: str + :keyword correlation_id: Correlation ID for event to call correlation. Also called ChainId for + skype chain ID. + :paramtype correlation_id: str + :keyword operation_context: Used by customers when calling mid-call actions to correlate the + request to the response event. + :paramtype operation_context: str + :keyword result_information: Contains the resulting SIP code/sub-code and message from NGC + services. + :paramtype result_information: ~azure.communication.callautomation.models.ResultInformation + """ + super().__init__(**kwargs) + self.call_connection_id = call_connection_id + self.server_call_id = server_call_id + self.correlation_id = correlation_id + self.operation_context = operation_context + self.result_information = result_information + + +class PlayOptions(_serialization.Model): + """PlayOptions. + + All required parameters must be populated in order to send to Azure. + + :ivar loop: The option to play the provided audio source in loop when set to true. Required. + :vartype loop: bool + """ + + _validation = { + "loop": {"required": True}, + } + + _attribute_map = { + "loop": {"key": "loop", "type": "bool"}, + } + + def __init__(self, *, loop: bool, **kwargs: Any) -> None: + """ + :keyword loop: The option to play the provided audio source in loop when set to true. Required. + :paramtype loop: bool + """ + super().__init__(**kwargs) + self.loop = loop + + +class PlayRequest(_serialization.Model): + """PlayRequest. + + All required parameters must be populated in order to send to Azure. + + :ivar play_source_info: The source of the audio to be played. Required. + :vartype play_source_info: ~azure.communication.callautomation.models.PlaySource + :ivar play_to: The list of call participants play provided audio to. + Plays to everyone in the call when not provided. + :vartype play_to: list[~azure.communication.callautomation.models.CommunicationIdentifierModel] + :ivar play_options: Defines options for playing the audio. + :vartype play_options: ~azure.communication.callautomation.models.PlayOptions + :ivar operation_context: The value to identify context of the operation. + :vartype operation_context: str + """ + + _validation = { + "play_source_info": {"required": True}, + } + + _attribute_map = { + "play_source_info": {"key": "playSourceInfo", "type": "PlaySource"}, + "play_to": {"key": "playTo", "type": "[CommunicationIdentifierModel]"}, + "play_options": {"key": "playOptions", "type": "PlayOptions"}, + "operation_context": {"key": "operationContext", "type": "str"}, + } + + def __init__( + self, + *, + play_source_info: "_models.PlaySource", + play_to: Optional[List["_models.CommunicationIdentifierModel"]] = None, + play_options: Optional["_models.PlayOptions"] = None, + operation_context: Optional[str] = None, + **kwargs: Any + ) -> None: + """ + :keyword play_source_info: The source of the audio to be played. Required. + :paramtype play_source_info: ~azure.communication.callautomation.models.PlaySource + :keyword play_to: The list of call participants play provided audio to. + Plays to everyone in the call when not provided. + :paramtype play_to: + list[~azure.communication.callautomation.models.CommunicationIdentifierModel] + :keyword play_options: Defines options for playing the audio. + :paramtype play_options: ~azure.communication.callautomation.models.PlayOptions + :keyword operation_context: The value to identify context of the operation. + :paramtype operation_context: str + """ + super().__init__(**kwargs) + self.play_source_info = play_source_info + self.play_to = play_to + self.play_options = play_options + self.operation_context = operation_context + + +class PlaySource(_serialization.Model): + """PlaySource. + + All required parameters must be populated in order to send to Azure. + + :ivar source_type: Defines the type of the play source. Required. Known values are: "file" and + "text". + :vartype source_type: str or ~azure.communication.callautomation.models.PlaySourceType + :ivar play_source_id: Defines the identifier to be used for caching related media. + :vartype play_source_id: str + :ivar file_source: Defines the file source info to be used for play. + :vartype file_source: ~azure.communication.callautomation.models.FileSource + :ivar text_source: Defines the text source info to be used for play. + :vartype text_source: ~azure.communication.callautomation.models.TextSource + """ + + _validation = { + "source_type": {"required": True}, + } + + _attribute_map = { + "source_type": {"key": "sourceType", "type": "str"}, + "play_source_id": {"key": "playSourceId", "type": "str"}, + "file_source": {"key": "fileSource", "type": "FileSource"}, + "text_source": {"key": "textSource", "type": "TextSource"}, + } + + def __init__( + self, + *, + source_type: Union[str, "_models.PlaySourceType"], + play_source_id: Optional[str] = None, + file_source: Optional["_models.FileSource"] = None, + text_source: Optional["_models.TextSource"] = None, + **kwargs: Any + ) -> None: + """ + :keyword source_type: Defines the type of the play source. Required. Known values are: "file" + and "text". + :paramtype source_type: str or ~azure.communication.callautomation.models.PlaySourceType + :keyword play_source_id: Defines the identifier to be used for caching related media. + :paramtype play_source_id: str + :keyword file_source: Defines the file source info to be used for play. + :paramtype file_source: ~azure.communication.callautomation.models.FileSource + :keyword text_source: Defines the text source info to be used for play. + :paramtype text_source: ~azure.communication.callautomation.models.TextSource + """ + super().__init__(**kwargs) + self.source_type = source_type + self.play_source_id = play_source_id + self.file_source = file_source + self.text_source = text_source + + +class RecognizeCanceled(_serialization.Model): + """RecognizeCanceled. + + :ivar call_connection_id: Call connection ID. + :vartype call_connection_id: str + :ivar server_call_id: Server call ID. + :vartype server_call_id: str + :ivar correlation_id: Correlation ID for event to call correlation. Also called ChainId for + skype chain ID. + :vartype correlation_id: str + :ivar operation_context: Used by customers when calling mid-call actions to correlate the + request to the response event. + :vartype operation_context: str + """ + + _attribute_map = { + "call_connection_id": {"key": "callConnectionId", "type": "str"}, + "server_call_id": {"key": "serverCallId", "type": "str"}, + "correlation_id": {"key": "correlationId", "type": "str"}, + "operation_context": {"key": "operationContext", "type": "str"}, + } + + def __init__( + self, + *, + call_connection_id: Optional[str] = None, + server_call_id: Optional[str] = None, + correlation_id: Optional[str] = None, + operation_context: Optional[str] = None, + **kwargs: Any + ) -> None: + """ + :keyword call_connection_id: Call connection ID. + :paramtype call_connection_id: str + :keyword server_call_id: Server call ID. + :paramtype server_call_id: str + :keyword correlation_id: Correlation ID for event to call correlation. Also called ChainId for + skype chain ID. + :paramtype correlation_id: str + :keyword operation_context: Used by customers when calling mid-call actions to correlate the + request to the response event. + :paramtype operation_context: str + """ + super().__init__(**kwargs) + self.call_connection_id = call_connection_id + self.server_call_id = server_call_id + self.correlation_id = correlation_id + self.operation_context = operation_context + + +class RecognizeCompleted(_serialization.Model): + """RecognizeCompleted. + + :ivar call_connection_id: Call connection ID. + :vartype call_connection_id: str + :ivar server_call_id: Server call ID. + :vartype server_call_id: str + :ivar correlation_id: Correlation ID for event to call correlation. Also called ChainId for + skype chain ID. + :vartype correlation_id: str + :ivar operation_context: Used by customers when calling mid-call actions to correlate the + request to the response event. + :vartype operation_context: str + :ivar result_information: Contains the resulting SIP code/sub-code and message from NGC + services. + :vartype result_information: ~azure.communication.callautomation.models.ResultInformation + :ivar recognition_type: Determines the sub-type of the recognize operation. + In case of cancel operation the this field is not set and is returned empty. Known values are: + "dtmf" and "choices". + :vartype recognition_type: str or ~azure.communication.callautomation.models.RecognitionType + :ivar collect_tones_result: Defines the result for RecognitionType = Dtmf. + :vartype collect_tones_result: ~azure.communication.callautomation.models.CollectTonesResult + :ivar choice_result: Defines the result for RecognitionType = Choices. + :vartype choice_result: ~azure.communication.callautomation.models.ChoiceResult + """ + + _attribute_map = { + "call_connection_id": {"key": "callConnectionId", "type": "str"}, + "server_call_id": {"key": "serverCallId", "type": "str"}, + "correlation_id": {"key": "correlationId", "type": "str"}, + "operation_context": {"key": "operationContext", "type": "str"}, + "result_information": {"key": "resultInformation", "type": "ResultInformation"}, + "recognition_type": {"key": "recognitionType", "type": "str"}, + "collect_tones_result": {"key": "collectTonesResult", "type": "CollectTonesResult"}, + "choice_result": {"key": "choiceResult", "type": "ChoiceResult"}, + } + + def __init__( + self, + *, + call_connection_id: Optional[str] = None, + server_call_id: Optional[str] = None, + correlation_id: Optional[str] = None, + operation_context: Optional[str] = None, + result_information: Optional["_models.ResultInformation"] = None, + recognition_type: Optional[Union[str, "_models.RecognitionType"]] = None, + collect_tones_result: Optional["_models.CollectTonesResult"] = None, + choice_result: Optional["_models.ChoiceResult"] = None, + **kwargs: Any + ) -> None: + """ + :keyword call_connection_id: Call connection ID. + :paramtype call_connection_id: str + :keyword server_call_id: Server call ID. + :paramtype server_call_id: str + :keyword correlation_id: Correlation ID for event to call correlation. Also called ChainId for + skype chain ID. + :paramtype correlation_id: str + :keyword operation_context: Used by customers when calling mid-call actions to correlate the + request to the response event. + :paramtype operation_context: str + :keyword result_information: Contains the resulting SIP code/sub-code and message from NGC + services. + :paramtype result_information: ~azure.communication.callautomation.models.ResultInformation + :keyword recognition_type: Determines the sub-type of the recognize operation. + In case of cancel operation the this field is not set and is returned empty. Known values are: + "dtmf" and "choices". + :paramtype recognition_type: str or ~azure.communication.callautomation.models.RecognitionType + :keyword collect_tones_result: Defines the result for RecognitionType = Dtmf. + :paramtype collect_tones_result: ~azure.communication.callautomation.models.CollectTonesResult + :keyword choice_result: Defines the result for RecognitionType = Choices. + :paramtype choice_result: ~azure.communication.callautomation.models.ChoiceResult + """ + super().__init__(**kwargs) + self.call_connection_id = call_connection_id + self.server_call_id = server_call_id + self.correlation_id = correlation_id + self.operation_context = operation_context + self.result_information = result_information + self.recognition_type = recognition_type + self.collect_tones_result = collect_tones_result + self.choice_result = choice_result + + +class RecognizeFailed(_serialization.Model): + """RecognizeFailed. + + :ivar call_connection_id: Call connection ID. + :vartype call_connection_id: str + :ivar server_call_id: Server call ID. + :vartype server_call_id: str + :ivar correlation_id: Correlation ID for event to call correlation. Also called ChainId for + skype chain ID. + :vartype correlation_id: str + :ivar operation_context: Used by customers when calling mid-call actions to correlate the + request to the response event. + :vartype operation_context: str + :ivar result_information: Contains the resulting SIP code/sub-code and message from NGC + services. + :vartype result_information: ~azure.communication.callautomation.models.ResultInformation + """ + + _attribute_map = { + "call_connection_id": {"key": "callConnectionId", "type": "str"}, + "server_call_id": {"key": "serverCallId", "type": "str"}, + "correlation_id": {"key": "correlationId", "type": "str"}, + "operation_context": {"key": "operationContext", "type": "str"}, + "result_information": {"key": "resultInformation", "type": "ResultInformation"}, + } + + def __init__( + self, + *, + call_connection_id: Optional[str] = None, + server_call_id: Optional[str] = None, + correlation_id: Optional[str] = None, + operation_context: Optional[str] = None, + result_information: Optional["_models.ResultInformation"] = None, + **kwargs: Any + ) -> None: + """ + :keyword call_connection_id: Call connection ID. + :paramtype call_connection_id: str + :keyword server_call_id: Server call ID. + :paramtype server_call_id: str + :keyword correlation_id: Correlation ID for event to call correlation. Also called ChainId for + skype chain ID. + :paramtype correlation_id: str + :keyword operation_context: Used by customers when calling mid-call actions to correlate the + request to the response event. + :paramtype operation_context: str + :keyword result_information: Contains the resulting SIP code/sub-code and message from NGC + services. + :paramtype result_information: ~azure.communication.callautomation.models.ResultInformation + """ + super().__init__(**kwargs) + self.call_connection_id = call_connection_id + self.server_call_id = server_call_id + self.correlation_id = correlation_id + self.operation_context = operation_context + self.result_information = result_information + + +class RecognizeOptions(_serialization.Model): + """RecognizeOptions. + + All required parameters must be populated in order to send to Azure. + + :ivar interrupt_prompt: Determines if we interrupt the prompt and start recognizing. + :vartype interrupt_prompt: bool + :ivar initial_silence_timeout_in_seconds: Time to wait for first input after prompt (if any). + :vartype initial_silence_timeout_in_seconds: int + :ivar target_participant: Target participant of DTMF tone recognition. Required. + :vartype target_participant: + ~azure.communication.callautomation.models.CommunicationIdentifierModel + :ivar dtmf_options: Defines configurations for DTMF. + :vartype dtmf_options: ~azure.communication.callautomation.models.DtmfOptions + :ivar choices: Defines Ivr choices for recognize. + :vartype choices: list[~azure.communication.callautomation.models.Choice] + """ + + _validation = { + "initial_silence_timeout_in_seconds": {"maximum": 300, "minimum": 0}, + "target_participant": {"required": True}, + } + + _attribute_map = { + "interrupt_prompt": {"key": "interruptPrompt", "type": "bool"}, + "initial_silence_timeout_in_seconds": {"key": "initialSilenceTimeoutInSeconds", "type": "int"}, + "target_participant": {"key": "targetParticipant", "type": "CommunicationIdentifierModel"}, + "dtmf_options": {"key": "dtmfOptions", "type": "DtmfOptions"}, + "choices": {"key": "choices", "type": "[Choice]"}, + } + + def __init__( + self, + *, + target_participant: "_models.CommunicationIdentifierModel", + interrupt_prompt: Optional[bool] = None, + initial_silence_timeout_in_seconds: Optional[int] = None, + dtmf_options: Optional["_models.DtmfOptions"] = None, + choices: Optional[List["_models.Choice"]] = None, + **kwargs: Any + ) -> None: + """ + :keyword interrupt_prompt: Determines if we interrupt the prompt and start recognizing. + :paramtype interrupt_prompt: bool + :keyword initial_silence_timeout_in_seconds: Time to wait for first input after prompt (if + any). + :paramtype initial_silence_timeout_in_seconds: int + :keyword target_participant: Target participant of DTMF tone recognition. Required. + :paramtype target_participant: + ~azure.communication.callautomation.models.CommunicationIdentifierModel + :keyword dtmf_options: Defines configurations for DTMF. + :paramtype dtmf_options: ~azure.communication.callautomation.models.DtmfOptions + :keyword choices: Defines Ivr choices for recognize. + :paramtype choices: list[~azure.communication.callautomation.models.Choice] + """ + super().__init__(**kwargs) + self.interrupt_prompt = interrupt_prompt + self.initial_silence_timeout_in_seconds = initial_silence_timeout_in_seconds + self.target_participant = target_participant + self.dtmf_options = dtmf_options + self.choices = choices + + +class RecognizeRequest(_serialization.Model): + """RecognizeRequest. + + All required parameters must be populated in order to send to Azure. + + :ivar recognize_input_type: Determines the type of the recognition. Required. Known values are: + "dtmf" and "choices". + :vartype recognize_input_type: str or + ~azure.communication.callautomation.models.RecognizeInputType + :ivar play_prompt: The source of the audio to be played for recognition. + :vartype play_prompt: ~azure.communication.callautomation.models.PlaySource + :ivar interrupt_call_media_operation: If set recognize can barge into other existing + queued-up/currently-processing requests. + :vartype interrupt_call_media_operation: bool + :ivar recognize_options: Defines options for recognition. Required. + :vartype recognize_options: ~azure.communication.callautomation.models.RecognizeOptions + :ivar operation_context: The value to identify context of the operation. + :vartype operation_context: str + """ + + _validation = { + "recognize_input_type": {"required": True}, + "recognize_options": {"required": True}, + } + + _attribute_map = { + "recognize_input_type": {"key": "recognizeInputType", "type": "str"}, + "play_prompt": {"key": "playPrompt", "type": "PlaySource"}, + "interrupt_call_media_operation": {"key": "interruptCallMediaOperation", "type": "bool"}, + "recognize_options": {"key": "recognizeOptions", "type": "RecognizeOptions"}, + "operation_context": {"key": "operationContext", "type": "str"}, + } + + def __init__( + self, + *, + recognize_input_type: Union[str, "_models.RecognizeInputType"], + recognize_options: "_models.RecognizeOptions", + play_prompt: Optional["_models.PlaySource"] = None, + interrupt_call_media_operation: Optional[bool] = None, + operation_context: Optional[str] = None, + **kwargs: Any + ) -> None: + """ + :keyword recognize_input_type: Determines the type of the recognition. Required. Known values + are: "dtmf" and "choices". + :paramtype recognize_input_type: str or + ~azure.communication.callautomation.models.RecognizeInputType + :keyword play_prompt: The source of the audio to be played for recognition. + :paramtype play_prompt: ~azure.communication.callautomation.models.PlaySource + :keyword interrupt_call_media_operation: If set recognize can barge into other existing + queued-up/currently-processing requests. + :paramtype interrupt_call_media_operation: bool + :keyword recognize_options: Defines options for recognition. Required. + :paramtype recognize_options: ~azure.communication.callautomation.models.RecognizeOptions + :keyword operation_context: The value to identify context of the operation. + :paramtype operation_context: str + """ + super().__init__(**kwargs) + self.recognize_input_type = recognize_input_type + self.play_prompt = play_prompt + self.interrupt_call_media_operation = interrupt_call_media_operation + self.recognize_options = recognize_options + self.operation_context = operation_context + + +class RecordingStateChanged(_serialization.Model): + """RecordingStateChanged. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar call_connection_id: Call connection ID. + :vartype call_connection_id: str + :ivar server_call_id: Server call ID. + :vartype server_call_id: str + :ivar correlation_id: Correlation ID for event to call correlation. Also called ChainId for + skype chain ID. + :vartype correlation_id: str + :ivar recording_id: The call recording id. + :vartype recording_id: str + :ivar state: Known values are: "active" and "inactive". + :vartype state: str or ~azure.communication.callautomation.models.RecordingState + :ivar start_date_time: The time of the recording started. + :vartype start_date_time: ~datetime.datetime + """ + + _validation = { + "recording_id": {"readonly": True}, + "start_date_time": {"readonly": True}, + } + + _attribute_map = { + "call_connection_id": {"key": "callConnectionId", "type": "str"}, + "server_call_id": {"key": "serverCallId", "type": "str"}, + "correlation_id": {"key": "correlationId", "type": "str"}, + "recording_id": {"key": "recordingId", "type": "str"}, + "state": {"key": "state", "type": "str"}, + "start_date_time": {"key": "startDateTime", "type": "iso-8601"}, + } + + def __init__( + self, + *, + call_connection_id: Optional[str] = None, + server_call_id: Optional[str] = None, + correlation_id: Optional[str] = None, + state: Optional[Union[str, "_models.RecordingState"]] = None, + **kwargs: Any + ) -> None: + """ + :keyword call_connection_id: Call connection ID. + :paramtype call_connection_id: str + :keyword server_call_id: Server call ID. + :paramtype server_call_id: str + :keyword correlation_id: Correlation ID for event to call correlation. Also called ChainId for + skype chain ID. + :paramtype correlation_id: str + :keyword state: Known values are: "active" and "inactive". + :paramtype state: str or ~azure.communication.callautomation.models.RecordingState + """ + super().__init__(**kwargs) + self.call_connection_id = call_connection_id + self.server_call_id = server_call_id + self.correlation_id = correlation_id + self.recording_id = None + self.state = state + self.start_date_time = None + + +class RecordingStateResponse(_serialization.Model): + """RecordingStateResponse. + + :ivar recording_id: + :vartype recording_id: str + :ivar recording_state: Known values are: "active" and "inactive". + :vartype recording_state: str or ~azure.communication.callautomation.models.RecordingState + """ + + _attribute_map = { + "recording_id": {"key": "recordingId", "type": "str"}, + "recording_state": {"key": "recordingState", "type": "str"}, + } + + def __init__( + self, + *, + recording_id: Optional[str] = None, + recording_state: Optional[Union[str, "_models.RecordingState"]] = None, + **kwargs: Any + ) -> None: + """ + :keyword recording_id: + :paramtype recording_id: str + :keyword recording_state: Known values are: "active" and "inactive". + :paramtype recording_state: str or ~azure.communication.callautomation.models.RecordingState + """ + super().__init__(**kwargs) + self.recording_id = recording_id + self.recording_state = recording_state + + +class RedirectCallRequest(_serialization.Model): + """The request payload for redirecting the call. + + All required parameters must be populated in order to send to Azure. + + :ivar incoming_call_context: The context associated with the call. Required. + :vartype incoming_call_context: str + :ivar target: The target identity to redirect the call to. Required. + :vartype target: ~azure.communication.callautomation.models.CommunicationIdentifierModel + """ + + _validation = { + "incoming_call_context": {"required": True}, + "target": {"required": True}, + } + + _attribute_map = { + "incoming_call_context": {"key": "incomingCallContext", "type": "str"}, + "target": {"key": "target", "type": "CommunicationIdentifierModel"}, + } + + def __init__( + self, *, incoming_call_context: str, target: "_models.CommunicationIdentifierModel", **kwargs: Any + ) -> None: + """ + :keyword incoming_call_context: The context associated with the call. Required. + :paramtype incoming_call_context: str + :keyword target: The target identity to redirect the call to. Required. + :paramtype target: ~azure.communication.callautomation.models.CommunicationIdentifierModel + """ + super().__init__(**kwargs) + self.incoming_call_context = incoming_call_context + self.target = target + + +class RejectCallRequest(_serialization.Model): + """The request payload for rejecting the call. + + All required parameters must be populated in order to send to Azure. + + :ivar incoming_call_context: The context associated with the call. Required. + :vartype incoming_call_context: str + :ivar call_reject_reason: The rejection reason. Known values are: "none", "busy", and + "forbidden". + :vartype call_reject_reason: str or ~azure.communication.callautomation.models.CallRejectReason + """ + + _validation = { + "incoming_call_context": {"required": True}, + } + + _attribute_map = { + "incoming_call_context": {"key": "incomingCallContext", "type": "str"}, + "call_reject_reason": {"key": "callRejectReason", "type": "str"}, + } + + def __init__( + self, + *, + incoming_call_context: str, + call_reject_reason: Optional[Union[str, "_models.CallRejectReason"]] = None, + **kwargs: Any + ) -> None: + """ + :keyword incoming_call_context: The context associated with the call. Required. + :paramtype incoming_call_context: str + :keyword call_reject_reason: The rejection reason. Known values are: "none", "busy", and + "forbidden". + :paramtype call_reject_reason: str or + ~azure.communication.callautomation.models.CallRejectReason + """ + super().__init__(**kwargs) + self.incoming_call_context = incoming_call_context + self.call_reject_reason = call_reject_reason + + +class RemoveParticipantRequest(_serialization.Model): + """The remove participant by identifier request. + + All required parameters must be populated in order to send to Azure. + + :ivar participant_to_remove: The participants to be removed from the call. Required. + :vartype participant_to_remove: + ~azure.communication.callautomation.models.CommunicationIdentifierModel + :ivar operation_context: Used by customers when calling mid-call actions to correlate the + request to the response event. + :vartype operation_context: str + """ + + _validation = { + "participant_to_remove": {"required": True}, + } + + _attribute_map = { + "participant_to_remove": {"key": "participantToRemove", "type": "CommunicationIdentifierModel"}, + "operation_context": {"key": "operationContext", "type": "str"}, + } + + def __init__( + self, + *, + participant_to_remove: "_models.CommunicationIdentifierModel", + operation_context: Optional[str] = None, + **kwargs: Any + ) -> None: + """ + :keyword participant_to_remove: The participants to be removed from the call. Required. + :paramtype participant_to_remove: + ~azure.communication.callautomation.models.CommunicationIdentifierModel + :keyword operation_context: Used by customers when calling mid-call actions to correlate the + request to the response event. + :paramtype operation_context: str + """ + super().__init__(**kwargs) + self.participant_to_remove = participant_to_remove + self.operation_context = operation_context + + +class RemoveParticipantResponse(_serialization.Model): + """The response payload for removing participants of the call. + + :ivar operation_context: The operation context provided by client. + :vartype operation_context: str + """ + + _attribute_map = { + "operation_context": {"key": "operationContext", "type": "str"}, + } + + def __init__(self, *, operation_context: Optional[str] = None, **kwargs: Any) -> None: + """ + :keyword operation_context: The operation context provided by client. + :paramtype operation_context: str + """ + super().__init__(**kwargs) + self.operation_context = operation_context + + +class ResultInformation(_serialization.Model): + """ResultInformation. + + :ivar code: + :vartype code: int + :ivar sub_code: + :vartype sub_code: int + :ivar message: + :vartype message: str + """ + + _attribute_map = { + "code": {"key": "code", "type": "int"}, + "sub_code": {"key": "subCode", "type": "int"}, + "message": {"key": "message", "type": "str"}, + } + + def __init__( + self, + *, + code: Optional[int] = None, + sub_code: Optional[int] = None, + message: Optional[str] = None, + **kwargs: Any + ) -> None: + """ + :keyword code: + :paramtype code: int + :keyword sub_code: + :paramtype sub_code: int + :keyword message: + :paramtype message: str + """ + super().__init__(**kwargs) + self.code = code + self.sub_code = sub_code + self.message = message + + +class StartCallRecordingRequest(_serialization.Model): + """The request payload start for call recording operation with call locator. + + All required parameters must be populated in order to send to Azure. + + :ivar call_locator: The call locator. Required. + :vartype call_locator: ~azure.communication.callautomation.models.CallLocator + :ivar recording_state_callback_uri: The uri to send notifications to. + :vartype recording_state_callback_uri: str + :ivar recording_content_type: The content type of call recording. Known values are: "audio" and + "audioVideo". + :vartype recording_content_type: str or + ~azure.communication.callautomation.models.RecordingContentType + :ivar recording_channel_type: The channel type of call recording. Known values are: "mixed" and + "unmixed". + :vartype recording_channel_type: str or + ~azure.communication.callautomation.models.RecordingChannelType + :ivar recording_format_type: The format type of call recording. Known values are: "wav", "mp3", + and "mp4". + :vartype recording_format_type: str or + ~azure.communication.callautomation.models.RecordingFormatType + :ivar audio_channel_participant_ordering: The sequential order in which audio channels are + assigned to participants in the unmixed recording. + When 'recordingChannelType' is set to 'unmixed' and `audioChannelParticipantOrdering is not + specified, + the audio channel to participant mapping will be automatically assigned based on the order in + which participant + first audio was detected. Channel to participant mapping details can be found in the metadata + of the recording. + :vartype audio_channel_participant_ordering: + list[~azure.communication.callautomation.models.CommunicationIdentifierModel] + :ivar recording_storage_type: Recording storage mode. When set to 'BlobStorage', specify + required parameter 'ExternalStorageLocation', to export recording to your own blob container. + Known values are: "acs" and "blobStorage". + :vartype recording_storage_type: str or + ~azure.communication.callautomation.models.RecordingStorageType + :ivar external_storage_location: The location where recording is stored, when + RecordingStorageType is set to 'BlobStorage'. + :vartype external_storage_location: str + """ + + _validation = { + "call_locator": {"required": True}, + } + + _attribute_map = { + "call_locator": {"key": "callLocator", "type": "CallLocator"}, + "recording_state_callback_uri": {"key": "recordingStateCallbackUri", "type": "str"}, + "recording_content_type": {"key": "recordingContentType", "type": "str"}, + "recording_channel_type": {"key": "recordingChannelType", "type": "str"}, + "recording_format_type": {"key": "recordingFormatType", "type": "str"}, + "audio_channel_participant_ordering": { + "key": "audioChannelParticipantOrdering", + "type": "[CommunicationIdentifierModel]", + }, + "recording_storage_type": {"key": "recordingStorageType", "type": "str"}, + "external_storage_location": {"key": "externalStorageLocation", "type": "str"}, + } + + def __init__( + self, + *, + call_locator: "_models.CallLocator", + recording_state_callback_uri: Optional[str] = None, + recording_content_type: Optional[Union[str, "_models.RecordingContentType"]] = None, + recording_channel_type: Optional[Union[str, "_models.RecordingChannelType"]] = None, + recording_format_type: Optional[Union[str, "_models.RecordingFormatType"]] = None, + audio_channel_participant_ordering: Optional[List["_models.CommunicationIdentifierModel"]] = None, + recording_storage_type: Optional[Union[str, "_models.RecordingStorageType"]] = None, + external_storage_location: Optional[str] = None, + **kwargs: Any + ) -> None: + """ + :keyword call_locator: The call locator. Required. + :paramtype call_locator: ~azure.communication.callautomation.models.CallLocator + :keyword recording_state_callback_uri: The uri to send notifications to. + :paramtype recording_state_callback_uri: str + :keyword recording_content_type: The content type of call recording. Known values are: "audio" + and "audioVideo". + :paramtype recording_content_type: str or + ~azure.communication.callautomation.models.RecordingContentType + :keyword recording_channel_type: The channel type of call recording. Known values are: "mixed" + and "unmixed". + :paramtype recording_channel_type: str or + ~azure.communication.callautomation.models.RecordingChannelType + :keyword recording_format_type: The format type of call recording. Known values are: "wav", + "mp3", and "mp4". + :paramtype recording_format_type: str or + ~azure.communication.callautomation.models.RecordingFormatType + :keyword audio_channel_participant_ordering: The sequential order in which audio channels are + assigned to participants in the unmixed recording. + When 'recordingChannelType' is set to 'unmixed' and `audioChannelParticipantOrdering is not + specified, + the audio channel to participant mapping will be automatically assigned based on the order in + which participant + first audio was detected. Channel to participant mapping details can be found in the metadata + of the recording. + :paramtype audio_channel_participant_ordering: + list[~azure.communication.callautomation.models.CommunicationIdentifierModel] + :keyword recording_storage_type: Recording storage mode. When set to 'BlobStorage', specify + required parameter 'ExternalStorageLocation', to export recording to your own blob container. + Known values are: "acs" and "blobStorage". + :paramtype recording_storage_type: str or + ~azure.communication.callautomation.models.RecordingStorageType + :keyword external_storage_location: The location where recording is stored, when + RecordingStorageType is set to 'BlobStorage'. + :paramtype external_storage_location: str + """ + super().__init__(**kwargs) + self.call_locator = call_locator + self.recording_state_callback_uri = recording_state_callback_uri + self.recording_content_type = recording_content_type + self.recording_channel_type = recording_channel_type + self.recording_format_type = recording_format_type + self.audio_channel_participant_ordering = audio_channel_participant_ordering + self.recording_storage_type = recording_storage_type + self.external_storage_location = external_storage_location + + +class TextSource(_serialization.Model): + """TextSource. + + All required parameters must be populated in order to send to Azure. + + :ivar text: Text for the cognitive service to be played. Required. + :vartype text: str + :ivar source_locale: Source language locale to be played + Refer to available locales here: :code:``. + :vartype source_locale: str + :ivar voice_gender: Voice gender type. Known values are: "male" and "female". + :vartype voice_gender: str or ~azure.communication.callautomation.models.Gender + :ivar voice_name: Voice name to be played + Refer to available Text-to-speech voices here: :code:``. + :vartype voice_name: str + """ + + _validation = { + "text": {"required": True}, + } + + _attribute_map = { + "text": {"key": "text", "type": "str"}, + "source_locale": {"key": "sourceLocale", "type": "str"}, + "voice_gender": {"key": "voiceGender", "type": "str"}, + "voice_name": {"key": "voiceName", "type": "str"}, + } + + def __init__( + self, + *, + text: str, + source_locale: Optional[str] = None, + voice_gender: Optional[Union[str, "_models.Gender"]] = None, + voice_name: Optional[str] = None, + **kwargs: Any + ) -> None: + """ + :keyword text: Text for the cognitive service to be played. Required. + :paramtype text: str + :keyword source_locale: Source language locale to be played + Refer to available locales here: :code:``. + :paramtype source_locale: str + :keyword voice_gender: Voice gender type. Known values are: "male" and "female". + :paramtype voice_gender: str or ~azure.communication.callautomation.models.Gender + :keyword voice_name: Voice name to be played + Refer to available Text-to-speech voices here: :code:``. + :paramtype voice_name: str + """ + super().__init__(**kwargs) + self.text = text + self.source_locale = source_locale + self.voice_gender = voice_gender + self.voice_name = voice_name + + +class TransferCallResponse(_serialization.Model): + """The response payload for transferring the call. + + :ivar operation_context: The operation context provided by client. + :vartype operation_context: str + """ + + _attribute_map = { + "operation_context": {"key": "operationContext", "type": "str"}, + } + + def __init__(self, *, operation_context: Optional[str] = None, **kwargs: Any) -> None: + """ + :keyword operation_context: The operation context provided by client. + :paramtype operation_context: str + """ + super().__init__(**kwargs) + self.operation_context = operation_context + + +class TransferToParticipantRequest(_serialization.Model): + """The request payload for transferring call to a participant. + + All required parameters must be populated in order to send to Azure. + + :ivar target_participant: The identity of the target where call should be transferred to. + Required. + :vartype target_participant: + ~azure.communication.callautomation.models.CommunicationIdentifierModel + :ivar transferee_caller_id: The caller ID of the transferee when transferring to PSTN. + :vartype transferee_caller_id: + ~azure.communication.callautomation.models.PhoneNumberIdentifierModel + :ivar custom_context: Used by customer to send custom context to targets. + :vartype custom_context: ~azure.communication.callautomation.models.CustomContext + :ivar operation_context: Used by customers when calling mid-call actions to correlate the + request to the response event. + :vartype operation_context: str + """ + + _validation = { + "target_participant": {"required": True}, + } + + _attribute_map = { + "target_participant": {"key": "targetParticipant", "type": "CommunicationIdentifierModel"}, + "transferee_caller_id": {"key": "transfereeCallerId", "type": "PhoneNumberIdentifierModel"}, + "custom_context": {"key": "customContext", "type": "CustomContext"}, + "operation_context": {"key": "operationContext", "type": "str"}, + } + + def __init__( + self, + *, + target_participant: "_models.CommunicationIdentifierModel", + transferee_caller_id: Optional["_models.PhoneNumberIdentifierModel"] = None, + custom_context: Optional["_models.CustomContext"] = None, + operation_context: Optional[str] = None, + **kwargs: Any + ) -> None: + """ + :keyword target_participant: The identity of the target where call should be transferred to. + Required. + :paramtype target_participant: + ~azure.communication.callautomation.models.CommunicationIdentifierModel + :keyword transferee_caller_id: The caller ID of the transferee when transferring to PSTN. + :paramtype transferee_caller_id: + ~azure.communication.callautomation.models.PhoneNumberIdentifierModel + :keyword custom_context: Used by customer to send custom context to targets. + :paramtype custom_context: ~azure.communication.callautomation.models.CustomContext + :keyword operation_context: Used by customers when calling mid-call actions to correlate the + request to the response event. + :paramtype operation_context: str + """ + super().__init__(**kwargs) + self.target_participant = target_participant + self.transferee_caller_id = transferee_caller_id + self.custom_context = custom_context + self.operation_context = operation_context + + +class UnmuteParticipantsRequest(_serialization.Model): + """The request payload for unmuting participant from the call. + + All required parameters must be populated in order to send to Azure. + + :ivar target_participants: Participants to be unmuted from the call. + Only ACS Users are supported. Required. + :vartype target_participants: + list[~azure.communication.callautomation.models.CommunicationIdentifierModel] + :ivar operation_context: Used by customers when calling mid-call actions to correlate the + request to the response event. + :vartype operation_context: str + """ + + _validation = { + "target_participants": {"required": True}, + } + + _attribute_map = { + "target_participants": {"key": "targetParticipants", "type": "[CommunicationIdentifierModel]"}, + "operation_context": {"key": "operationContext", "type": "str"}, + } + + def __init__( + self, + *, + target_participants: List["_models.CommunicationIdentifierModel"], + operation_context: Optional[str] = None, + **kwargs: Any + ) -> None: + """ + :keyword target_participants: Participants to be unmuted from the call. + Only ACS Users are supported. Required. + :paramtype target_participants: + list[~azure.communication.callautomation.models.CommunicationIdentifierModel] + :keyword operation_context: Used by customers when calling mid-call actions to correlate the + request to the response event. + :paramtype operation_context: str + """ + super().__init__(**kwargs) + self.target_participants = target_participants + self.operation_context = operation_context + + +class UnmuteParticipantsResponse(_serialization.Model): + """The response payload for unmuting participants from the call. + + :ivar operation_context: The operation context provided by client. + :vartype operation_context: str + """ + + _attribute_map = { + "operation_context": {"key": "operationContext", "type": "str"}, + } + + def __init__(self, *, operation_context: Optional[str] = None, **kwargs: Any) -> None: + """ + :keyword operation_context: The operation context provided by client. + :paramtype operation_context: str + """ + super().__init__(**kwargs) + self.operation_context = operation_context diff --git a/sdk/keyvault/azure-keyvault-administration/azure/keyvault/administration/_generated/v7_4_preview_1/models/_patch.py b/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_generated/models/_patch.py similarity index 100% rename from sdk/keyvault/azure-keyvault-administration/azure/keyvault/administration/_generated/v7_4_preview_1/models/_patch.py rename to sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_generated/models/_patch.py diff --git a/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_generated/operations/__init__.py b/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_generated/operations/__init__.py new file mode 100644 index 000000000000..5a21927092cc --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_generated/operations/__init__.py @@ -0,0 +1,25 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from ._operations import AzureCommunicationCallAutomationServiceOperationsMixin +from ._operations import CallConnectionOperations +from ._operations import CallMediaOperations +from ._operations import CallRecordingOperations + +from ._patch import __all__ as _patch_all +from ._patch import * # pylint: disable=unused-wildcard-import +from ._patch import patch_sdk as _patch_sdk + +__all__ = [ + "AzureCommunicationCallAutomationServiceOperationsMixin", + "CallConnectionOperations", + "CallMediaOperations", + "CallRecordingOperations", +] +__all__.extend([p for p in _patch_all if p not in __all__]) +_patch_sdk() diff --git a/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_generated/operations/_operations.py b/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_generated/operations/_operations.py new file mode 100644 index 000000000000..628f5e2e8fcf --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_generated/operations/_operations.py @@ -0,0 +1,3274 @@ +# pylint: disable=too-many-lines +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +import sys +from typing import Any, Callable, Dict, IO, Optional, TypeVar, Union, overload + +from azure.core.exceptions import ( + ClientAuthenticationError, + HttpResponseError, + ResourceExistsError, + ResourceNotFoundError, + ResourceNotModifiedError, + map_error, +) +from azure.core.pipeline import PipelineResponse +from azure.core.pipeline.transport import HttpResponse +from azure.core.rest import HttpRequest +from azure.core.tracing.decorator import distributed_trace +from azure.core.utils import case_insensitive_dict + +from .. import models as _models +from .._serialization import Serializer +from .._vendor import AzureCommunicationCallAutomationServiceMixinABC, _format_url_section + +if sys.version_info >= (3, 8): + from typing import Literal # pylint: disable=no-name-in-module, ungrouped-imports +else: + from typing_extensions import Literal # type: ignore # pylint: disable=ungrouped-imports +T = TypeVar("T") +ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] + +_SERIALIZER = Serializer() +_SERIALIZER.client_side_validation = False + + +def build_azure_communication_call_automation_service_create_call_request( + *, repeatability_request_id: Optional[str] = None, repeatability_first_sent: Optional[str] = None, **kwargs: Any +) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + api_version: Literal["2023-01-15-preview"] = kwargs.pop( + "api_version", _params.pop("api-version", "2023-01-15-preview") + ) + accept = _headers.pop("Accept", "application/json") + + # Construct URL + _url = "/calling/callConnections" + + # Construct parameters + _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") + + # Construct headers + if repeatability_request_id is not None: + _headers["Repeatability-Request-ID"] = _SERIALIZER.header( + "repeatability_request_id", repeatability_request_id, "str" + ) + if repeatability_first_sent is not None: + _headers["Repeatability-First-Sent"] = _SERIALIZER.header( + "repeatability_first_sent", repeatability_first_sent, "str" + ) + if content_type is not None: + _headers["Content-Type"] = _SERIALIZER.header("content_type", content_type, "str") + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="POST", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_azure_communication_call_automation_service_answer_call_request( + *, repeatability_request_id: Optional[str] = None, repeatability_first_sent: Optional[str] = None, **kwargs: Any +) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + api_version: Literal["2023-01-15-preview"] = kwargs.pop( + "api_version", _params.pop("api-version", "2023-01-15-preview") + ) + accept = _headers.pop("Accept", "application/json") + + # Construct URL + _url = "/calling/callConnections:answer" + + # Construct parameters + _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") + + # Construct headers + if repeatability_request_id is not None: + _headers["Repeatability-Request-ID"] = _SERIALIZER.header( + "repeatability_request_id", repeatability_request_id, "str" + ) + if repeatability_first_sent is not None: + _headers["Repeatability-First-Sent"] = _SERIALIZER.header( + "repeatability_first_sent", repeatability_first_sent, "str" + ) + if content_type is not None: + _headers["Content-Type"] = _SERIALIZER.header("content_type", content_type, "str") + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="POST", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_azure_communication_call_automation_service_redirect_call_request( + *, repeatability_request_id: Optional[str] = None, repeatability_first_sent: Optional[str] = None, **kwargs: Any +) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + api_version: Literal["2023-01-15-preview"] = kwargs.pop( + "api_version", _params.pop("api-version", "2023-01-15-preview") + ) + accept = _headers.pop("Accept", "application/json") + + # Construct URL + _url = "/calling/callConnections:redirect" + + # Construct parameters + _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") + + # Construct headers + if repeatability_request_id is not None: + _headers["Repeatability-Request-ID"] = _SERIALIZER.header( + "repeatability_request_id", repeatability_request_id, "str" + ) + if repeatability_first_sent is not None: + _headers["Repeatability-First-Sent"] = _SERIALIZER.header( + "repeatability_first_sent", repeatability_first_sent, "str" + ) + if content_type is not None: + _headers["Content-Type"] = _SERIALIZER.header("content_type", content_type, "str") + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="POST", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_azure_communication_call_automation_service_reject_call_request( + *, repeatability_request_id: Optional[str] = None, repeatability_first_sent: Optional[str] = None, **kwargs: Any +) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + api_version: Literal["2023-01-15-preview"] = kwargs.pop( + "api_version", _params.pop("api-version", "2023-01-15-preview") + ) + accept = _headers.pop("Accept", "application/json") + + # Construct URL + _url = "/calling/callConnections:reject" + + # Construct parameters + _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") + + # Construct headers + if repeatability_request_id is not None: + _headers["Repeatability-Request-ID"] = _SERIALIZER.header( + "repeatability_request_id", repeatability_request_id, "str" + ) + if repeatability_first_sent is not None: + _headers["Repeatability-First-Sent"] = _SERIALIZER.header( + "repeatability_first_sent", repeatability_first_sent, "str" + ) + if content_type is not None: + _headers["Content-Type"] = _SERIALIZER.header("content_type", content_type, "str") + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="POST", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_call_connection_get_call_request(call_connection_id: str, **kwargs: Any) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + api_version: Literal["2023-01-15-preview"] = kwargs.pop( + "api_version", _params.pop("api-version", "2023-01-15-preview") + ) + accept = _headers.pop("Accept", "application/json") + + # Construct URL + _url = "/calling/callConnections/{callConnectionId}" + path_format_arguments = { + "callConnectionId": _SERIALIZER.url("call_connection_id", call_connection_id, "str"), + } + + _url: str = _format_url_section(_url, **path_format_arguments) # type: ignore + + # Construct parameters + _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") + + # Construct headers + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_call_connection_hangup_call_request(call_connection_id: str, **kwargs: Any) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + api_version: Literal["2023-01-15-preview"] = kwargs.pop( + "api_version", _params.pop("api-version", "2023-01-15-preview") + ) + accept = _headers.pop("Accept", "application/json") + + # Construct URL + _url = "/calling/callConnections/{callConnectionId}" + path_format_arguments = { + "callConnectionId": _SERIALIZER.url("call_connection_id", call_connection_id, "str"), + } + + _url: str = _format_url_section(_url, **path_format_arguments) # type: ignore + + # Construct parameters + _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") + + # Construct headers + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="DELETE", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_call_connection_terminate_call_request( + call_connection_id: str, + *, + repeatability_request_id: Optional[str] = None, + repeatability_first_sent: Optional[str] = None, + **kwargs: Any +) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + api_version: Literal["2023-01-15-preview"] = kwargs.pop( + "api_version", _params.pop("api-version", "2023-01-15-preview") + ) + accept = _headers.pop("Accept", "application/json") + + # Construct URL + _url = "/calling/callConnections/{callConnectionId}:terminate" + path_format_arguments = { + "callConnectionId": _SERIALIZER.url("call_connection_id", call_connection_id, "str"), + } + + _url: str = _format_url_section(_url, **path_format_arguments) # type: ignore + + # Construct parameters + _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") + + # Construct headers + if repeatability_request_id is not None: + _headers["Repeatability-Request-ID"] = _SERIALIZER.header( + "repeatability_request_id", repeatability_request_id, "str" + ) + if repeatability_first_sent is not None: + _headers["Repeatability-First-Sent"] = _SERIALIZER.header( + "repeatability_first_sent", repeatability_first_sent, "str" + ) + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="POST", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_call_connection_transfer_to_participant_request( + call_connection_id: str, + *, + repeatability_request_id: Optional[str] = None, + repeatability_first_sent: Optional[str] = None, + **kwargs: Any +) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + api_version: Literal["2023-01-15-preview"] = kwargs.pop( + "api_version", _params.pop("api-version", "2023-01-15-preview") + ) + accept = _headers.pop("Accept", "application/json") + + # Construct URL + _url = "/calling/callConnections/{callConnectionId}:transferToParticipant" + path_format_arguments = { + "callConnectionId": _SERIALIZER.url("call_connection_id", call_connection_id, "str"), + } + + _url: str = _format_url_section(_url, **path_format_arguments) # type: ignore + + # Construct parameters + _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") + + # Construct headers + if repeatability_request_id is not None: + _headers["Repeatability-Request-ID"] = _SERIALIZER.header( + "repeatability_request_id", repeatability_request_id, "str" + ) + if repeatability_first_sent is not None: + _headers["Repeatability-First-Sent"] = _SERIALIZER.header( + "repeatability_first_sent", repeatability_first_sent, "str" + ) + if content_type is not None: + _headers["Content-Type"] = _SERIALIZER.header("content_type", content_type, "str") + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="POST", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_call_connection_get_participants_request(call_connection_id: str, **kwargs: Any) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + api_version: Literal["2023-01-15-preview"] = kwargs.pop( + "api_version", _params.pop("api-version", "2023-01-15-preview") + ) + accept = _headers.pop("Accept", "application/json") + + # Construct URL + _url = "/calling/callConnections/{callConnectionId}/participants" + path_format_arguments = { + "callConnectionId": _SERIALIZER.url("call_connection_id", call_connection_id, "str"), + } + + _url: str = _format_url_section(_url, **path_format_arguments) # type: ignore + + # Construct parameters + _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") + + # Construct headers + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_call_connection_add_participant_request( + call_connection_id: str, + *, + repeatability_request_id: Optional[str] = None, + repeatability_first_sent: Optional[str] = None, + **kwargs: Any +) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + api_version: Literal["2023-01-15-preview"] = kwargs.pop( + "api_version", _params.pop("api-version", "2023-01-15-preview") + ) + accept = _headers.pop("Accept", "application/json") + + # Construct URL + _url = "/calling/callConnections/{callConnectionId}/participants:add" + path_format_arguments = { + "callConnectionId": _SERIALIZER.url("call_connection_id", call_connection_id, "str"), + } + + _url: str = _format_url_section(_url, **path_format_arguments) # type: ignore + + # Construct parameters + _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") + + # Construct headers + if repeatability_request_id is not None: + _headers["Repeatability-Request-ID"] = _SERIALIZER.header( + "repeatability_request_id", repeatability_request_id, "str" + ) + if repeatability_first_sent is not None: + _headers["Repeatability-First-Sent"] = _SERIALIZER.header( + "repeatability_first_sent", repeatability_first_sent, "str" + ) + if content_type is not None: + _headers["Content-Type"] = _SERIALIZER.header("content_type", content_type, "str") + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="POST", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_call_connection_remove_participant_request( + call_connection_id: str, + *, + repeatability_request_id: Optional[str] = None, + repeatability_first_sent: Optional[str] = None, + **kwargs: Any +) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + api_version: Literal["2023-01-15-preview"] = kwargs.pop( + "api_version", _params.pop("api-version", "2023-01-15-preview") + ) + accept = _headers.pop("Accept", "application/json") + + # Construct URL + _url = "/calling/callConnections/{callConnectionId}/participants:remove" + path_format_arguments = { + "callConnectionId": _SERIALIZER.url("call_connection_id", call_connection_id, "str"), + } + + _url: str = _format_url_section(_url, **path_format_arguments) # type: ignore + + # Construct parameters + _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") + + # Construct headers + if repeatability_request_id is not None: + _headers["Repeatability-Request-ID"] = _SERIALIZER.header( + "repeatability_request_id", repeatability_request_id, "str" + ) + if repeatability_first_sent is not None: + _headers["Repeatability-First-Sent"] = _SERIALIZER.header( + "repeatability_first_sent", repeatability_first_sent, "str" + ) + if content_type is not None: + _headers["Content-Type"] = _SERIALIZER.header("content_type", content_type, "str") + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="POST", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_call_connection_mute_request( + call_connection_id: str, + *, + repeatability_request_id: Optional[str] = None, + repeatability_first_sent: Optional[str] = None, + **kwargs: Any +) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + api_version: Literal["2023-01-15-preview"] = kwargs.pop( + "api_version", _params.pop("api-version", "2023-01-15-preview") + ) + accept = _headers.pop("Accept", "application/json") + + # Construct URL + _url = "/calling/callConnections/{callConnectionId}/participants:mute" + path_format_arguments = { + "callConnectionId": _SERIALIZER.url("call_connection_id", call_connection_id, "str"), + } + + _url: str = _format_url_section(_url, **path_format_arguments) # type: ignore + + # Construct parameters + _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") + + # Construct headers + if repeatability_request_id is not None: + _headers["Repeatability-Request-ID"] = _SERIALIZER.header( + "repeatability_request_id", repeatability_request_id, "str" + ) + if repeatability_first_sent is not None: + _headers["Repeatability-First-Sent"] = _SERIALIZER.header( + "repeatability_first_sent", repeatability_first_sent, "str" + ) + if content_type is not None: + _headers["Content-Type"] = _SERIALIZER.header("content_type", content_type, "str") + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="POST", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_call_connection_unmute_request( + call_connection_id: str, + *, + repeatability_request_id: Optional[str] = None, + repeatability_first_sent: Optional[str] = None, + **kwargs: Any +) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + api_version: Literal["2023-01-15-preview"] = kwargs.pop( + "api_version", _params.pop("api-version", "2023-01-15-preview") + ) + accept = _headers.pop("Accept", "application/json") + + # Construct URL + _url = "/calling/callConnections/{callConnectionId}/participants:unmute" + path_format_arguments = { + "callConnectionId": _SERIALIZER.url("call_connection_id", call_connection_id, "str"), + } + + _url: str = _format_url_section(_url, **path_format_arguments) # type: ignore + + # Construct parameters + _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") + + # Construct headers + if repeatability_request_id is not None: + _headers["Repeatability-Request-ID"] = _SERIALIZER.header( + "repeatability_request_id", repeatability_request_id, "str" + ) + if repeatability_first_sent is not None: + _headers["Repeatability-First-Sent"] = _SERIALIZER.header( + "repeatability_first_sent", repeatability_first_sent, "str" + ) + if content_type is not None: + _headers["Content-Type"] = _SERIALIZER.header("content_type", content_type, "str") + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="POST", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_call_connection_get_participant_request( + call_connection_id: str, participant_raw_id: str, **kwargs: Any +) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + api_version: Literal["2023-01-15-preview"] = kwargs.pop( + "api_version", _params.pop("api-version", "2023-01-15-preview") + ) + accept = _headers.pop("Accept", "application/json") + + # Construct URL + _url = "/calling/callConnections/{callConnectionId}/participants/{participantRawId}" + path_format_arguments = { + "callConnectionId": _SERIALIZER.url("call_connection_id", call_connection_id, "str"), + "participantRawId": _SERIALIZER.url("participant_raw_id", participant_raw_id, "str"), + } + + _url: str = _format_url_section(_url, **path_format_arguments) # type: ignore + + # Construct parameters + _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") + + # Construct headers + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_call_media_play_request(call_connection_id: str, **kwargs: Any) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + api_version: Literal["2023-01-15-preview"] = kwargs.pop( + "api_version", _params.pop("api-version", "2023-01-15-preview") + ) + accept = _headers.pop("Accept", "application/json") + + # Construct URL + _url = "/calling/callConnections/{callConnectionId}:play" + path_format_arguments = { + "callConnectionId": _SERIALIZER.url("call_connection_id", call_connection_id, "str"), + } + + _url: str = _format_url_section(_url, **path_format_arguments) # type: ignore + + # Construct parameters + _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") + + # Construct headers + if content_type is not None: + _headers["Content-Type"] = _SERIALIZER.header("content_type", content_type, "str") + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="POST", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_call_media_cancel_all_media_operations_request(call_connection_id: str, **kwargs: Any) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + api_version: Literal["2023-01-15-preview"] = kwargs.pop( + "api_version", _params.pop("api-version", "2023-01-15-preview") + ) + accept = _headers.pop("Accept", "application/json") + + # Construct URL + _url = "/calling/callConnections/{callConnectionId}:cancelAllMediaOperations" + path_format_arguments = { + "callConnectionId": _SERIALIZER.url("call_connection_id", call_connection_id, "str"), + } + + _url: str = _format_url_section(_url, **path_format_arguments) # type: ignore + + # Construct parameters + _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") + + # Construct headers + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="POST", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_call_media_recognize_request(call_connection_id: str, **kwargs: Any) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + api_version: Literal["2023-01-15-preview"] = kwargs.pop( + "api_version", _params.pop("api-version", "2023-01-15-preview") + ) + accept = _headers.pop("Accept", "application/json") + + # Construct URL + _url = "/calling/callConnections/{callConnectionId}:recognize" + path_format_arguments = { + "callConnectionId": _SERIALIZER.url("call_connection_id", call_connection_id, "str"), + } + + _url: str = _format_url_section(_url, **path_format_arguments) # type: ignore + + # Construct parameters + _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") + + # Construct headers + if content_type is not None: + _headers["Content-Type"] = _SERIALIZER.header("content_type", content_type, "str") + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="POST", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_call_recording_start_recording_request( + *, repeatability_request_id: Optional[str] = None, repeatability_first_sent: Optional[str] = None, **kwargs: Any +) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + api_version: Literal["2023-01-15-preview"] = kwargs.pop( + "api_version", _params.pop("api-version", "2023-01-15-preview") + ) + accept = _headers.pop("Accept", "application/json") + + # Construct URL + _url = "/calling/recordings" + + # Construct parameters + _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") + + # Construct headers + if repeatability_request_id is not None: + _headers["Repeatability-Request-ID"] = _SERIALIZER.header( + "repeatability_request_id", repeatability_request_id, "str" + ) + if repeatability_first_sent is not None: + _headers["Repeatability-First-Sent"] = _SERIALIZER.header( + "repeatability_first_sent", repeatability_first_sent, "str" + ) + if content_type is not None: + _headers["Content-Type"] = _SERIALIZER.header("content_type", content_type, "str") + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="POST", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_call_recording_get_recording_properties_request(recording_id: str, **kwargs: Any) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + api_version: Literal["2023-01-15-preview"] = kwargs.pop( + "api_version", _params.pop("api-version", "2023-01-15-preview") + ) + accept = _headers.pop("Accept", "application/json") + + # Construct URL + _url = "/calling/recordings/{recordingId}" + path_format_arguments = { + "recordingId": _SERIALIZER.url("recording_id", recording_id, "str"), + } + + _url: str = _format_url_section(_url, **path_format_arguments) # type: ignore + + # Construct parameters + _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") + + # Construct headers + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_call_recording_stop_recording_request(recording_id: str, **kwargs: Any) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + api_version: Literal["2023-01-15-preview"] = kwargs.pop( + "api_version", _params.pop("api-version", "2023-01-15-preview") + ) + accept = _headers.pop("Accept", "application/json") + + # Construct URL + _url = "/calling/recordings/{recordingId}" + path_format_arguments = { + "recordingId": _SERIALIZER.url("recording_id", recording_id, "str"), + } + + _url: str = _format_url_section(_url, **path_format_arguments) # type: ignore + + # Construct parameters + _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") + + # Construct headers + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="DELETE", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_call_recording_pause_recording_request(recording_id: str, **kwargs: Any) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + api_version: Literal["2023-01-15-preview"] = kwargs.pop( + "api_version", _params.pop("api-version", "2023-01-15-preview") + ) + accept = _headers.pop("Accept", "application/json") + + # Construct URL + _url = "/calling/recordings/{recordingId}:pause" + path_format_arguments = { + "recordingId": _SERIALIZER.url("recording_id", recording_id, "str"), + } + + _url: str = _format_url_section(_url, **path_format_arguments) # type: ignore + + # Construct parameters + _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") + + # Construct headers + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="POST", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_call_recording_resume_recording_request(recording_id: str, **kwargs: Any) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + api_version: Literal["2023-01-15-preview"] = kwargs.pop( + "api_version", _params.pop("api-version", "2023-01-15-preview") + ) + accept = _headers.pop("Accept", "application/json") + + # Construct URL + _url = "/calling/recordings/{recordingId}:resume" + path_format_arguments = { + "recordingId": _SERIALIZER.url("recording_id", recording_id, "str"), + } + + _url: str = _format_url_section(_url, **path_format_arguments) # type: ignore + + # Construct parameters + _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") + + # Construct headers + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="POST", url=_url, params=_params, headers=_headers, **kwargs) + + +class AzureCommunicationCallAutomationServiceOperationsMixin(AzureCommunicationCallAutomationServiceMixinABC): + @overload + def create_call( + self, + create_call_request: _models.CreateCallRequest, + *, + repeatability_request_id: Optional[str] = None, + repeatability_first_sent: Optional[str] = None, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.CallConnectionProperties: + """Create an outbound call. + + Create an outbound call. + + :param create_call_request: The create call request. Required. + :type create_call_request: ~azure.communication.callautomation.models.CreateCallRequest + :keyword repeatability_request_id: If specified, the client directs that the request is + repeatable; that is, that the client can make the request multiple times with the same + Repeatability-Request-Id and get back an appropriate response without the server executing the + request multiple times. The value of the Repeatability-Request-Id is an opaque string + representing a client-generated unique identifier for the request. It is a version 4 (random) + UUID. Default value is None. + :paramtype repeatability_request_id: str + :keyword repeatability_first_sent: If Repeatability-Request-ID header is specified, then + Repeatability-First-Sent header must also be specified. The value should be the date and time + at which the request was first created, expressed using the IMF-fixdate form of HTTP-date. + Example: Sun, 06 Nov 1994 08:49:37 GMT. Default value is None. + :paramtype repeatability_first_sent: str + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: CallConnectionProperties + :rtype: ~azure.communication.callautomation.models.CallConnectionProperties + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + def create_call( + self, + create_call_request: IO, + *, + repeatability_request_id: Optional[str] = None, + repeatability_first_sent: Optional[str] = None, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.CallConnectionProperties: + """Create an outbound call. + + Create an outbound call. + + :param create_call_request: The create call request. Required. + :type create_call_request: IO + :keyword repeatability_request_id: If specified, the client directs that the request is + repeatable; that is, that the client can make the request multiple times with the same + Repeatability-Request-Id and get back an appropriate response without the server executing the + request multiple times. The value of the Repeatability-Request-Id is an opaque string + representing a client-generated unique identifier for the request. It is a version 4 (random) + UUID. Default value is None. + :paramtype repeatability_request_id: str + :keyword repeatability_first_sent: If Repeatability-Request-ID header is specified, then + Repeatability-First-Sent header must also be specified. The value should be the date and time + at which the request was first created, expressed using the IMF-fixdate form of HTTP-date. + Example: Sun, 06 Nov 1994 08:49:37 GMT. Default value is None. + :paramtype repeatability_first_sent: str + :keyword content_type: Body Parameter content-type. Content type parameter for binary body. + Default value is "application/json". + :paramtype content_type: str + :return: CallConnectionProperties + :rtype: ~azure.communication.callautomation.models.CallConnectionProperties + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @distributed_trace + def create_call( + self, + create_call_request: Union[_models.CreateCallRequest, IO], + *, + repeatability_request_id: Optional[str] = None, + repeatability_first_sent: Optional[str] = None, + **kwargs: Any + ) -> _models.CallConnectionProperties: + """Create an outbound call. + + Create an outbound call. + + :param create_call_request: The create call request. Is either a CreateCallRequest type or a IO + type. Required. + :type create_call_request: ~azure.communication.callautomation.models.CreateCallRequest or IO + :keyword repeatability_request_id: If specified, the client directs that the request is + repeatable; that is, that the client can make the request multiple times with the same + Repeatability-Request-Id and get back an appropriate response without the server executing the + request multiple times. The value of the Repeatability-Request-Id is an opaque string + representing a client-generated unique identifier for the request. It is a version 4 (random) + UUID. Default value is None. + :paramtype repeatability_request_id: str + :keyword repeatability_first_sent: If Repeatability-Request-ID header is specified, then + Repeatability-First-Sent header must also be specified. The value should be the date and time + at which the request was first created, expressed using the IMF-fixdate form of HTTP-date. + Example: Sun, 06 Nov 1994 08:49:37 GMT. Default value is None. + :paramtype repeatability_first_sent: str + :keyword content_type: Body Parameter content-type. Known values are: 'application/json'. + Default value is None. + :paramtype content_type: str + :return: CallConnectionProperties + :rtype: ~azure.communication.callautomation.models.CallConnectionProperties + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = kwargs.pop("params", {}) or {} + + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[_models.CallConnectionProperties] = kwargs.pop("cls", None) + + content_type = content_type or "application/json" + _json = None + _content = None + if isinstance(create_call_request, (IO, bytes)): + _content = create_call_request + else: + _json = self._serialize.body(create_call_request, "CreateCallRequest") + + request = build_azure_communication_call_automation_service_create_call_request( + repeatability_request_id=repeatability_request_id, + repeatability_first_sent=repeatability_first_sent, + content_type=content_type, + api_version=self._config.api_version, + json=_json, + content=_content, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + request.url = self._client.format_url(request.url, **path_format_arguments) + + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + request, stream=False, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [201]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.CommunicationErrorResponse, pipeline_response) + raise HttpResponseError(response=response, model=error) + + deserialized = self._deserialize("CallConnectionProperties", pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + + @overload + def answer_call( + self, + answer_call_request: _models.AnswerCallRequest, + *, + repeatability_request_id: Optional[str] = None, + repeatability_first_sent: Optional[str] = None, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.CallConnectionProperties: + """Answer a Call. + + Answer a call using the IncomingCallContext from Event Grid. + + :param answer_call_request: The answer call request. Required. + :type answer_call_request: ~azure.communication.callautomation.models.AnswerCallRequest + :keyword repeatability_request_id: If specified, the client directs that the request is + repeatable; that is, that the client can make the request multiple times with the same + Repeatability-Request-Id and get back an appropriate response without the server executing the + request multiple times. The value of the Repeatability-Request-Id is an opaque string + representing a client-generated unique identifier for the request. It is a version 4 (random) + UUID. Default value is None. + :paramtype repeatability_request_id: str + :keyword repeatability_first_sent: If Repeatability-Request-ID header is specified, then + Repeatability-First-Sent header must also be specified. The value should be the date and time + at which the request was first created, expressed using the IMF-fixdate form of HTTP-date. + Example: Sun, 06 Nov 1994 08:49:37 GMT. Default value is None. + :paramtype repeatability_first_sent: str + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: CallConnectionProperties + :rtype: ~azure.communication.callautomation.models.CallConnectionProperties + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + def answer_call( + self, + answer_call_request: IO, + *, + repeatability_request_id: Optional[str] = None, + repeatability_first_sent: Optional[str] = None, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.CallConnectionProperties: + """Answer a Call. + + Answer a call using the IncomingCallContext from Event Grid. + + :param answer_call_request: The answer call request. Required. + :type answer_call_request: IO + :keyword repeatability_request_id: If specified, the client directs that the request is + repeatable; that is, that the client can make the request multiple times with the same + Repeatability-Request-Id and get back an appropriate response without the server executing the + request multiple times. The value of the Repeatability-Request-Id is an opaque string + representing a client-generated unique identifier for the request. It is a version 4 (random) + UUID. Default value is None. + :paramtype repeatability_request_id: str + :keyword repeatability_first_sent: If Repeatability-Request-ID header is specified, then + Repeatability-First-Sent header must also be specified. The value should be the date and time + at which the request was first created, expressed using the IMF-fixdate form of HTTP-date. + Example: Sun, 06 Nov 1994 08:49:37 GMT. Default value is None. + :paramtype repeatability_first_sent: str + :keyword content_type: Body Parameter content-type. Content type parameter for binary body. + Default value is "application/json". + :paramtype content_type: str + :return: CallConnectionProperties + :rtype: ~azure.communication.callautomation.models.CallConnectionProperties + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @distributed_trace + def answer_call( + self, + answer_call_request: Union[_models.AnswerCallRequest, IO], + *, + repeatability_request_id: Optional[str] = None, + repeatability_first_sent: Optional[str] = None, + **kwargs: Any + ) -> _models.CallConnectionProperties: + """Answer a Call. + + Answer a call using the IncomingCallContext from Event Grid. + + :param answer_call_request: The answer call request. Is either a AnswerCallRequest type or a IO + type. Required. + :type answer_call_request: ~azure.communication.callautomation.models.AnswerCallRequest or IO + :keyword repeatability_request_id: If specified, the client directs that the request is + repeatable; that is, that the client can make the request multiple times with the same + Repeatability-Request-Id and get back an appropriate response without the server executing the + request multiple times. The value of the Repeatability-Request-Id is an opaque string + representing a client-generated unique identifier for the request. It is a version 4 (random) + UUID. Default value is None. + :paramtype repeatability_request_id: str + :keyword repeatability_first_sent: If Repeatability-Request-ID header is specified, then + Repeatability-First-Sent header must also be specified. The value should be the date and time + at which the request was first created, expressed using the IMF-fixdate form of HTTP-date. + Example: Sun, 06 Nov 1994 08:49:37 GMT. Default value is None. + :paramtype repeatability_first_sent: str + :keyword content_type: Body Parameter content-type. Known values are: 'application/json'. + Default value is None. + :paramtype content_type: str + :return: CallConnectionProperties + :rtype: ~azure.communication.callautomation.models.CallConnectionProperties + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = kwargs.pop("params", {}) or {} + + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[_models.CallConnectionProperties] = kwargs.pop("cls", None) + + content_type = content_type or "application/json" + _json = None + _content = None + if isinstance(answer_call_request, (IO, bytes)): + _content = answer_call_request + else: + _json = self._serialize.body(answer_call_request, "AnswerCallRequest") + + request = build_azure_communication_call_automation_service_answer_call_request( + repeatability_request_id=repeatability_request_id, + repeatability_first_sent=repeatability_first_sent, + content_type=content_type, + api_version=self._config.api_version, + json=_json, + content=_content, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + request.url = self._client.format_url(request.url, **path_format_arguments) + + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + request, stream=False, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.CommunicationErrorResponse, pipeline_response) + raise HttpResponseError(response=response, model=error) + + deserialized = self._deserialize("CallConnectionProperties", pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + + @overload + def redirect_call( # pylint: disable=inconsistent-return-statements + self, + redirect_call_request: _models.RedirectCallRequest, + *, + repeatability_request_id: Optional[str] = None, + repeatability_first_sent: Optional[str] = None, + content_type: str = "application/json", + **kwargs: Any + ) -> None: + """Redirect a call. + + Redirect a call. + + :param redirect_call_request: The redirect call request. Required. + :type redirect_call_request: ~azure.communication.callautomation.models.RedirectCallRequest + :keyword repeatability_request_id: If specified, the client directs that the request is + repeatable; that is, that the client can make the request multiple times with the same + Repeatability-Request-Id and get back an appropriate response without the server executing the + request multiple times. The value of the Repeatability-Request-Id is an opaque string + representing a client-generated unique identifier for the request. It is a version 4 (random) + UUID. Default value is None. + :paramtype repeatability_request_id: str + :keyword repeatability_first_sent: If Repeatability-Request-ID header is specified, then + Repeatability-First-Sent header must also be specified. The value should be the date and time + at which the request was first created, expressed using the IMF-fixdate form of HTTP-date. + Example: Sun, 06 Nov 1994 08:49:37 GMT. Default value is None. + :paramtype repeatability_first_sent: str + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: None + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + def redirect_call( # pylint: disable=inconsistent-return-statements + self, + redirect_call_request: IO, + *, + repeatability_request_id: Optional[str] = None, + repeatability_first_sent: Optional[str] = None, + content_type: str = "application/json", + **kwargs: Any + ) -> None: + """Redirect a call. + + Redirect a call. + + :param redirect_call_request: The redirect call request. Required. + :type redirect_call_request: IO + :keyword repeatability_request_id: If specified, the client directs that the request is + repeatable; that is, that the client can make the request multiple times with the same + Repeatability-Request-Id and get back an appropriate response without the server executing the + request multiple times. The value of the Repeatability-Request-Id is an opaque string + representing a client-generated unique identifier for the request. It is a version 4 (random) + UUID. Default value is None. + :paramtype repeatability_request_id: str + :keyword repeatability_first_sent: If Repeatability-Request-ID header is specified, then + Repeatability-First-Sent header must also be specified. The value should be the date and time + at which the request was first created, expressed using the IMF-fixdate form of HTTP-date. + Example: Sun, 06 Nov 1994 08:49:37 GMT. Default value is None. + :paramtype repeatability_first_sent: str + :keyword content_type: Body Parameter content-type. Content type parameter for binary body. + Default value is "application/json". + :paramtype content_type: str + :return: None + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @distributed_trace + def redirect_call( # pylint: disable=inconsistent-return-statements + self, + redirect_call_request: Union[_models.RedirectCallRequest, IO], + *, + repeatability_request_id: Optional[str] = None, + repeatability_first_sent: Optional[str] = None, + **kwargs: Any + ) -> None: + """Redirect a call. + + Redirect a call. + + :param redirect_call_request: The redirect call request. Is either a RedirectCallRequest type + or a IO type. Required. + :type redirect_call_request: ~azure.communication.callautomation.models.RedirectCallRequest or + IO + :keyword repeatability_request_id: If specified, the client directs that the request is + repeatable; that is, that the client can make the request multiple times with the same + Repeatability-Request-Id and get back an appropriate response without the server executing the + request multiple times. The value of the Repeatability-Request-Id is an opaque string + representing a client-generated unique identifier for the request. It is a version 4 (random) + UUID. Default value is None. + :paramtype repeatability_request_id: str + :keyword repeatability_first_sent: If Repeatability-Request-ID header is specified, then + Repeatability-First-Sent header must also be specified. The value should be the date and time + at which the request was first created, expressed using the IMF-fixdate form of HTTP-date. + Example: Sun, 06 Nov 1994 08:49:37 GMT. Default value is None. + :paramtype repeatability_first_sent: str + :keyword content_type: Body Parameter content-type. Known values are: 'application/json'. + Default value is None. + :paramtype content_type: str + :return: None + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = kwargs.pop("params", {}) or {} + + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[None] = kwargs.pop("cls", None) + + content_type = content_type or "application/json" + _json = None + _content = None + if isinstance(redirect_call_request, (IO, bytes)): + _content = redirect_call_request + else: + _json = self._serialize.body(redirect_call_request, "RedirectCallRequest") + + request = build_azure_communication_call_automation_service_redirect_call_request( + repeatability_request_id=repeatability_request_id, + repeatability_first_sent=repeatability_first_sent, + content_type=content_type, + api_version=self._config.api_version, + json=_json, + content=_content, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + request.url = self._client.format_url(request.url, **path_format_arguments) + + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + request, stream=False, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [204]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.CommunicationErrorResponse, pipeline_response) + raise HttpResponseError(response=response, model=error) + + if cls: + return cls(pipeline_response, None, {}) + + @overload + def reject_call( # pylint: disable=inconsistent-return-statements + self, + reject_call_request: _models.RejectCallRequest, + *, + repeatability_request_id: Optional[str] = None, + repeatability_first_sent: Optional[str] = None, + content_type: str = "application/json", + **kwargs: Any + ) -> None: + """Reject the call. + + Reject the call. + + :param reject_call_request: The reject call request. Required. + :type reject_call_request: ~azure.communication.callautomation.models.RejectCallRequest + :keyword repeatability_request_id: If specified, the client directs that the request is + repeatable; that is, that the client can make the request multiple times with the same + Repeatability-Request-Id and get back an appropriate response without the server executing the + request multiple times. The value of the Repeatability-Request-Id is an opaque string + representing a client-generated unique identifier for the request. It is a version 4 (random) + UUID. Default value is None. + :paramtype repeatability_request_id: str + :keyword repeatability_first_sent: If Repeatability-Request-ID header is specified, then + Repeatability-First-Sent header must also be specified. The value should be the date and time + at which the request was first created, expressed using the IMF-fixdate form of HTTP-date. + Example: Sun, 06 Nov 1994 08:49:37 GMT. Default value is None. + :paramtype repeatability_first_sent: str + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: None + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + def reject_call( # pylint: disable=inconsistent-return-statements + self, + reject_call_request: IO, + *, + repeatability_request_id: Optional[str] = None, + repeatability_first_sent: Optional[str] = None, + content_type: str = "application/json", + **kwargs: Any + ) -> None: + """Reject the call. + + Reject the call. + + :param reject_call_request: The reject call request. Required. + :type reject_call_request: IO + :keyword repeatability_request_id: If specified, the client directs that the request is + repeatable; that is, that the client can make the request multiple times with the same + Repeatability-Request-Id and get back an appropriate response without the server executing the + request multiple times. The value of the Repeatability-Request-Id is an opaque string + representing a client-generated unique identifier for the request. It is a version 4 (random) + UUID. Default value is None. + :paramtype repeatability_request_id: str + :keyword repeatability_first_sent: If Repeatability-Request-ID header is specified, then + Repeatability-First-Sent header must also be specified. The value should be the date and time + at which the request was first created, expressed using the IMF-fixdate form of HTTP-date. + Example: Sun, 06 Nov 1994 08:49:37 GMT. Default value is None. + :paramtype repeatability_first_sent: str + :keyword content_type: Body Parameter content-type. Content type parameter for binary body. + Default value is "application/json". + :paramtype content_type: str + :return: None + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @distributed_trace + def reject_call( # pylint: disable=inconsistent-return-statements + self, + reject_call_request: Union[_models.RejectCallRequest, IO], + *, + repeatability_request_id: Optional[str] = None, + repeatability_first_sent: Optional[str] = None, + **kwargs: Any + ) -> None: + """Reject the call. + + Reject the call. + + :param reject_call_request: The reject call request. Is either a RejectCallRequest type or a IO + type. Required. + :type reject_call_request: ~azure.communication.callautomation.models.RejectCallRequest or IO + :keyword repeatability_request_id: If specified, the client directs that the request is + repeatable; that is, that the client can make the request multiple times with the same + Repeatability-Request-Id and get back an appropriate response without the server executing the + request multiple times. The value of the Repeatability-Request-Id is an opaque string + representing a client-generated unique identifier for the request. It is a version 4 (random) + UUID. Default value is None. + :paramtype repeatability_request_id: str + :keyword repeatability_first_sent: If Repeatability-Request-ID header is specified, then + Repeatability-First-Sent header must also be specified. The value should be the date and time + at which the request was first created, expressed using the IMF-fixdate form of HTTP-date. + Example: Sun, 06 Nov 1994 08:49:37 GMT. Default value is None. + :paramtype repeatability_first_sent: str + :keyword content_type: Body Parameter content-type. Known values are: 'application/json'. + Default value is None. + :paramtype content_type: str + :return: None + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = kwargs.pop("params", {}) or {} + + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[None] = kwargs.pop("cls", None) + + content_type = content_type or "application/json" + _json = None + _content = None + if isinstance(reject_call_request, (IO, bytes)): + _content = reject_call_request + else: + _json = self._serialize.body(reject_call_request, "RejectCallRequest") + + request = build_azure_communication_call_automation_service_reject_call_request( + repeatability_request_id=repeatability_request_id, + repeatability_first_sent=repeatability_first_sent, + content_type=content_type, + api_version=self._config.api_version, + json=_json, + content=_content, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + request.url = self._client.format_url(request.url, **path_format_arguments) + + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + request, stream=False, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [204]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.CommunicationErrorResponse, pipeline_response) + raise HttpResponseError(response=response, model=error) + + if cls: + return cls(pipeline_response, None, {}) + + +class CallConnectionOperations: + """ + .. warning:: + **DO NOT** instantiate this class directly. + + Instead, you should access the following operations through + :class:`~azure.communication.callautomation.AzureCommunicationCallAutomationService`'s + :attr:`call_connection` attribute. + """ + + models = _models + + def __init__(self, *args, **kwargs): + input_args = list(args) + self._client = input_args.pop(0) if input_args else kwargs.pop("client") + self._config = input_args.pop(0) if input_args else kwargs.pop("config") + self._serialize = input_args.pop(0) if input_args else kwargs.pop("serializer") + self._deserialize = input_args.pop(0) if input_args else kwargs.pop("deserializer") + + @distributed_trace + def get_call(self, call_connection_id: str, **kwargs: Any) -> _models.CallConnectionProperties: + """Get call connection. + + Get call connection. + + :param call_connection_id: The call connection id. Required. + :type call_connection_id: str + :return: CallConnectionProperties + :rtype: ~azure.communication.callautomation.models.CallConnectionProperties + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[_models.CallConnectionProperties] = kwargs.pop("cls", None) + + request = build_call_connection_get_call_request( + call_connection_id=call_connection_id, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + request.url = self._client.format_url(request.url, **path_format_arguments) + + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + request, stream=False, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.CommunicationErrorResponse, pipeline_response) + raise HttpResponseError(response=response, model=error) + + deserialized = self._deserialize("CallConnectionProperties", pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + + @distributed_trace + def hangup_call( # pylint: disable=inconsistent-return-statements + self, call_connection_id: str, **kwargs: Any + ) -> None: + """Hangup the call. + + Hangup the call. + + :param call_connection_id: The call connection id. Required. + :type call_connection_id: str + :return: None + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[None] = kwargs.pop("cls", None) + + request = build_call_connection_hangup_call_request( + call_connection_id=call_connection_id, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + request.url = self._client.format_url(request.url, **path_format_arguments) + + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + request, stream=False, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [204]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.CommunicationErrorResponse, pipeline_response) + raise HttpResponseError(response=response, model=error) + + if cls: + return cls(pipeline_response, None, {}) + + @distributed_trace + def terminate_call( # pylint: disable=inconsistent-return-statements + self, + call_connection_id: str, + *, + repeatability_request_id: Optional[str] = None, + repeatability_first_sent: Optional[str] = None, + **kwargs: Any + ) -> None: + """Terminate a call using CallConnectionId. + + Terminate a call using CallConnectionId. + + :param call_connection_id: The terminate call request. Required. + :type call_connection_id: str + :keyword repeatability_request_id: If specified, the client directs that the request is + repeatable; that is, that the client can make the request multiple times with the same + Repeatability-Request-Id and get back an appropriate response without the server executing the + request multiple times. The value of the Repeatability-Request-Id is an opaque string + representing a client-generated unique identifier for the request. It is a version 4 (random) + UUID. Default value is None. + :paramtype repeatability_request_id: str + :keyword repeatability_first_sent: If Repeatability-Request-ID header is specified, then + Repeatability-First-Sent header must also be specified. The value should be the date and time + at which the request was first created, expressed using the IMF-fixdate form of HTTP-date. + Example: Sun, 06 Nov 1994 08:49:37 GMT. Default value is None. + :paramtype repeatability_first_sent: str + :return: None + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[None] = kwargs.pop("cls", None) + + request = build_call_connection_terminate_call_request( + call_connection_id=call_connection_id, + repeatability_request_id=repeatability_request_id, + repeatability_first_sent=repeatability_first_sent, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + request.url = self._client.format_url(request.url, **path_format_arguments) + + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + request, stream=False, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [204]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.CommunicationErrorResponse, pipeline_response) + raise HttpResponseError(response=response, model=error) + + if cls: + return cls(pipeline_response, None, {}) + + @overload + def transfer_to_participant( + self, + call_connection_id: str, + transfer_to_participant_request: _models.TransferToParticipantRequest, + *, + repeatability_request_id: Optional[str] = None, + repeatability_first_sent: Optional[str] = None, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.TransferCallResponse: + """Transfer the call to a participant. + + Transfer the call to a participant. + + :param call_connection_id: The call connection id. Required. + :type call_connection_id: str + :param transfer_to_participant_request: The transfer to participant request. Required. + :type transfer_to_participant_request: + ~azure.communication.callautomation.models.TransferToParticipantRequest + :keyword repeatability_request_id: If specified, the client directs that the request is + repeatable; that is, that the client can make the request multiple times with the same + Repeatability-Request-Id and get back an appropriate response without the server executing the + request multiple times. The value of the Repeatability-Request-Id is an opaque string + representing a client-generated unique identifier for the request. It is a version 4 (random) + UUID. Default value is None. + :paramtype repeatability_request_id: str + :keyword repeatability_first_sent: If Repeatability-Request-ID header is specified, then + Repeatability-First-Sent header must also be specified. The value should be the date and time + at which the request was first created, expressed using the IMF-fixdate form of HTTP-date. + Example: Sun, 06 Nov 1994 08:49:37 GMT. Default value is None. + :paramtype repeatability_first_sent: str + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: TransferCallResponse + :rtype: ~azure.communication.callautomation.models.TransferCallResponse + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + def transfer_to_participant( + self, + call_connection_id: str, + transfer_to_participant_request: IO, + *, + repeatability_request_id: Optional[str] = None, + repeatability_first_sent: Optional[str] = None, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.TransferCallResponse: + """Transfer the call to a participant. + + Transfer the call to a participant. + + :param call_connection_id: The call connection id. Required. + :type call_connection_id: str + :param transfer_to_participant_request: The transfer to participant request. Required. + :type transfer_to_participant_request: IO + :keyword repeatability_request_id: If specified, the client directs that the request is + repeatable; that is, that the client can make the request multiple times with the same + Repeatability-Request-Id and get back an appropriate response without the server executing the + request multiple times. The value of the Repeatability-Request-Id is an opaque string + representing a client-generated unique identifier for the request. It is a version 4 (random) + UUID. Default value is None. + :paramtype repeatability_request_id: str + :keyword repeatability_first_sent: If Repeatability-Request-ID header is specified, then + Repeatability-First-Sent header must also be specified. The value should be the date and time + at which the request was first created, expressed using the IMF-fixdate form of HTTP-date. + Example: Sun, 06 Nov 1994 08:49:37 GMT. Default value is None. + :paramtype repeatability_first_sent: str + :keyword content_type: Body Parameter content-type. Content type parameter for binary body. + Default value is "application/json". + :paramtype content_type: str + :return: TransferCallResponse + :rtype: ~azure.communication.callautomation.models.TransferCallResponse + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @distributed_trace + def transfer_to_participant( + self, + call_connection_id: str, + transfer_to_participant_request: Union[_models.TransferToParticipantRequest, IO], + *, + repeatability_request_id: Optional[str] = None, + repeatability_first_sent: Optional[str] = None, + **kwargs: Any + ) -> _models.TransferCallResponse: + """Transfer the call to a participant. + + Transfer the call to a participant. + + :param call_connection_id: The call connection id. Required. + :type call_connection_id: str + :param transfer_to_participant_request: The transfer to participant request. Is either a + TransferToParticipantRequest type or a IO type. Required. + :type transfer_to_participant_request: + ~azure.communication.callautomation.models.TransferToParticipantRequest or IO + :keyword repeatability_request_id: If specified, the client directs that the request is + repeatable; that is, that the client can make the request multiple times with the same + Repeatability-Request-Id and get back an appropriate response without the server executing the + request multiple times. The value of the Repeatability-Request-Id is an opaque string + representing a client-generated unique identifier for the request. It is a version 4 (random) + UUID. Default value is None. + :paramtype repeatability_request_id: str + :keyword repeatability_first_sent: If Repeatability-Request-ID header is specified, then + Repeatability-First-Sent header must also be specified. The value should be the date and time + at which the request was first created, expressed using the IMF-fixdate form of HTTP-date. + Example: Sun, 06 Nov 1994 08:49:37 GMT. Default value is None. + :paramtype repeatability_first_sent: str + :keyword content_type: Body Parameter content-type. Known values are: 'application/json'. + Default value is None. + :paramtype content_type: str + :return: TransferCallResponse + :rtype: ~azure.communication.callautomation.models.TransferCallResponse + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = kwargs.pop("params", {}) or {} + + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[_models.TransferCallResponse] = kwargs.pop("cls", None) + + content_type = content_type or "application/json" + _json = None + _content = None + if isinstance(transfer_to_participant_request, (IO, bytes)): + _content = transfer_to_participant_request + else: + _json = self._serialize.body(transfer_to_participant_request, "TransferToParticipantRequest") + + request = build_call_connection_transfer_to_participant_request( + call_connection_id=call_connection_id, + repeatability_request_id=repeatability_request_id, + repeatability_first_sent=repeatability_first_sent, + content_type=content_type, + api_version=self._config.api_version, + json=_json, + content=_content, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + request.url = self._client.format_url(request.url, **path_format_arguments) + + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + request, stream=False, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [202]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.CommunicationErrorResponse, pipeline_response) + raise HttpResponseError(response=response, model=error) + + deserialized = self._deserialize("TransferCallResponse", pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + + @distributed_trace + def get_participants(self, call_connection_id: str, **kwargs: Any) -> _models.GetParticipantsResponse: + """Get participants from a call. + + Get participants from a call. + + :param call_connection_id: The call connection Id. Required. + :type call_connection_id: str + :return: GetParticipantsResponse + :rtype: ~azure.communication.callautomation.models.GetParticipantsResponse + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[_models.GetParticipantsResponse] = kwargs.pop("cls", None) + + request = build_call_connection_get_participants_request( + call_connection_id=call_connection_id, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + request.url = self._client.format_url(request.url, **path_format_arguments) + + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + request, stream=False, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.CommunicationErrorResponse, pipeline_response) + raise HttpResponseError(response=response, model=error) + + deserialized = self._deserialize("GetParticipantsResponse", pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + + @overload + def add_participant( + self, + call_connection_id: str, + add_participant_request: _models.AddParticipantRequest, + *, + repeatability_request_id: Optional[str] = None, + repeatability_first_sent: Optional[str] = None, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.AddParticipantResponse: + """Add participants to the call. + + Add participants to the call. + + :param call_connection_id: The call connection Id. Required. + :type call_connection_id: str + :param add_participant_request: Required. + :type add_participant_request: ~azure.communication.callautomation.models.AddParticipantRequest + :keyword repeatability_request_id: If specified, the client directs that the request is + repeatable; that is, that the client can make the request multiple times with the same + Repeatability-Request-Id and get back an appropriate response without the server executing the + request multiple times. The value of the Repeatability-Request-Id is an opaque string + representing a client-generated unique identifier for the request. It is a version 4 (random) + UUID. Default value is None. + :paramtype repeatability_request_id: str + :keyword repeatability_first_sent: If Repeatability-Request-ID header is specified, then + Repeatability-First-Sent header must also be specified. The value should be the date and time + at which the request was first created, expressed using the IMF-fixdate form of HTTP-date. + Example: Sun, 06 Nov 1994 08:49:37 GMT. Default value is None. + :paramtype repeatability_first_sent: str + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: AddParticipantResponse + :rtype: ~azure.communication.callautomation.models.AddParticipantResponse + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + def add_participant( + self, + call_connection_id: str, + add_participant_request: IO, + *, + repeatability_request_id: Optional[str] = None, + repeatability_first_sent: Optional[str] = None, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.AddParticipantResponse: + """Add participants to the call. + + Add participants to the call. + + :param call_connection_id: The call connection Id. Required. + :type call_connection_id: str + :param add_participant_request: Required. + :type add_participant_request: IO + :keyword repeatability_request_id: If specified, the client directs that the request is + repeatable; that is, that the client can make the request multiple times with the same + Repeatability-Request-Id and get back an appropriate response without the server executing the + request multiple times. The value of the Repeatability-Request-Id is an opaque string + representing a client-generated unique identifier for the request. It is a version 4 (random) + UUID. Default value is None. + :paramtype repeatability_request_id: str + :keyword repeatability_first_sent: If Repeatability-Request-ID header is specified, then + Repeatability-First-Sent header must also be specified. The value should be the date and time + at which the request was first created, expressed using the IMF-fixdate form of HTTP-date. + Example: Sun, 06 Nov 1994 08:49:37 GMT. Default value is None. + :paramtype repeatability_first_sent: str + :keyword content_type: Body Parameter content-type. Content type parameter for binary body. + Default value is "application/json". + :paramtype content_type: str + :return: AddParticipantResponse + :rtype: ~azure.communication.callautomation.models.AddParticipantResponse + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @distributed_trace + def add_participant( + self, + call_connection_id: str, + add_participant_request: Union[_models.AddParticipantRequest, IO], + *, + repeatability_request_id: Optional[str] = None, + repeatability_first_sent: Optional[str] = None, + **kwargs: Any + ) -> _models.AddParticipantResponse: + """Add participants to the call. + + Add participants to the call. + + :param call_connection_id: The call connection Id. Required. + :type call_connection_id: str + :param add_participant_request: Is either a AddParticipantRequest type or a IO type. Required. + :type add_participant_request: ~azure.communication.callautomation.models.AddParticipantRequest + or IO + :keyword repeatability_request_id: If specified, the client directs that the request is + repeatable; that is, that the client can make the request multiple times with the same + Repeatability-Request-Id and get back an appropriate response without the server executing the + request multiple times. The value of the Repeatability-Request-Id is an opaque string + representing a client-generated unique identifier for the request. It is a version 4 (random) + UUID. Default value is None. + :paramtype repeatability_request_id: str + :keyword repeatability_first_sent: If Repeatability-Request-ID header is specified, then + Repeatability-First-Sent header must also be specified. The value should be the date and time + at which the request was first created, expressed using the IMF-fixdate form of HTTP-date. + Example: Sun, 06 Nov 1994 08:49:37 GMT. Default value is None. + :paramtype repeatability_first_sent: str + :keyword content_type: Body Parameter content-type. Known values are: 'application/json'. + Default value is None. + :paramtype content_type: str + :return: AddParticipantResponse + :rtype: ~azure.communication.callautomation.models.AddParticipantResponse + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = kwargs.pop("params", {}) or {} + + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[_models.AddParticipantResponse] = kwargs.pop("cls", None) + + content_type = content_type or "application/json" + _json = None + _content = None + if isinstance(add_participant_request, (IO, bytes)): + _content = add_participant_request + else: + _json = self._serialize.body(add_participant_request, "AddParticipantRequest") + + request = build_call_connection_add_participant_request( + call_connection_id=call_connection_id, + repeatability_request_id=repeatability_request_id, + repeatability_first_sent=repeatability_first_sent, + content_type=content_type, + api_version=self._config.api_version, + json=_json, + content=_content, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + request.url = self._client.format_url(request.url, **path_format_arguments) + + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + request, stream=False, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [202]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.CommunicationErrorResponse, pipeline_response) + raise HttpResponseError(response=response, model=error) + + deserialized = self._deserialize("AddParticipantResponse", pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + + @overload + def remove_participant( + self, + call_connection_id: str, + remove_participant_request: _models.RemoveParticipantRequest, + *, + repeatability_request_id: Optional[str] = None, + repeatability_first_sent: Optional[str] = None, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.RemoveParticipantResponse: + """Remove participant from the call using identifier. + + Remove participant from the call using identifier. + + :param call_connection_id: The call connection id. Required. + :type call_connection_id: str + :param remove_participant_request: The participant to be removed from the call. Required. + :type remove_participant_request: + ~azure.communication.callautomation.models.RemoveParticipantRequest + :keyword repeatability_request_id: If specified, the client directs that the request is + repeatable; that is, that the client can make the request multiple times with the same + Repeatability-Request-Id and get back an appropriate response without the server executing the + request multiple times. The value of the Repeatability-Request-Id is an opaque string + representing a client-generated unique identifier for the request. It is a version 4 (random) + UUID. Default value is None. + :paramtype repeatability_request_id: str + :keyword repeatability_first_sent: If Repeatability-Request-ID header is specified, then + Repeatability-First-Sent header must also be specified. The value should be the date and time + at which the request was first created, expressed using the IMF-fixdate form of HTTP-date. + Example: Sun, 06 Nov 1994 08:49:37 GMT. Default value is None. + :paramtype repeatability_first_sent: str + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: RemoveParticipantResponse + :rtype: ~azure.communication.callautomation.models.RemoveParticipantResponse + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + def remove_participant( + self, + call_connection_id: str, + remove_participant_request: IO, + *, + repeatability_request_id: Optional[str] = None, + repeatability_first_sent: Optional[str] = None, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.RemoveParticipantResponse: + """Remove participant from the call using identifier. + + Remove participant from the call using identifier. + + :param call_connection_id: The call connection id. Required. + :type call_connection_id: str + :param remove_participant_request: The participant to be removed from the call. Required. + :type remove_participant_request: IO + :keyword repeatability_request_id: If specified, the client directs that the request is + repeatable; that is, that the client can make the request multiple times with the same + Repeatability-Request-Id and get back an appropriate response without the server executing the + request multiple times. The value of the Repeatability-Request-Id is an opaque string + representing a client-generated unique identifier for the request. It is a version 4 (random) + UUID. Default value is None. + :paramtype repeatability_request_id: str + :keyword repeatability_first_sent: If Repeatability-Request-ID header is specified, then + Repeatability-First-Sent header must also be specified. The value should be the date and time + at which the request was first created, expressed using the IMF-fixdate form of HTTP-date. + Example: Sun, 06 Nov 1994 08:49:37 GMT. Default value is None. + :paramtype repeatability_first_sent: str + :keyword content_type: Body Parameter content-type. Content type parameter for binary body. + Default value is "application/json". + :paramtype content_type: str + :return: RemoveParticipantResponse + :rtype: ~azure.communication.callautomation.models.RemoveParticipantResponse + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @distributed_trace + def remove_participant( + self, + call_connection_id: str, + remove_participant_request: Union[_models.RemoveParticipantRequest, IO], + *, + repeatability_request_id: Optional[str] = None, + repeatability_first_sent: Optional[str] = None, + **kwargs: Any + ) -> _models.RemoveParticipantResponse: + """Remove participant from the call using identifier. + + Remove participant from the call using identifier. + + :param call_connection_id: The call connection id. Required. + :type call_connection_id: str + :param remove_participant_request: The participant to be removed from the call. Is either a + RemoveParticipantRequest type or a IO type. Required. + :type remove_participant_request: + ~azure.communication.callautomation.models.RemoveParticipantRequest or IO + :keyword repeatability_request_id: If specified, the client directs that the request is + repeatable; that is, that the client can make the request multiple times with the same + Repeatability-Request-Id and get back an appropriate response without the server executing the + request multiple times. The value of the Repeatability-Request-Id is an opaque string + representing a client-generated unique identifier for the request. It is a version 4 (random) + UUID. Default value is None. + :paramtype repeatability_request_id: str + :keyword repeatability_first_sent: If Repeatability-Request-ID header is specified, then + Repeatability-First-Sent header must also be specified. The value should be the date and time + at which the request was first created, expressed using the IMF-fixdate form of HTTP-date. + Example: Sun, 06 Nov 1994 08:49:37 GMT. Default value is None. + :paramtype repeatability_first_sent: str + :keyword content_type: Body Parameter content-type. Known values are: 'application/json'. + Default value is None. + :paramtype content_type: str + :return: RemoveParticipantResponse + :rtype: ~azure.communication.callautomation.models.RemoveParticipantResponse + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = kwargs.pop("params", {}) or {} + + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[_models.RemoveParticipantResponse] = kwargs.pop("cls", None) + + content_type = content_type or "application/json" + _json = None + _content = None + if isinstance(remove_participant_request, (IO, bytes)): + _content = remove_participant_request + else: + _json = self._serialize.body(remove_participant_request, "RemoveParticipantRequest") + + request = build_call_connection_remove_participant_request( + call_connection_id=call_connection_id, + repeatability_request_id=repeatability_request_id, + repeatability_first_sent=repeatability_first_sent, + content_type=content_type, + api_version=self._config.api_version, + json=_json, + content=_content, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + request.url = self._client.format_url(request.url, **path_format_arguments) + + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + request, stream=False, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [202]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.CommunicationErrorResponse, pipeline_response) + raise HttpResponseError(response=response, model=error) + + deserialized = self._deserialize("RemoveParticipantResponse", pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + + @overload + def mute( + self, + call_connection_id: str, + mute_participants_request: _models.MuteParticipantsRequest, + *, + repeatability_request_id: Optional[str] = None, + repeatability_first_sent: Optional[str] = None, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.MuteParticipantsResponse: + """Mute participants from the call using identifier. + + Mute participants from the call using identifier. + + :param call_connection_id: The call connection id. Required. + :type call_connection_id: str + :param mute_participants_request: The participants to be muted from the call. Required. + :type mute_participants_request: + ~azure.communication.callautomation.models.MuteParticipantsRequest + :keyword repeatability_request_id: If specified, the client directs that the request is + repeatable; that is, that the client can make the request multiple times with the same + Repeatability-Request-Id and get back an appropriate response without the server executing the + request multiple times. The value of the Repeatability-Request-Id is an opaque string + representing a client-generated unique identifier for the request. It is a version 4 (random) + UUID. Default value is None. + :paramtype repeatability_request_id: str + :keyword repeatability_first_sent: If Repeatability-Request-ID header is specified, then + Repeatability-First-Sent header must also be specified. The value should be the date and time + at which the request was first created, expressed using the IMF-fixdate form of HTTP-date. + Example: Sun, 06 Nov 1994 08:49:37 GMT. Default value is None. + :paramtype repeatability_first_sent: str + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: MuteParticipantsResponse + :rtype: ~azure.communication.callautomation.models.MuteParticipantsResponse + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + def mute( + self, + call_connection_id: str, + mute_participants_request: IO, + *, + repeatability_request_id: Optional[str] = None, + repeatability_first_sent: Optional[str] = None, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.MuteParticipantsResponse: + """Mute participants from the call using identifier. + + Mute participants from the call using identifier. + + :param call_connection_id: The call connection id. Required. + :type call_connection_id: str + :param mute_participants_request: The participants to be muted from the call. Required. + :type mute_participants_request: IO + :keyword repeatability_request_id: If specified, the client directs that the request is + repeatable; that is, that the client can make the request multiple times with the same + Repeatability-Request-Id and get back an appropriate response without the server executing the + request multiple times. The value of the Repeatability-Request-Id is an opaque string + representing a client-generated unique identifier for the request. It is a version 4 (random) + UUID. Default value is None. + :paramtype repeatability_request_id: str + :keyword repeatability_first_sent: If Repeatability-Request-ID header is specified, then + Repeatability-First-Sent header must also be specified. The value should be the date and time + at which the request was first created, expressed using the IMF-fixdate form of HTTP-date. + Example: Sun, 06 Nov 1994 08:49:37 GMT. Default value is None. + :paramtype repeatability_first_sent: str + :keyword content_type: Body Parameter content-type. Content type parameter for binary body. + Default value is "application/json". + :paramtype content_type: str + :return: MuteParticipantsResponse + :rtype: ~azure.communication.callautomation.models.MuteParticipantsResponse + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @distributed_trace + def mute( + self, + call_connection_id: str, + mute_participants_request: Union[_models.MuteParticipantsRequest, IO], + *, + repeatability_request_id: Optional[str] = None, + repeatability_first_sent: Optional[str] = None, + **kwargs: Any + ) -> _models.MuteParticipantsResponse: + """Mute participants from the call using identifier. + + Mute participants from the call using identifier. + + :param call_connection_id: The call connection id. Required. + :type call_connection_id: str + :param mute_participants_request: The participants to be muted from the call. Is either a + MuteParticipantsRequest type or a IO type. Required. + :type mute_participants_request: + ~azure.communication.callautomation.models.MuteParticipantsRequest or IO + :keyword repeatability_request_id: If specified, the client directs that the request is + repeatable; that is, that the client can make the request multiple times with the same + Repeatability-Request-Id and get back an appropriate response without the server executing the + request multiple times. The value of the Repeatability-Request-Id is an opaque string + representing a client-generated unique identifier for the request. It is a version 4 (random) + UUID. Default value is None. + :paramtype repeatability_request_id: str + :keyword repeatability_first_sent: If Repeatability-Request-ID header is specified, then + Repeatability-First-Sent header must also be specified. The value should be the date and time + at which the request was first created, expressed using the IMF-fixdate form of HTTP-date. + Example: Sun, 06 Nov 1994 08:49:37 GMT. Default value is None. + :paramtype repeatability_first_sent: str + :keyword content_type: Body Parameter content-type. Known values are: 'application/json'. + Default value is None. + :paramtype content_type: str + :return: MuteParticipantsResponse + :rtype: ~azure.communication.callautomation.models.MuteParticipantsResponse + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = kwargs.pop("params", {}) or {} + + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[_models.MuteParticipantsResponse] = kwargs.pop("cls", None) + + content_type = content_type or "application/json" + _json = None + _content = None + if isinstance(mute_participants_request, (IO, bytes)): + _content = mute_participants_request + else: + _json = self._serialize.body(mute_participants_request, "MuteParticipantsRequest") + + request = build_call_connection_mute_request( + call_connection_id=call_connection_id, + repeatability_request_id=repeatability_request_id, + repeatability_first_sent=repeatability_first_sent, + content_type=content_type, + api_version=self._config.api_version, + json=_json, + content=_content, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + request.url = self._client.format_url(request.url, **path_format_arguments) + + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + request, stream=False, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [202]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.CommunicationErrorResponse, pipeline_response) + raise HttpResponseError(response=response, model=error) + + deserialized = self._deserialize("MuteParticipantsResponse", pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + + @overload + def unmute( + self, + call_connection_id: str, + unmute_participants_request: _models.UnmuteParticipantsRequest, + *, + repeatability_request_id: Optional[str] = None, + repeatability_first_sent: Optional[str] = None, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.UnmuteParticipantsResponse: + """Unmute participants from the call using identifier. + + Unmute participants from the call using identifier. + + :param call_connection_id: The call connection id. Required. + :type call_connection_id: str + :param unmute_participants_request: The participants to be unmuted from the call. Required. + :type unmute_participants_request: + ~azure.communication.callautomation.models.UnmuteParticipantsRequest + :keyword repeatability_request_id: If specified, the client directs that the request is + repeatable; that is, that the client can make the request multiple times with the same + Repeatability-Request-Id and get back an appropriate response without the server executing the + request multiple times. The value of the Repeatability-Request-Id is an opaque string + representing a client-generated unique identifier for the request. It is a version 4 (random) + UUID. Default value is None. + :paramtype repeatability_request_id: str + :keyword repeatability_first_sent: If Repeatability-Request-ID header is specified, then + Repeatability-First-Sent header must also be specified. The value should be the date and time + at which the request was first created, expressed using the IMF-fixdate form of HTTP-date. + Example: Sun, 06 Nov 1994 08:49:37 GMT. Default value is None. + :paramtype repeatability_first_sent: str + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: UnmuteParticipantsResponse + :rtype: ~azure.communication.callautomation.models.UnmuteParticipantsResponse + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + def unmute( + self, + call_connection_id: str, + unmute_participants_request: IO, + *, + repeatability_request_id: Optional[str] = None, + repeatability_first_sent: Optional[str] = None, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.UnmuteParticipantsResponse: + """Unmute participants from the call using identifier. + + Unmute participants from the call using identifier. + + :param call_connection_id: The call connection id. Required. + :type call_connection_id: str + :param unmute_participants_request: The participants to be unmuted from the call. Required. + :type unmute_participants_request: IO + :keyword repeatability_request_id: If specified, the client directs that the request is + repeatable; that is, that the client can make the request multiple times with the same + Repeatability-Request-Id and get back an appropriate response without the server executing the + request multiple times. The value of the Repeatability-Request-Id is an opaque string + representing a client-generated unique identifier for the request. It is a version 4 (random) + UUID. Default value is None. + :paramtype repeatability_request_id: str + :keyword repeatability_first_sent: If Repeatability-Request-ID header is specified, then + Repeatability-First-Sent header must also be specified. The value should be the date and time + at which the request was first created, expressed using the IMF-fixdate form of HTTP-date. + Example: Sun, 06 Nov 1994 08:49:37 GMT. Default value is None. + :paramtype repeatability_first_sent: str + :keyword content_type: Body Parameter content-type. Content type parameter for binary body. + Default value is "application/json". + :paramtype content_type: str + :return: UnmuteParticipantsResponse + :rtype: ~azure.communication.callautomation.models.UnmuteParticipantsResponse + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @distributed_trace + def unmute( + self, + call_connection_id: str, + unmute_participants_request: Union[_models.UnmuteParticipantsRequest, IO], + *, + repeatability_request_id: Optional[str] = None, + repeatability_first_sent: Optional[str] = None, + **kwargs: Any + ) -> _models.UnmuteParticipantsResponse: + """Unmute participants from the call using identifier. + + Unmute participants from the call using identifier. + + :param call_connection_id: The call connection id. Required. + :type call_connection_id: str + :param unmute_participants_request: The participants to be unmuted from the call. Is either a + UnmuteParticipantsRequest type or a IO type. Required. + :type unmute_participants_request: + ~azure.communication.callautomation.models.UnmuteParticipantsRequest or IO + :keyword repeatability_request_id: If specified, the client directs that the request is + repeatable; that is, that the client can make the request multiple times with the same + Repeatability-Request-Id and get back an appropriate response without the server executing the + request multiple times. The value of the Repeatability-Request-Id is an opaque string + representing a client-generated unique identifier for the request. It is a version 4 (random) + UUID. Default value is None. + :paramtype repeatability_request_id: str + :keyword repeatability_first_sent: If Repeatability-Request-ID header is specified, then + Repeatability-First-Sent header must also be specified. The value should be the date and time + at which the request was first created, expressed using the IMF-fixdate form of HTTP-date. + Example: Sun, 06 Nov 1994 08:49:37 GMT. Default value is None. + :paramtype repeatability_first_sent: str + :keyword content_type: Body Parameter content-type. Known values are: 'application/json'. + Default value is None. + :paramtype content_type: str + :return: UnmuteParticipantsResponse + :rtype: ~azure.communication.callautomation.models.UnmuteParticipantsResponse + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = kwargs.pop("params", {}) or {} + + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[_models.UnmuteParticipantsResponse] = kwargs.pop("cls", None) + + content_type = content_type or "application/json" + _json = None + _content = None + if isinstance(unmute_participants_request, (IO, bytes)): + _content = unmute_participants_request + else: + _json = self._serialize.body(unmute_participants_request, "UnmuteParticipantsRequest") + + request = build_call_connection_unmute_request( + call_connection_id=call_connection_id, + repeatability_request_id=repeatability_request_id, + repeatability_first_sent=repeatability_first_sent, + content_type=content_type, + api_version=self._config.api_version, + json=_json, + content=_content, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + request.url = self._client.format_url(request.url, **path_format_arguments) + + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + request, stream=False, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [202]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.CommunicationErrorResponse, pipeline_response) + raise HttpResponseError(response=response, model=error) + + deserialized = self._deserialize("UnmuteParticipantsResponse", pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + + @distributed_trace + def get_participant( + self, call_connection_id: str, participant_raw_id: str, **kwargs: Any + ) -> _models.CallParticipant: + """Get participant from a call. + + Get participant from a call. + + :param call_connection_id: The call connection Id. Required. + :type call_connection_id: str + :param participant_raw_id: Raw id of the participant to retrieve. Required. + :type participant_raw_id: str + :return: CallParticipant + :rtype: ~azure.communication.callautomation.models.CallParticipant + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[_models.CallParticipant] = kwargs.pop("cls", None) + + request = build_call_connection_get_participant_request( + call_connection_id=call_connection_id, + participant_raw_id=participant_raw_id, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + request.url = self._client.format_url(request.url, **path_format_arguments) + + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + request, stream=False, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.CommunicationErrorResponse, pipeline_response) + raise HttpResponseError(response=response, model=error) + + deserialized = self._deserialize("CallParticipant", pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + + +class CallMediaOperations: + """ + .. warning:: + **DO NOT** instantiate this class directly. + + Instead, you should access the following operations through + :class:`~azure.communication.callautomation.AzureCommunicationCallAutomationService`'s + :attr:`call_media` attribute. + """ + + models = _models + + def __init__(self, *args, **kwargs): + input_args = list(args) + self._client = input_args.pop(0) if input_args else kwargs.pop("client") + self._config = input_args.pop(0) if input_args else kwargs.pop("config") + self._serialize = input_args.pop(0) if input_args else kwargs.pop("serializer") + self._deserialize = input_args.pop(0) if input_args else kwargs.pop("deserializer") + + @overload + def play( # pylint: disable=inconsistent-return-statements + self, + call_connection_id: str, + play_request: _models.PlayRequest, + *, + content_type: str = "application/json", + **kwargs: Any + ) -> None: + """Plays audio to participants in the call. + + Plays audio to participants in the call. + + :param call_connection_id: The call connection id. Required. + :type call_connection_id: str + :param play_request: play request payload. Required. + :type play_request: ~azure.communication.callautomation.models.PlayRequest + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: None + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + def play( # pylint: disable=inconsistent-return-statements + self, call_connection_id: str, play_request: IO, *, content_type: str = "application/json", **kwargs: Any + ) -> None: + """Plays audio to participants in the call. + + Plays audio to participants in the call. + + :param call_connection_id: The call connection id. Required. + :type call_connection_id: str + :param play_request: play request payload. Required. + :type play_request: IO + :keyword content_type: Body Parameter content-type. Content type parameter for binary body. + Default value is "application/json". + :paramtype content_type: str + :return: None + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @distributed_trace + def play( # pylint: disable=inconsistent-return-statements + self, call_connection_id: str, play_request: Union[_models.PlayRequest, IO], **kwargs: Any + ) -> None: + """Plays audio to participants in the call. + + Plays audio to participants in the call. + + :param call_connection_id: The call connection id. Required. + :type call_connection_id: str + :param play_request: play request payload. Is either a PlayRequest type or a IO type. Required. + :type play_request: ~azure.communication.callautomation.models.PlayRequest or IO + :keyword content_type: Body Parameter content-type. Known values are: 'application/json'. + Default value is None. + :paramtype content_type: str + :return: None + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = kwargs.pop("params", {}) or {} + + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[None] = kwargs.pop("cls", None) + + content_type = content_type or "application/json" + _json = None + _content = None + if isinstance(play_request, (IO, bytes)): + _content = play_request + else: + _json = self._serialize.body(play_request, "PlayRequest") + + request = build_call_media_play_request( + call_connection_id=call_connection_id, + content_type=content_type, + api_version=self._config.api_version, + json=_json, + content=_content, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + request.url = self._client.format_url(request.url, **path_format_arguments) + + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + request, stream=False, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [202]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.CommunicationErrorResponse, pipeline_response) + raise HttpResponseError(response=response, model=error) + + if cls: + return cls(pipeline_response, None, {}) + + @distributed_trace + def cancel_all_media_operations( # pylint: disable=inconsistent-return-statements + self, call_connection_id: str, **kwargs: Any + ) -> None: + """Cancel all media operations in a call. + + Cancel all media operations in a call. + + :param call_connection_id: The call connection id. Required. + :type call_connection_id: str + :return: None + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[None] = kwargs.pop("cls", None) + + request = build_call_media_cancel_all_media_operations_request( + call_connection_id=call_connection_id, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + request.url = self._client.format_url(request.url, **path_format_arguments) + + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + request, stream=False, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [202]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.CommunicationErrorResponse, pipeline_response) + raise HttpResponseError(response=response, model=error) + + if cls: + return cls(pipeline_response, None, {}) + + @overload + def recognize( # pylint: disable=inconsistent-return-statements + self, + call_connection_id: str, + recognize_request: _models.RecognizeRequest, + *, + content_type: str = "application/json", + **kwargs: Any + ) -> None: + """Recognize media from call. + + Recognize media from call. + + :param call_connection_id: The call connection id. Required. + :type call_connection_id: str + :param recognize_request: The media recognize request. Required. + :type recognize_request: ~azure.communication.callautomation.models.RecognizeRequest + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: None + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + def recognize( # pylint: disable=inconsistent-return-statements + self, call_connection_id: str, recognize_request: IO, *, content_type: str = "application/json", **kwargs: Any + ) -> None: + """Recognize media from call. + + Recognize media from call. + + :param call_connection_id: The call connection id. Required. + :type call_connection_id: str + :param recognize_request: The media recognize request. Required. + :type recognize_request: IO + :keyword content_type: Body Parameter content-type. Content type parameter for binary body. + Default value is "application/json". + :paramtype content_type: str + :return: None + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @distributed_trace + def recognize( # pylint: disable=inconsistent-return-statements + self, call_connection_id: str, recognize_request: Union[_models.RecognizeRequest, IO], **kwargs: Any + ) -> None: + """Recognize media from call. + + Recognize media from call. + + :param call_connection_id: The call connection id. Required. + :type call_connection_id: str + :param recognize_request: The media recognize request. Is either a RecognizeRequest type or a + IO type. Required. + :type recognize_request: ~azure.communication.callautomation.models.RecognizeRequest or IO + :keyword content_type: Body Parameter content-type. Known values are: 'application/json'. + Default value is None. + :paramtype content_type: str + :return: None + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = kwargs.pop("params", {}) or {} + + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[None] = kwargs.pop("cls", None) + + content_type = content_type or "application/json" + _json = None + _content = None + if isinstance(recognize_request, (IO, bytes)): + _content = recognize_request + else: + _json = self._serialize.body(recognize_request, "RecognizeRequest") + + request = build_call_media_recognize_request( + call_connection_id=call_connection_id, + content_type=content_type, + api_version=self._config.api_version, + json=_json, + content=_content, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + request.url = self._client.format_url(request.url, **path_format_arguments) + + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + request, stream=False, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [202]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.CommunicationErrorResponse, pipeline_response) + raise HttpResponseError(response=response, model=error) + + if cls: + return cls(pipeline_response, None, {}) + + +class CallRecordingOperations: + """ + .. warning:: + **DO NOT** instantiate this class directly. + + Instead, you should access the following operations through + :class:`~azure.communication.callautomation.AzureCommunicationCallAutomationService`'s + :attr:`call_recording` attribute. + """ + + models = _models + + def __init__(self, *args, **kwargs): + input_args = list(args) + self._client = input_args.pop(0) if input_args else kwargs.pop("client") + self._config = input_args.pop(0) if input_args else kwargs.pop("config") + self._serialize = input_args.pop(0) if input_args else kwargs.pop("serializer") + self._deserialize = input_args.pop(0) if input_args else kwargs.pop("deserializer") + + @overload + def start_recording( + self, + start_call_recording: _models.StartCallRecordingRequest, + *, + repeatability_request_id: Optional[str] = None, + repeatability_first_sent: Optional[str] = None, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.RecordingStateResponse: + """Start recording the call. + + Start recording the call. + + :param start_call_recording: The request body of start call recording request. Required. + :type start_call_recording: + ~azure.communication.callautomation.models.StartCallRecordingRequest + :keyword repeatability_request_id: If specified, the client directs that the request is + repeatable; that is, that the client can make the request multiple times with the same + Repeatability-Request-Id and get back an appropriate response without the server executing the + request multiple times. The value of the Repeatability-Request-Id is an opaque string + representing a client-generated unique identifier for the request. It is a version 4 (random) + UUID. Default value is None. + :paramtype repeatability_request_id: str + :keyword repeatability_first_sent: If Repeatability-Request-ID header is specified, then + Repeatability-First-Sent header must also be specified. The value should be the date and time + at which the request was first created, expressed using the IMF-fixdate form of HTTP-date. + Example: Sun, 06 Nov 1994 08:49:37 GMT. Default value is None. + :paramtype repeatability_first_sent: str + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: RecordingStateResponse + :rtype: ~azure.communication.callautomation.models.RecordingStateResponse + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + def start_recording( + self, + start_call_recording: IO, + *, + repeatability_request_id: Optional[str] = None, + repeatability_first_sent: Optional[str] = None, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.RecordingStateResponse: + """Start recording the call. + + Start recording the call. + + :param start_call_recording: The request body of start call recording request. Required. + :type start_call_recording: IO + :keyword repeatability_request_id: If specified, the client directs that the request is + repeatable; that is, that the client can make the request multiple times with the same + Repeatability-Request-Id and get back an appropriate response without the server executing the + request multiple times. The value of the Repeatability-Request-Id is an opaque string + representing a client-generated unique identifier for the request. It is a version 4 (random) + UUID. Default value is None. + :paramtype repeatability_request_id: str + :keyword repeatability_first_sent: If Repeatability-Request-ID header is specified, then + Repeatability-First-Sent header must also be specified. The value should be the date and time + at which the request was first created, expressed using the IMF-fixdate form of HTTP-date. + Example: Sun, 06 Nov 1994 08:49:37 GMT. Default value is None. + :paramtype repeatability_first_sent: str + :keyword content_type: Body Parameter content-type. Content type parameter for binary body. + Default value is "application/json". + :paramtype content_type: str + :return: RecordingStateResponse + :rtype: ~azure.communication.callautomation.models.RecordingStateResponse + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @distributed_trace + def start_recording( + self, + start_call_recording: Union[_models.StartCallRecordingRequest, IO], + *, + repeatability_request_id: Optional[str] = None, + repeatability_first_sent: Optional[str] = None, + **kwargs: Any + ) -> _models.RecordingStateResponse: + """Start recording the call. + + Start recording the call. + + :param start_call_recording: The request body of start call recording request. Is either a + StartCallRecordingRequest type or a IO type. Required. + :type start_call_recording: + ~azure.communication.callautomation.models.StartCallRecordingRequest or IO + :keyword repeatability_request_id: If specified, the client directs that the request is + repeatable; that is, that the client can make the request multiple times with the same + Repeatability-Request-Id and get back an appropriate response without the server executing the + request multiple times. The value of the Repeatability-Request-Id is an opaque string + representing a client-generated unique identifier for the request. It is a version 4 (random) + UUID. Default value is None. + :paramtype repeatability_request_id: str + :keyword repeatability_first_sent: If Repeatability-Request-ID header is specified, then + Repeatability-First-Sent header must also be specified. The value should be the date and time + at which the request was first created, expressed using the IMF-fixdate form of HTTP-date. + Example: Sun, 06 Nov 1994 08:49:37 GMT. Default value is None. + :paramtype repeatability_first_sent: str + :keyword content_type: Body Parameter content-type. Known values are: 'application/json'. + Default value is None. + :paramtype content_type: str + :return: RecordingStateResponse + :rtype: ~azure.communication.callautomation.models.RecordingStateResponse + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = kwargs.pop("params", {}) or {} + + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[_models.RecordingStateResponse] = kwargs.pop("cls", None) + + content_type = content_type or "application/json" + _json = None + _content = None + if isinstance(start_call_recording, (IO, bytes)): + _content = start_call_recording + else: + _json = self._serialize.body(start_call_recording, "StartCallRecordingRequest") + + request = build_call_recording_start_recording_request( + repeatability_request_id=repeatability_request_id, + repeatability_first_sent=repeatability_first_sent, + content_type=content_type, + api_version=self._config.api_version, + json=_json, + content=_content, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + request.url = self._client.format_url(request.url, **path_format_arguments) + + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + request, stream=False, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.CommunicationErrorResponse, pipeline_response) + raise HttpResponseError(response=response, model=error) + + deserialized = self._deserialize("RecordingStateResponse", pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + + @distributed_trace + def get_recording_properties(self, recording_id: str, **kwargs: Any) -> _models.RecordingStateResponse: + """Get call recording properties. + + Get call recording properties. + + :param recording_id: The recording id. Required. + :type recording_id: str + :return: RecordingStateResponse + :rtype: ~azure.communication.callautomation.models.RecordingStateResponse + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[_models.RecordingStateResponse] = kwargs.pop("cls", None) + + request = build_call_recording_get_recording_properties_request( + recording_id=recording_id, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + request.url = self._client.format_url(request.url, **path_format_arguments) + + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + request, stream=False, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.CommunicationErrorResponse, pipeline_response) + raise HttpResponseError(response=response, model=error) + + deserialized = self._deserialize("RecordingStateResponse", pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + + @distributed_trace + def stop_recording( # pylint: disable=inconsistent-return-statements + self, recording_id: str, **kwargs: Any + ) -> None: + """Stop recording the call. + + Stop recording the call. + + :param recording_id: The recording id. Required. + :type recording_id: str + :return: None + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[None] = kwargs.pop("cls", None) + + request = build_call_recording_stop_recording_request( + recording_id=recording_id, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + request.url = self._client.format_url(request.url, **path_format_arguments) + + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + request, stream=False, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [204]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.CommunicationErrorResponse, pipeline_response) + raise HttpResponseError(response=response, model=error) + + if cls: + return cls(pipeline_response, None, {}) + + @distributed_trace + def pause_recording( # pylint: disable=inconsistent-return-statements + self, recording_id: str, **kwargs: Any + ) -> None: + """Pause recording the call. + + Pause recording the call. + + :param recording_id: The recording id. Required. + :type recording_id: str + :return: None + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[None] = kwargs.pop("cls", None) + + request = build_call_recording_pause_recording_request( + recording_id=recording_id, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + request.url = self._client.format_url(request.url, **path_format_arguments) + + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + request, stream=False, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [202]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.CommunicationErrorResponse, pipeline_response) + raise HttpResponseError(response=response, model=error) + + if cls: + return cls(pipeline_response, None, {}) + + @distributed_trace + def resume_recording( # pylint: disable=inconsistent-return-statements + self, recording_id: str, **kwargs: Any + ) -> None: + """Resume recording the call. + + Resume recording the call. + + :param recording_id: The recording id. Required. + :type recording_id: str + :return: None + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[None] = kwargs.pop("cls", None) + + request = build_call_recording_resume_recording_request( + recording_id=recording_id, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + request.url = self._client.format_url(request.url, **path_format_arguments) + + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + request, stream=False, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [202]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.CommunicationErrorResponse, pipeline_response) + raise HttpResponseError(response=response, model=error) + + if cls: + return cls(pipeline_response, None, {}) diff --git a/sdk/keyvault/azure-keyvault-administration/azure/keyvault/administration/_generated/v7_4_preview_1/operations/_patch.py b/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_generated/operations/_patch.py similarity index 100% rename from sdk/keyvault/azure-keyvault-administration/azure/keyvault/administration/_generated/v7_4_preview_1/operations/_patch.py rename to sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_generated/operations/_patch.py diff --git a/sdk/keyvault/azure-keyvault-administration/azure/keyvault/administration/_generated/v7_4_preview_1/py.typed b/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_generated/py.typed similarity index 100% rename from sdk/keyvault/azure-keyvault-administration/azure/keyvault/administration/_generated/v7_4_preview_1/py.typed rename to sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_generated/py.typed diff --git a/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_models.py b/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_models.py new file mode 100644 index 000000000000..35466f2af53b --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_models.py @@ -0,0 +1,591 @@ +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ +from typing import Any, List, Optional, Union + +from enum import Enum +from typing import Dict + +from azure.core import CaseInsensitiveEnumMeta + +from ._generated.models import ( + CallLocator, + StartCallRecordingRequest as StartCallRecordingRequestRest, + RecordingContentType, RecordingChannelType, RecordingFormatType, + CommunicationIdentifierModel, + CallConnectionStateModel, + RecordingStorageType, + RecognizeInputType, + MediaStreamingConfiguration as MediaStreamingConfigurationRest, + CallParticipant as CallParticipantRest, + CallConnectionProperties as CallConnectionPropertiesRest, + GetParticipantsResponse as GetParticipantsResponseRest, + AddParticipantResponse as AddParticipantResponseRest +) + +from ._shared.models import ( + CommunicationIdentifier, + PhoneNumberIdentifier, +) + +from ._communication_identifier_serializer import ( + deserialize_phone_identifier, + deserialize_identifier, + serialize_identifier +) + +class ServerCallLocator(object): + """ + The locator used for joining or taking action on a server call. + + :ivar locator_id: The server call id. + :vartype locator_id: str + """ + def __init__( + self, + *, + locator_id: str, + **kwargs: Any + ) -> None: + + super().__init__(**kwargs) + self.id = locator_id + self.kind = "serverCallLocator" + + def _to_generated(self): + + return CallLocator(kind=self.kind, + server_call_id=self.id + ) + + +class GroupCallLocator(object): + """ + The locator used for joining or taking action on a group call. + + :ivar locator_id: The group call id. + :vartype locator_id: str + """ + def __init__( + self, + *, + locator_id: str, + **kwargs: Any + ) -> None: + + super().__init__(**kwargs) + self.id = locator_id + self.kind = "groupCallLocator" + + def _to_generated(self): + + return CallLocator(kind=self.kind, + group_call_id=self.id + ) + + +class StartRecordingOptions(object): + def __init__( + self, + *, + call_locator: Union[ServerCallLocator, GroupCallLocator], + recording_state_callback_uri: Optional[str] = None, + recording_content: Optional[Union[str, + "RecordingContent"]] = None, + recording_channel: Optional[Union[str, + "RecordingChannel"]] = None, + recording_format: Optional[Union[str, + "RecordingFormat"]] = None, + audio_channel_participant_ordering: Optional[List["CommunicationIdentifier"]] = None, + recording_storage: Optional[Union[str, + "RecordingStorage"]] = None, + **kwargs: Any + ) -> None: + """ + :keyword call_locator: The call locator. Required. + :paramtype call_locator: ~azure.communication.callautomation.models.CallLocator + :keyword recording_state_callback_uri: The uri to send notifications to. + :paramtype recording_state_callback_uri: str + :keyword recording_content_type: The content type of call recording. Known values are: "audio" + and "audioVideo". + :paramtype recording_content_type: str or + ~azure.communication.callautomation.models.RecordingContent + :keyword recording_channel_type: The channel type of call recording. Known values are: "mixed" + and "unmixed". + :paramtype recording_channel_type: str or + ~azure.communication.callautomation.models.RecordingChannel + :keyword recording_format_type: The format type of call recording. Known values are: "wav", + "mp3", and "mp4". + :paramtype recording_format_type: str or + ~azure.communication.callautomation.models.RecordingFormat + :keyword audio_channel_participant_ordering: The sequential order in which audio channels are + assigned to participants in the unmixed recording. + When 'recordingChannelType' is set to 'unmixed' and `audioChannelParticipantOrdering is not + specified, + the audio channel to participant mapping will be automatically assigned based on the order in + which participant + first audio was detected. Channel to participant mapping details can be found in the metadata + of the recording. + :paramtype audio_channel_participant_ordering: + list[~azure.communication.callautomation.models.CommunicationIdentifierModel] + :keyword recording_storage_type: Recording storage mode. ``External`` enables bring your own + storage. Known values are: "acs" and "azureBlob". + :paramtype recording_storage_type: str or + ~azure.communication.callautomation.models.RecordingStorageType + """ + super().__init__(**kwargs) + self.call_locator = call_locator + self.recording_state_callback_uri = recording_state_callback_uri + self.recording_content_type = recording_content + self.recording_channel_type = recording_channel + self.recording_format_type = recording_format + self.audio_channel_participant_ordering = audio_channel_participant_ordering + self.recording_storage_type = recording_storage + + def _to_generated(self): + audio_channel_participant_ordering_list:List[CommunicationIdentifierModel] = None + if self.audio_channel_participant_ordering is not None: + audio_channel_participant_ordering_list=[ + serialize_identifier(identifier) for identifier + in self.audio_channel_participant_ordering] + + return StartCallRecordingRequestRest( + call_locator=self.call_locator._to_generated(# pylint:disable=protected-access + ), + recording_state_callback_uri=self.recording_state_callback_uri, + recording_content_type=self.recording_content_type, + recording_channel_type=self.recording_channel_type, + recording_format_type=self.recording_format_type, + audio_channel_participant_ordering=audio_channel_participant_ordering_list, + recording_storage_type=self.recording_storage_type + ) + + +class RecordingStateResponse(object): + """RecordingStateResponse. + + :ivar recording_id: + :vartype recording_id: str + :ivar recording_state: Known values are: "active" and "inactive". + :vartype recording_state: str or ~azure.communication.callautomation.models.RecordingState + """ + + # pylint:disable=protected-access + + def __init__( + self, + **kwargs # type: Any + ): + self.recording_id = kwargs['recording_id'] + self.recording_state = kwargs['recording_state'] + + @classmethod + def _from_generated(cls, recording_state_response): + + return cls( + recording_id=recording_state_response.recording_id, + recording_state=recording_state_response.recording_state + ) + + +class PlaySource(object): + """ + The PlaySource model. + + :ivar play_source_id: Defines the identifier to be used for caching related media. + :vartype play_source_id: str + """ + + def __init__( + self, + **kwargs + ): + self.play_source_id = kwargs['play_source_id'] + + +class FileSource(PlaySource): + """ + The FileSource model. + + :ivar uri: Uri for the audio file to be played. + :vartype uri: str + """ + + def __init__( + self, + **kwargs + ): + self.uri = kwargs['uri'] + super().__init__(play_source_id=kwargs.get('play_source_id')) + +class Gender(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """Voice gender type.""" + + MALE = "male" + FEMALE = "female" + + +class CallMediaRecognizeOptions(object): + """ + Options to configure the Recognize operation. + + :ivar input_type: Determines the type of the recognition. + :vartype input_type: str or ~azure.communication.callautomation.models.RecognizeInputType + :ivar target_participant: Target participant of DTMF tone recognition. + :vartype target_participant: ~azure.communication.callautomation.models.CommunicationIdentifierModel + :ivar initial_silence_timeout: Time to wait for first input after prompt in seconds (if any). + :vartype initial_silence_timeout: int + :ivar play_prompt: The source of the audio to be played for recognition. + :vartype play_prompt: ~azure.communication.callautomation.models.PlaySource + :ivar interrupt_call_media_operation: If set recognize can barge into + other existing queued-up/currently-processing requests. + :vartype interrupt_call_media_operation: bool + :ivar operation_context: The value to identify context of the operation. + :vartype operation_context: str + :ivar interrupt_prompt: Determines if we interrupt the prompt and start recognizing. + :vartype interrupt_prompt: bool + """ + + def __init__( + self, + input_type, + target_participant, + **kwargs + ): + self.input_type = input_type + self.target_participant = target_participant + self.initial_silence_timeout = 5 + self.play_prompt = kwargs.get('play_prompt') + self.interrupt_call_media_operation = kwargs.get( + 'interrupt_call_media_operation') + self.stop_current_operations = kwargs.get('stop_current_operations') + self.operation_context = kwargs.get('operation_context') + self.interrupt_prompt = kwargs.get('interrupt_prompt') + + +class CallMediaRecognizeDtmfOptions(CallMediaRecognizeOptions): + """ + The recognize configuration specific to DTMF. + + :ivar max_tones_to_collect: Maximum number of DTMF to be collected. + :vartype max_tones_to_collect: int + :ivar inter_tone_timeout: Time to wait between DTMF inputs to stop recognizing. + :vartype inter_tone_timeout: int + :ivar stop_dtmf_tones: List of tones that will stop recognizing. + :vartype stop_dtmf_tones: list[~azure.communication.callautomation.models.Tone] + """ + + def __init__( + self, + target_participant, + max_tones_to_collect, + **kwargs + ): + self.max_tones_to_collect = max_tones_to_collect + self.inter_tone_timeout = kwargs.get('inter_tone_timeout') + self.stop_dtmf_tones = kwargs.get('stop_dtmf_tones') + super().__init__(RecognizeInputType.DTMF, target_participant, **kwargs) + + +class DtmfTone(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """Tone.""" + + ZERO = "zero" + ONE = "one" + TWO = "two" + THREE = "three" + FOUR = "four" + FIVE = "five" + SIX = "six" + SEVEN = "seven" + EIGHT = "eight" + NINE = "nine" + A = "a" + B = "b" + C = "c" + D = "d" + POUND = "pound" + ASTERISK = "asterisk" + +class CallInvite(object): + def __init__( + self, + target: CommunicationIdentifier, + *, + sourceCallIdNumber: Optional[PhoneNumberIdentifier] = None, + sourceDisplayName: Optional[str] = None, + sipHeaders: Optional[Dict[str, str]] = None, + voipHeaders: Optional[Dict[str, str]] = None, + **kwargs: Any + ) -> None: + """ + :keyword target: Target's identity. Required. + :paramtype target: CommunicationIdentifier + :keyword sourceCallIdNumber: Caller's phone number identifier + :paramtype sourceCallIdNumber: PhoneNumberIdentifier + :keyword sourceDisplayName: Set display name for caller + :paramtype sourceDisplayName: str + :keyword sipHeaders: Custom context for PSTN + :paramtype sipHeaders: str + :keyword voipHeaders: Custom context for VOIP + :paramtype voipHeaders: str + """ + super().__init__(**kwargs) + self.target = target + self.sourceCallIdNumber = sourceCallIdNumber + self.sourceDisplayName = sourceDisplayName + self.sipHeaders = sipHeaders + self.voipHeaders = voipHeaders + + +class CallConnectionProperties(object): + """Properties of a call connection.""" + + def __init__( + self, + *, + call_connection_id: Optional[str] = None, + server_call_id: Optional[str] = None, + targets: Optional[List[CommunicationIdentifier]] = None, + call_connection_state: Optional[Union[str, + CallConnectionStateModel]] = None, + callback_uri: Optional[str] = None, + media_subscription_id: Optional[str] = None, + source_caller_id_number: Optional[PhoneNumberIdentifier] = None, + source_display_name: Optional[str] = None, + source_identity: Optional[CommunicationIdentifier] = None, + **kwargs: Any + ) -> None: + """ + :keyword call_connection_id: The call connection id. + :paramtype call_connection_id: str + :keyword server_call_id: The server call id. + :paramtype server_call_id: str + :keyword targets: The targets of the call. + :paramtype targets: + list[CommunicationIdentifier] + :keyword call_connection_state: The state of the call connection. Known values are: "unknown", + "connecting", "connected", "transferring", "transferAccepted", "disconnecting", and + "disconnected". + :paramtype call_connection_state: str or CallConnectionStateModel + :keyword callback_uri: The callback URI. + :paramtype callback_uri: str + :keyword media_subscription_id: SubscriptionId for media streaming. + :paramtype media_subscription_id: str + :keyword source_caller_id_number: The source caller Id, a phone number, that's shown to the + PSTN participant being invited. + Required only when calling a PSTN callee. + :paramtype source_caller_id_number: PhoneNumberIdentifier + :keyword source_display_name: Display name of the call if dialing out to a pstn number. + :paramtype source_display_name: str + :keyword source_identity: Source identity. + :paramtype source_identity: CommunicationIdentifier + """ + super().__init__(**kwargs) + self.call_connection_id = call_connection_id + self.server_call_id = server_call_id + self.targets = targets + self.call_connection_state = call_connection_state + self.callback_uri = callback_uri + self.media_subscription_id = media_subscription_id + self.source_caller_id_number = source_caller_id_number + self.source_display_name = source_display_name + self.source_identity = source_identity + + @classmethod + def _from_generated(cls, call_connection_properties_generated: CallConnectionPropertiesRest): + target_models = [] + for target in call_connection_properties_generated.targets: + target_models.append(deserialize_identifier(target)) + + return cls( + call_connection_id=call_connection_properties_generated.call_connection_id, + server_call_id=call_connection_properties_generated.server_call_id, + targets=target_models, + call_connection_state=call_connection_properties_generated.call_connection_state, + callback_uri=call_connection_properties_generated.callback_uri, + media_subscription_id=call_connection_properties_generated.media_subscription_id, + source_caller_id_number=deserialize_phone_identifier( + call_connection_properties_generated.source_caller_id_number) + if call_connection_properties_generated.source_caller_id_number + else None, + source_display_name=call_connection_properties_generated.source_display_name, + source_identity=deserialize_identifier(call_connection_properties_generated.source_identity) + if call_connection_properties_generated.source_identity + else None) + + +class CallParticipant(object): + """Contract model of an ACS call participant. + """ + + def __init__( + self, + identifier: CommunicationIdentifier, + *, + is_muted: Optional[bool] = False, + **kwargs: Any + ) -> None: + """ + :keyword identifier: Communication identifier of the participant. + :paramtype identifier: CommunicationIdentifier + :keyword is_muted: Is participant muted. + :paramtype is_muted: bool + """ + super().__init__(**kwargs) + self.identifier = identifier + self.is_muted = is_muted + + @classmethod + def _from_generated(cls, call_participant_generated: CallParticipantRest): + return cls( + identifier=deserialize_identifier(call_participant_generated.identifier), + is_muted=call_participant_generated.is_muted) + +class GetParticipantsResponse(object): + """The response payload for getting participants of the call.""" + + def __init__( + self, + values: List[CallParticipant], + *, + next_link: Optional[str] = None, + **kwargs: Any + ) -> None: + """ + :keyword values: List of the current participants in the call. + :paramtype values: list[CallParticipant] + :keyword next_link: Continue of the list of participants. + :paramtype next_link: str + """ + super().__init__(**kwargs) + self.values = values + self.next_link = next_link + + @classmethod + def _from_generated(cls, get_participant_response_generated: GetParticipantsResponseRest): + return cls(values=[CallParticipant._from_generated(# pylint:disable=protected-access + participant) for participant in get_participant_response_generated.values], + next_link=get_participant_response_generated.next_link) + + +class AddParticipantResponse(object): + """The response payload for adding participants to the call. + """ + + def __init__( + self, + participant: CallParticipant, + *, + operation_context: Optional[str] = None, + **kwargs: Any + ) -> None: + """ + :keyword participant: List of current participants in the call. + :paramtype participant: CallParticipant + :keyword operation_context: The operation context provided by client. + :paramtype operation_context: str + """ + super().__init__(**kwargs) + self.participant = participant + self.operation_context = operation_context + + @classmethod + def _from_generated(cls, add_participant_response_generated: AddParticipantResponseRest): + return cls(participant=CallParticipant._from_generated(# pylint:disable=protected-access + add_participant_response_generated.participant), + operation_context=add_participant_response_generated.operation_context) + + +class MediaStreamingAudioChannelType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """Audio channel type to stream, eg. unmixed audio, mixed audio.""" + + MIXED = "mixed" + UNMIXED = "unmixed" + + +class MediaStreamingContentType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """Content type to stream, eg. audio, audio/video.""" + + AUDIO = "audio" + + +class MediaStreamingTransportType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """The type of transport to be used for media streaming, eg. Websocket.""" + + WEBSOCKET = "websocket" + + +class MediaStreamingConfiguration(object): + """Configuration of Media streaming. + + All required parameters must be populated in order to send to Azure. + """ + + def __init__( + self, + transport_url: str, + transport_type: Union[str, MediaStreamingTransportType], + content_type: Union[str, MediaStreamingContentType], + audio_channel_type: Union[str, MediaStreamingAudioChannelType], + **kwargs: Any + ) -> None: + """ + :keyword transport_url: Transport URL for media streaming. Required. + :paramtype transport_url: str + :keyword transport_type: The type of transport to be used for media streaming, eg. Websocket. + Required. "websocket" + :paramtype transport_type: str or MediaStreamingTransportType + :keyword content_type: Content type to stream, eg. audio, audio/video. Required. "audio" + :paramtype content_type: str or MediaStreamingContentType + :keyword audio_channel_type: Audio channel type to stream, eg. unmixed audio, mixed audio. + Required. Known values are: "mixed" and "unmixed". + :paramtype audio_channel_type: str or MediaStreamingAudioChannelType + """ + super().__init__(**kwargs) + self.transport_url = transport_url + self.transport_type = transport_type + self.content_type = content_type + self.audio_channel_type = audio_channel_type + + def to_generated(self): + return MediaStreamingConfigurationRest( + transport_url=self.transport_url, + transport_type=self.transport_type, + content_type=self.content_type, + audio_channel_type=self.audio_channel_type + ) + + +class CallRejectReason(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """The rejection reason.""" + + NONE = "none" + BUSY = "busy" + FORBIDDEN = "forbidden" + + +class RecordingContent(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """Recording content type.""" + + AUDIO = RecordingContentType.AUDIO.value + AUDIO_VIDEO = RecordingContentType.AUDIO_VIDEO.value + +class RecordingChannel(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """Recording channel type.""" + + MIXED = RecordingChannelType.MIXED.value + UNMIXED = RecordingChannelType.UNMIXED.value + +class RecordingFormat(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """Recording format type.""" + WAV = RecordingFormatType.WAV.value + MP4 = RecordingFormatType.MP4.value + MP3 = RecordingFormatType.MP3.value + +class RecordingStorage(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """Recording storage type.""" + + ACS = RecordingStorageType.ACS.value + BLOB_STORAGE = RecordingStorageType.BLOB_STORAGE.value diff --git a/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_shared/__init__.py b/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_shared/__init__.py new file mode 100644 index 000000000000..5b396cd202e8 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_shared/__init__.py @@ -0,0 +1,5 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- diff --git a/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_shared/models.py b/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_shared/models.py new file mode 100644 index 000000000000..daed730ddea1 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_shared/models.py @@ -0,0 +1,239 @@ +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ +# pylint: skip-file + +from enum import Enum, EnumMeta +import re +from six import with_metaclass +from typing import Mapping, Optional, Union, Any +try: + from typing import Protocol, TypedDict +except ImportError: + from typing_extensions import Protocol, TypedDict + +from azure.core import CaseInsensitiveEnumMeta + + +class CommunicationIdentifierKind(with_metaclass(CaseInsensitiveEnumMeta, str, Enum)): + """Communication Identifier Kind.""" + + UNKNOWN = "unknown" + COMMUNICATION_USER = "communication_user" + PHONE_NUMBER = "phone_number" + MICROSOFT_TEAMS_USER = "microsoft_teams_user" + + +class CommunicationCloudEnvironment(with_metaclass(CaseInsensitiveEnumMeta, str, Enum)): + """The cloud environment that the identifier belongs to""" + + PUBLIC = "PUBLIC" + DOD = "DOD" + GCCH = "GCCH" + + +class CommunicationIdentifier(Protocol): + """Communication Identifier. + + :ivar str raw_id: Optional raw ID of the identifier. + :ivar kind: The type of identifier. + :vartype kind: str or CommunicationIdentifierKind + :ivar Mapping[str, Any] properties: The properties of the identifier. + """ + raw_id = None # type: Optional[str] + kind = None # type: Optional[Union[CommunicationIdentifierKind, str]] + properties = {} # type: Mapping[str, Any] + + +CommunicationUserProperties = TypedDict( + 'CommunicationUserProperties', + id=str +) + + +class CommunicationUserIdentifier(object): + """Represents a user in Azure Communication Service. + + :ivar str raw_id: Optional raw ID of the identifier. + :ivar kind: The type of identifier. + :vartype kind: str or CommunicationIdentifierKind + :ivar Mapping[str, Any] properties: The properties of the identifier. + The keys in this mapping include: + - `id`(str): ID of the Communication user as returned from Azure Communication Identity. + + :param str id: ID of the Communication user as returned from Azure Communication Identity. + """ + kind = CommunicationIdentifierKind.COMMUNICATION_USER + + def __init__(self, id, **kwargs): + # type: (str, Any) -> None + self.raw_id = kwargs.get('raw_id', id) + self.properties = CommunicationUserProperties(id=id) + + def __eq__(self, other): + return self.__dict__ == other.__dict__ + + +PhoneNumberProperties = TypedDict( + 'PhoneNumberProperties', + value=str +) + + +class PhoneNumberIdentifier(object): + """Represents a phone number. + + :ivar str raw_id: Optional raw ID of the identifier. + :ivar kind: The type of identifier. + :vartype kind: str or CommunicationIdentifierKind + :ivar Mapping properties: The properties of the identifier. + The keys in this mapping include: + - `value`(str): The phone number in E.164 format. + + :param str value: The phone number. + """ + kind = CommunicationIdentifierKind.PHONE_NUMBER + + def __init__(self, value, **kwargs): + # type: (str, Any) -> None + self.raw_id = kwargs.get('raw_id') + self.properties = PhoneNumberProperties(value=value) + if self.raw_id is None: + self.raw_id = _phone_number_raw_id(self) + + +def _phone_number_raw_id(identifier: PhoneNumberIdentifier) -> str: + value = identifier.properties['value'] + # We just assume correct E.164 format here because + # validation should only happen server-side, not client-side. + return f'4:{value}' + + +class UnknownIdentifier(object): + """Represents an identifier of an unknown type. + + It will be encountered in communications with endpoints that are not + identifiable by this version of the SDK. + + :ivar str raw_id: Optional raw ID of the identifier. + :ivar kind: The type of identifier. + :vartype kind: str or CommunicationIdentifierKind + :ivar Mapping properties: The properties of the identifier. + :param str identifier: The ID of the identifier. + """ + kind = CommunicationIdentifierKind.UNKNOWN + + def __init__(self, identifier): + # type: (str) -> None + self.raw_id = identifier + self.properties = {} + + def __eq__(self, other): + return self.__dict__ == other.__dict__ + + +MicrosoftTeamsUserProperties = TypedDict( + 'MicrosoftTeamsUserProperties', + user_id=str, + is_anonymous=bool, + cloud=Union[CommunicationCloudEnvironment, str] +) + + +class MicrosoftTeamsUserIdentifier(object): + """Represents an identifier for a Microsoft Teams user. + + :ivar str raw_id: Optional raw ID of the identifier. + :ivar kind: The type of identifier. + :vartype kind: str or CommunicationIdentifierKind + :ivar Mapping properties: The properties of the identifier. + The keys in this mapping include: + - `user_id`(str): The id of the Microsoft Teams user. If the user isn't anonymous, + the id is the AAD object id of the user. + - `is_anonymous` (bool): Set this to true if the user is anonymous for example when joining + a meeting with a share link. + - `cloud` (str): Cloud environment that this identifier belongs to. + + :param str user_id: Microsoft Teams user id. + :keyword bool is_anonymous: `True` if the identifier is anonymous. Default value is `False`. + :keyword cloud: Cloud environment that the user belongs to. Default value is `PUBLIC`. + :paramtype cloud: str or ~azure.communication.callautomation.CommunicationCloudEnvironment + """ + kind = CommunicationIdentifierKind.MICROSOFT_TEAMS_USER + + def __init__(self, user_id, **kwargs): + # type: (str, Any) -> None + self.raw_id = kwargs.get('raw_id') + self.properties = MicrosoftTeamsUserProperties( + user_id=user_id, + is_anonymous=kwargs.get('is_anonymous', False), + cloud=kwargs.get('cloud') or CommunicationCloudEnvironment.PUBLIC + ) + if self.raw_id is None: + self.raw_id = _microsoft_teams_user_raw_id(self) + + +def _microsoft_teams_user_raw_id(identifier: MicrosoftTeamsUserIdentifier) -> str: + user_id = identifier.properties['user_id'] + if identifier.properties['is_anonymous']: + return '8:teamsvisitor:{}'.format(user_id) + cloud = identifier.properties['cloud'] + if cloud == CommunicationCloudEnvironment.DOD: + return '8:dod:{}'.format(user_id) + elif cloud == CommunicationCloudEnvironment.GCCH: + return '8:gcch:{}'.format(user_id) + elif cloud == CommunicationCloudEnvironment.PUBLIC: + return '8:orgid:{}'.format(user_id) + return '8:orgid:{}'.format(user_id) + + +def identifier_from_raw_id(raw_id: str) -> CommunicationIdentifier: + """ + Creates a CommunicationIdentifier from a given raw ID. + + When storing raw IDs use this function to restore the identifier that was encoded in the raw ID. + + :param str raw_id: A raw ID to construct the CommunicationIdentifier from. + """ + if raw_id.startswith('4:'): + return PhoneNumberIdentifier( + value = raw_id[len('4:'):] + ) + + segments = raw_id.split(':', maxsplit=2) + if len(segments) < 3: + return UnknownIdentifier(identifier=raw_id) + + prefix = '{}:{}:'.format(segments[0], segments[1]) + suffix = raw_id[len(prefix):] + if prefix == '8:teamsvisitor:': + return MicrosoftTeamsUserIdentifier( + user_id=suffix, + is_anonymous=True + ) + elif prefix == '8:orgid:': + return MicrosoftTeamsUserIdentifier( + user_id=suffix, + is_anonymous=False, + cloud='PUBLIC' + ) + elif prefix == '8:dod:': + return MicrosoftTeamsUserIdentifier( + user_id=suffix, + is_anonymous=False, + cloud='DOD' + ) + elif prefix == '8:gcch:': + return MicrosoftTeamsUserIdentifier( + user_id=suffix, + is_anonymous=False, + cloud='GCCH' + ) + elif prefix in ['8:acs:', '8:spool:', '8:dod-acs:', '8:gcch-acs:']: + return CommunicationUserIdentifier( + id=raw_id + ) + return UnknownIdentifier( + identifier=raw_id + ) diff --git a/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_shared/policy.py b/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_shared/policy.py new file mode 100644 index 000000000000..de6ccc113f54 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_shared/policy.py @@ -0,0 +1,96 @@ +# ------------------------------------------------------------------------ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# ------------------------------------------------------------------------- + +import hashlib +import urllib +import base64 +import hmac +from azure.core.credentials import AzureKeyCredential +from azure.core.pipeline.policies import SansIOHTTPPolicy +from .utils import get_current_utc_time + +class HMACCredentialsPolicy(SansIOHTTPPolicy): + """Implementation of HMAC authentication policy. + """ + + def __init__(self, + host, # type: str + access_key, # type: Union[str, AzureKeyCredential] + decode_url=False # type: bool + ): + # type: (...) -> None + super(HMACCredentialsPolicy, self).__init__() + + if host.startswith("https://"): + self._host = host.replace("https://", "") + + if host.startswith("http://"): + self._host = host.replace("http://", "") + + self._access_key = access_key + self._decode_url = decode_url + + def _compute_hmac(self, + value # type: str + ): + if isinstance(self._access_key, AzureKeyCredential): + decoded_secret = base64.b64decode(self._access_key.key) + else: + decoded_secret = base64.b64decode(self._access_key) + + digest = hmac.new( + decoded_secret, value.encode("utf-8"), hashlib.sha256 + ).digest() + + return base64.b64encode(digest).decode("utf-8") + + def _sign_request(self, request): + verb = request.http_request.method.upper() + + # Get the path and query from url, which looks like https://host/path/query + query_url = str(request.http_request.url[len(self._host) + 8:]) + + if self._decode_url: + query_url = urllib.parse.unquote(query_url) + + signed_headers = "x-ms-date;host;x-ms-content-sha256" + + utc_now = get_current_utc_time() + if request.http_request.body is None: + request.http_request.body = "" + content_digest = hashlib.sha256( + (request.http_request.body.encode("utf-8")) + ).digest() + content_hash = base64.b64encode(content_digest).decode("utf-8") + + string_to_sign = ( + verb + + "\n" + + query_url + + "\n" + + utc_now + + ";" + + self._host + + ";" + + content_hash + ) + + signature = self._compute_hmac(string_to_sign) + + signature_header = { + "x-ms-date": utc_now, + "x-ms-content-sha256": content_hash, + "x-ms-return-client-request-id": "true", + "Authorization": "HMAC-SHA256 SignedHeaders=" +\ + signed_headers + "&Signature=" + signature, + } + + request.http_request.headers.update(signature_header) + + return request + + def on_request(self, request): + self._sign_request(request) diff --git a/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_shared/user_credential.py b/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_shared/user_credential.py new file mode 100644 index 000000000000..f4a89336ad58 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_shared/user_credential.py @@ -0,0 +1,145 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- + +from threading import Lock, Condition, Timer, TIMEOUT_MAX, Event +from datetime import timedelta +from typing import Any +import six +from .utils import get_current_utc_as_int +from .utils import create_access_token + + +class CommunicationTokenCredential(object): + """Credential type used for authenticating to an Azure Communication service. + :param str token: The token used to authenticate to an Azure Communication service. + :keyword token_refresher: The sync token refresher to provide capacity to fetch a fresh token. + The returned token must be valid (expiration date must be in the future). + :paramtype token_refresher: Callable[[], AccessToken] + :keyword bool proactive_refresh: Whether to refresh the token proactively or not. + If the proactive refreshing is enabled ('proactive_refresh' is true), the credential will use + a background thread to attempt to refresh the token within 10 minutes before the cached token expires, + the proactive refresh will request a new token by calling the 'token_refresher' callback. + When 'proactive_refresh' is enabled, the Credential object must be either run within a context manager + or the 'close' method must be called once the object usage has been finished. + :raises: TypeError if paramater 'token' is not a string + :raises: ValueError if the 'proactive_refresh' is enabled without providing the 'token_refresher' callable. + """ + + _ON_DEMAND_REFRESHING_INTERVAL_MINUTES = 2 + _DEFAULT_AUTOREFRESH_INTERVAL_MINUTES = 10 + + def __init__(self, token: str, **kwargs: Any): + if not isinstance(token, six.string_types): + raise TypeError("Token must be a string.") + self._token = create_access_token(token) + self._token_refresher = kwargs.pop('token_refresher', None) + self._proactive_refresh = kwargs.pop('proactive_refresh', False) + if(self._proactive_refresh and self._token_refresher is None): + raise ValueError("When 'proactive_refresh' is True, 'token_refresher' must not be None.") + self._timer = None + self._lock = Condition(Lock()) + self._some_thread_refreshing = False + self._is_closed = Event() + + def get_token(self, *scopes, **kwargs): # pylint: disable=unused-argument + # type (*str, **Any) -> AccessToken + """The value of the configured token. + :rtype: ~azure.core.credentials.AccessToken + """ + if self._proactive_refresh and self._is_closed.is_set(): + raise RuntimeError("An instance of CommunicationTokenCredential cannot be reused once it has been closed.") + + if not self._token_refresher or not self._is_token_expiring_soon(self._token): + return self._token + self._update_token_and_reschedule() + return self._token + + def _update_token_and_reschedule(self): + should_this_thread_refresh = False + with self._lock: + while self._is_token_expiring_soon(self._token): + if self._some_thread_refreshing: + if self._is_token_valid(self._token): + return self._token + self._wait_till_lock_owner_finishes_refreshing() + else: + should_this_thread_refresh = True + self._some_thread_refreshing = True + break + + if should_this_thread_refresh: + try: + new_token = self._token_refresher() + if not self._is_token_valid(new_token): + raise ValueError( + "The token returned from the token_refresher is expired.") + with self._lock: + self._token = new_token + self._some_thread_refreshing = False + self._lock.notify_all() + except: + with self._lock: + self._some_thread_refreshing = False + self._lock.notify_all() + raise + if self._proactive_refresh: + self._schedule_refresh() + return self._token + + def _schedule_refresh(self): + if self._is_closed.is_set(): + return + if self._timer is not None: + self._timer.cancel() + + token_ttl = self._token.expires_on - get_current_utc_as_int() + + if self._is_token_expiring_soon(self._token): + # Schedule the next refresh for when it reaches a certain percentage of the remaining lifetime. + timespan = token_ttl // 2 + else: + # Schedule the next refresh for when it gets in to the soon-to-expire window. + timespan = token_ttl - timedelta( + minutes=self._DEFAULT_AUTOREFRESH_INTERVAL_MINUTES).total_seconds() + if timespan <= TIMEOUT_MAX: + self._timer = Timer(timespan, self._update_token_and_reschedule) + self._timer.daemon = True + self._timer.start() + + def _wait_till_lock_owner_finishes_refreshing(self): + self._lock.release() + self._lock.acquire() + + def _is_token_expiring_soon(self, token): + if self._proactive_refresh: + interval = timedelta( + minutes=self._DEFAULT_AUTOREFRESH_INTERVAL_MINUTES) + else: + interval = timedelta( + minutes=self._ON_DEMAND_REFRESHING_INTERVAL_MINUTES) + return ((token.expires_on - get_current_utc_as_int()) + < interval.total_seconds()) + + @classmethod + def _is_token_valid(cls, token): + return get_current_utc_as_int() < token.expires_on + + def __enter__(self): + if self._proactive_refresh: + if self._is_closed.is_set(): + raise RuntimeError( + "An instance of CommunicationTokenCredential cannot be reused once it has been closed.") + self._schedule_refresh() + return self + + def __exit__(self, *args): + self.close() + + def close(self) -> None: + if self._timer is not None: + self._timer.cancel() + self._timer = None + self._is_closed.set() diff --git a/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_shared/user_credential_async.py b/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_shared/user_credential_async.py new file mode 100644 index 000000000000..c41dc363c3e4 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_shared/user_credential_async.py @@ -0,0 +1,151 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- + +from asyncio import Condition, Lock, Event +from datetime import timedelta +from typing import Any +import sys +import six +from .utils import get_current_utc_as_int +from .utils import create_access_token +from .utils_async import AsyncTimer + + +class CommunicationTokenCredential(object): + """Credential type used for authenticating to an Azure Communication service. + :param str token: The token used to authenticate to an Azure Communication service. + :keyword token_refresher: The async token refresher to provide capacity to fetch a fresh token. + The returned token must be valid (expiration date must be in the future). + :paramtype token_refresher: Callable[[], Awaitable[AccessToken]] + :keyword bool proactive_refresh: Whether to refresh the token proactively or not. + If the proactive refreshing is enabled ('proactive_refresh' is true), the credential will use + a background thread to attempt to refresh the token within 10 minutes before the cached token expires, + the proactive refresh will request a new token by calling the 'token_refresher' callback. + When 'proactive_refresh is enabled', the Credential object must be either run within a context manager + or the 'close' method must be called once the object usage has been finished. + :raises: TypeError if paramater 'token' is not a string + :raises: ValueError if the 'proactive_refresh' is enabled without providing the 'token_refresher' function. + """ + + _ON_DEMAND_REFRESHING_INTERVAL_MINUTES = 2 + _DEFAULT_AUTOREFRESH_INTERVAL_MINUTES = 10 + + def __init__(self, token: str, **kwargs: Any): + if not isinstance(token, six.string_types): + raise TypeError("Token must be a string.") + self._token = create_access_token(token) + self._token_refresher = kwargs.pop('token_refresher', None) + self._proactive_refresh = kwargs.pop('proactive_refresh', False) + if(self._proactive_refresh and self._token_refresher is None): + raise ValueError("When 'proactive_refresh' is True, 'token_refresher' must not be None.") + self._timer = None + self._async_mutex = Lock() + if sys.version_info[:3] == (3, 10, 0): + # Workaround for Python 3.10 bug(https://bugs.python.org/issue45416): + getattr(self._async_mutex, '_get_loop', lambda: None)() + self._lock = Condition(self._async_mutex) + self._some_thread_refreshing = False + self._is_closed = Event() + + async def get_token(self, *scopes, **kwargs): # pylint: disable=unused-argument + # type (*str, **Any) -> AccessToken + """The value of the configured token. + :rtype: ~azure.core.credentials.AccessToken + """ + if self._proactive_refresh and self._is_closed.is_set(): + raise RuntimeError("An instance of CommunicationTokenCredential cannot be reused once it has been closed.") + + if not self._token_refresher or not self._is_token_expiring_soon(self._token): + return self._token + await self._update_token_and_reschedule() + return self._token + + async def _update_token_and_reschedule(self): + should_this_thread_refresh = False + async with self._lock: + while self._is_token_expiring_soon(self._token): + if self._some_thread_refreshing: + if self._is_token_valid(self._token): + return self._token + await self._wait_till_lock_owner_finishes_refreshing() + else: + should_this_thread_refresh = True + self._some_thread_refreshing = True + break + + if should_this_thread_refresh: + try: + new_token = await self._token_refresher() + if not self._is_token_valid(new_token): + raise ValueError( + "The token returned from the token_refresher is expired.") + async with self._lock: + self._token = new_token + self._some_thread_refreshing = False + self._lock.notify_all() + except: + async with self._lock: + self._some_thread_refreshing = False + self._lock.notify_all() + raise + if self._proactive_refresh: + self._schedule_refresh() + return self._token + + def _schedule_refresh(self): + if self._is_closed.is_set(): + return + if self._timer is not None: + self._timer.cancel() + + token_ttl = self._token.expires_on - get_current_utc_as_int() + + if self._is_token_expiring_soon(self._token): + # Schedule the next refresh for when it reaches a certain percentage of the remaining lifetime. + timespan = token_ttl // 2 + else: + # Schedule the next refresh for when it gets in to the soon-to-expire window. + timespan = token_ttl - timedelta( + minutes=self._DEFAULT_AUTOREFRESH_INTERVAL_MINUTES).total_seconds() + + self._timer = AsyncTimer(timespan, self._update_token_and_reschedule) + self._timer.start() + + async def _wait_till_lock_owner_finishes_refreshing(self): + + self._lock.release() + await self._lock.acquire() + + def _is_token_expiring_soon(self, token): + if self._proactive_refresh: + interval = timedelta( + minutes=self._DEFAULT_AUTOREFRESH_INTERVAL_MINUTES) + else: + interval = timedelta( + minutes=self._ON_DEMAND_REFRESHING_INTERVAL_MINUTES) + return ((token.expires_on - get_current_utc_as_int()) + < interval.total_seconds()) + + @classmethod + def _is_token_valid(cls, token): + return get_current_utc_as_int() < token.expires_on + + async def __aenter__(self): + if self._proactive_refresh: + if self._is_closed.is_set(): + raise RuntimeError( + "An instance of CommunicationTokenCredential cannot be reused once it has been closed.") + self._schedule_refresh() + return self + + async def __aexit__(self, *args): + await self.close() + + async def close(self) -> None: + if self._timer is not None: + self._timer.cancel() + self._timer = None + self._is_closed.set() diff --git a/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_shared/utils.py b/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_shared/utils.py new file mode 100644 index 000000000000..d08774afd6d7 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_shared/utils.py @@ -0,0 +1,135 @@ +# ------------------------------------------------------------------------ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# ------------------------------------------------------------------------- + +import base64 +import json +import calendar +from typing import (cast, + Tuple, + Union, + ) +from datetime import datetime +from msrest.serialization import TZ_UTC +from azure.core.credentials import AccessToken, AzureKeyCredential + + +def _convert_datetime_to_utc_int(input_datetime): + """ + Converts DateTime in local time to the Epoch in UTC in second. + + :param input_datetime: Input datetime + :type input_datetime: datetime + :return: Integer + :rtype: int + """ + return int(calendar.timegm(input_datetime.utctimetuple())) + + +def parse_connection_str(conn_str): + # type: (str) -> Tuple[str, str, str, str] + if conn_str is None: + raise ValueError( + "Connection string is undefined." + ) + endpoint = None + shared_access_key = None + for element in conn_str.split(";"): + key, _, value = element.partition("=") + if key.lower() == "endpoint": + endpoint = value.rstrip("/") + elif key.lower() == "accesskey": + shared_access_key = value + if not all([endpoint, shared_access_key]): + raise ValueError( + "Invalid connection string. You can get the connection string from your resource page in the Azure Portal. " + "The format should be as follows: endpoint=https:///;accesskey=" + ) + left_slash_pos = cast(str, endpoint).find("//") + if left_slash_pos != -1: + host = cast(str, endpoint)[left_slash_pos + 2:] + else: + host = str(endpoint) + + return host, str(shared_access_key) + + +def get_current_utc_time(): + # type: () -> str + return str(datetime.now(tz=TZ_UTC).strftime("%a, %d %b %Y %H:%M:%S ")) + "GMT" + + +def get_current_utc_as_int(): + # type: () -> int + current_utc_datetime = datetime.utcnow() + return _convert_datetime_to_utc_int(current_utc_datetime) + + +def create_access_token(token): + # type: (str) -> AccessToken + """Creates an instance of azure.core.credentials.AccessToken from a + string token. The input string is jwt token in the following form: + .. + This method looks into the token_payload which is a json and extracts the expiry time + for that token and creates a tuple of type azure.core.credentials.AccessToken + (, ) + :param token: User token + :type token: str + :return: Instance of azure.core.credentials.AccessToken - token and expiry date of it + :rtype: ~azure.core.credentials.AccessToken + """ + + token_parse_err_msg = "Token is not formatted correctly" + parts = token.split(".") + + if len(parts) < 3: + raise ValueError(token_parse_err_msg) + + try: + padded_base64_payload = base64.b64decode( + parts[1] + '==').decode('ascii') + payload = json.loads(padded_base64_payload) + return AccessToken(token, + _convert_datetime_to_utc_int(datetime.fromtimestamp(payload['exp'], TZ_UTC))) + except ValueError as val_error: + raise ValueError(token_parse_err_msg) from val_error + + +def get_authentication_policy( + endpoint, # type: str + credential, # type: Union[TokenCredential, AzureKeyCredential, str] + decode_url=False, # type: bool + is_async=False, # type: bool +): + # type: (...) -> Union[BearerTokenCredentialPolicy, HMACCredentialsPolicy] + """Returns the correct authentication policy based + on which credential is being passed. + :param endpoint: The endpoint to which we are authenticating to. + :type endpoint: str + :param credential: The credential we use to authenticate to the service + :type credential: Union[TokenCredential, AzureKeyCredential, str] + :param isAsync: For async clients there is a need to decode the url + :type bool: isAsync or str + :rtype: ~azure.core.pipeline.policies.BearerTokenCredentialPolicy or + ~azure.communication.callautomation.shared.policy.HMACCredentialsPolicy + """ + + if credential is None: + raise ValueError("Parameter 'credential' must not be None.") + if hasattr(credential, "get_token"): + if is_async: + from azure.core.pipeline.policies import AsyncBearerTokenCredentialPolicy + return AsyncBearerTokenCredentialPolicy( + credential, "https://communication.azure.com//.default") + from azure.core.pipeline.policies import BearerTokenCredentialPolicy + return BearerTokenCredentialPolicy( + credential, "https://communication.azure.com//.default") + if isinstance(credential, (AzureKeyCredential, str)): + from .._shared.policy import HMACCredentialsPolicy + return HMACCredentialsPolicy(endpoint, credential, decode_url=decode_url) + + raise TypeError(f"Unsupported credential: {format(type(credential))}." + "Use an access token string to use HMACCredentialsPolicy" + "or a token credential from azure.identity") diff --git a/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_shared/utils_async.py b/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_shared/utils_async.py new file mode 100644 index 000000000000..86e0e04d273c --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_shared/utils_async.py @@ -0,0 +1,31 @@ +# ------------------------------------------------------------------------ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# ------------------------------------------------------------------------- + +import asyncio + + +class AsyncTimer: + """A non-blocking timer, that calls a function after a specified number of seconds: + :param int interval: time interval in seconds + :param callable callback: function to be called after the interval has elapsed + """ + + def __init__(self, interval, callback): + self._interval = interval + self._callback = callback + self._task = None + + def start(self): + self._task = asyncio.ensure_future(self._job()) + + async def _job(self): + await asyncio.sleep(self._interval) + await self._callback() + + def cancel(self): + if self._task is not None: + self._task.cancel() + self._task = None diff --git a/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_version.py b/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_version.py new file mode 100644 index 000000000000..9320f1e15f35 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_version.py @@ -0,0 +1,9 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- + +VERSION = "1.0.0b1" + +SDK_MONIKER = f"communication-callautomation/{format(VERSION)}" # type: str diff --git a/sdk/ml/azure-ai-ml/tests/featureset/__init__.py b/sdk/communication/azure-communication-callautomation/azure/communication/callautomation/py.typed similarity index 100% rename from sdk/ml/azure-ai-ml/tests/featureset/__init__.py rename to sdk/communication/azure-communication-callautomation/azure/communication/callautomation/py.typed diff --git a/sdk/communication/azure-communication-callautomation/dev_requirements.txt b/sdk/communication/azure-communication-callautomation/dev_requirements.txt new file mode 100644 index 000000000000..798d5914eb22 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/dev_requirements.txt @@ -0,0 +1,6 @@ +-e ../../../tools/azure-sdk-tools +-e ../../identity/azure-identity +-e ../azure-communication-identity +-e ../../../tools/azure-devtools +../../core/azure-core +aiohttp>=3.0 \ No newline at end of file diff --git a/sdk/communication/azure-communication-callautomation/pyproject.toml b/sdk/communication/azure-communication-callautomation/pyproject.toml new file mode 100644 index 000000000000..ff779a518143 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/pyproject.toml @@ -0,0 +1,5 @@ +[tool.azure-sdk-build] +mypy = false +pyright = false +type_check_samples = false +verifytypes = false diff --git a/sdk/communication/azure-communication-callautomation/samples/create_call_sample.py b/sdk/communication/azure-communication-callautomation/samples/create_call_sample.py new file mode 100644 index 000000000000..695aa059990f --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/samples/create_call_sample.py @@ -0,0 +1,38 @@ +# coding: utf-8 + +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- + +import os +import sys +from azure.communication.callautomation import ( + CallAutomationClient, + CallInvite, + CommunicationUserIdentifier +) + +sys.path.append("..") + +class CallAutomationCreateCallSample(object): + + connection_string = os.getenv("COMMUNICATION_CONNECTION_STRING") + + def create_call_to_single(self): + callautomation_client = CallAutomationClient.from_connection_string(self.connection_string) + + # Creating a call + user = CommunicationUserIdentifier("8:acs:123") + call_invite = CallInvite(target=user) + callback_uri = "https://contoso.com/event" + + response = callautomation_client.create_call(call_invite, callback_uri) + + # callconnection id of the call + print(response.call_connection_properties.call_connection_id) + +if __name__ == '__main__': + sample = CallAutomationCreateCallSample() + sample.create_call_to_single() \ No newline at end of file diff --git a/sdk/communication/azure-communication-callautomation/sdk_packaging.toml b/sdk/communication/azure-communication-callautomation/sdk_packaging.toml new file mode 100644 index 000000000000..34e91dfcf6fd --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/sdk_packaging.toml @@ -0,0 +1,7 @@ +[packaging] +auto_update = false +package_name = "azure-communication-callautomation" +package_pprint_name = "Communication Call Automation" +package_doc_id = "" +is_stable = false +is_arm = false \ No newline at end of file diff --git a/sdk/communication/azure-communication-callautomation/setup.py b/sdk/communication/azure-communication-callautomation/setup.py new file mode 100644 index 000000000000..806b7f93bfee --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/setup.py @@ -0,0 +1,76 @@ +from setuptools import setup, find_packages +import os +from io import open +import re + +# example setup.py Feel free to copy the entire "azure-template" folder into a package folder named +# with "azure-". Ensure that the below arguments to setup() are updated to reflect +# your package. + +# this setup.py is set up in a specific way to keep the azure* and azure-mgmt-* namespaces WORKING all the way +# up from python 3.7. Reference here: https://github.com/Azure/azure-sdk-for-python/wiki/Azure-packaging + +PACKAGE_NAME = "azure-communication-callautomation" +PACKAGE_PPRINT_NAME = "Communication Call Automation" + +# a-b-c => a/b/c +package_folder_path = PACKAGE_NAME.replace('-', '/') +# a-b-c => a.b.c +namespace_name = PACKAGE_NAME.replace('-', '.') + +# Version extraction inspired from 'requests' +with open(os.path.join(package_folder_path, '_version.py'), 'r') as fd: + version = re.search(r'^VERSION\s*=\s*[\'"]([^\'"]*)[\'"]', + fd.read(), re.MULTILINE).group(1) +if not version: + raise RuntimeError('Cannot find version information') + +with open('README.md', encoding='utf-8') as f: + long_description = f.read() + +setup( + name=PACKAGE_NAME, + version=version, + description='Microsoft Azure {} Client Library for Python'.format(PACKAGE_PPRINT_NAME), + long_description=long_description, + long_description_content_type='text/markdown', + license='MIT License', + author='Microsoft Corporation', + author_email='azpysdkhelp@microsoft.com', + url='https://github.com/Azure/azure-sdk-for-python', + classifiers=[ + "Development Status :: 4 - Beta", + 'Programming Language :: Python', + "Programming Language :: Python :: 3 :: Only", + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.7', + 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', + 'Programming Language :: Python :: 3.10', + 'License :: OSI Approved :: MIT License', + ], + zip_safe=False, + packages=find_packages(exclude=[ + 'tests', + # Exclude packages that will be covered by PEP420 or nspkg + 'azure', + 'azure.communication' + ]), + python_requires=">=3.7", + include_package_data=True, + package_data={ + 'pytyped': ['py.typed'], + }, + install_requires=[ + "msrest>=0.7.1", + "azure-core<2.0.0,>=1.24.0", + 'six>=1.11.0' + ], + extras_require={ + ":python_version<'3.8'": ["typing-extensions"] + }, + project_urls = { + 'Bug Reports': 'https://github.com/Azure/azure-sdk-for-python/issues', + 'Source': 'https://github.com/Azure/azure-sdk-for-python', + } +) diff --git a/sdk/communication/azure-communication-callautomation/swagger/SWAGGER.md b/sdk/communication/azure-communication-callautomation/swagger/SWAGGER.md new file mode 100644 index 000000000000..0d4434dfb2ff --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/swagger/SWAGGER.md @@ -0,0 +1,34 @@ +# Azure Communication Configuration for Python + +> see https://aka.ms/autorest + +### Setup +```ps +npm install -g autorest +``` + +### Generation +```ps +cd +autorest SWAGGER.md +``` + +### Settings + +```yaml +tag: package-2023-01-15-preview +require: https://raw.githubusercontent.com/williamzhao87/azure-rest-api-specs/0d0cd5af40aa17af76ce0307ac5512351c38e3bc/specification/communication/data-plane/CallAutomation/readme.md +output-folder: ../azure/communication/callautomation/_generated +models-mode: msrest +namespace: azure.communication.callautomation +package-name: azure-communication-callautomation +license-header: MICROSOFT_MIT_NO_VERSION +enable-xml: true +clear-output-folder: true +no-namespace-folders: true +python: true +v3: true +no-async: false +add-credential: false +title: Azure Communication Call Automation Service +``` diff --git a/sdk/communication/azure-communication-callautomation/tests/_shared/__init__.py b/sdk/communication/azure-communication-callautomation/tests/_shared/__init__.py new file mode 100644 index 000000000000..841b812e10ba --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/tests/_shared/__init__.py @@ -0,0 +1,6 @@ +# coding: utf-8 +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- \ No newline at end of file diff --git a/sdk/communication/azure-communication-callautomation/tests/_shared/async_fake_token_credential.py b/sdk/communication/azure-communication-callautomation/tests/_shared/async_fake_token_credential.py new file mode 100644 index 000000000000..53fb4d103c9b --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/tests/_shared/async_fake_token_credential.py @@ -0,0 +1,14 @@ + +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +from azure.core.credentials import AccessToken + +class AsyncFakeTokenCredential(object): + def __init__(self): + self.token = AccessToken("Fake Token", 0) + + async def get_token(self, *args): + return self.token diff --git a/sdk/communication/azure-communication-callautomation/tests/_shared/asynctestcase.py b/sdk/communication/azure-communication-callautomation/tests/_shared/asynctestcase.py new file mode 100644 index 000000000000..4c331bb79598 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/tests/_shared/asynctestcase.py @@ -0,0 +1,26 @@ +# coding: utf-8 +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import functools +import asyncio +from azure_devtools.scenario_tests.utilities import trim_kwargs_from_test_function +from .testcase import CommunicationTestCase + +class AsyncCommunicationTestCase(CommunicationTestCase): + + @staticmethod + def await_prepared_test(test_fn): + """Synchronous wrapper for async test methods. Used to avoid making changes + upstream to AbstractPreparer (which doesn't await the functions it wraps) + """ + + @functools.wraps(test_fn) + def run(test_class_instance, *args, **kwargs): + trim_kwargs_from_test_function(test_fn, kwargs) + loop = asyncio.get_event_loop() + return loop.run_until_complete(test_fn(test_class_instance, **kwargs)) + + return run \ No newline at end of file diff --git a/sdk/communication/azure-communication-callautomation/tests/_shared/communication_service_preparer.py b/sdk/communication/azure-communication-callautomation/tests/_shared/communication_service_preparer.py new file mode 100644 index 000000000000..4f8eccb5d19f --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/tests/_shared/communication_service_preparer.py @@ -0,0 +1,12 @@ +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ + +import functools +from devtools_testutils import PowerShellPreparer + +CommunicationPreparer = functools.partial( + PowerShellPreparer, "communication", + communication_livetest_dynamic_connection_string="endpoint=https://sanitized.communication.azure.com/;accesskey=fake===" +) diff --git a/sdk/communication/azure-communication-callautomation/tests/_shared/fake_token_credential.py b/sdk/communication/azure-communication-callautomation/tests/_shared/fake_token_credential.py new file mode 100644 index 000000000000..eac266e8ed5c --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/tests/_shared/fake_token_credential.py @@ -0,0 +1,14 @@ + +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +from azure.core.credentials import AccessToken + +class FakeTokenCredential(object): + def __init__(self): + self.token = AccessToken("Fake Token", 0) + + def get_token(self, *args): + return self.token diff --git a/sdk/communication/azure-communication-callautomation/tests/_shared/helper.py b/sdk/communication/azure-communication-callautomation/tests/_shared/helper.py new file mode 100644 index 000000000000..9b7b9fc179e6 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/tests/_shared/helper.py @@ -0,0 +1,74 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import re +import base64 +from azure_devtools.scenario_tests import RecordingProcessor +from datetime import datetime, timedelta +from functools import wraps +from urllib.parse import urlparse +import sys + +def generate_token_with_custom_expiry(valid_for_seconds): + return generate_token_with_custom_expiry_epoch((datetime.now() + timedelta(seconds=valid_for_seconds)).timestamp()) + +def generate_token_with_custom_expiry_epoch(expires_on_epoch): + expiry_json = f'{{"exp": {str(expires_on_epoch)} }}' + base64expiry = base64.b64encode( + expiry_json.encode('utf-8')).decode('utf-8').rstrip("=") + token_template = (f'''eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9. + {base64expiry}.adM-ddBZZlQ1WlN3pdPBOF5G4Wh9iZpxNP_fSvpF4cWs''') + return token_template + + +class URIIdentityReplacer(RecordingProcessor): + """Replace the identity in request uri""" + def process_request(self, request): + resource = (urlparse(request.uri).netloc).split('.')[0] + request.uri = re.sub('/identities/([^/?]+)', '/identities/sanitized', request.uri) + request.uri = re.sub(resource, 'sanitized', request.uri) + request.uri = re.sub('/identities/([^/?]+)', '/identities/sanitized', request.uri) + request.uri = re.sub(resource, 'sanitized', request.uri) + return request + + def process_response(self, response): + if 'url' in response: + response['url'] = re.sub('/identities/([^/?]+)', '/identities/sanitized', response['url']) + return response + +class URIMsalUsernameReplacer(RecordingProcessor): + """Replace the MSAL username in request uri""" + def process_request(self, request): + resource = (urlparse(request.uri).netloc).split('.')[0] + request.uri = re.sub('common/userrealm/([^/.]+)', 'common/userrealm/sanitized@test', request.uri) + request.uri = re.sub(resource, 'sanitized', request.uri) + return request + + def process_response(self, response): + if 'url' in response: + response['url'] = re.sub('common/userrealm/([^/.]+)', 'common/userrealm/sanitized@test', response['url']) + return response + +class URIReplacerProcessor(RecordingProcessor): + def __init__(self, keys=None, replacement="sanitized"): + self._keys = keys if keys else [] + self._replacement = replacement + + def process_request(self, request): + request.uri = re.sub( + "https://([^/?])*.communication", + "https://sanitized.communication", + request.uri, + ) + return request + + def process_response(self, response): + if 'url' in response : + response['url'] = re.sub( + "https://([^/?])*.communication", + "https://sanitized.communication", + response['url'], + ) + return response \ No newline at end of file diff --git a/sdk/communication/azure-communication-callautomation/tests/_shared/testcase.py b/sdk/communication/azure-communication-callautomation/tests/_shared/testcase.py new file mode 100644 index 000000000000..3ce591594b2a --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/tests/_shared/testcase.py @@ -0,0 +1,109 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import os +import re +from enum import auto, Enum +from devtools_testutils import AzureTestCase +from azure.communication.callautomation._shared.utils import parse_connection_str +from azure_devtools.scenario_tests import RecordingProcessor, ReplayableTest +from azure_devtools.scenario_tests.utilities import is_text_payload + +class ResponseReplacerProcessor(RecordingProcessor): + def __init__(self, keys=None, replacement="sanitized"): + self._keys = keys if keys else [] + self._replacement = replacement + + def process_response(self, response): + def sanitize_dict(dictionary): + for key in dictionary: + value = dictionary[key] + if isinstance(value, str): + dictionary[key] = re.sub( + r"("+'|'.join(self._keys)+r")", + self._replacement, + dictionary[key]) + elif isinstance(value, dict): + sanitize_dict(value) + + sanitize_dict(response) + + return response + +class BodyReplacerProcessor(RecordingProcessor): + """Sanitize the sensitive info inside request or response bodies""" + + def __init__(self, keys=None, replacement="sanitized"): + self._replacement = replacement + self._keys = keys if keys else [] + + def process_request(self, request): + if is_text_payload(request) and request.body: + request.body = self._replace_keys(request.body.decode()).encode() + + return request + + def process_response(self, response): + if is_text_payload(response) and response['body']['string']: + response['body']['string'] = self._replace_keys(response['body']['string']) + + return response + + def _replace_keys(self, body): + def _replace_recursively(obj): + if isinstance(obj, dict): + for key in obj: + value = obj[key] + if key in self._keys: + obj[key] = self._replacement + elif key == 'iceServers': + _replace_recursively(value[0]) + elif key == 'urls': + obj[key][0] = "turn.skype.com" + else: + _replace_recursively(value) + elif isinstance(obj, list): + for i in obj: + _replace_recursively(i) + + import json + try: + body = json.loads(body) + _replace_recursively(body) + + except (KeyError, ValueError): + return body + + return json.dumps(body) + +class CommunicationTestResourceType(Enum): + """Type of ACS resource used for livetests.""" + UNSPECIFIED = auto() + DYNAMIC = auto() + STATIC = auto() + +class CommunicationTestCase(AzureTestCase): + FILTER_HEADERS = ReplayableTest.FILTER_HEADERS + ['x-azure-ref', 'x-ms-content-sha256', 'location'] + + def __init__(self, method_name, *args, **kwargs): + super(CommunicationTestCase, self).__init__(method_name, *args, **kwargs) + + def setUp(self, resource_type=CommunicationTestResourceType.UNSPECIFIED): + super(CommunicationTestCase, self).setUp() + self.connection_str = self._get_connection_str(resource_type) + endpoint, _ = parse_connection_str(self.connection_str) + self._resource_name = endpoint.split(".")[0] + self.scrubber.register_name_pair(self._resource_name, "sanitized") + + def _get_connection_str(self, resource_type): + if self.is_playback(): + return "endpoint=https://sanitized.communication.azure.com/;accesskey=fake===" + if resource_type == CommunicationTestResourceType.UNSPECIFIED: + return os.getenv('COMMUNICATION_LIVETEST_DYNAMIC_CONNECTION_STRING') or \ + os.getenv('COMMUNICATION_LIVETEST_STATIC_CONNECTION_STRING') + if resource_type == CommunicationTestResourceType.DYNAMIC: + return os.getenv('COMMUNICATION_LIVETEST_DYNAMIC_CONNECTION_STRING') + if resource_type == CommunicationTestResourceType.STATIC: + return os.getenv('COMMUNICATION_LIVETEST_STATIC_CONNECTION_STRING') diff --git a/sdk/communication/azure-communication-callautomation/tests/_shared/utils.py b/sdk/communication/azure-communication-callautomation/tests/_shared/utils.py new file mode 100644 index 000000000000..33ef09fca4e1 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/tests/_shared/utils.py @@ -0,0 +1,74 @@ +# ------------------------------------------------------------------------ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# ------------------------------------------------------------------------- +import os +from typing import ( # pylint: disable=unused-import + cast, + Tuple, +) +from azure.core.pipeline.policies import HttpLoggingPolicy, HeadersPolicy + +def create_token_credential(): + # type: () -> FakeTokenCredential or DefaultAzureCredential + from devtools_testutils import is_live + if not is_live(): + from .fake_token_credential import FakeTokenCredential + return FakeTokenCredential() + from azure.identity import DefaultAzureCredential + return DefaultAzureCredential() + +def async_create_token_credential(): + # type: () -> AsyncFakeTokenCredential or DefaultAzureCredential + from devtools_testutils import is_live + if not is_live(): + from .async_fake_token_credential import AsyncFakeTokenCredential + return AsyncFakeTokenCredential() + from azure.identity.aio import DefaultAzureCredential + return DefaultAzureCredential() + +def get_http_logging_policy(**kwargs): + http_logging_policy = HttpLoggingPolicy(**kwargs) + http_logging_policy.allowed_header_names.update( + { + "MS-CV" + } + ) + return http_logging_policy + +def get_header_policy(**kwargs): + header_policy = HeadersPolicy(**kwargs) + + useragent = os.getenv("AZURE_USERAGENT_OVERRIDE") + if useragent: + header_policy.add_header("x-ms-useragent", useragent) + + return header_policy + +def parse_connection_str(conn_str): + # type: (str) -> Tuple[str, str, str, str] + if conn_str is None: + raise ValueError( + "Connection string is undefined." + ) + endpoint = None + shared_access_key = None + for element in conn_str.split(";"): + key, _, value = element.partition("=") + if key.lower() == "endpoint": + endpoint = value.rstrip("/") + elif key.lower() == "accesskey": + shared_access_key = value + if not all([endpoint, shared_access_key]): + raise ValueError( + "Invalid connection string. You can get the connection string from your resource page in the Azure Portal. " + "The format should be as follows: endpoint=https:///;accesskey=" + ) + left_slash_pos = cast(str, endpoint).find("//") + if left_slash_pos != -1: + host = cast(str, endpoint)[left_slash_pos + 2:] + else: + host = str(endpoint) + + return host, str(shared_access_key) \ No newline at end of file diff --git a/sdk/communication/azure-communication-callautomation/tests/callautomation_test_case.py b/sdk/communication/azure-communication-callautomation/tests/callautomation_test_case.py new file mode 100644 index 000000000000..3d557eb5a9e3 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/tests/callautomation_test_case.py @@ -0,0 +1,28 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import os +from typing import TYPE_CHECKING, Any, Dict, Optional # pylint: disable=unused-import +from _shared.testcase import CommunicationTestCase +from azure.communication.callautomation import CallAutomationClient + +class CallAutomationTestCase(CommunicationTestCase): + def __init__(self, method_name, **kwargs): + super(CallAutomationTestCase, self).__init__(method_name, **kwargs) + def create_client(self, endpoint): + credential = self.get_credential(CallAutomationClient) + return self.create_client_from_credential( + CallAutomationClient, + credential=credential, + endpoint=endpoint, + ) + def _get_connection_str(self, resource_type): + if self.is_playback(): + return "endpoint=https://sanitized.communication.azure.com/;accesskey=fake===" + else: + con_str = os.getenv('COMMUNICATION_CONNECTION_STRING_CALLAUTOMATION') + if con_str == None: + return super(CallAutomationTestCase, self)._get_connection_str(resource_type) + return con_str \ No newline at end of file diff --git a/sdk/communication/azure-communication-callautomation/tests/test_callautomation_client.py b/sdk/communication/azure-communication-callautomation/tests/test_callautomation_client.py new file mode 100644 index 000000000000..910aaacf3e31 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/tests/test_callautomation_client.py @@ -0,0 +1,55 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import unittest + +from typing import TYPE_CHECKING, Any, Dict, Optional # pylint: disable=unused-import +from azure.core.credentials import AzureKeyCredential +from azure.communication.callautomation import ( + CallAutomationClient, + CallInvite, + CommunicationUserIdentifier +) + +from unittest_helpers import mock_response + +from unittest.mock import Mock + +class TestCallAutomationClient(unittest.TestCase): + call_connection_id = "10000000-0000-0000-0000-000000000000" + server_callI_id = "12345" + callback_uri = "https://contoso.com/event" + communication_user_id = "8:acs:123" + communication_user_source_id = "8:acs:456" + + def test_create_call(self): + raised = False + + def mock_send(*_, **__): + return mock_response(status_code=201, json_payload={ + "callConnectionId": self.call_connection_id, + "serverCallId": self.server_callI_id, + "callbackUri": self.callback_uri, + "targets": [{"rawId": self.communication_user_id, "communicationUser": { "id": self.communication_user_id }}], + "sourceIdentity": {"rawId": self.communication_user_source_id,"communicationUser": {"id": self.communication_user_source_id}}}) + + # target endpoint for ACS User + user = CommunicationUserIdentifier(self.communication_user_id) + + # make invitation + call_invite = CallInvite(target=user) + + callautomation_client = CallAutomationClient("https://endpoint", AzureKeyCredential("fakeCredential=="), transport=Mock(send=mock_send)) + response = None + try: + response = callautomation_client.create_call(call_invite, self.callback_uri) + except: + raised = True + raise + + self.assertFalse(raised, 'Expected is no excpetion raised') + self.assertEqual(self.call_connection_id, response.call_connection_properties.call_connection_id) + self.assertEqual(self.server_callI_id, response.call_connection_properties.server_call_id) + self.assertEqual(self.callback_uri, response.call_connection_properties.callback_uri) \ No newline at end of file diff --git a/sdk/communication/azure-communication-callautomation/tests/unittest_helpers.py b/sdk/communication/azure-communication-callautomation/tests/unittest_helpers.py new file mode 100644 index 000000000000..9d24a0aa86eb --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/tests/unittest_helpers.py @@ -0,0 +1,20 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import json + +from unittest import mock + +def mock_response(status_code=200, headers=None, json_payload=None): + response = mock.Mock(status_code=status_code, headers=headers or {}) + if json_payload is not None: + response.text = lambda encoding=None: json.dumps(json_payload) + response.headers["content-type"] = "application/json" + response.content_type = "application/json" + else: + response.text = lambda encoding=None: "" + response.headers["content-type"] = "text/plain" + response.content_type = "text/plain" + return response diff --git a/sdk/communication/azure-communication-chat/README.md b/sdk/communication/azure-communication-chat/README.md index 3912c800bb45..8d94f22ac6dd 100644 --- a/sdk/communication/azure-communication-chat/README.md +++ b/sdk/communication/azure-communication-chat/README.md @@ -3,7 +3,11 @@ This package contains a Python SDK for Azure Communication Services for Chat. Read more about Azure Communication Services [here](https://docs.microsoft.com/azure/communication-services/overview) -[Source code](https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/communication/azure-communication-chat) | [Package (Pypi)](https://pypi.org/project/azure-communication-chat/) | [API reference documentation](https://azuresdkdocs.blob.core.windows.net/$web/python/azure-communication-chat/1.0.0b5/index.html) | [Product documentation](https://docs.microsoft.com/azure/communication-services/) +[Source code](https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/communication/azure-communication-chat) +| [Package (Pypi)](https://pypi.org/project/azure-communication-chat/) +| [Package (Conda)](https://anaconda.org/microsoft/azure-communication/) +| [API reference documentation](https://azuresdkdocs.blob.core.windows.net/$web/python/azure-communication-chat/1.0.0b5/index.html) +| [Product documentation](https://docs.microsoft.com/azure/communication-services/) ## _Disclaimer_ diff --git a/sdk/communication/azure-communication-chat/tests.yml b/sdk/communication/azure-communication-chat/tests.yml index 75731ab2906c..e6c6ac25eb06 100644 --- a/sdk/communication/azure-communication-chat/tests.yml +++ b/sdk/communication/azure-communication-chat/tests.yml @@ -19,3 +19,5 @@ stages: - $(sub-config-communication-int-test-resources-common) - $(sub-config-communication-int-test-resources-python) Clouds: Public,Int + TestResourceDirectories: + - communication/test-resources/ diff --git a/sdk/communication/azure-communication-email/CHANGELOG.md b/sdk/communication/azure-communication-email/CHANGELOG.md index 3366b3c19bf0..c7630531abaa 100644 --- a/sdk/communication/azure-communication-email/CHANGELOG.md +++ b/sdk/communication/azure-communication-email/CHANGELOG.md @@ -1,5 +1,15 @@ # Release History +## 1.0.0b3 (Unreleased) + +### Features Added + +### Breaking Changes + +### Bugs Fixed + +### Other Changes + ## 1.0.0b2 (2023-03-01) ### Features Added diff --git a/sdk/communication/azure-communication-email/azure/communication/email/_version.py b/sdk/communication/azure-communication-email/azure/communication/email/_version.py index 35c017c02a3f..7146df2de5b0 100644 --- a/sdk/communication/azure-communication-email/azure/communication/email/_version.py +++ b/sdk/communication/azure-communication-email/azure/communication/email/_version.py @@ -6,6 +6,6 @@ # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- -VERSION = "1.0.0b2" +VERSION = "1.0.0b3" SDK_MONIKER = "communication-email/{}".format(VERSION) # type: str diff --git a/sdk/communication/test-resources.json b/sdk/communication/azure-communication-email/test-resources.json similarity index 100% rename from sdk/communication/test-resources.json rename to sdk/communication/azure-communication-email/test-resources.json diff --git a/sdk/communication/azure-communication-email/tests.yml b/sdk/communication/azure-communication-email/tests.yml index bb35b376d96c..8d9607c446b3 100644 --- a/sdk/communication/azure-communication-email/tests.yml +++ b/sdk/communication/azure-communication-email/tests.yml @@ -12,9 +12,19 @@ stages: - $(sub-config-azure-cloud-test-resources) - $(sub-config-communication-services-cloud-test-resources-common) - $(sub-config-communication-services-cloud-test-resources-python) + Int: + SubscriptionConfigurations: + - $(sub-config-communication-int-test-resources-common) + - $(sub-config-communication-int-test-resources-python) + PPE: + SubscriptionConfigurations: + - $(sub-config-communication-ppe-test-resources-common) + - $(sub-config-communication-ppe-test-resources-python) MatrixReplace: - TestSamples=.*/true - Clouds: Public + Clouds: 'Public,PPE,Int' EnvVars: AZURE_SKIP_LIVE_RECORDING: 'True' AZURE_TEST_RUN_LIVE: 'true' + TestResourceDirectories: + - communication/azure-communication-email/ diff --git a/sdk/communication/azure-communication-identity/README.md b/sdk/communication/azure-communication-identity/README.md index 6a79a6afbe0b..790e0798fca0 100644 --- a/sdk/communication/azure-communication-identity/README.md +++ b/sdk/communication/azure-communication-identity/README.md @@ -2,7 +2,11 @@ Azure Communication Identity client package is intended to be used to setup the basics for opening a way to use Azure Communication Service offerings. This package helps to create identity user tokens to be used by other client packages such as chat, calling, sms. -[Source code](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/communication/azure-communication-identity) | [Package (Pypi)](https://pypi.org/project/azure-communication-identity/) | [API reference documentation](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/communication/azure-communication-identity) | [Product documentation](https://docs.microsoft.com/azure/communication-services/quickstarts/access-tokens?pivots=programming-language-python) +[Source code](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/communication/azure-communication-identity) +| [Package (Pypi)](https://pypi.org/project/azure-communication-identity/) +| [Package (Conda)](https://anaconda.org/microsoft/azure-communication/) +| [API reference documentation](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/communication/azure-communication-identity) +| [Product documentation](https://docs.microsoft.com/azure/communication-services/quickstarts/access-tokens?pivots=programming-language-python) ## _Disclaimer_ diff --git a/sdk/communication/azure-communication-identity/tests.yml b/sdk/communication/azure-communication-identity/tests.yml index 254a5634baa4..058c7f9ab01f 100644 --- a/sdk/communication/azure-communication-identity/tests.yml +++ b/sdk/communication/azure-communication-identity/tests.yml @@ -26,3 +26,5 @@ stages: EnvVars: AZURE_SKIP_LIVE_RECORDING: 'True' AZURE_TEST_RUN_LIVE: 'true' + TestResourceDirectories: + - communication/test-resources/ diff --git a/sdk/communication/azure-communication-networktraversal/tests.yml b/sdk/communication/azure-communication-networktraversal/tests.yml index 122fe6170843..8e37ea332098 100644 --- a/sdk/communication/azure-communication-networktraversal/tests.yml +++ b/sdk/communication/azure-communication-networktraversal/tests.yml @@ -19,3 +19,5 @@ stages: - $(sub-config-communication-int-test-resources-common) - $(sub-config-communication-int-test-resources-python) Clouds: Public + TestResourceDirectories: + - communication/test-resources/ diff --git a/sdk/communication/azure-communication-phonenumbers/CHANGELOG.md b/sdk/communication/azure-communication-phonenumbers/CHANGELOG.md index fbc4e4d70605..33c99763e247 100644 --- a/sdk/communication/azure-communication-phonenumbers/CHANGELOG.md +++ b/sdk/communication/azure-communication-phonenumbers/CHANGELOG.md @@ -4,6 +4,8 @@ ### Features Added - API version `2022-12-01` is now the default for Phone Numbers clients. +- Added support for SIP routing API version `2023-03-01`, releasing SIP routing functionality from public preview to GA. +- Added environment variable `AZURE_TEST_DOMAIN` for SIP routing tests to support domain verification. ### Breaking Changes diff --git a/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/_phone_numbers_client.py b/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/_phone_numbers_client.py index 84f772707ccd..72e0a4b4d47e 100644 --- a/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/_phone_numbers_client.py +++ b/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/_phone_numbers_client.py @@ -13,7 +13,6 @@ PhoneNumberCapabilitiesRequest, PhoneNumberPurchaseRequest, PhoneNumberType, - PhoneNumberAssignmentType ) from ._shared.utils import parse_connection_str, get_authentication_policy from ._version import SDK_MONIKER @@ -55,7 +54,6 @@ def __init__( self, endpoint, # type: str credential, # type: Union[TokenCredential, AzureKeyCredential] - accepted_language=None, # type: str **kwargs # type: Any ): # type: (...) -> None @@ -70,7 +68,7 @@ def __init__( "You need to provide account shared key to authenticate.") self._endpoint = endpoint - self._accepted_language = accepted_language + self._accepted_language = kwargs.pop("accepted_language", None) self._api_version = kwargs.pop("api_version", DEFAULT_VERSION.value) self._phone_number_client = PhoneNumbersClientGen( self._endpoint, @@ -386,8 +384,6 @@ def list_available_area_codes( self, country_code, # type: str phone_number_type, # type: PhoneNumberType - assignment_type=None, # type: PhoneNumberAssignmentType - locality=None, # type: str **kwargs # type: Any ): # type: (...) -> ItemPaged[PhoneNumberAreaCode] @@ -417,8 +413,10 @@ def list_available_area_codes( return self._phone_number_client.phone_numbers.list_area_codes( country_code, phone_number_type=phone_number_type, - assignment_type=assignment_type, - locality=locality, + assignment_type=kwargs.pop( + "assignment_type", None), + locality=kwargs.pop( + "locality", None), administrative_division=kwargs.pop( "administrative_division", None), **kwargs diff --git a/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/aio/_phone_numbers_client_async.py b/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/aio/_phone_numbers_client_async.py index 18a00f35874a..007569cacc14 100644 --- a/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/aio/_phone_numbers_client_async.py +++ b/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/aio/_phone_numbers_client_async.py @@ -7,15 +7,12 @@ from typing import TYPE_CHECKING, Union from azure.core.tracing.decorator import distributed_trace from azure.core.tracing.decorator_async import distributed_trace_async -from azure.core.paging import ItemPaged -from azure.core.polling import LROPoller from .._generated.aio._client import PhoneNumbersClient as PhoneNumbersClientGen from .._generated.models import ( PhoneNumberSearchRequest, PhoneNumberCapabilitiesRequest, PhoneNumberPurchaseRequest, PhoneNumberType, - PhoneNumberAssignmentType ) from .._shared.utils import parse_connection_str, get_authentication_policy from .._version import SDK_MONIKER @@ -56,8 +53,7 @@ class PhoneNumbersClient(object): def __init__( self, endpoint, # type: str - credential, # type: AsyncTokenCredential - accepted_language=None, + credential, # type: Union[AsyncTokenCredential, AzureKeyCredential] **kwargs # type: Any ): # type: (...) -> None @@ -72,7 +68,7 @@ def __init__( "You need to provide account shared key to authenticate.") self._endpoint = endpoint - self._accepted_language = accepted_language + self._accepted_language = kwargs.pop("accepted_language", None) self._api_version = kwargs.pop("api_version", DEFAULT_VERSION.value) self._phone_number_client = PhoneNumbersClientGen( self._endpoint, @@ -385,11 +381,9 @@ def list_available_area_codes( self, country_code, # type: str phone_number_type, # type: PhoneNumberType - assignment_type=None, # type: PhoneNumberAssignmentType - locality=None, # type: str **kwargs # type: Any ): - # type: (...) -> ItemPaged[PhoneNumberAreaCode] + # type: (...) -> AsyncItemPaged[PhoneNumberAreaCode] """Gets the list of available area codes. :param country_code: The ISO 3166-2 country/region two letter code, e.g. US. Required. @@ -416,8 +410,10 @@ def list_available_area_codes( return self._phone_number_client.phone_numbers.list_area_codes( country_code, phone_number_type=phone_number_type, - assignment_type=assignment_type, - locality=locality, + assignment_type=kwargs.pop( + "assignment_type", None), + locality=kwargs.pop( + "locality", None), administrative_division=kwargs.pop( "administrative_division", None), **kwargs diff --git a/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/__init__.py b/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/__init__.py index 5acebe42166f..8a794b0629c3 100644 --- a/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/__init__.py +++ b/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/__init__.py @@ -6,8 +6,7 @@ from ._sip_routing_client import SipRoutingClient -from ._generated.models import SipTrunkRoute -from ._models import SipTrunk +from ._models import SipTrunk, SipTrunkRoute __all__ = [ 'SipRoutingClient', diff --git a/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_generated/__init__.py b/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_generated/__init__.py index 4fd624f506ea..f5f8d85781b7 100644 --- a/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_generated/__init__.py +++ b/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_generated/__init__.py @@ -6,10 +6,18 @@ # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- -from ._sip_routing_service import SIPRoutingService -__all__ = ['SIPRoutingService'] +from ._client import SIPRoutingService -# `._patch.py` is used for handwritten extensions to the generated code -# Example: https://github.com/Azure/azure-sdk-for-python/blob/main/doc/dev/customize_code/how-to-patch-sdk-code.md -from ._patch import patch_sdk -patch_sdk() +try: + from ._patch import __all__ as _patch_all + from ._patch import * # pylint: disable=unused-wildcard-import +except ImportError: + _patch_all = [] +from ._patch import patch_sdk as _patch_sdk + +__all__ = [ + "SIPRoutingService", +] +__all__.extend([p for p in _patch_all if p not in __all__]) + +_patch_sdk() diff --git a/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_generated/_sip_routing_service.py b/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_generated/_client.py similarity index 59% rename from sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_generated/_sip_routing_service.py rename to sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_generated/_client.py index 4307dbdbc139..a208014817ab 100644 --- a/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_generated/_sip_routing_service.py +++ b/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_generated/_client.py @@ -7,64 +7,54 @@ # -------------------------------------------------------------------------- from copy import deepcopy -from typing import TYPE_CHECKING - -from msrest import Deserializer, Serializer +from typing import Any from azure.core import PipelineClient +from azure.core.rest import HttpRequest, HttpResponse -from . import models +from . import models as _models from ._configuration import SIPRoutingServiceConfiguration -from .operations import SIPRoutingServiceOperationsMixin - -if TYPE_CHECKING: - # pylint: disable=unused-import,ungrouped-imports - from typing import Any +from ._serialization import Deserializer, Serializer +from .operations import SipRoutingOperations - from azure.core.rest import HttpRequest, HttpResponse -class SIPRoutingService(SIPRoutingServiceOperationsMixin): +class SIPRoutingService: # pylint: disable=client-accepts-api-version-keyword """SipRouting Service. + :ivar sip_routing: SipRoutingOperations operations + :vartype sip_routing: + azure.communication.phonenumbers.siprouting.operations.SipRoutingOperations :param endpoint: The communication resource, for example - https://resourcename.communication.azure.com. + https://resourcename.communication.azure.com. Required. :type endpoint: str - :keyword api_version: Api Version. Default value is "2021-05-01-preview". Note that overriding - this default value may result in unsupported behavior. + :keyword api_version: Api Version. Default value is "2023-03-01". Note that overriding this + default value may result in unsupported behavior. :paramtype api_version: str """ - def __init__( - self, - endpoint, # type: str - **kwargs # type: Any - ): - # type: (...) -> None - _base_url = '{endpoint}' + def __init__( # pylint: disable=missing-client-constructor-parameter-credential + self, endpoint: str, **kwargs: Any + ) -> None: + _endpoint = "{endpoint}" self._config = SIPRoutingServiceConfiguration(endpoint=endpoint, **kwargs) - self._client = PipelineClient(base_url=_base_url, config=self._config, **kwargs) + self._client: PipelineClient = PipelineClient(base_url=_endpoint, config=self._config, **kwargs) - client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)} + client_models = {k: v for k, v in _models.__dict__.items() if isinstance(v, type)} self._serialize = Serializer(client_models) self._deserialize = Deserializer(client_models) self._serialize.client_side_validation = False + self.sip_routing = SipRoutingOperations(self._client, self._config, self._serialize, self._deserialize) - - def _send_request( - self, - request, # type: HttpRequest - **kwargs # type: Any - ): - # type: (...) -> HttpResponse + def send_request(self, request: HttpRequest, **kwargs: Any) -> HttpResponse: """Runs the network request through the client's chained policies. >>> from azure.core.rest import HttpRequest >>> request = HttpRequest("GET", "https://www.example.org/") - >>> response = client._send_request(request) + >>> response = client.send_request(request) - For more information on this code flow, see https://aka.ms/azsdk/python/protocol/quickstart + For more information on this code flow, see https://aka.ms/azsdk/dpcodegen/python/send_request :param request: The network request you want to make. Required. :type request: ~azure.core.rest.HttpRequest @@ -75,21 +65,18 @@ def _send_request( request_copy = deepcopy(request) path_format_arguments = { - "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, 'str', skip_quote=True), + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), } request_copy.url = self._client.format_url(request_copy.url, **path_format_arguments) return self._client.send_request(request_copy, **kwargs) - def close(self): - # type: () -> None + def close(self) -> None: self._client.close() - def __enter__(self): - # type: () -> SIPRoutingService + def __enter__(self) -> "SIPRoutingService": self._client.__enter__() return self - def __exit__(self, *exc_details): - # type: (Any) -> None + def __exit__(self, *exc_details: Any) -> None: self._client.__exit__(*exc_details) diff --git a/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_generated/_configuration.py b/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_generated/_configuration.py index fc539cb35bc7..f5f875c5bae8 100644 --- a/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_generated/_configuration.py +++ b/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_generated/_configuration.py @@ -6,17 +6,20 @@ # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- -from typing import TYPE_CHECKING +import sys +from typing import Any from azure.core.configuration import Configuration from azure.core.pipeline import policies -if TYPE_CHECKING: - # pylint: disable=unused-import,ungrouped-imports - from typing import Any +if sys.version_info >= (3, 8): + from typing import Literal # pylint: disable=no-name-in-module, ungrouped-imports +else: + from typing_extensions import Literal # type: ignore # pylint: disable=ungrouped-imports VERSION = "unknown" + class SIPRoutingServiceConfiguration(Configuration): # pylint: disable=too-many-instance-attributes """Configuration for SIPRoutingService. @@ -24,41 +27,32 @@ class SIPRoutingServiceConfiguration(Configuration): # pylint: disable=too-many attributes. :param endpoint: The communication resource, for example - https://resourcename.communication.azure.com. + https://resourcename.communication.azure.com. Required. :type endpoint: str - :keyword api_version: Api Version. Default value is "2021-05-01-preview". Note that overriding - this default value may result in unsupported behavior. + :keyword api_version: Api Version. Default value is "2023-03-01". Note that overriding this + default value may result in unsupported behavior. :paramtype api_version: str """ - def __init__( - self, - endpoint, # type: str - **kwargs # type: Any - ): - # type: (...) -> None + def __init__(self, endpoint: str, **kwargs: Any) -> None: super(SIPRoutingServiceConfiguration, self).__init__(**kwargs) - api_version = kwargs.pop('api_version', "2021-05-01-preview") # type: str + api_version: Literal["2023-03-01"] = kwargs.pop("api_version", "2023-03-01") if endpoint is None: raise ValueError("Parameter 'endpoint' must not be None.") self.endpoint = endpoint self.api_version = api_version - kwargs.setdefault('sdk_moniker', 'siproutingservice/{}'.format(VERSION)) + kwargs.setdefault("sdk_moniker", "siproutingservice/{}".format(VERSION)) self._configure(**kwargs) - def _configure( - self, - **kwargs # type: Any - ): - # type: (...) -> None - self.user_agent_policy = kwargs.get('user_agent_policy') or policies.UserAgentPolicy(**kwargs) - self.headers_policy = kwargs.get('headers_policy') or policies.HeadersPolicy(**kwargs) - self.proxy_policy = kwargs.get('proxy_policy') or policies.ProxyPolicy(**kwargs) - self.logging_policy = kwargs.get('logging_policy') or policies.NetworkTraceLoggingPolicy(**kwargs) - self.http_logging_policy = kwargs.get('http_logging_policy') or policies.HttpLoggingPolicy(**kwargs) - self.retry_policy = kwargs.get('retry_policy') or policies.RetryPolicy(**kwargs) - self.custom_hook_policy = kwargs.get('custom_hook_policy') or policies.CustomHookPolicy(**kwargs) - self.redirect_policy = kwargs.get('redirect_policy') or policies.RedirectPolicy(**kwargs) - self.authentication_policy = kwargs.get('authentication_policy') + def _configure(self, **kwargs: Any) -> None: + self.user_agent_policy = kwargs.get("user_agent_policy") or policies.UserAgentPolicy(**kwargs) + self.headers_policy = kwargs.get("headers_policy") or policies.HeadersPolicy(**kwargs) + self.proxy_policy = kwargs.get("proxy_policy") or policies.ProxyPolicy(**kwargs) + self.logging_policy = kwargs.get("logging_policy") or policies.NetworkTraceLoggingPolicy(**kwargs) + self.http_logging_policy = kwargs.get("http_logging_policy") or policies.HttpLoggingPolicy(**kwargs) + self.retry_policy = kwargs.get("retry_policy") or policies.RetryPolicy(**kwargs) + self.custom_hook_policy = kwargs.get("custom_hook_policy") or policies.CustomHookPolicy(**kwargs) + self.redirect_policy = kwargs.get("redirect_policy") or policies.RedirectPolicy(**kwargs) + self.authentication_policy = kwargs.get("authentication_policy") diff --git a/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_generated/_patch.py b/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_generated/_patch.py index 74e48ecd07cf..f99e77fef986 100644 --- a/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_generated/_patch.py +++ b/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_generated/_patch.py @@ -28,4 +28,4 @@ # This file is used for handwritten extensions to the generated code. Example: # https://github.com/Azure/azure-sdk-for-python/blob/main/doc/dev/customize_code/how-to-patch-sdk-code.md def patch_sdk(): - pass \ No newline at end of file + pass diff --git a/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_generated/_serialization.py b/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_generated/_serialization.py new file mode 100644 index 000000000000..f17c068e833e --- /dev/null +++ b/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_generated/_serialization.py @@ -0,0 +1,1996 @@ +# -------------------------------------------------------------------------- +# +# Copyright (c) Microsoft Corporation. All rights reserved. +# +# The MIT License (MIT) +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the ""Software""), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +# IN THE SOFTWARE. +# +# -------------------------------------------------------------------------- + +# pylint: skip-file +# pyright: reportUnnecessaryTypeIgnoreComment=false + +from base64 import b64decode, b64encode +import calendar +import datetime +import decimal +import email +from enum import Enum +import json +import logging +import re +import sys +import codecs +from typing import ( + Dict, + Any, + cast, + Optional, + Union, + AnyStr, + IO, + Mapping, + Callable, + TypeVar, + MutableMapping, + Type, + List, + Mapping, +) + +try: + from urllib import quote # type: ignore +except ImportError: + from urllib.parse import quote +import xml.etree.ElementTree as ET + +import isodate # type: ignore + +from azure.core.exceptions import DeserializationError, SerializationError, raise_with_traceback +from azure.core.serialization import NULL as AzureCoreNull + +_BOM = codecs.BOM_UTF8.decode(encoding="utf-8") + +ModelType = TypeVar("ModelType", bound="Model") +JSON = MutableMapping[str, Any] + + +class RawDeserializer: + + # Accept "text" because we're open minded people... + JSON_REGEXP = re.compile(r"^(application|text)/([a-z+.]+\+)?json$") + + # Name used in context + CONTEXT_NAME = "deserialized_data" + + @classmethod + def deserialize_from_text(cls, data: Optional[Union[AnyStr, IO]], content_type: Optional[str] = None) -> Any: + """Decode data according to content-type. + + Accept a stream of data as well, but will be load at once in memory for now. + + If no content-type, will return the string version (not bytes, not stream) + + :param data: Input, could be bytes or stream (will be decoded with UTF8) or text + :type data: str or bytes or IO + :param str content_type: The content type. + """ + if hasattr(data, "read"): + # Assume a stream + data = cast(IO, data).read() + + if isinstance(data, bytes): + data_as_str = data.decode(encoding="utf-8-sig") + else: + # Explain to mypy the correct type. + data_as_str = cast(str, data) + + # Remove Byte Order Mark if present in string + data_as_str = data_as_str.lstrip(_BOM) + + if content_type is None: + return data + + if cls.JSON_REGEXP.match(content_type): + try: + return json.loads(data_as_str) + except ValueError as err: + raise DeserializationError("JSON is invalid: {}".format(err), err) + elif "xml" in (content_type or []): + try: + + try: + if isinstance(data, unicode): # type: ignore + # If I'm Python 2.7 and unicode XML will scream if I try a "fromstring" on unicode string + data_as_str = data_as_str.encode(encoding="utf-8") # type: ignore + except NameError: + pass + + return ET.fromstring(data_as_str) # nosec + except ET.ParseError: + # It might be because the server has an issue, and returned JSON with + # content-type XML.... + # So let's try a JSON load, and if it's still broken + # let's flow the initial exception + def _json_attemp(data): + try: + return True, json.loads(data) + except ValueError: + return False, None # Don't care about this one + + success, json_result = _json_attemp(data) + if success: + return json_result + # If i'm here, it's not JSON, it's not XML, let's scream + # and raise the last context in this block (the XML exception) + # The function hack is because Py2.7 messes up with exception + # context otherwise. + _LOGGER.critical("Wasn't XML not JSON, failing") + raise_with_traceback(DeserializationError, "XML is invalid") + raise DeserializationError("Cannot deserialize content-type: {}".format(content_type)) + + @classmethod + def deserialize_from_http_generics(cls, body_bytes: Optional[Union[AnyStr, IO]], headers: Mapping) -> Any: + """Deserialize from HTTP response. + + Use bytes and headers to NOT use any requests/aiohttp or whatever + specific implementation. + Headers will tested for "content-type" + """ + # Try to use content-type from headers if available + content_type = None + if "content-type" in headers: + content_type = headers["content-type"].split(";")[0].strip().lower() + # Ouch, this server did not declare what it sent... + # Let's guess it's JSON... + # Also, since Autorest was considering that an empty body was a valid JSON, + # need that test as well.... + else: + content_type = "application/json" + + if body_bytes: + return cls.deserialize_from_text(body_bytes, content_type) + return None + + +try: + basestring # type: ignore + unicode_str = unicode # type: ignore +except NameError: + basestring = str + unicode_str = str + +_LOGGER = logging.getLogger(__name__) + +try: + _long_type = long # type: ignore +except NameError: + _long_type = int + + +class UTC(datetime.tzinfo): + """Time Zone info for handling UTC""" + + def utcoffset(self, dt): + """UTF offset for UTC is 0.""" + return datetime.timedelta(0) + + def tzname(self, dt): + """Timestamp representation.""" + return "Z" + + def dst(self, dt): + """No daylight saving for UTC.""" + return datetime.timedelta(hours=1) + + +try: + from datetime import timezone as _FixedOffset # type: ignore +except ImportError: # Python 2.7 + + class _FixedOffset(datetime.tzinfo): # type: ignore + """Fixed offset in minutes east from UTC. + Copy/pasted from Python doc + :param datetime.timedelta offset: offset in timedelta format + """ + + def __init__(self, offset): + self.__offset = offset + + def utcoffset(self, dt): + return self.__offset + + def tzname(self, dt): + return str(self.__offset.total_seconds() / 3600) + + def __repr__(self): + return "".format(self.tzname(None)) + + def dst(self, dt): + return datetime.timedelta(0) + + def __getinitargs__(self): + return (self.__offset,) + + +try: + from datetime import timezone + + TZ_UTC = timezone.utc +except ImportError: + TZ_UTC = UTC() # type: ignore + +_FLATTEN = re.compile(r"(? None: + self.additional_properties: Dict[str, Any] = {} + for k in kwargs: + if k not in self._attribute_map: + _LOGGER.warning("%s is not a known attribute of class %s and will be ignored", k, self.__class__) + elif k in self._validation and self._validation[k].get("readonly", False): + _LOGGER.warning("Readonly attribute %s will be ignored in class %s", k, self.__class__) + else: + setattr(self, k, kwargs[k]) + + def __eq__(self, other: Any) -> bool: + """Compare objects by comparing all attributes.""" + if isinstance(other, self.__class__): + return self.__dict__ == other.__dict__ + return False + + def __ne__(self, other: Any) -> bool: + """Compare objects by comparing all attributes.""" + return not self.__eq__(other) + + def __str__(self) -> str: + return str(self.__dict__) + + @classmethod + def enable_additional_properties_sending(cls) -> None: + cls._attribute_map["additional_properties"] = {"key": "", "type": "{object}"} + + @classmethod + def is_xml_model(cls) -> bool: + try: + cls._xml_map # type: ignore + except AttributeError: + return False + return True + + @classmethod + def _create_xml_node(cls): + """Create XML node.""" + try: + xml_map = cls._xml_map # type: ignore + except AttributeError: + xml_map = {} + + return _create_xml_node(xml_map.get("name", cls.__name__), xml_map.get("prefix", None), xml_map.get("ns", None)) + + def serialize(self, keep_readonly: bool = False, **kwargs: Any) -> JSON: + """Return the JSON that would be sent to azure from this model. + + This is an alias to `as_dict(full_restapi_key_transformer, keep_readonly=False)`. + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize(self, keep_readonly=keep_readonly, **kwargs) + + def as_dict( + self, + keep_readonly: bool = True, + key_transformer: Callable[[str, Dict[str, Any], Any], Any] = attribute_transformer, + **kwargs: Any + ) -> JSON: + """Return a dict that can be serialized using json.dump. + + Advanced usage might optionally use a callback as parameter: + + .. code::python + + def my_key_transformer(key, attr_desc, value): + return key + + Key is the attribute name used in Python. Attr_desc + is a dict of metadata. Currently contains 'type' with the + msrest type and 'key' with the RestAPI encoded key. + Value is the current value in this object. + + The string returned will be used to serialize the key. + If the return type is a list, this is considered hierarchical + result dict. + + See the three examples in this file: + + - attribute_transformer + - full_restapi_key_transformer + - last_restapi_key_transformer + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param function key_transformer: A key transformer function. + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize(self, key_transformer=key_transformer, keep_readonly=keep_readonly, **kwargs) + + @classmethod + def _infer_class_models(cls): + try: + str_models = cls.__module__.rsplit(".", 1)[0] + models = sys.modules[str_models] + client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)} + if cls.__name__ not in client_models: + raise ValueError("Not Autorest generated code") + except Exception: + # Assume it's not Autorest generated (tests?). Add ourselves as dependencies. + client_models = {cls.__name__: cls} + return client_models + + @classmethod + def deserialize(cls: Type[ModelType], data: Any, content_type: Optional[str] = None) -> ModelType: + """Parse a str using the RestAPI syntax and return a model. + + :param str data: A str using RestAPI structure. JSON by default. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises: DeserializationError if something went wrong + """ + deserializer = Deserializer(cls._infer_class_models()) + return deserializer(cls.__name__, data, content_type=content_type) + + @classmethod + def from_dict( + cls: Type[ModelType], + data: Any, + key_extractors: Optional[Callable[[str, Dict[str, Any], Any], Any]] = None, + content_type: Optional[str] = None, + ) -> ModelType: + """Parse a dict using given key extractor return a model. + + By default consider key + extractors (rest_key_case_insensitive_extractor, attribute_key_case_insensitive_extractor + and last_rest_key_case_insensitive_extractor) + + :param dict data: A dict using RestAPI structure + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises: DeserializationError if something went wrong + """ + deserializer = Deserializer(cls._infer_class_models()) + deserializer.key_extractors = ( # type: ignore + [ # type: ignore + attribute_key_case_insensitive_extractor, + rest_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + if key_extractors is None + else key_extractors + ) + return deserializer(cls.__name__, data, content_type=content_type) + + @classmethod + def _flatten_subtype(cls, key, objects): + if "_subtype_map" not in cls.__dict__: + return {} + result = dict(cls._subtype_map[key]) + for valuetype in cls._subtype_map[key].values(): + result.update(objects[valuetype]._flatten_subtype(key, objects)) + return result + + @classmethod + def _classify(cls, response, objects): + """Check the class _subtype_map for any child classes. + We want to ignore any inherited _subtype_maps. + Remove the polymorphic key from the initial data. + """ + for subtype_key in cls.__dict__.get("_subtype_map", {}).keys(): + subtype_value = None + + if not isinstance(response, ET.Element): + rest_api_response_key = cls._get_rest_key_parts(subtype_key)[-1] + subtype_value = response.pop(rest_api_response_key, None) or response.pop(subtype_key, None) + else: + subtype_value = xml_key_extractor(subtype_key, cls._attribute_map[subtype_key], response) + if subtype_value: + # Try to match base class. Can be class name only + # (bug to fix in Autorest to support x-ms-discriminator-name) + if cls.__name__ == subtype_value: + return cls + flatten_mapping_type = cls._flatten_subtype(subtype_key, objects) + try: + return objects[flatten_mapping_type[subtype_value]] # type: ignore + except KeyError: + _LOGGER.warning( + "Subtype value %s has no mapping, use base class %s.", + subtype_value, + cls.__name__, + ) + break + else: + _LOGGER.warning("Discriminator %s is absent or null, use base class %s.", subtype_key, cls.__name__) + break + return cls + + @classmethod + def _get_rest_key_parts(cls, attr_key): + """Get the RestAPI key of this attr, split it and decode part + :param str attr_key: Attribute key must be in attribute_map. + :returns: A list of RestAPI part + :rtype: list + """ + rest_split_key = _FLATTEN.split(cls._attribute_map[attr_key]["key"]) + return [_decode_attribute_map_key(key_part) for key_part in rest_split_key] + + +def _decode_attribute_map_key(key): + """This decode a key in an _attribute_map to the actual key we want to look at + inside the received data. + + :param str key: A key string from the generated code + """ + return key.replace("\\.", ".") + + +class Serializer(object): + """Request object model serializer.""" + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + _xml_basic_types_serializers = {"bool": lambda x: str(x).lower()} + days = {0: "Mon", 1: "Tue", 2: "Wed", 3: "Thu", 4: "Fri", 5: "Sat", 6: "Sun"} + months = { + 1: "Jan", + 2: "Feb", + 3: "Mar", + 4: "Apr", + 5: "May", + 6: "Jun", + 7: "Jul", + 8: "Aug", + 9: "Sep", + 10: "Oct", + 11: "Nov", + 12: "Dec", + } + validation = { + "min_length": lambda x, y: len(x) < y, + "max_length": lambda x, y: len(x) > y, + "minimum": lambda x, y: x < y, + "maximum": lambda x, y: x > y, + "minimum_ex": lambda x, y: x <= y, + "maximum_ex": lambda x, y: x >= y, + "min_items": lambda x, y: len(x) < y, + "max_items": lambda x, y: len(x) > y, + "pattern": lambda x, y: not re.match(y, x, re.UNICODE), + "unique": lambda x, y: len(x) != len(set(x)), + "multiple": lambda x, y: x % y != 0, + } + + def __init__(self, classes: Optional[Mapping[str, Type[ModelType]]] = None): + self.serialize_type = { + "iso-8601": Serializer.serialize_iso, + "rfc-1123": Serializer.serialize_rfc, + "unix-time": Serializer.serialize_unix, + "duration": Serializer.serialize_duration, + "date": Serializer.serialize_date, + "time": Serializer.serialize_time, + "decimal": Serializer.serialize_decimal, + "long": Serializer.serialize_long, + "bytearray": Serializer.serialize_bytearray, + "base64": Serializer.serialize_base64, + "object": self.serialize_object, + "[]": self.serialize_iter, + "{}": self.serialize_dict, + } + self.dependencies: Dict[str, Type[ModelType]] = dict(classes) if classes else {} + self.key_transformer = full_restapi_key_transformer + self.client_side_validation = True + + def _serialize(self, target_obj, data_type=None, **kwargs): + """Serialize data into a string according to type. + + :param target_obj: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, dict + :raises: SerializationError if serialization fails. + """ + key_transformer = kwargs.get("key_transformer", self.key_transformer) + keep_readonly = kwargs.get("keep_readonly", False) + if target_obj is None: + return None + + attr_name = None + class_name = target_obj.__class__.__name__ + + if data_type: + return self.serialize_data(target_obj, data_type, **kwargs) + + if not hasattr(target_obj, "_attribute_map"): + data_type = type(target_obj).__name__ + if data_type in self.basic_types.values(): + return self.serialize_data(target_obj, data_type, **kwargs) + + # Force "is_xml" kwargs if we detect a XML model + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + is_xml_model_serialization = kwargs.setdefault("is_xml", target_obj.is_xml_model()) + + serialized = {} + if is_xml_model_serialization: + serialized = target_obj._create_xml_node() + try: + attributes = target_obj._attribute_map + for attr, attr_desc in attributes.items(): + attr_name = attr + if not keep_readonly and target_obj._validation.get(attr_name, {}).get("readonly", False): + continue + + if attr_name == "additional_properties" and attr_desc["key"] == "": + if target_obj.additional_properties is not None: + serialized.update(target_obj.additional_properties) + continue + try: + + orig_attr = getattr(target_obj, attr) + if is_xml_model_serialization: + pass # Don't provide "transformer" for XML for now. Keep "orig_attr" + else: # JSON + keys, orig_attr = key_transformer(attr, attr_desc.copy(), orig_attr) + keys = keys if isinstance(keys, list) else [keys] + + kwargs["serialization_ctxt"] = attr_desc + new_attr = self.serialize_data(orig_attr, attr_desc["type"], **kwargs) + + if is_xml_model_serialization: + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + xml_prefix = xml_desc.get("prefix", None) + xml_ns = xml_desc.get("ns", None) + if xml_desc.get("attr", False): + if xml_ns: + ET.register_namespace(xml_prefix, xml_ns) + xml_name = "{}{}".format(xml_ns, xml_name) + serialized.set(xml_name, new_attr) # type: ignore + continue + if xml_desc.get("text", False): + serialized.text = new_attr # type: ignore + continue + if isinstance(new_attr, list): + serialized.extend(new_attr) # type: ignore + elif isinstance(new_attr, ET.Element): + # If the down XML has no XML/Name, we MUST replace the tag with the local tag. But keeping the namespaces. + if "name" not in getattr(orig_attr, "_xml_map", {}): + splitted_tag = new_attr.tag.split("}") + if len(splitted_tag) == 2: # Namespace + new_attr.tag = "}".join([splitted_tag[0], xml_name]) + else: + new_attr.tag = xml_name + serialized.append(new_attr) # type: ignore + else: # That's a basic type + # Integrate namespace if necessary + local_node = _create_xml_node(xml_name, xml_prefix, xml_ns) + local_node.text = unicode_str(new_attr) + serialized.append(local_node) # type: ignore + else: # JSON + for k in reversed(keys): # type: ignore + new_attr = {k: new_attr} + + _new_attr = new_attr + _serialized = serialized + for k in keys: # type: ignore + if k not in _serialized: + _serialized.update(_new_attr) # type: ignore + _new_attr = _new_attr[k] # type: ignore + _serialized = _serialized[k] + except ValueError: + continue + + except (AttributeError, KeyError, TypeError) as err: + msg = "Attribute {} in object {} cannot be serialized.\n{}".format(attr_name, class_name, str(target_obj)) + raise_with_traceback(SerializationError, msg, err) + else: + return serialized + + def body(self, data, data_type, **kwargs): + """Serialize data intended for a request body. + + :param data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: dict + :raises: SerializationError if serialization fails. + :raises: ValueError if data is None + """ + + # Just in case this is a dict + internal_data_type_str = data_type.strip("[]{}") + internal_data_type = self.dependencies.get(internal_data_type_str, None) + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + if internal_data_type and issubclass(internal_data_type, Model): + is_xml_model_serialization = kwargs.setdefault("is_xml", internal_data_type.is_xml_model()) + else: + is_xml_model_serialization = False + if internal_data_type and not isinstance(internal_data_type, Enum): + try: + deserializer = Deserializer(self.dependencies) + # Since it's on serialization, it's almost sure that format is not JSON REST + # We're not able to deal with additional properties for now. + deserializer.additional_properties_detection = False + if is_xml_model_serialization: + deserializer.key_extractors = [ # type: ignore + attribute_key_case_insensitive_extractor, + ] + else: + deserializer.key_extractors = [ + rest_key_case_insensitive_extractor, + attribute_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + data = deserializer._deserialize(data_type, data) + except DeserializationError as err: + raise_with_traceback(SerializationError, "Unable to build a model: " + str(err), err) + + return self._serialize(data, data_type, **kwargs) + + def url(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL path. + + :param data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :raises: TypeError if serialization fails. + :raises: ValueError if data is None + """ + try: + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + + if kwargs.get("skip_quote") is True: + output = str(output) + else: + output = quote(str(output), safe="") + except SerializationError: + raise TypeError("{} must be type {}.".format(name, data_type)) + else: + return output + + def query(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL query. + + :param data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :raises: TypeError if serialization fails. + :raises: ValueError if data is None + """ + try: + # Treat the list aside, since we don't want to encode the div separator + if data_type.startswith("["): + internal_data_type = data_type[1:-1] + data = [self.serialize_data(d, internal_data_type, **kwargs) if d is not None else "" for d in data] + if not kwargs.get("skip_quote", False): + data = [quote(str(d), safe="") for d in data] + return str(self.serialize_iter(data, internal_data_type, **kwargs)) + + # Not a list, regular serialization + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + if kwargs.get("skip_quote") is True: + output = str(output) + else: + output = quote(str(output), safe="") + except SerializationError: + raise TypeError("{} must be type {}.".format(name, data_type)) + else: + return str(output) + + def header(self, name, data, data_type, **kwargs): + """Serialize data intended for a request header. + + :param data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :raises: TypeError if serialization fails. + :raises: ValueError if data is None + """ + try: + if data_type in ["[str]"]: + data = ["" if d is None else d for d in data] + + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + except SerializationError: + raise TypeError("{} must be type {}.".format(name, data_type)) + else: + return str(output) + + def serialize_data(self, data, data_type, **kwargs): + """Serialize generic data according to supplied data type. + + :param data: The data to be serialized. + :param str data_type: The type to be serialized from. + :param bool required: Whether it's essential that the data not be + empty or None + :raises: AttributeError if required data is None. + :raises: ValueError if data is None + :raises: SerializationError if serialization fails. + """ + if data is None: + raise ValueError("No value for given attribute") + + try: + if data is AzureCoreNull: + return None + if data_type in self.basic_types.values(): + return self.serialize_basic(data, data_type, **kwargs) + + elif data_type in self.serialize_type: + return self.serialize_type[data_type](data, **kwargs) + + # If dependencies is empty, try with current data class + # It has to be a subclass of Enum anyway + enum_type = self.dependencies.get(data_type, data.__class__) + if issubclass(enum_type, Enum): + return Serializer.serialize_enum(data, enum_obj=enum_type) + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.serialize_type: + return self.serialize_type[iter_type](data, data_type[1:-1], **kwargs) + + except (ValueError, TypeError) as err: + msg = "Unable to serialize value: {!r} as type: {!r}." + raise_with_traceback(SerializationError, msg.format(data, data_type), err) + else: + return self._serialize(data, **kwargs) + + @classmethod + def _get_custom_serializers(cls, data_type, **kwargs): + custom_serializer = kwargs.get("basic_types_serializers", {}).get(data_type) + if custom_serializer: + return custom_serializer + if kwargs.get("is_xml", False): + return cls._xml_basic_types_serializers.get(data_type) + + @classmethod + def serialize_basic(cls, data, data_type, **kwargs): + """Serialize basic builting data type. + Serializes objects to str, int, float or bool. + + Possible kwargs: + - basic_types_serializers dict[str, callable] : If set, use the callable as serializer + - is_xml bool : If set, use xml_basic_types_serializers + + :param data: Object to be serialized. + :param str data_type: Type of object in the iterable. + """ + custom_serializer = cls._get_custom_serializers(data_type, **kwargs) + if custom_serializer: + return custom_serializer(data) + if data_type == "str": + return cls.serialize_unicode(data) + return eval(data_type)(data) # nosec + + @classmethod + def serialize_unicode(cls, data): + """Special handling for serializing unicode strings in Py2. + Encode to UTF-8 if unicode, otherwise handle as a str. + + :param data: Object to be serialized. + :rtype: str + """ + try: # If I received an enum, return its value + return data.value + except AttributeError: + pass + + try: + if isinstance(data, unicode): # type: ignore + # Don't change it, JSON and XML ElementTree are totally able + # to serialize correctly u'' strings + return data + except NameError: + return str(data) + else: + return str(data) + + def serialize_iter(self, data, iter_type, div=None, **kwargs): + """Serialize iterable. + + Supported kwargs: + - serialization_ctxt dict : The current entry of _attribute_map, or same format. + serialization_ctxt['type'] should be same as data_type. + - is_xml bool : If set, serialize as XML + + :param list attr: Object to be serialized. + :param str iter_type: Type of object in the iterable. + :param bool required: Whether the objects in the iterable must + not be None or empty. + :param str div: If set, this str will be used to combine the elements + in the iterable into a combined string. Default is 'None'. + :rtype: list, str + """ + if isinstance(data, str): + raise SerializationError("Refuse str type as a valid iter type.") + + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + is_xml = kwargs.get("is_xml", False) + + serialized = [] + for d in data: + try: + serialized.append(self.serialize_data(d, iter_type, **kwargs)) + except ValueError: + serialized.append(None) + + if div: + serialized = ["" if s is None else str(s) for s in serialized] + serialized = div.join(serialized) + + if "xml" in serialization_ctxt or is_xml: + # XML serialization is more complicated + xml_desc = serialization_ctxt.get("xml", {}) + xml_name = xml_desc.get("name") + if not xml_name: + xml_name = serialization_ctxt["key"] + + # Create a wrap node if necessary (use the fact that Element and list have "append") + is_wrapped = xml_desc.get("wrapped", False) + node_name = xml_desc.get("itemsName", xml_name) + if is_wrapped: + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + else: + final_result = [] + # All list elements to "local_node" + for el in serialized: + if isinstance(el, ET.Element): + el_node = el + else: + el_node = _create_xml_node(node_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + if el is not None: # Otherwise it writes "None" :-p + el_node.text = str(el) + final_result.append(el_node) + return final_result + return serialized + + def serialize_dict(self, attr, dict_type, **kwargs): + """Serialize a dictionary of objects. + + :param dict attr: Object to be serialized. + :param str dict_type: Type of object in the dictionary. + :param bool required: Whether the objects in the dictionary must + not be None or empty. + :rtype: dict + """ + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_data(value, dict_type, **kwargs) + except ValueError: + serialized[self.serialize_unicode(key)] = None + + if "xml" in serialization_ctxt: + # XML serialization is more complicated + xml_desc = serialization_ctxt["xml"] + xml_name = xml_desc["name"] + + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + for key, value in serialized.items(): + ET.SubElement(final_result, key).text = value + return final_result + + return serialized + + def serialize_object(self, attr, **kwargs): + """Serialize a generic object. + This will be handled as a dictionary. If object passed in is not + a basic type (str, int, float, dict, list) it will simply be + cast to str. + + :param dict attr: Object to be serialized. + :rtype: dict or str + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + return attr + obj_type = type(attr) + if obj_type in self.basic_types: + return self.serialize_basic(attr, self.basic_types[obj_type], **kwargs) + if obj_type is _long_type: + return self.serialize_long(attr) + if obj_type is unicode_str: + return self.serialize_unicode(attr) + if obj_type is datetime.datetime: + return self.serialize_iso(attr) + if obj_type is datetime.date: + return self.serialize_date(attr) + if obj_type is datetime.time: + return self.serialize_time(attr) + if obj_type is datetime.timedelta: + return self.serialize_duration(attr) + if obj_type is decimal.Decimal: + return self.serialize_decimal(attr) + + # If it's a model or I know this dependency, serialize as a Model + elif obj_type in self.dependencies.values() or isinstance(attr, Model): + return self._serialize(attr) + + if obj_type == dict: + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_object(value, **kwargs) + except ValueError: + serialized[self.serialize_unicode(key)] = None + return serialized + + if obj_type == list: + serialized = [] + for obj in attr: + try: + serialized.append(self.serialize_object(obj, **kwargs)) + except ValueError: + pass + return serialized + return str(attr) + + @staticmethod + def serialize_enum(attr, enum_obj=None): + try: + result = attr.value + except AttributeError: + result = attr + try: + enum_obj(result) # type: ignore + return result + except ValueError: + for enum_value in enum_obj: # type: ignore + if enum_value.value.lower() == str(attr).lower(): + return enum_value.value + error = "{!r} is not valid value for enum {!r}" + raise SerializationError(error.format(attr, enum_obj)) + + @staticmethod + def serialize_bytearray(attr, **kwargs): + """Serialize bytearray into base-64 string. + + :param attr: Object to be serialized. + :rtype: str + """ + return b64encode(attr).decode() + + @staticmethod + def serialize_base64(attr, **kwargs): + """Serialize str into base-64 string. + + :param attr: Object to be serialized. + :rtype: str + """ + encoded = b64encode(attr).decode("ascii") + return encoded.strip("=").replace("+", "-").replace("/", "_") + + @staticmethod + def serialize_decimal(attr, **kwargs): + """Serialize Decimal object to float. + + :param attr: Object to be serialized. + :rtype: float + """ + return float(attr) + + @staticmethod + def serialize_long(attr, **kwargs): + """Serialize long (Py2) or int (Py3). + + :param attr: Object to be serialized. + :rtype: int/long + """ + return _long_type(attr) + + @staticmethod + def serialize_date(attr, **kwargs): + """Serialize Date object into ISO-8601 formatted string. + + :param Date attr: Object to be serialized. + :rtype: str + """ + if isinstance(attr, str): + attr = isodate.parse_date(attr) + t = "{:04}-{:02}-{:02}".format(attr.year, attr.month, attr.day) + return t + + @staticmethod + def serialize_time(attr, **kwargs): + """Serialize Time object into ISO-8601 formatted string. + + :param datetime.time attr: Object to be serialized. + :rtype: str + """ + if isinstance(attr, str): + attr = isodate.parse_time(attr) + t = "{:02}:{:02}:{:02}".format(attr.hour, attr.minute, attr.second) + if attr.microsecond: + t += ".{:02}".format(attr.microsecond) + return t + + @staticmethod + def serialize_duration(attr, **kwargs): + """Serialize TimeDelta object into ISO-8601 formatted string. + + :param TimeDelta attr: Object to be serialized. + :rtype: str + """ + if isinstance(attr, str): + attr = isodate.parse_duration(attr) + return isodate.duration_isoformat(attr) + + @staticmethod + def serialize_rfc(attr, **kwargs): + """Serialize Datetime object into RFC-1123 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises: TypeError if format invalid. + """ + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + except AttributeError: + raise TypeError("RFC1123 object must be valid Datetime object.") + + return "{}, {:02} {} {:04} {:02}:{:02}:{:02} GMT".format( + Serializer.days[utc.tm_wday], + utc.tm_mday, + Serializer.months[utc.tm_mon], + utc.tm_year, + utc.tm_hour, + utc.tm_min, + utc.tm_sec, + ) + + @staticmethod + def serialize_iso(attr, **kwargs): + """Serialize Datetime object into ISO-8601 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises: SerializationError if format invalid. + """ + if isinstance(attr, str): + attr = isodate.parse_datetime(attr) + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + if utc.tm_year > 9999 or utc.tm_year < 1: + raise OverflowError("Hit max or min date") + + microseconds = str(attr.microsecond).rjust(6, "0").rstrip("0").ljust(3, "0") + if microseconds: + microseconds = "." + microseconds + date = "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}".format( + utc.tm_year, utc.tm_mon, utc.tm_mday, utc.tm_hour, utc.tm_min, utc.tm_sec + ) + return date + microseconds + "Z" + except (ValueError, OverflowError) as err: + msg = "Unable to serialize datetime object." + raise_with_traceback(SerializationError, msg, err) + except AttributeError as err: + msg = "ISO-8601 object must be valid Datetime object." + raise_with_traceback(TypeError, msg, err) + + @staticmethod + def serialize_unix(attr, **kwargs): + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param Datetime attr: Object to be serialized. + :rtype: int + :raises: SerializationError if format invalid + """ + if isinstance(attr, int): + return attr + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + return int(calendar.timegm(attr.utctimetuple())) + except AttributeError: + raise TypeError("Unix time object must be valid Datetime object.") + + +def rest_key_extractor(attr, attr_desc, data): + key = attr_desc["key"] + working_data = data + + while "." in key: + # Need the cast, as for some reasons "split" is typed as list[str | Any] + dict_keys = cast(List[str], _FLATTEN.split(key)) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = working_data.get(working_key, data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + # https://github.com/Azure/msrest-for-python/issues/197 + return None + key = ".".join(dict_keys[1:]) + + return working_data.get(key) + + +def rest_key_case_insensitive_extractor(attr, attr_desc, data): + key = attr_desc["key"] + working_data = data + + while "." in key: + dict_keys = _FLATTEN.split(key) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = attribute_key_case_insensitive_extractor(working_key, None, working_data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + # https://github.com/Azure/msrest-for-python/issues/197 + return None + key = ".".join(dict_keys[1:]) + + if working_data: + return attribute_key_case_insensitive_extractor(key, None, working_data) + + +def last_rest_key_extractor(attr, attr_desc, data): + """Extract the attribute in "data" based on the last part of the JSON path key.""" + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_extractor(dict_keys[-1], None, data) + + +def last_rest_key_case_insensitive_extractor(attr, attr_desc, data): + """Extract the attribute in "data" based on the last part of the JSON path key. + + This is the case insensitive version of "last_rest_key_extractor" + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_case_insensitive_extractor(dict_keys[-1], None, data) + + +def attribute_key_extractor(attr, _, data): + return data.get(attr) + + +def attribute_key_case_insensitive_extractor(attr, _, data): + found_key = None + lower_attr = attr.lower() + for key in data: + if lower_attr == key.lower(): + found_key = key + break + + return data.get(found_key) + + +def _extract_name_from_internal_type(internal_type): + """Given an internal type XML description, extract correct XML name with namespace. + + :param dict internal_type: An model type + :rtype: tuple + :returns: A tuple XML name + namespace dict + """ + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + xml_name = internal_type_xml_map.get("name", internal_type.__name__) + xml_ns = internal_type_xml_map.get("ns", None) + if xml_ns: + xml_name = "{}{}".format(xml_ns, xml_name) + return xml_name + + +def xml_key_extractor(attr, attr_desc, data): + if isinstance(data, dict): + return None + + # Test if this model is XML ready first + if not isinstance(data, ET.Element): + return None + + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + + # Look for a children + is_iter_type = attr_desc["type"].startswith("[") + is_wrapped = xml_desc.get("wrapped", False) + internal_type = attr_desc.get("internalType", None) + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + + # Integrate namespace if necessary + xml_ns = xml_desc.get("ns", internal_type_xml_map.get("ns", None)) + if xml_ns: + xml_name = "{}{}".format(xml_ns, xml_name) + + # If it's an attribute, that's simple + if xml_desc.get("attr", False): + return data.get(xml_name) + + # If it's x-ms-text, that's simple too + if xml_desc.get("text", False): + return data.text + + # Scenario where I take the local name: + # - Wrapped node + # - Internal type is an enum (considered basic types) + # - Internal type has no XML/Name node + if is_wrapped or (internal_type and (issubclass(internal_type, Enum) or "name" not in internal_type_xml_map)): + children = data.findall(xml_name) + # If internal type has a local name and it's not a list, I use that name + elif not is_iter_type and internal_type and "name" in internal_type_xml_map: + xml_name = _extract_name_from_internal_type(internal_type) + children = data.findall(xml_name) + # That's an array + else: + if internal_type: # Complex type, ignore itemsName and use the complex type name + items_name = _extract_name_from_internal_type(internal_type) + else: + items_name = xml_desc.get("itemsName", xml_name) + children = data.findall(items_name) + + if len(children) == 0: + if is_iter_type: + if is_wrapped: + return None # is_wrapped no node, we want None + else: + return [] # not wrapped, assume empty list + return None # Assume it's not there, maybe an optional node. + + # If is_iter_type and not wrapped, return all found children + if is_iter_type: + if not is_wrapped: + return children + else: # Iter and wrapped, should have found one node only (the wrap one) + if len(children) != 1: + raise DeserializationError( + "Tried to deserialize an array not wrapped, and found several nodes '{}'. Maybe you should declare this array as wrapped?".format( + xml_name + ) + ) + return list(children[0]) # Might be empty list and that's ok. + + # Here it's not a itertype, we should have found one element only or empty + if len(children) > 1: + raise DeserializationError("Find several XML '{}' where it was not expected".format(xml_name)) + return children[0] + + +class Deserializer(object): + """Response object model deserializer. + + :param dict classes: Class type dictionary for deserializing complex types. + :ivar list key_extractors: Ordered list of extractors to be used by this deserializer. + """ + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + valid_date = re.compile(r"\d{4}[-]\d{2}[-]\d{2}T\d{2}:\d{2}:\d{2}" r"\.?\d*Z?[-+]?[\d{2}]?:?[\d{2}]?") + + def __init__(self, classes: Optional[Mapping[str, Type[ModelType]]] = None): + self.deserialize_type = { + "iso-8601": Deserializer.deserialize_iso, + "rfc-1123": Deserializer.deserialize_rfc, + "unix-time": Deserializer.deserialize_unix, + "duration": Deserializer.deserialize_duration, + "date": Deserializer.deserialize_date, + "time": Deserializer.deserialize_time, + "decimal": Deserializer.deserialize_decimal, + "long": Deserializer.deserialize_long, + "bytearray": Deserializer.deserialize_bytearray, + "base64": Deserializer.deserialize_base64, + "object": self.deserialize_object, + "[]": self.deserialize_iter, + "{}": self.deserialize_dict, + } + self.deserialize_expected_types = { + "duration": (isodate.Duration, datetime.timedelta), + "iso-8601": (datetime.datetime), + } + self.dependencies: Dict[str, Type[ModelType]] = dict(classes) if classes else {} + self.key_extractors = [rest_key_extractor, xml_key_extractor] + # Additional properties only works if the "rest_key_extractor" is used to + # extract the keys. Making it to work whatever the key extractor is too much + # complicated, with no real scenario for now. + # So adding a flag to disable additional properties detection. This flag should be + # used if your expect the deserialization to NOT come from a JSON REST syntax. + # Otherwise, result are unexpected + self.additional_properties_detection = True + + def __call__(self, target_obj, response_data, content_type=None): + """Call the deserializer to process a REST response. + + :param str target_obj: Target data type to deserialize to. + :param requests.Response response_data: REST response object. + :param str content_type: Swagger "produces" if available. + :raises: DeserializationError if deserialization fails. + :return: Deserialized object. + """ + data = self._unpack_content(response_data, content_type) + return self._deserialize(target_obj, data) + + def _deserialize(self, target_obj, data): + """Call the deserializer on a model. + + Data needs to be already deserialized as JSON or XML ElementTree + + :param str target_obj: Target data type to deserialize to. + :param object data: Object to deserialize. + :raises: DeserializationError if deserialization fails. + :return: Deserialized object. + """ + # This is already a model, go recursive just in case + if hasattr(data, "_attribute_map"): + constants = [name for name, config in getattr(data, "_validation", {}).items() if config.get("constant")] + try: + for attr, mapconfig in data._attribute_map.items(): + if attr in constants: + continue + value = getattr(data, attr) + if value is None: + continue + local_type = mapconfig["type"] + internal_data_type = local_type.strip("[]{}") + if internal_data_type not in self.dependencies or isinstance(internal_data_type, Enum): + continue + setattr(data, attr, self._deserialize(local_type, value)) + return data + except AttributeError: + return + + response, class_name = self._classify_target(target_obj, data) + + if isinstance(response, basestring): + return self.deserialize_data(data, response) + elif isinstance(response, type) and issubclass(response, Enum): + return self.deserialize_enum(data, response) + + if data is None: + return data + try: + attributes = response._attribute_map # type: ignore + d_attrs = {} + for attr, attr_desc in attributes.items(): + # Check empty string. If it's not empty, someone has a real "additionalProperties"... + if attr == "additional_properties" and attr_desc["key"] == "": + continue + raw_value = None + # Enhance attr_desc with some dynamic data + attr_desc = attr_desc.copy() # Do a copy, do not change the real one + internal_data_type = attr_desc["type"].strip("[]{}") + if internal_data_type in self.dependencies: + attr_desc["internalType"] = self.dependencies[internal_data_type] + + for key_extractor in self.key_extractors: + found_value = key_extractor(attr, attr_desc, data) + if found_value is not None: + if raw_value is not None and raw_value != found_value: + msg = ( + "Ignoring extracted value '%s' from %s for key '%s'" + " (duplicate extraction, follow extractors order)" + ) + _LOGGER.warning(msg, found_value, key_extractor, attr) + continue + raw_value = found_value + + value = self.deserialize_data(raw_value, attr_desc["type"]) + d_attrs[attr] = value + except (AttributeError, TypeError, KeyError) as err: + msg = "Unable to deserialize to object: " + class_name # type: ignore + raise_with_traceback(DeserializationError, msg, err) + else: + additional_properties = self._build_additional_properties(attributes, data) + return self._instantiate_model(response, d_attrs, additional_properties) + + def _build_additional_properties(self, attribute_map, data): + if not self.additional_properties_detection: + return None + if "additional_properties" in attribute_map and attribute_map.get("additional_properties", {}).get("key") != "": + # Check empty string. If it's not empty, someone has a real "additionalProperties" + return None + if isinstance(data, ET.Element): + data = {el.tag: el.text for el in data} + + known_keys = { + _decode_attribute_map_key(_FLATTEN.split(desc["key"])[0]) + for desc in attribute_map.values() + if desc["key"] != "" + } + present_keys = set(data.keys()) + missing_keys = present_keys - known_keys + return {key: data[key] for key in missing_keys} + + def _classify_target(self, target, data): + """Check to see whether the deserialization target object can + be classified into a subclass. + Once classification has been determined, initialize object. + + :param str target: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + """ + if target is None: + return None, None + + if isinstance(target, basestring): + try: + target = self.dependencies[target] + except KeyError: + return target, target + + try: + target = target._classify(data, self.dependencies) + except AttributeError: + pass # Target is not a Model, no classify + return target, target.__class__.__name__ # type: ignore + + def failsafe_deserialize(self, target_obj, data, content_type=None): + """Ignores any errors encountered in deserialization, + and falls back to not deserializing the object. Recommended + for use in error deserialization, as we want to return the + HttpResponseError to users, and not have them deal with + a deserialization error. + + :param str target_obj: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :param str content_type: Swagger "produces" if available. + """ + try: + return self(target_obj, data, content_type=content_type) + except: + _LOGGER.debug( + "Ran into a deserialization error. Ignoring since this is failsafe deserialization", exc_info=True + ) + return None + + @staticmethod + def _unpack_content(raw_data, content_type=None): + """Extract the correct structure for deserialization. + + If raw_data is a PipelineResponse, try to extract the result of RawDeserializer. + if we can't, raise. Your Pipeline should have a RawDeserializer. + + If not a pipeline response and raw_data is bytes or string, use content-type + to decode it. If no content-type, try JSON. + + If raw_data is something else, bypass all logic and return it directly. + + :param raw_data: Data to be processed. + :param content_type: How to parse if raw_data is a string/bytes. + :raises JSONDecodeError: If JSON is requested and parsing is impossible. + :raises UnicodeDecodeError: If bytes is not UTF8 + """ + # Assume this is enough to detect a Pipeline Response without importing it + context = getattr(raw_data, "context", {}) + if context: + if RawDeserializer.CONTEXT_NAME in context: + return context[RawDeserializer.CONTEXT_NAME] + raise ValueError("This pipeline didn't have the RawDeserializer policy; can't deserialize") + + # Assume this is enough to recognize universal_http.ClientResponse without importing it + if hasattr(raw_data, "body"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text(), raw_data.headers) + + # Assume this enough to recognize requests.Response without importing it. + if hasattr(raw_data, "_content_consumed"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text, raw_data.headers) + + if isinstance(raw_data, (basestring, bytes)) or hasattr(raw_data, "read"): + return RawDeserializer.deserialize_from_text(raw_data, content_type) # type: ignore + return raw_data + + def _instantiate_model(self, response, attrs, additional_properties=None): + """Instantiate a response model passing in deserialized args. + + :param response: The response model class. + :param d_attrs: The deserialized response attributes. + """ + if callable(response): + subtype = getattr(response, "_subtype_map", {}) + try: + readonly = [k for k, v in response._validation.items() if v.get("readonly")] + const = [k for k, v in response._validation.items() if v.get("constant")] + kwargs = {k: v for k, v in attrs.items() if k not in subtype and k not in readonly + const} + response_obj = response(**kwargs) + for attr in readonly: + setattr(response_obj, attr, attrs.get(attr)) + if additional_properties: + response_obj.additional_properties = additional_properties + return response_obj + except TypeError as err: + msg = "Unable to deserialize {} into model {}. ".format(kwargs, response) # type: ignore + raise DeserializationError(msg + str(err)) + else: + try: + for attr, value in attrs.items(): + setattr(response, attr, value) + return response + except Exception as exp: + msg = "Unable to populate response model. " + msg += "Type: {}, Error: {}".format(type(response), exp) + raise DeserializationError(msg) + + def deserialize_data(self, data, data_type): + """Process data for deserialization according to data type. + + :param str data: The response string to be deserialized. + :param str data_type: The type to deserialize to. + :raises: DeserializationError if deserialization fails. + :return: Deserialized object. + """ + if data is None: + return data + + try: + if not data_type: + return data + if data_type in self.basic_types.values(): + return self.deserialize_basic(data, data_type) + if data_type in self.deserialize_type: + if isinstance(data, self.deserialize_expected_types.get(data_type, tuple())): + return data + + is_a_text_parsing_type = lambda x: x not in ["object", "[]", r"{}"] + if isinstance(data, ET.Element) and is_a_text_parsing_type(data_type) and not data.text: + return None + data_val = self.deserialize_type[data_type](data) + return data_val + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.deserialize_type: + return self.deserialize_type[iter_type](data, data_type[1:-1]) + + obj_type = self.dependencies[data_type] + if issubclass(obj_type, Enum): + if isinstance(data, ET.Element): + data = data.text + return self.deserialize_enum(data, obj_type) + + except (ValueError, TypeError, AttributeError) as err: + msg = "Unable to deserialize response data." + msg += " Data: {}, {}".format(data, data_type) + raise_with_traceback(DeserializationError, msg, err) + else: + return self._deserialize(obj_type, data) + + def deserialize_iter(self, attr, iter_type): + """Deserialize an iterable. + + :param list attr: Iterable to be deserialized. + :param str iter_type: The type of object in the iterable. + :rtype: list + """ + if attr is None: + return None + if isinstance(attr, ET.Element): # If I receive an element here, get the children + attr = list(attr) + if not isinstance(attr, (list, set)): + raise DeserializationError("Cannot deserialize as [{}] an object of type {}".format(iter_type, type(attr))) + return [self.deserialize_data(a, iter_type) for a in attr] + + def deserialize_dict(self, attr, dict_type): + """Deserialize a dictionary. + + :param dict/list attr: Dictionary to be deserialized. Also accepts + a list of key, value pairs. + :param str dict_type: The object type of the items in the dictionary. + :rtype: dict + """ + if isinstance(attr, list): + return {x["key"]: self.deserialize_data(x["value"], dict_type) for x in attr} + + if isinstance(attr, ET.Element): + # Transform value into {"Key": "value"} + attr = {el.tag: el.text for el in attr} + return {k: self.deserialize_data(v, dict_type) for k, v in attr.items()} + + def deserialize_object(self, attr, **kwargs): + """Deserialize a generic object. + This will be handled as a dictionary. + + :param dict attr: Dictionary to be deserialized. + :rtype: dict + :raises: TypeError if non-builtin datatype encountered. + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + # Do no recurse on XML, just return the tree as-is + return attr + if isinstance(attr, basestring): + return self.deserialize_basic(attr, "str") + obj_type = type(attr) + if obj_type in self.basic_types: + return self.deserialize_basic(attr, self.basic_types[obj_type]) + if obj_type is _long_type: + return self.deserialize_long(attr) + + if obj_type == dict: + deserialized = {} + for key, value in attr.items(): + try: + deserialized[key] = self.deserialize_object(value, **kwargs) + except ValueError: + deserialized[key] = None + return deserialized + + if obj_type == list: + deserialized = [] + for obj in attr: + try: + deserialized.append(self.deserialize_object(obj, **kwargs)) + except ValueError: + pass + return deserialized + + else: + error = "Cannot deserialize generic object with type: " + raise TypeError(error + str(obj_type)) + + def deserialize_basic(self, attr, data_type): + """Deserialize basic builtin data type from string. + Will attempt to convert to str, int, float and bool. + This function will also accept '1', '0', 'true' and 'false' as + valid bool values. + + :param str attr: response string to be deserialized. + :param str data_type: deserialization data type. + :rtype: str, int, float or bool + :raises: TypeError if string format is not valid. + """ + # If we're here, data is supposed to be a basic type. + # If it's still an XML node, take the text + if isinstance(attr, ET.Element): + attr = attr.text + if not attr: + if data_type == "str": + # None or '', node is empty string. + return "" + else: + # None or '', node with a strong type is None. + # Don't try to model "empty bool" or "empty int" + return None + + if data_type == "bool": + if attr in [True, False, 1, 0]: + return bool(attr) + elif isinstance(attr, basestring): + if attr.lower() in ["true", "1"]: + return True + elif attr.lower() in ["false", "0"]: + return False + raise TypeError("Invalid boolean value: {}".format(attr)) + + if data_type == "str": + return self.deserialize_unicode(attr) + return eval(data_type)(attr) # nosec + + @staticmethod + def deserialize_unicode(data): + """Preserve unicode objects in Python 2, otherwise return data + as a string. + + :param str data: response string to be deserialized. + :rtype: str or unicode + """ + # We might be here because we have an enum modeled as string, + # and we try to deserialize a partial dict with enum inside + if isinstance(data, Enum): + return data + + # Consider this is real string + try: + if isinstance(data, unicode): # type: ignore + return data + except NameError: + return str(data) + else: + return str(data) + + @staticmethod + def deserialize_enum(data, enum_obj): + """Deserialize string into enum object. + + If the string is not a valid enum value it will be returned as-is + and a warning will be logged. + + :param str data: Response string to be deserialized. If this value is + None or invalid it will be returned as-is. + :param Enum enum_obj: Enum object to deserialize to. + :rtype: Enum + """ + if isinstance(data, enum_obj) or data is None: + return data + if isinstance(data, Enum): + data = data.value + if isinstance(data, int): + # Workaround. We might consider remove it in the future. + # https://github.com/Azure/azure-rest-api-specs/issues/141 + try: + return list(enum_obj.__members__.values())[data] + except IndexError: + error = "{!r} is not a valid index for enum {!r}" + raise DeserializationError(error.format(data, enum_obj)) + try: + return enum_obj(str(data)) + except ValueError: + for enum_value in enum_obj: + if enum_value.value.lower() == str(data).lower(): + return enum_value + # We don't fail anymore for unknown value, we deserialize as a string + _LOGGER.warning("Deserializer is not able to find %s as valid enum in %s", data, enum_obj) + return Deserializer.deserialize_unicode(data) + + @staticmethod + def deserialize_bytearray(attr): + """Deserialize string into bytearray. + + :param str attr: response string to be deserialized. + :rtype: bytearray + :raises: TypeError if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return bytearray(b64decode(attr)) # type: ignore + + @staticmethod + def deserialize_base64(attr): + """Deserialize base64 encoded string into string. + + :param str attr: response string to be deserialized. + :rtype: bytearray + :raises: TypeError if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + padding = "=" * (3 - (len(attr) + 3) % 4) # type: ignore + attr = attr + padding # type: ignore + encoded = attr.replace("-", "+").replace("_", "/") + return b64decode(encoded) + + @staticmethod + def deserialize_decimal(attr): + """Deserialize string into Decimal object. + + :param str attr: response string to be deserialized. + :rtype: Decimal + :raises: DeserializationError if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + return decimal.Decimal(attr) # type: ignore + except decimal.DecimalException as err: + msg = "Invalid decimal {}".format(attr) + raise_with_traceback(DeserializationError, msg, err) + + @staticmethod + def deserialize_long(attr): + """Deserialize string into long (Py2) or int (Py3). + + :param str attr: response string to be deserialized. + :rtype: long or int + :raises: ValueError if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return _long_type(attr) # type: ignore + + @staticmethod + def deserialize_duration(attr): + """Deserialize ISO-8601 formatted string into TimeDelta object. + + :param str attr: response string to be deserialized. + :rtype: TimeDelta + :raises: DeserializationError if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + duration = isodate.parse_duration(attr) + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize duration object." + raise_with_traceback(DeserializationError, msg, err) + else: + return duration + + @staticmethod + def deserialize_date(attr): + """Deserialize ISO-8601 formatted string into Date object. + + :param str attr: response string to be deserialized. + :rtype: Date + :raises: DeserializationError if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + # This must NOT use defaultmonth/defaultday. Using None ensure this raises an exception. + return isodate.parse_date(attr, defaultmonth=None, defaultday=None) + + @staticmethod + def deserialize_time(attr): + """Deserialize ISO-8601 formatted string into time object. + + :param str attr: response string to be deserialized. + :rtype: datetime.time + :raises: DeserializationError if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + return isodate.parse_time(attr) + + @staticmethod + def deserialize_rfc(attr): + """Deserialize RFC-1123 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :rtype: Datetime + :raises: DeserializationError if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + parsed_date = email.utils.parsedate_tz(attr) # type: ignore + date_obj = datetime.datetime( + *parsed_date[:6], tzinfo=_FixedOffset(datetime.timedelta(minutes=(parsed_date[9] or 0) / 60)) + ) + if not date_obj.tzinfo: + date_obj = date_obj.astimezone(tz=TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to rfc datetime object." + raise_with_traceback(DeserializationError, msg, err) + else: + return date_obj + + @staticmethod + def deserialize_iso(attr): + """Deserialize ISO-8601 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :rtype: Datetime + :raises: DeserializationError if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + attr = attr.upper() # type: ignore + match = Deserializer.valid_date.match(attr) + if not match: + raise ValueError("Invalid datetime string: " + attr) + + check_decimal = attr.split(".") + if len(check_decimal) > 1: + decimal_str = "" + for digit in check_decimal[1]: + if digit.isdigit(): + decimal_str += digit + else: + break + if len(decimal_str) > 6: + attr = attr.replace(decimal_str, decimal_str[0:6]) + + date_obj = isodate.parse_datetime(attr) + test_utc = date_obj.utctimetuple() + if test_utc.tm_year > 9999 or test_utc.tm_year < 1: + raise OverflowError("Hit max or min date") + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize datetime object." + raise_with_traceback(DeserializationError, msg, err) + else: + return date_obj + + @staticmethod + def deserialize_unix(attr): + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param int attr: Object to be serialized. + :rtype: Datetime + :raises: DeserializationError if format invalid + """ + if isinstance(attr, ET.Element): + attr = int(attr.text) # type: ignore + try: + date_obj = datetime.datetime.fromtimestamp(attr, TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to unix datetime object." + raise_with_traceback(DeserializationError, msg, err) + else: + return date_obj diff --git a/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_generated/aio/__init__.py b/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_generated/aio/__init__.py index 4fd624f506ea..f5f8d85781b7 100644 --- a/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_generated/aio/__init__.py +++ b/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_generated/aio/__init__.py @@ -6,10 +6,18 @@ # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- -from ._sip_routing_service import SIPRoutingService -__all__ = ['SIPRoutingService'] +from ._client import SIPRoutingService -# `._patch.py` is used for handwritten extensions to the generated code -# Example: https://github.com/Azure/azure-sdk-for-python/blob/main/doc/dev/customize_code/how-to-patch-sdk-code.md -from ._patch import patch_sdk -patch_sdk() +try: + from ._patch import __all__ as _patch_all + from ._patch import * # pylint: disable=unused-wildcard-import +except ImportError: + _patch_all = [] +from ._patch import patch_sdk as _patch_sdk + +__all__ = [ + "SIPRoutingService", +] +__all__.extend([p for p in _patch_all if p not in __all__]) + +_patch_sdk() diff --git a/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_generated/aio/_sip_routing_service.py b/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_generated/aio/_client.py similarity index 63% rename from sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_generated/aio/_sip_routing_service.py rename to sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_generated/aio/_client.py index 2f2b9c446a36..bac48c7651a1 100644 --- a/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_generated/aio/_sip_routing_service.py +++ b/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_generated/aio/_client.py @@ -9,55 +9,52 @@ from copy import deepcopy from typing import Any, Awaitable -from msrest import Deserializer, Serializer - from azure.core import AsyncPipelineClient from azure.core.rest import AsyncHttpResponse, HttpRequest -from .. import models +from .. import models as _models +from .._serialization import Deserializer, Serializer from ._configuration import SIPRoutingServiceConfiguration -from .operations import SIPRoutingServiceOperationsMixin +from .operations import SipRoutingOperations + -class SIPRoutingService(SIPRoutingServiceOperationsMixin): +class SIPRoutingService: # pylint: disable=client-accepts-api-version-keyword """SipRouting Service. + :ivar sip_routing: SipRoutingOperations operations + :vartype sip_routing: + azure.communication.phonenumbers.siprouting.aio.operations.SipRoutingOperations :param endpoint: The communication resource, for example - https://resourcename.communication.azure.com. + https://resourcename.communication.azure.com. Required. :type endpoint: str - :keyword api_version: Api Version. Default value is "2021-05-01-preview". Note that overriding - this default value may result in unsupported behavior. + :keyword api_version: Api Version. Default value is "2023-03-01". Note that overriding this + default value may result in unsupported behavior. :paramtype api_version: str """ - def __init__( - self, - endpoint: str, - **kwargs: Any + def __init__( # pylint: disable=missing-client-constructor-parameter-credential + self, endpoint: str, **kwargs: Any ) -> None: - _base_url = '{endpoint}' + _endpoint = "{endpoint}" self._config = SIPRoutingServiceConfiguration(endpoint=endpoint, **kwargs) - self._client = AsyncPipelineClient(base_url=_base_url, config=self._config, **kwargs) + self._client: AsyncPipelineClient = AsyncPipelineClient(base_url=_endpoint, config=self._config, **kwargs) - client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)} + client_models = {k: v for k, v in _models.__dict__.items() if isinstance(v, type)} self._serialize = Serializer(client_models) self._deserialize = Deserializer(client_models) self._serialize.client_side_validation = False + self.sip_routing = SipRoutingOperations(self._client, self._config, self._serialize, self._deserialize) - - def _send_request( - self, - request: HttpRequest, - **kwargs: Any - ) -> Awaitable[AsyncHttpResponse]: + def send_request(self, request: HttpRequest, **kwargs: Any) -> Awaitable[AsyncHttpResponse]: """Runs the network request through the client's chained policies. >>> from azure.core.rest import HttpRequest >>> request = HttpRequest("GET", "https://www.example.org/") - >>> response = await client._send_request(request) + >>> response = await client.send_request(request) - For more information on this code flow, see https://aka.ms/azsdk/python/protocol/quickstart + For more information on this code flow, see https://aka.ms/azsdk/dpcodegen/python/send_request :param request: The network request you want to make. Required. :type request: ~azure.core.rest.HttpRequest @@ -68,7 +65,7 @@ def _send_request( request_copy = deepcopy(request) path_format_arguments = { - "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, 'str', skip_quote=True), + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), } request_copy.url = self._client.format_url(request_copy.url, **path_format_arguments) @@ -81,5 +78,5 @@ async def __aenter__(self) -> "SIPRoutingService": await self._client.__aenter__() return self - async def __aexit__(self, *exc_details) -> None: + async def __aexit__(self, *exc_details: Any) -> None: await self._client.__aexit__(*exc_details) diff --git a/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_generated/aio/_configuration.py b/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_generated/aio/_configuration.py index 4f3b51093831..d5b3279527e3 100644 --- a/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_generated/aio/_configuration.py +++ b/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_generated/aio/_configuration.py @@ -6,13 +6,20 @@ # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- +import sys from typing import Any from azure.core.configuration import Configuration from azure.core.pipeline import policies +if sys.version_info >= (3, 8): + from typing import Literal # pylint: disable=no-name-in-module, ungrouped-imports +else: + from typing_extensions import Literal # type: ignore # pylint: disable=ungrouped-imports + VERSION = "unknown" + class SIPRoutingServiceConfiguration(Configuration): # pylint: disable=too-many-instance-attributes """Configuration for SIPRoutingService. @@ -20,39 +27,32 @@ class SIPRoutingServiceConfiguration(Configuration): # pylint: disable=too-many attributes. :param endpoint: The communication resource, for example - https://resourcename.communication.azure.com. + https://resourcename.communication.azure.com. Required. :type endpoint: str - :keyword api_version: Api Version. Default value is "2021-05-01-preview". Note that overriding - this default value may result in unsupported behavior. + :keyword api_version: Api Version. Default value is "2023-03-01". Note that overriding this + default value may result in unsupported behavior. :paramtype api_version: str """ - def __init__( - self, - endpoint: str, - **kwargs: Any - ) -> None: + def __init__(self, endpoint: str, **kwargs: Any) -> None: super(SIPRoutingServiceConfiguration, self).__init__(**kwargs) - api_version = kwargs.pop('api_version', "2021-05-01-preview") # type: str + api_version: Literal["2023-03-01"] = kwargs.pop("api_version", "2023-03-01") if endpoint is None: raise ValueError("Parameter 'endpoint' must not be None.") self.endpoint = endpoint self.api_version = api_version - kwargs.setdefault('sdk_moniker', 'siproutingservice/{}'.format(VERSION)) + kwargs.setdefault("sdk_moniker", "siproutingservice/{}".format(VERSION)) self._configure(**kwargs) - def _configure( - self, - **kwargs: Any - ) -> None: - self.user_agent_policy = kwargs.get('user_agent_policy') or policies.UserAgentPolicy(**kwargs) - self.headers_policy = kwargs.get('headers_policy') or policies.HeadersPolicy(**kwargs) - self.proxy_policy = kwargs.get('proxy_policy') or policies.ProxyPolicy(**kwargs) - self.logging_policy = kwargs.get('logging_policy') or policies.NetworkTraceLoggingPolicy(**kwargs) - self.http_logging_policy = kwargs.get('http_logging_policy') or policies.HttpLoggingPolicy(**kwargs) - self.retry_policy = kwargs.get('retry_policy') or policies.AsyncRetryPolicy(**kwargs) - self.custom_hook_policy = kwargs.get('custom_hook_policy') or policies.CustomHookPolicy(**kwargs) - self.redirect_policy = kwargs.get('redirect_policy') or policies.AsyncRedirectPolicy(**kwargs) - self.authentication_policy = kwargs.get('authentication_policy') + def _configure(self, **kwargs: Any) -> None: + self.user_agent_policy = kwargs.get("user_agent_policy") or policies.UserAgentPolicy(**kwargs) + self.headers_policy = kwargs.get("headers_policy") or policies.HeadersPolicy(**kwargs) + self.proxy_policy = kwargs.get("proxy_policy") or policies.ProxyPolicy(**kwargs) + self.logging_policy = kwargs.get("logging_policy") or policies.NetworkTraceLoggingPolicy(**kwargs) + self.http_logging_policy = kwargs.get("http_logging_policy") or policies.HttpLoggingPolicy(**kwargs) + self.retry_policy = kwargs.get("retry_policy") or policies.AsyncRetryPolicy(**kwargs) + self.custom_hook_policy = kwargs.get("custom_hook_policy") or policies.CustomHookPolicy(**kwargs) + self.redirect_policy = kwargs.get("redirect_policy") or policies.AsyncRedirectPolicy(**kwargs) + self.authentication_policy = kwargs.get("authentication_policy") diff --git a/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_generated/aio/_patch.py b/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_generated/aio/_patch.py index 74e48ecd07cf..f99e77fef986 100644 --- a/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_generated/aio/_patch.py +++ b/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_generated/aio/_patch.py @@ -28,4 +28,4 @@ # This file is used for handwritten extensions to the generated code. Example: # https://github.com/Azure/azure-sdk-for-python/blob/main/doc/dev/customize_code/how-to-patch-sdk-code.md def patch_sdk(): - pass \ No newline at end of file + pass diff --git a/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_generated/aio/operations/__init__.py b/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_generated/aio/operations/__init__.py index f73fee5205e1..aa58cdc26a48 100644 --- a/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_generated/aio/operations/__init__.py +++ b/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_generated/aio/operations/__init__.py @@ -6,8 +6,14 @@ # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- -from ._sip_routing_service_operations import SIPRoutingServiceOperationsMixin +from ._operations import SipRoutingOperations + +from ._patch import __all__ as _patch_all +from ._patch import * # pylint: disable=unused-wildcard-import +from ._patch import patch_sdk as _patch_sdk __all__ = [ - 'SIPRoutingServiceOperationsMixin', + "SipRoutingOperations", ] +__all__.extend([p for p in _patch_all if p not in __all__]) +_patch_sdk() diff --git a/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_generated/aio/operations/_operations.py b/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_generated/aio/operations/_operations.py new file mode 100644 index 000000000000..9ab4525cb3bc --- /dev/null +++ b/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_generated/aio/operations/_operations.py @@ -0,0 +1,216 @@ +# pylint: disable=too-many-lines +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +from typing import Any, Callable, Dict, IO, Optional, TypeVar, Union, overload + +from azure.core.exceptions import ( + ClientAuthenticationError, + HttpResponseError, + ResourceExistsError, + ResourceNotFoundError, + ResourceNotModifiedError, + map_error, +) +from azure.core.pipeline import PipelineResponse +from azure.core.pipeline.transport import AsyncHttpResponse +from azure.core.rest import HttpRequest +from azure.core.tracing.decorator_async import distributed_trace_async +from azure.core.utils import case_insensitive_dict + +from ... import models as _models +from ...operations._operations import build_sip_routing_get_request, build_sip_routing_update_request + +T = TypeVar("T") +ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] + + +class SipRoutingOperations: + """ + .. warning:: + **DO NOT** instantiate this class directly. + + Instead, you should access the following operations through + :class:`~azure.communication.phonenumbers.siprouting.aio.SIPRoutingService`'s + :attr:`sip_routing` attribute. + """ + + models = _models + + def __init__(self, *args, **kwargs) -> None: + input_args = list(args) + self._client = input_args.pop(0) if input_args else kwargs.pop("client") + self._config = input_args.pop(0) if input_args else kwargs.pop("config") + self._serialize = input_args.pop(0) if input_args else kwargs.pop("serializer") + self._deserialize = input_args.pop(0) if input_args else kwargs.pop("deserializer") + + @distributed_trace_async + async def get(self, **kwargs: Any) -> _models.SipConfiguration: + """Gets SIP configuration for resource. + + Gets SIP configuration for resource. + + :return: SipConfiguration + :rtype: ~azure.communication.phonenumbers.siprouting.models.SipConfiguration + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[_models.SipConfiguration] = kwargs.pop("cls", None) + + request = build_sip_routing_get_request( + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + request.url = self._client.format_url(request.url, **path_format_arguments) + + _stream = False + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.CommunicationErrorResponse, pipeline_response) + raise HttpResponseError(response=response, model=error) + + deserialized = self._deserialize("SipConfiguration", pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + + @overload + async def update( + self, + body: Optional[_models.SipConfiguration] = None, + *, + content_type: str = "application/merge-patch+json", + **kwargs: Any + ) -> _models.SipConfiguration: + """Updates SIP configuration for resource. + + Updates SIP configuration for resource. + + :param body: Sip configuration update object. Default value is None. + :type body: ~azure.communication.phonenumbers.siprouting.models.SipConfiguration + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/merge-patch+json". + :paramtype content_type: str + :return: SipConfiguration + :rtype: ~azure.communication.phonenumbers.siprouting.models.SipConfiguration + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + async def update( + self, body: Optional[IO] = None, *, content_type: str = "application/merge-patch+json", **kwargs: Any + ) -> _models.SipConfiguration: + """Updates SIP configuration for resource. + + Updates SIP configuration for resource. + + :param body: Sip configuration update object. Default value is None. + :type body: IO + :keyword content_type: Body Parameter content-type. Content type parameter for binary body. + Default value is "application/merge-patch+json". + :paramtype content_type: str + :return: SipConfiguration + :rtype: ~azure.communication.phonenumbers.siprouting.models.SipConfiguration + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @distributed_trace_async + async def update( + self, body: Optional[Union[_models.SipConfiguration, IO]] = None, **kwargs: Any + ) -> _models.SipConfiguration: + """Updates SIP configuration for resource. + + Updates SIP configuration for resource. + + :param body: Sip configuration update object. Is either a SipConfiguration type or a IO type. + Default value is None. + :type body: ~azure.communication.phonenumbers.siprouting.models.SipConfiguration or IO + :keyword content_type: Body Parameter content-type. Known values are: + 'application/merge-patch+json'. Default value is None. + :paramtype content_type: str + :return: SipConfiguration + :rtype: ~azure.communication.phonenumbers.siprouting.models.SipConfiguration + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = kwargs.pop("params", {}) or {} + + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[_models.SipConfiguration] = kwargs.pop("cls", None) + + content_type = content_type or "application/merge-patch+json" + _json = None + _content = None + if isinstance(body, (IO, bytes)): + _content = body + else: + if body is not None: + _json = self._serialize.body(body, "SipConfiguration") + else: + _json = None + + request = build_sip_routing_update_request( + content_type=content_type, + api_version=self._config.api_version, + json=_json, + content=_content, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + request.url = self._client.format_url(request.url, **path_format_arguments) + + _stream = False + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.CommunicationErrorResponse, pipeline_response) + raise HttpResponseError(response=response, model=error) + + deserialized = self._deserialize("SipConfiguration", pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized diff --git a/sdk/keyvault/azure-keyvault-keys/azure/keyvault/keys/_generated/v7_4_preview_1/_patch.py b/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_generated/aio/operations/_patch.py similarity index 100% rename from sdk/keyvault/azure-keyvault-keys/azure/keyvault/keys/_generated/v7_4_preview_1/_patch.py rename to sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_generated/aio/operations/_patch.py diff --git a/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_generated/aio/operations/_sip_routing_service_operations.py b/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_generated/aio/operations/_sip_routing_service_operations.py deleted file mode 100644 index 9a01dcc1afb5..000000000000 --- a/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_generated/aio/operations/_sip_routing_service_operations.py +++ /dev/null @@ -1,143 +0,0 @@ -# pylint: disable=too-many-lines -# coding=utf-8 -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- -from typing import Any, Callable, Dict, Optional, TypeVar - -from azure.core.exceptions import ClientAuthenticationError, HttpResponseError, ResourceExistsError, ResourceNotFoundError, map_error -from azure.core.pipeline import PipelineResponse -from azure.core.pipeline.transport import AsyncHttpResponse -from azure.core.rest import HttpRequest -from azure.core.tracing.decorator_async import distributed_trace_async - -from ... import models as _models -from ..._vendor import _convert_request -from ...operations._sip_routing_service_operations import build_get_sip_configuration_request, build_patch_sip_configuration_request -T = TypeVar('T') -ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] - -class SIPRoutingServiceOperationsMixin: - - @distributed_trace_async - async def get_sip_configuration( - self, - **kwargs: Any - ) -> "_models.SipConfiguration": - """Gets SIP configuration for resource. - - Gets SIP configuration for resource. - - :keyword callable cls: A custom type or function that will be passed the direct response - :return: SipConfiguration, or the result of cls(response) - :rtype: ~azure.communication.phonenumbers.siprouting.models.SipConfiguration - :raises: ~azure.core.exceptions.HttpResponseError - """ - cls = kwargs.pop('cls', None) # type: ClsType["_models.SipConfiguration"] - error_map = { - 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError - } - error_map.update(kwargs.pop('error_map', {})) - - api_version = kwargs.pop('api_version', "2021-05-01-preview") # type: str - - - request = build_get_sip_configuration_request( - api_version=api_version, - template_url=self.get_sip_configuration.metadata['url'], - ) - request = _convert_request(request) - path_format_arguments = { - "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, 'str', skip_quote=True), - } - request.url = self._client.format_url(request.url, **path_format_arguments) - - pipeline_response = await self._client._pipeline.run( # pylint: disable=protected-access - request, - stream=False, - **kwargs - ) - response = pipeline_response.http_response - - if response.status_code not in [200]: - map_error(status_code=response.status_code, response=response, error_map=error_map) - error = self._deserialize.failsafe_deserialize(_models.CommunicationErrorResponse, pipeline_response) - raise HttpResponseError(response=response, model=error) - - deserialized = self._deserialize('SipConfiguration', pipeline_response) - - if cls: - return cls(pipeline_response, deserialized, {}) - - return deserialized - - get_sip_configuration.metadata = {'url': "/sip"} # type: ignore - - - @distributed_trace_async - async def patch_sip_configuration( - self, - body: Optional["_models.SipConfiguration"] = None, - **kwargs: Any - ) -> "_models.SipConfiguration": - """Patches SIP configuration for resource. - - Patches SIP configuration for resource. - - :param body: Configuration patch. Default value is None. - :type body: ~azure.communication.phonenumbers.siprouting.models.SipConfiguration - :keyword callable cls: A custom type or function that will be passed the direct response - :return: SipConfiguration, or the result of cls(response) - :rtype: ~azure.communication.phonenumbers.siprouting.models.SipConfiguration - :raises: ~azure.core.exceptions.HttpResponseError - """ - cls = kwargs.pop('cls', None) # type: ClsType["_models.SipConfiguration"] - error_map = { - 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError - } - error_map.update(kwargs.pop('error_map', {})) - - api_version = kwargs.pop('api_version', "2021-05-01-preview") # type: str - content_type = kwargs.pop('content_type', "application/merge-patch+json") # type: Optional[str] - - if body is not None: - _json = self._serialize.body(body, 'SipConfiguration') - else: - _json = None - - request = build_patch_sip_configuration_request( - api_version=api_version, - content_type=content_type, - json=_json, - template_url=self.patch_sip_configuration.metadata['url'], - ) - request = _convert_request(request) - path_format_arguments = { - "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, 'str', skip_quote=True), - } - request.url = self._client.format_url(request.url, **path_format_arguments) - - pipeline_response = await self._client._pipeline.run( # pylint: disable=protected-access - request, - stream=False, - **kwargs - ) - response = pipeline_response.http_response - - if response.status_code not in [200]: - map_error(status_code=response.status_code, response=response, error_map=error_map) - error = self._deserialize.failsafe_deserialize(_models.CommunicationErrorResponse, pipeline_response) - raise HttpResponseError(response=response, model=error) - - deserialized = self._deserialize('SipConfiguration', pipeline_response) - - if cls: - return cls(pipeline_response, deserialized, {}) - - return deserialized - - patch_sip_configuration.metadata = {'url': "/sip"} # type: ignore - diff --git a/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_generated/models/__init__.py b/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_generated/models/__init__.py index 1195f3916992..1d29e58c1947 100644 --- a/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_generated/models/__init__.py +++ b/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_generated/models/__init__.py @@ -6,23 +6,21 @@ # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- -try: - from ._models_py3 import CommunicationError - from ._models_py3 import CommunicationErrorResponse - from ._models_py3 import SipConfiguration - from ._models_py3 import SipTrunkInternal - from ._models_py3 import SipTrunkRoute -except (SyntaxError, ImportError): - from ._models import CommunicationError # type: ignore - from ._models import CommunicationErrorResponse # type: ignore - from ._models import SipConfiguration # type: ignore - from ._models import SipTrunkInternal # type: ignore - from ._models import SipTrunkRoute # type: ignore +from ._models import CommunicationError +from ._models import CommunicationErrorResponse +from ._models import SipConfiguration +from ._models import SipTrunkInternal +from ._models import SipTrunkRouteInternal +from ._patch import __all__ as _patch_all +from ._patch import * # pylint: disable=unused-wildcard-import +from ._patch import patch_sdk as _patch_sdk __all__ = [ - 'CommunicationError', - 'CommunicationErrorResponse', - 'SipConfiguration', - 'SipTrunkInternal', - 'SipTrunkRoute', + "CommunicationError", + "CommunicationErrorResponse", + "SipConfiguration", + "SipTrunkInternal", + "SipTrunkRouteInternal", ] +__all__.extend([p for p in _patch_all if p not in __all__]) +_patch_sdk() diff --git a/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_generated/models/_models.py b/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_generated/models/_models.py index 67ddb3f297f9..1b76b2daea54 100644 --- a/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_generated/models/_models.py +++ b/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_generated/models/_models.py @@ -1,4 +1,5 @@ # coding=utf-8 +# pylint: disable=too-many-lines # -------------------------------------------------------------------------- # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. See License.txt in the project root for license information. @@ -6,20 +7,25 @@ # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- -from azure.core.exceptions import HttpResponseError -import msrest.serialization +from typing import Any, Dict, List, Optional, TYPE_CHECKING +from .. import _serialization -class CommunicationError(msrest.serialization.Model): +if TYPE_CHECKING: + # pylint: disable=unused-import,ungrouped-imports + from .. import models as _models + + +class CommunicationError(_serialization.Model): """The Communication Services error. Variables are only populated by the server, and will be ignored when sending a request. All required parameters must be populated in order to send to Azure. - :ivar code: Required. The error code. + :ivar code: The error code. Required. :vartype code: str - :ivar message: Required. The error message. + :ivar message: The error message. Required. :vartype message: str :ivar target: The error target. :vartype target: str @@ -30,146 +36,147 @@ class CommunicationError(msrest.serialization.Model): """ _validation = { - 'code': {'required': True}, - 'message': {'required': True}, - 'target': {'readonly': True}, - 'details': {'readonly': True}, - 'inner_error': {'readonly': True}, + "code": {"required": True}, + "message": {"required": True}, + "target": {"readonly": True}, + "details": {"readonly": True}, + "inner_error": {"readonly": True}, } _attribute_map = { - 'code': {'key': 'code', 'type': 'str'}, - 'message': {'key': 'message', 'type': 'str'}, - 'target': {'key': 'target', 'type': 'str'}, - 'details': {'key': 'details', 'type': '[CommunicationError]'}, - 'inner_error': {'key': 'innererror', 'type': 'CommunicationError'}, + "code": {"key": "code", "type": "str"}, + "message": {"key": "message", "type": "str"}, + "target": {"key": "target", "type": "str"}, + "details": {"key": "details", "type": "[CommunicationError]"}, + "inner_error": {"key": "innererror", "type": "CommunicationError"}, } - def __init__( - self, - **kwargs - ): + def __init__(self, *, code: str, message: str, **kwargs: Any) -> None: """ - :keyword code: Required. The error code. + :keyword code: The error code. Required. :paramtype code: str - :keyword message: Required. The error message. + :keyword message: The error message. Required. :paramtype message: str """ - super(CommunicationError, self).__init__(**kwargs) - self.code = kwargs['code'] - self.message = kwargs['message'] + super().__init__(**kwargs) + self.code = code + self.message = message self.target = None self.details = None self.inner_error = None -class CommunicationErrorResponse(msrest.serialization.Model): +class CommunicationErrorResponse(_serialization.Model): """The Communication Services error. All required parameters must be populated in order to send to Azure. - :ivar error: Required. The Communication Services error. + :ivar error: The Communication Services error. Required. :vartype error: ~azure.communication.phonenumbers.siprouting.models.CommunicationError """ _validation = { - 'error': {'required': True}, + "error": {"required": True}, } _attribute_map = { - 'error': {'key': 'error', 'type': 'CommunicationError'}, + "error": {"key": "error", "type": "CommunicationError"}, } - def __init__( - self, - **kwargs - ): + def __init__(self, *, error: "_models.CommunicationError", **kwargs: Any) -> None: """ - :keyword error: Required. The Communication Services error. + :keyword error: The Communication Services error. Required. :paramtype error: ~azure.communication.phonenumbers.siprouting.models.CommunicationError """ - super(CommunicationErrorResponse, self).__init__(**kwargs) - self.error = kwargs['error'] + super().__init__(**kwargs) + self.error = error -class SipConfiguration(msrest.serialization.Model): +class SipConfiguration(_serialization.Model): """Represents a SIP configuration. -When a call is being routed the routes are applied in the same order as in the routes list. -A route is matched by its number pattern. -Call is then directed into route's first available trunk, based on the order in the route's trunks list. + When a call is being routed the routes are applied in the same order as in the routes list. + A route is matched by its number pattern. + Call is then directed into route's first available trunk, based on the order in the route's + trunks list. :ivar trunks: SIP trunks for routing calls. Map key is trunk's FQDN (1-249 characters). :vartype trunks: dict[str, ~azure.communication.phonenumbers.siprouting.models.SipTrunkInternal] :ivar routes: Trunk routes for routing calls. - :vartype routes: list[~azure.communication.phonenumbers.siprouting.models.SipTrunkRoute] + :vartype routes: + list[~azure.communication.phonenumbers.siprouting.models.SipTrunkRouteInternal] """ + _validation = { + "routes": {"max_items": 250, "min_items": 0}, + } + _attribute_map = { - 'trunks': {'key': 'trunks', 'type': '{SipTrunkInternal}'}, - 'routes': {'key': 'routes', 'type': '[SipTrunkRoute]'}, + "trunks": {"key": "trunks", "type": "{SipTrunkInternal}"}, + "routes": {"key": "routes", "type": "[SipTrunkRouteInternal]"}, } def __init__( self, - **kwargs - ): + *, + trunks: Optional[Dict[str, "_models.SipTrunkInternal"]] = None, + routes: Optional[List["_models.SipTrunkRouteInternal"]] = None, + **kwargs: Any + ) -> None: """ :keyword trunks: SIP trunks for routing calls. Map key is trunk's FQDN (1-249 characters). :paramtype trunks: dict[str, ~azure.communication.phonenumbers.siprouting.models.SipTrunkInternal] :keyword routes: Trunk routes for routing calls. - :paramtype routes: list[~azure.communication.phonenumbers.siprouting.models.SipTrunkRoute] + :paramtype routes: + list[~azure.communication.phonenumbers.siprouting.models.SipTrunkRouteInternal] """ - super(SipConfiguration, self).__init__(**kwargs) - self.trunks = kwargs.get('trunks', None) - self.routes = kwargs.get('routes', None) + super().__init__(**kwargs) + self.trunks = trunks + self.routes = routes -class SipTrunkInternal(msrest.serialization.Model): +class SipTrunkInternal(_serialization.Model): """Represents a SIP trunk for routing calls. See RFC 4904. All required parameters must be populated in order to send to Azure. - :ivar sip_signaling_port: Required. Gets or sets SIP signaling port of the trunk. + :ivar sip_signaling_port: Gets or sets SIP signaling port of the trunk. Required. :vartype sip_signaling_port: int """ _validation = { - 'sip_signaling_port': {'required': True}, + "sip_signaling_port": {"required": True}, } _attribute_map = { - 'sip_signaling_port': {'key': 'sipSignalingPort', 'type': 'int'}, + "sip_signaling_port": {"key": "sipSignalingPort", "type": "int"}, } - def __init__( - self, - **kwargs - ): + def __init__(self, *, sip_signaling_port: int, **kwargs: Any) -> None: """ - :keyword sip_signaling_port: Required. Gets or sets SIP signaling port of the trunk. + :keyword sip_signaling_port: Gets or sets SIP signaling port of the trunk. Required. :paramtype sip_signaling_port: int """ - super(SipTrunkInternal, self).__init__(**kwargs) - self.sip_signaling_port = kwargs['sip_signaling_port'] + super().__init__(**kwargs) + self.sip_signaling_port = sip_signaling_port -class SipTrunkRoute(msrest.serialization.Model): +class SipTrunkRouteInternal(_serialization.Model): """Represents a trunk route for routing calls. All required parameters must be populated in order to send to Azure. :ivar description: Gets or sets description of the route. :vartype description: str - :ivar name: Required. Gets or sets name of the route. + :ivar name: Gets or sets name of the route. Required. :vartype name: str - :ivar number_pattern: Required. Gets or sets regex number pattern for routing calls. .NET regex - format is supported. + :ivar number_pattern: Gets or sets regex number pattern for routing calls. .NET regex format is + supported. The regex should match only digits with an optional '+' prefix without spaces. - I.e. "^+[1-9][0-9]{3,23}$". + I.e. "^+[1-9][0-9]{3,23}$". Required. :vartype number_pattern: str :ivar trunks: Gets or sets list of SIP trunks for routing calls. Trunks are represented as FQDN. @@ -177,38 +184,44 @@ class SipTrunkRoute(msrest.serialization.Model): """ _validation = { - 'description': {'max_length': 1024, 'min_length': 0}, - 'name': {'required': True, 'max_length': 256, 'min_length': 0}, - 'number_pattern': {'required': True, 'max_length': 1024, 'min_length': 0}, + "description": {"max_length": 1024}, + "name": {"required": True, "max_length": 256}, + "number_pattern": {"required": True, "max_length": 1024}, + "trunks": {"max_items": 250, "min_items": 0}, } _attribute_map = { - 'description': {'key': 'description', 'type': 'str'}, - 'name': {'key': 'name', 'type': 'str'}, - 'number_pattern': {'key': 'numberPattern', 'type': 'str'}, - 'trunks': {'key': 'trunks', 'type': '[str]'}, + "description": {"key": "description", "type": "str"}, + "name": {"key": "name", "type": "str"}, + "number_pattern": {"key": "numberPattern", "type": "str"}, + "trunks": {"key": "trunks", "type": "[str]"}, } def __init__( self, - **kwargs - ): + *, + name: str, + number_pattern: str, + description: Optional[str] = None, + trunks: Optional[List[str]] = None, + **kwargs: Any + ) -> None: """ :keyword description: Gets or sets description of the route. :paramtype description: str - :keyword name: Required. Gets or sets name of the route. + :keyword name: Gets or sets name of the route. Required. :paramtype name: str - :keyword number_pattern: Required. Gets or sets regex number pattern for routing calls. .NET - regex format is supported. + :keyword number_pattern: Gets or sets regex number pattern for routing calls. .NET regex format + is supported. The regex should match only digits with an optional '+' prefix without spaces. - I.e. "^+[1-9][0-9]{3,23}$". + I.e. "^+[1-9][0-9]{3,23}$". Required. :paramtype number_pattern: str :keyword trunks: Gets or sets list of SIP trunks for routing calls. Trunks are represented as FQDN. :paramtype trunks: list[str] """ - super(SipTrunkRoute, self).__init__(**kwargs) - self.description = kwargs.get('description', None) - self.name = kwargs['name'] - self.number_pattern = kwargs['number_pattern'] - self.trunks = kwargs.get('trunks', None) + super().__init__(**kwargs) + self.description = description + self.name = name + self.number_pattern = number_pattern + self.trunks = trunks diff --git a/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_generated/models/_models_py3.py b/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_generated/models/_models_py3.py deleted file mode 100644 index d8fde711e0ba..000000000000 --- a/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_generated/models/_models_py3.py +++ /dev/null @@ -1,231 +0,0 @@ -# coding=utf-8 -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from typing import Dict, List, Optional - -from azure.core.exceptions import HttpResponseError -import msrest.serialization - - -class CommunicationError(msrest.serialization.Model): - """The Communication Services error. - - Variables are only populated by the server, and will be ignored when sending a request. - - All required parameters must be populated in order to send to Azure. - - :ivar code: Required. The error code. - :vartype code: str - :ivar message: Required. The error message. - :vartype message: str - :ivar target: The error target. - :vartype target: str - :ivar details: Further details about specific errors that led to this error. - :vartype details: list[~azure.communication.phonenumbers.siprouting.models.CommunicationError] - :ivar inner_error: The inner error if any. - :vartype inner_error: ~azure.communication.phonenumbers.siprouting.models.CommunicationError - """ - - _validation = { - 'code': {'required': True}, - 'message': {'required': True}, - 'target': {'readonly': True}, - 'details': {'readonly': True}, - 'inner_error': {'readonly': True}, - } - - _attribute_map = { - 'code': {'key': 'code', 'type': 'str'}, - 'message': {'key': 'message', 'type': 'str'}, - 'target': {'key': 'target', 'type': 'str'}, - 'details': {'key': 'details', 'type': '[CommunicationError]'}, - 'inner_error': {'key': 'innererror', 'type': 'CommunicationError'}, - } - - def __init__( - self, - *, - code: str, - message: str, - **kwargs - ): - """ - :keyword code: Required. The error code. - :paramtype code: str - :keyword message: Required. The error message. - :paramtype message: str - """ - super(CommunicationError, self).__init__(**kwargs) - self.code = code - self.message = message - self.target = None - self.details = None - self.inner_error = None - - -class CommunicationErrorResponse(msrest.serialization.Model): - """The Communication Services error. - - All required parameters must be populated in order to send to Azure. - - :ivar error: Required. The Communication Services error. - :vartype error: ~azure.communication.phonenumbers.siprouting.models.CommunicationError - """ - - _validation = { - 'error': {'required': True}, - } - - _attribute_map = { - 'error': {'key': 'error', 'type': 'CommunicationError'}, - } - - def __init__( - self, - *, - error: "CommunicationError", - **kwargs - ): - """ - :keyword error: Required. The Communication Services error. - :paramtype error: ~azure.communication.phonenumbers.siprouting.models.CommunicationError - """ - super(CommunicationErrorResponse, self).__init__(**kwargs) - self.error = error - - -class SipConfiguration(msrest.serialization.Model): - """Represents a SIP configuration. -When a call is being routed the routes are applied in the same order as in the routes list. -A route is matched by its number pattern. -Call is then directed into route's first available trunk, based on the order in the route's trunks list. - - :ivar trunks: SIP trunks for routing calls. - Map key is trunk's FQDN (1-249 characters). - :vartype trunks: dict[str, - ~azure.communication.phonenumbers.siprouting.models.SipTrunkInternal] - :ivar routes: Trunk routes for routing calls. - :vartype routes: list[~azure.communication.phonenumbers.siprouting.models.SipTrunkRoute] - """ - - _attribute_map = { - 'trunks': {'key': 'trunks', 'type': '{SipTrunkInternal}'}, - 'routes': {'key': 'routes', 'type': '[SipTrunkRoute]'}, - } - - def __init__( - self, - *, - trunks: Optional[Dict[str, "SipTrunkInternal"]] = None, - routes: Optional[List["SipTrunkRoute"]] = None, - **kwargs - ): - """ - :keyword trunks: SIP trunks for routing calls. - Map key is trunk's FQDN (1-249 characters). - :paramtype trunks: dict[str, - ~azure.communication.phonenumbers.siprouting.models.SipTrunkInternal] - :keyword routes: Trunk routes for routing calls. - :paramtype routes: list[~azure.communication.phonenumbers.siprouting.models.SipTrunkRoute] - """ - super(SipConfiguration, self).__init__(**kwargs) - self.trunks = trunks - self.routes = routes - - -class SipTrunkInternal(msrest.serialization.Model): - """Represents a SIP trunk for routing calls. See RFC 4904. - - All required parameters must be populated in order to send to Azure. - - :ivar sip_signaling_port: Required. Gets or sets SIP signaling port of the trunk. - :vartype sip_signaling_port: int - """ - - _validation = { - 'sip_signaling_port': {'required': True}, - } - - _attribute_map = { - 'sip_signaling_port': {'key': 'sipSignalingPort', 'type': 'int'}, - } - - def __init__( - self, - *, - sip_signaling_port: int, - **kwargs - ): - """ - :keyword sip_signaling_port: Required. Gets or sets SIP signaling port of the trunk. - :paramtype sip_signaling_port: int - """ - super(SipTrunkInternal, self).__init__(**kwargs) - self.sip_signaling_port = sip_signaling_port - - -class SipTrunkRoute(msrest.serialization.Model): - """Represents a trunk route for routing calls. - - All required parameters must be populated in order to send to Azure. - - :ivar description: Gets or sets description of the route. - :vartype description: str - :ivar name: Required. Gets or sets name of the route. - :vartype name: str - :ivar number_pattern: Required. Gets or sets regex number pattern for routing calls. .NET regex - format is supported. - The regex should match only digits with an optional '+' prefix without spaces. - I.e. "^+[1-9][0-9]{3,23}$". - :vartype number_pattern: str - :ivar trunks: Gets or sets list of SIP trunks for routing calls. Trunks are represented as - FQDN. - :vartype trunks: list[str] - """ - - _validation = { - 'description': {'max_length': 1024, 'min_length': 0}, - 'name': {'required': True, 'max_length': 256, 'min_length': 0}, - 'number_pattern': {'required': True, 'max_length': 1024, 'min_length': 0}, - } - - _attribute_map = { - 'description': {'key': 'description', 'type': 'str'}, - 'name': {'key': 'name', 'type': 'str'}, - 'number_pattern': {'key': 'numberPattern', 'type': 'str'}, - 'trunks': {'key': 'trunks', 'type': '[str]'}, - } - - def __init__( - self, - *, - name: str, - number_pattern: str, - description: Optional[str] = None, - trunks: Optional[List[str]] = None, - **kwargs - ): - """ - :keyword description: Gets or sets description of the route. - :paramtype description: str - :keyword name: Required. Gets or sets name of the route. - :paramtype name: str - :keyword number_pattern: Required. Gets or sets regex number pattern for routing calls. .NET - regex format is supported. - The regex should match only digits with an optional '+' prefix without spaces. - I.e. "^+[1-9][0-9]{3,23}$". - :paramtype number_pattern: str - :keyword trunks: Gets or sets list of SIP trunks for routing calls. Trunks are represented as - FQDN. - :paramtype trunks: list[str] - """ - super(SipTrunkRoute, self).__init__(**kwargs) - self.description = description - self.name = name - self.number_pattern = number_pattern - self.trunks = trunks diff --git a/sdk/keyvault/azure-keyvault-keys/azure/keyvault/keys/_generated/v7_4_preview_1/aio/_patch.py b/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_generated/models/_patch.py similarity index 100% rename from sdk/keyvault/azure-keyvault-keys/azure/keyvault/keys/_generated/v7_4_preview_1/aio/_patch.py rename to sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_generated/models/_patch.py diff --git a/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_generated/operations/__init__.py b/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_generated/operations/__init__.py index f73fee5205e1..aa58cdc26a48 100644 --- a/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_generated/operations/__init__.py +++ b/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_generated/operations/__init__.py @@ -6,8 +6,14 @@ # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- -from ._sip_routing_service_operations import SIPRoutingServiceOperationsMixin +from ._operations import SipRoutingOperations + +from ._patch import __all__ as _patch_all +from ._patch import * # pylint: disable=unused-wildcard-import +from ._patch import patch_sdk as _patch_sdk __all__ = [ - 'SIPRoutingServiceOperationsMixin', + "SipRoutingOperations", ] +__all__.extend([p for p in _patch_all if p not in __all__]) +_patch_sdk() diff --git a/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_generated/operations/_operations.py b/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_generated/operations/_operations.py new file mode 100644 index 000000000000..5b7264a436cf --- /dev/null +++ b/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_generated/operations/_operations.py @@ -0,0 +1,265 @@ +# pylint: disable=too-many-lines +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +import sys +from typing import Any, Callable, Dict, IO, Optional, TypeVar, Union, overload + +from azure.core.exceptions import ( + ClientAuthenticationError, + HttpResponseError, + ResourceExistsError, + ResourceNotFoundError, + ResourceNotModifiedError, + map_error, +) +from azure.core.pipeline import PipelineResponse +from azure.core.pipeline.transport import HttpResponse +from azure.core.rest import HttpRequest +from azure.core.tracing.decorator import distributed_trace +from azure.core.utils import case_insensitive_dict + +from .. import models as _models +from .._serialization import Serializer + +if sys.version_info >= (3, 8): + from typing import Literal # pylint: disable=no-name-in-module, ungrouped-imports +else: + from typing_extensions import Literal # type: ignore # pylint: disable=ungrouped-imports +T = TypeVar("T") +ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] + +_SERIALIZER = Serializer() +_SERIALIZER.client_side_validation = False + + +def build_sip_routing_get_request(**kwargs: Any) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + api_version: Literal["2023-03-01"] = kwargs.pop("api_version", _params.pop("api-version", "2023-03-01")) + accept = _headers.pop("Accept", "application/json") + + # Construct URL + _url = "/sip" + + # Construct parameters + _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") + + # Construct headers + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_sip_routing_update_request(**kwargs: Any) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + api_version: Literal["2023-03-01"] = kwargs.pop("api_version", _params.pop("api-version", "2023-03-01")) + accept = _headers.pop("Accept", "application/json") + + # Construct URL + _url = "/sip" + + # Construct parameters + _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") + + # Construct headers + if content_type is not None: + _headers["Content-Type"] = _SERIALIZER.header("content_type", content_type, "str") + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="PATCH", url=_url, params=_params, headers=_headers, **kwargs) + + +class SipRoutingOperations: + """ + .. warning:: + **DO NOT** instantiate this class directly. + + Instead, you should access the following operations through + :class:`~azure.communication.phonenumbers.siprouting.SIPRoutingService`'s + :attr:`sip_routing` attribute. + """ + + models = _models + + def __init__(self, *args, **kwargs): + input_args = list(args) + self._client = input_args.pop(0) if input_args else kwargs.pop("client") + self._config = input_args.pop(0) if input_args else kwargs.pop("config") + self._serialize = input_args.pop(0) if input_args else kwargs.pop("serializer") + self._deserialize = input_args.pop(0) if input_args else kwargs.pop("deserializer") + + @distributed_trace + def get(self, **kwargs: Any) -> _models.SipConfiguration: + """Gets SIP configuration for resource. + + Gets SIP configuration for resource. + + :return: SipConfiguration + :rtype: ~azure.communication.phonenumbers.siprouting.models.SipConfiguration + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[_models.SipConfiguration] = kwargs.pop("cls", None) + + request = build_sip_routing_get_request( + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + request.url = self._client.format_url(request.url, **path_format_arguments) + + _stream = False + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.CommunicationErrorResponse, pipeline_response) + raise HttpResponseError(response=response, model=error) + + deserialized = self._deserialize("SipConfiguration", pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + + @overload + def update( + self, + body: Optional[_models.SipConfiguration] = None, + *, + content_type: str = "application/merge-patch+json", + **kwargs: Any + ) -> _models.SipConfiguration: + """Updates SIP configuration for resource. + + Updates SIP configuration for resource. + + :param body: Sip configuration update object. Default value is None. + :type body: ~azure.communication.phonenumbers.siprouting.models.SipConfiguration + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/merge-patch+json". + :paramtype content_type: str + :return: SipConfiguration + :rtype: ~azure.communication.phonenumbers.siprouting.models.SipConfiguration + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + def update( + self, body: Optional[IO] = None, *, content_type: str = "application/merge-patch+json", **kwargs: Any + ) -> _models.SipConfiguration: + """Updates SIP configuration for resource. + + Updates SIP configuration for resource. + + :param body: Sip configuration update object. Default value is None. + :type body: IO + :keyword content_type: Body Parameter content-type. Content type parameter for binary body. + Default value is "application/merge-patch+json". + :paramtype content_type: str + :return: SipConfiguration + :rtype: ~azure.communication.phonenumbers.siprouting.models.SipConfiguration + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @distributed_trace + def update( + self, body: Optional[Union[_models.SipConfiguration, IO]] = None, **kwargs: Any + ) -> _models.SipConfiguration: + """Updates SIP configuration for resource. + + Updates SIP configuration for resource. + + :param body: Sip configuration update object. Is either a SipConfiguration type or a IO type. + Default value is None. + :type body: ~azure.communication.phonenumbers.siprouting.models.SipConfiguration or IO + :keyword content_type: Body Parameter content-type. Known values are: + 'application/merge-patch+json'. Default value is None. + :paramtype content_type: str + :return: SipConfiguration + :rtype: ~azure.communication.phonenumbers.siprouting.models.SipConfiguration + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = kwargs.pop("params", {}) or {} + + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[_models.SipConfiguration] = kwargs.pop("cls", None) + + content_type = content_type or "application/merge-patch+json" + _json = None + _content = None + if isinstance(body, (IO, bytes)): + _content = body + else: + if body is not None: + _json = self._serialize.body(body, "SipConfiguration") + else: + _json = None + + request = build_sip_routing_update_request( + content_type=content_type, + api_version=self._config.api_version, + json=_json, + content=_content, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + request.url = self._client.format_url(request.url, **path_format_arguments) + + _stream = False + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.CommunicationErrorResponse, pipeline_response) + raise HttpResponseError(response=response, model=error) + + deserialized = self._deserialize("SipConfiguration", pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized diff --git a/sdk/keyvault/azure-keyvault-keys/azure/keyvault/keys/_generated/v7_4_preview_1/aio/operations/_patch.py b/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_generated/operations/_patch.py similarity index 100% rename from sdk/keyvault/azure-keyvault-keys/azure/keyvault/keys/_generated/v7_4_preview_1/aio/operations/_patch.py rename to sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_generated/operations/_patch.py diff --git a/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_generated/operations/_sip_routing_service_operations.py b/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_generated/operations/_sip_routing_service_operations.py deleted file mode 100644 index 1de42380b4c5..000000000000 --- a/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_generated/operations/_sip_routing_service_operations.py +++ /dev/null @@ -1,211 +0,0 @@ -# pylint: disable=too-many-lines -# coding=utf-8 -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- -from typing import TYPE_CHECKING - -from msrest import Serializer - -from azure.core.exceptions import ClientAuthenticationError, HttpResponseError, ResourceExistsError, ResourceNotFoundError, map_error -from azure.core.pipeline import PipelineResponse -from azure.core.pipeline.transport import HttpResponse -from azure.core.rest import HttpRequest -from azure.core.tracing.decorator import distributed_trace - -from .. import models as _models -from .._vendor import _convert_request - -if TYPE_CHECKING: - # pylint: disable=unused-import,ungrouped-imports - from typing import Any, Callable, Dict, Optional, TypeVar - T = TypeVar('T') - ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] - -_SERIALIZER = Serializer() -_SERIALIZER.client_side_validation = False -# fmt: off - -def build_get_sip_configuration_request( - **kwargs # type: Any -): - # type: (...) -> HttpRequest - api_version = kwargs.pop('api_version', "2021-05-01-preview") # type: str - - accept = "application/json" - # Construct URL - _url = kwargs.pop("template_url", "/sip") - - # Construct parameters - _query_parameters = kwargs.pop("params", {}) # type: Dict[str, Any] - _query_parameters['api-version'] = _SERIALIZER.query("api_version", api_version, 'str') - - # Construct headers - _header_parameters = kwargs.pop("headers", {}) # type: Dict[str, Any] - _header_parameters['Accept'] = _SERIALIZER.header("accept", accept, 'str') - - return HttpRequest( - method="GET", - url=_url, - params=_query_parameters, - headers=_header_parameters, - **kwargs - ) - - -def build_patch_sip_configuration_request( - **kwargs # type: Any -): - # type: (...) -> HttpRequest - api_version = kwargs.pop('api_version', "2021-05-01-preview") # type: str - content_type = kwargs.pop('content_type', None) # type: Optional[str] - - accept = "application/json" - # Construct URL - _url = kwargs.pop("template_url", "/sip") - - # Construct parameters - _query_parameters = kwargs.pop("params", {}) # type: Dict[str, Any] - _query_parameters['api-version'] = _SERIALIZER.query("api_version", api_version, 'str') - - # Construct headers - _header_parameters = kwargs.pop("headers", {}) # type: Dict[str, Any] - if content_type is not None: - _header_parameters['Content-Type'] = _SERIALIZER.header("content_type", content_type, 'str') - _header_parameters['Accept'] = _SERIALIZER.header("accept", accept, 'str') - - return HttpRequest( - method="PATCH", - url=_url, - params=_query_parameters, - headers=_header_parameters, - **kwargs - ) - -# fmt: on -class SIPRoutingServiceOperationsMixin(object): - - @distributed_trace - def get_sip_configuration( - self, - **kwargs # type: Any - ): - # type: (...) -> "_models.SipConfiguration" - """Gets SIP configuration for resource. - - Gets SIP configuration for resource. - - :keyword callable cls: A custom type or function that will be passed the direct response - :return: SipConfiguration, or the result of cls(response) - :rtype: ~azure.communication.phonenumbers.siprouting.models.SipConfiguration - :raises: ~azure.core.exceptions.HttpResponseError - """ - cls = kwargs.pop('cls', None) # type: ClsType["_models.SipConfiguration"] - error_map = { - 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError - } - error_map.update(kwargs.pop('error_map', {})) - - api_version = kwargs.pop('api_version', "2021-05-01-preview") # type: str - - - request = build_get_sip_configuration_request( - api_version=api_version, - template_url=self.get_sip_configuration.metadata['url'], - ) - request = _convert_request(request) - path_format_arguments = { - "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, 'str', skip_quote=True), - } - request.url = self._client.format_url(request.url, **path_format_arguments) - - pipeline_response = self._client._pipeline.run( # pylint: disable=protected-access - request, - stream=False, - **kwargs - ) - response = pipeline_response.http_response - - if response.status_code not in [200]: - map_error(status_code=response.status_code, response=response, error_map=error_map) - error = self._deserialize.failsafe_deserialize(_models.CommunicationErrorResponse, pipeline_response) - raise HttpResponseError(response=response, model=error) - - deserialized = self._deserialize('SipConfiguration', pipeline_response) - - if cls: - return cls(pipeline_response, deserialized, {}) - - return deserialized - - get_sip_configuration.metadata = {'url': "/sip"} # type: ignore - - - @distributed_trace - def patch_sip_configuration( - self, - body=None, # type: Optional["_models.SipConfiguration"] - **kwargs # type: Any - ): - # type: (...) -> "_models.SipConfiguration" - """Patches SIP configuration for resource. - - Patches SIP configuration for resource. - - :param body: Configuration patch. Default value is None. - :type body: ~azure.communication.phonenumbers.siprouting.models.SipConfiguration - :keyword callable cls: A custom type or function that will be passed the direct response - :return: SipConfiguration, or the result of cls(response) - :rtype: ~azure.communication.phonenumbers.siprouting.models.SipConfiguration - :raises: ~azure.core.exceptions.HttpResponseError - """ - cls = kwargs.pop('cls', None) # type: ClsType["_models.SipConfiguration"] - error_map = { - 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError - } - error_map.update(kwargs.pop('error_map', {})) - - api_version = kwargs.pop('api_version', "2021-05-01-preview") # type: str - content_type = kwargs.pop('content_type', "application/merge-patch+json") # type: Optional[str] - - if body is not None: - _json = self._serialize.body(body, 'SipConfiguration') - else: - _json = None - - request = build_patch_sip_configuration_request( - api_version=api_version, - content_type=content_type, - json=_json, - template_url=self.patch_sip_configuration.metadata['url'], - ) - request = _convert_request(request) - path_format_arguments = { - "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, 'str', skip_quote=True), - } - request.url = self._client.format_url(request.url, **path_format_arguments) - - pipeline_response = self._client._pipeline.run( # pylint: disable=protected-access - request, - stream=False, - **kwargs - ) - response = pipeline_response.http_response - - if response.status_code not in [200]: - map_error(status_code=response.status_code, response=response, error_map=error_map) - error = self._deserialize.failsafe_deserialize(_models.CommunicationErrorResponse, pipeline_response) - raise HttpResponseError(response=response, model=error) - - deserialized = self._deserialize('SipConfiguration', pipeline_response) - - if cls: - return cls(pipeline_response, deserialized, {}) - - return deserialized - - patch_sip_configuration.metadata = {'url': "/sip"} # type: ignore - diff --git a/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_models.py b/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_models.py index ff54f4e1e2f3..27d7f74153cc 100644 --- a/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_models.py +++ b/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_models.py @@ -30,4 +30,50 @@ def __init__( """ self.fqdn = kwargs.get('fqdn', None) self.sip_signaling_port = kwargs.get('sip_signaling_port', None) - \ No newline at end of file + +class SipTrunkRoute(object): + """Represents a trunk route for routing calls. + + :ivar description: Gets or sets description of the route. + :vartype description: str + :ivar name: Gets or sets name of the route. Required. + :vartype name: str + :ivar number_pattern: Gets or sets regex number pattern for routing calls. .NET regex format is + supported. + The regex should match only digits with an optional '+' prefix without spaces. + I.e. "^+[1-9][0-9]{3,23}$". Required. + :vartype number_pattern: str + :ivar trunks: Gets or sets list of SIP trunks for routing calls. Trunks are represented as + FQDN. + :vartype trunks: list[str] + """ + + _attribute_map = { + 'description': {'key': 'description', 'type': 'str'}, + 'name': {'key': 'name', 'type': 'str'}, + 'number_pattern': {'key': 'numberPattern', 'type': 'str'}, + 'trunks': {'key': 'trunks', 'type': '[str]'}, + } + + def __init__( + self, + **kwargs + ): + """ + :keyword description: Gets or sets description of the route. + :paramtype description: Optional[str] + :keyword name: Gets or sets name of the route. Required. + :paramtype name: str + :keyword number_pattern: Gets or sets regex number pattern for routing calls. .NET regex format + is supported. + The regex should match only digits with an optional '+' prefix without spaces. + I.e. "^+[1-9][0-9]{3,23}$". Required. + :paramtype number_pattern: str + :keyword trunks: Gets or sets list of SIP trunks for routing calls. Trunks are represented as + FQDN. + :paramtype trunks: Optional[List[str]] + """ + self.description = kwargs.get('description', None) + self.name = kwargs.get('name', None) + self.number_pattern = kwargs.get('number_pattern', None) + self.trunks = kwargs.get('trunks',None) diff --git a/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_sip_routing_client.py b/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_sip_routing_client.py index 1bb26883dfd1..355e8ce21521 100644 --- a/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_sip_routing_client.py +++ b/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/_sip_routing_client.py @@ -9,13 +9,13 @@ from azure.core.tracing.decorator import distributed_trace -from._models import SipTrunk +from._models import SipTrunk, SipTrunkRoute from ._generated.models import ( SipConfiguration, - SipTrunkRoute, - SipTrunkInternal + SipTrunkInternal, + SipTrunkRouteInternal ) -from ._generated._sip_routing_service import SIPRoutingService +from ._generated._client import SIPRoutingService from .._shared.utils import ( parse_connection_str, get_authentication_policy @@ -90,26 +90,23 @@ def get_trunk( self, trunk_fqdn, # type: str **kwargs # type: Any - ): # type: (...) -> Optional[SipTrunk] + ): # type: (...) -> SipTrunk """Retrieve a single SIP trunk. :param trunk_fqdn: FQDN of the desired SIP trunk. :type trunk_fqdn: str - :returns: SIP trunk with specified trunk_fqdn. If it doesn't exist, returns None. - :rtype: ~azure.communication.siprouting.models.SipTrunk or None - :raises: ~azure.core.exceptions.HttpResponseError, ValueError, LookupError + :returns: SIP trunk with specified trunk_fqdn. If it doesn't exist, throws KeyError. + :rtype: ~azure.communication.siprouting.models.SipTrunk + :raises: ~azure.core.exceptions.HttpResponseError, ValueError, KeyError """ if trunk_fqdn is None: raise ValueError("Parameter 'trunk_fqdn' must not be None.") - config = self._rest_service.get_sip_configuration( + config = self._rest_service.sip_routing.get( **kwargs) - if trunk_fqdn in config.trunks: - trunk = config.trunks[trunk_fqdn] - return SipTrunk(fqdn=trunk_fqdn,sip_signaling_port=trunk.sip_signaling_port) - - return None + trunk = config.trunks[trunk_fqdn] + return SipTrunk(fqdn=trunk_fqdn,sip_signaling_port=trunk.sip_signaling_port) @distributed_trace def set_trunk( @@ -128,7 +125,7 @@ def set_trunk( if trunk is None: raise ValueError("Parameter 'trunk' must not be None.") - self._patch_trunks_([trunk],**kwargs) + self._update_trunks_([trunk],**kwargs) @distributed_trace def delete_trunk( @@ -147,7 +144,7 @@ def delete_trunk( if trunk_fqdn is None: raise ValueError("Parameter 'trunk_fqdn' must not be None.") - self._rest_service.patch_sip_configuration( + self._rest_service.sip_routing.update( body=SipConfiguration(trunks={trunk_fqdn:None}), **kwargs) @@ -175,10 +172,15 @@ def list_routes( :rtype: Iterable[~azure.communication.siprouting.models.SipTrunkRoute] :raises: ~azure.core.exceptions.HttpResponseError """ - config = self._rest_service.get_sip_configuration( + config = self._rest_service.sip_routing.get( **kwargs ) - return config.routes + return [SipTrunkRoute( + description=x.description, + name=x.name, + number_pattern=x.number_pattern, + trunks=x.trunks + ) for x in config.routes] @distributed_trace def set_trunks( @@ -207,7 +209,7 @@ def set_trunks( config.trunks[x.fqdn] = None if len(config.trunks) > 0: - self._rest_service.patch_sip_configuration( + self._rest_service.sip_routing.update( body=config, **kwargs ) @@ -228,23 +230,29 @@ def set_routes( if routes is None: raise ValueError("Parameter 'routes' must not be None.") - self._rest_service.patch_sip_configuration( - body=SipConfiguration(routes=routes), **kwargs + routes_internal = [SipTrunkRouteInternal( + description=x.description, + name=x.name, + number_pattern=x.number_pattern, + trunks=x.trunks + ) for x in routes] + self._rest_service.sip_routing.update( + body=SipConfiguration(routes=routes_internal), **kwargs ) def _list_trunks_(self, **kwargs): - config = self._rest_service.get_sip_configuration( + config = self._rest_service.sip_routing.get( **kwargs) return [SipTrunk(fqdn=k,sip_signaling_port=v.sip_signaling_port) for k,v in config.trunks.items()] - def _patch_trunks_(self, + def _update_trunks_(self, trunks, # type: List[SipTrunk] **kwargs # type: Any ): # type: (...) -> SipTrunk trunks_internal = {x.fqdn: SipTrunkInternal(sip_signaling_port=x.sip_signaling_port) for x in trunks} modified_config = SipConfiguration(trunks=trunks_internal) - new_config = self._rest_service.patch_sip_configuration( + new_config = self._rest_service.sip_routing.update( body=modified_config, **kwargs ) return [SipTrunk(fqdn=k,sip_signaling_port=v.sip_signaling_port) for k,v in new_config.trunks.items()] diff --git a/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/aio/_sip_routing_client_async.py b/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/aio/_sip_routing_client_async.py index 04e0feae7525..38e7e725a9e8 100644 --- a/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/aio/_sip_routing_client_async.py +++ b/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/siprouting/aio/_sip_routing_client_async.py @@ -9,13 +9,13 @@ from azure.core.tracing.decorator_async import distributed_trace_async -from .._models import SipTrunk +from .._models import SipTrunk, SipTrunkRoute from .._generated.models import ( SipConfiguration, - SipTrunkRoute, - SipTrunkInternal + SipTrunkInternal, + SipTrunkRouteInternal ) -from .._generated.aio._sip_routing_service import SIPRoutingService +from .._generated.aio._client import SIPRoutingService from ..._shared.utils import ( parse_connection_str, get_authentication_policy @@ -94,26 +94,23 @@ async def get_trunk( self, trunk_fqdn, # type: str **kwargs # type: Any - ): # type: (...) -> Optional[SipTrunk] + ): # type: (...) -> SipTrunk """Retrieve a single SIP trunk. :param trunk_fqdn: FQDN of the desired SIP trunk. :type trunk_fqdn: str - :returns: SIP trunk with specified trunk_fqdn. If it doesn't exist, returns None. - :rtype: ~azure.communication.siprouting.models.SipTrunk or None - :raises: ~azure.core.exceptions.HttpResponseError, ValueError, LookupError + :returns: SIP trunk with specified trunk_fqdn. If it doesn't exist, throws KeyError. + :rtype: ~azure.communication.siprouting.models.SipTrunk + :raises: ~azure.core.exceptions.HttpResponseError, ValueError, KeyError """ if trunk_fqdn is None: raise ValueError("Parameter 'trunk_fqdn' must not be None.") - config = await self._rest_service.get_sip_configuration( + config = await self._rest_service.sip_routing.get( **kwargs) - if trunk_fqdn in config.trunks: - trunk = config.trunks[trunk_fqdn] - return SipTrunk(fqdn=trunk_fqdn,sip_signaling_port=trunk.sip_signaling_port) - - return None + trunk = config.trunks[trunk_fqdn] + return SipTrunk(fqdn=trunk_fqdn,sip_signaling_port=trunk.sip_signaling_port) @distributed_trace_async async def set_trunk( @@ -132,7 +129,7 @@ async def set_trunk( if trunk is None: raise ValueError("Parameter 'trunk' must not be None.") - await self._patch_trunks_([trunk],**kwargs) + await self._update_trunks_([trunk],**kwargs) @distributed_trace_async async def delete_trunk( @@ -151,7 +148,7 @@ async def delete_trunk( if trunk_fqdn is None: raise ValueError("Parameter 'trunk_fqdn' must not be None.") - await self._rest_service.patch_sip_configuration( + await self._rest_service.sip_routing.update( body=SipConfiguration(trunks={trunk_fqdn:None}), **kwargs) @@ -179,10 +176,15 @@ async def list_routes( :rtype: Iterable[~azure.communication.siprouting.models.SipTrunkRoute] :raises: ~azure.core.exceptions.HttpResponseError """ - config = await self._rest_service.get_sip_configuration( + config = await self._rest_service.sip_routing.get( **kwargs ) - return config.routes + return [SipTrunkRoute( + description=x.description, + name=x.name, + number_pattern=x.number_pattern, + trunks=x.trunks + ) for x in config.routes] @distributed_trace_async async def set_trunks( @@ -211,7 +213,7 @@ async def set_trunks( config.trunks[x.fqdn] = None if len(config.trunks) > 0: - await self._rest_service.patch_sip_configuration( + await self._rest_service.sip_routing.update( body=config, **kwargs ) @@ -232,25 +234,31 @@ async def set_routes( if routes is None: raise ValueError("Parameter 'routes' must not be None.") - await self._rest_service.patch_sip_configuration( - body=SipConfiguration(routes=routes), + routes_internal = [SipTrunkRouteInternal( + description=x.description, + name=x.name, + number_pattern=x.number_pattern, + trunks=x.trunks + ) for x in routes] + await self._rest_service.sip_routing.update( + body=SipConfiguration(routes=routes_internal), **kwargs ) async def _list_trunks_(self, **kwargs): - config = await self._rest_service.get_sip_configuration( + config = await self._rest_service.sip_routing.get( **kwargs ) return [SipTrunk(fqdn=k,sip_signaling_port=v.sip_signaling_port) for k,v in config.trunks.items()] - async def _patch_trunks_(self, + async def _update_trunks_(self, trunks, # type: List[SipTrunk] **kwargs # type: Any ): # type: (...) -> SipTrunk trunks_internal = {x.fqdn: SipTrunkInternal(sip_signaling_port=x.sip_signaling_port) for x in trunks} modified_config = SipConfiguration(trunks=trunks_internal) - new_config = await self._rest_service.patch_sip_configuration( + new_config = await self._rest_service.sip_routing.update( body=modified_config, **kwargs ) return [SipTrunk(fqdn=k,sip_signaling_port=v.sip_signaling_port) for k,v in new_config.trunks.items()] diff --git a/sdk/communication/azure-communication-phonenumbers/swagger/SIP_ROUTING_SWAGGER.md b/sdk/communication/azure-communication-phonenumbers/swagger/SIP_ROUTING_SWAGGER.md index 8347a1dd5f76..4dc5ac3ddcbc 100644 --- a/sdk/communication/azure-communication-phonenumbers/swagger/SIP_ROUTING_SWAGGER.md +++ b/sdk/communication/azure-communication-phonenumbers/swagger/SIP_ROUTING_SWAGGER.md @@ -15,8 +15,8 @@ autorest SWAGGER.md ### Settings ``` yaml -require: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/15d66311cc2b64f04692fdf021d1b235b538e1bc/specification/communication/data-plane/SipRouting/readme.md -tag: package-2021-05-01-preview +require: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/communication/data-plane/SipRouting/readme.md +tag: package-2023-03 output-folder: ../azure/communication/phonenumbers/siprouting/_generated namespace: azure.communication.phonenumbers.siprouting no-namespace-folders: true @@ -26,13 +26,14 @@ python: true v3: true title: SIP Routing Service model-namespace: false +models-mode: msrest ``` -### Remove the -Patch types and use simple types instead, to simplify user interface +### Remove the -Update types and use simple types instead, to simplify user interface ``` yaml directive: from: swagger-document - where: $.paths.*[?(@.operationId == "PatchSipConfiguration")].parameters..[?(@.description == "Configuration patch.")] + where: $.paths.*[?(@.operationId == "SipRouting_Update")].parameters..[?(@.description == "Sip configuration update object.")] transform: > $.schema = {"$ref": "#/definitions/SipConfiguration"} ``` @@ -42,7 +43,7 @@ directive: from: swagger-document where: $.definitions transform: > - delete $.TrunkPatch + delete $.TrunkUpdate ``` ``` yaml @@ -50,7 +51,7 @@ directive: from: swagger-document where: $.definitions transform: > - delete $.SipConfigurationPatch + delete $.SipConfigurationUpdate ``` ### Directive renaming "Trunk" model to "SipTrunkInternal" @@ -62,36 +63,11 @@ directive: $["x-ms-client-name"] = "SipTrunkInternal"; ``` -### Directive renaming "TrunkRoute" model to "SipTrunkRoute" +### Directive renaming "TrunkRoute" model to "SipTrunkRouteInternal" ``` yaml directive: from: swagger-document where: "$.definitions.TrunkRoute" transform: > - $["x-ms-client-name"] = "SipTrunkRoute"; + $["x-ms-client-name"] = "SipTrunkRouteInternal"; ``` - -### Remove additional responses from Swagger, because they should be treated as errors and throw exception -``` yaml -directive: - from: swagger-document - where: $.paths.*[?(@.operationId == "PatchSipConfiguration")] - transform: > - delete $.responses["422"] -``` - -``` yaml -directive: - from: swagger-document - where: $.paths.*[?(@.operationId == "PatchSipConfiguration")] - transform: > - delete $.responses["415"] -``` - -``` yaml -directive: - from: swagger-document - where: $.paths.*[?(@.operationId == "PatchSipConfiguration")] - transform: > - delete $.responses["500"] -``` \ No newline at end of file diff --git a/sdk/communication/azure-communication-phonenumbers/test/conftest.py b/sdk/communication/azure-communication-phonenumbers/test/conftest.py index 90cd3a86e7d4..f44bdbb91462 100644 --- a/sdk/communication/azure-communication-phonenumbers/test/conftest.py +++ b/sdk/communication/azure-communication-phonenumbers/test/conftest.py @@ -45,15 +45,15 @@ def add_sanitizers(test_proxy): add_body_key_sanitizer(json_path="phoneNumbers[*].id", value="sanitized") add_body_key_sanitizer( json_path="phoneNumbers[*].phoneNumber", value="sanitized") - + + add_general_regex_sanitizer( + regex=r"-[0-9a-fA-F]{32}\.[0-9a-zA-Z\.]*(\.com|\.net|\.test)", value=".sanitized.com") + add_general_regex_sanitizer(regex=r"[%2B\d]{10,15}", value="sanitized") add_general_regex_sanitizer( regex=r"phoneNumbers/[%2B\d]{10,15}", value="phoneNumbers/sanitized") - add_general_regex_sanitizer( - regex=r"\.[0-9a-fA-F]{32}\.com", value=".sanitized.com") - add_header_regex_sanitizer(key="P3P", value="sanitized") add_header_regex_sanitizer(key="Set-Cookie", value="sanitized") add_header_regex_sanitizer(key="Date", value="sanitized") diff --git a/sdk/communication/azure-communication-phonenumbers/test/recordings/test_phone_number_administration_client.pyTestPhoneNumbersClienttest_update_phone_number_capabilities_with_invalid_number.json b/sdk/communication/azure-communication-phonenumbers/test/recordings/test_phone_number_administration_client.pyTestPhoneNumbersClienttest_update_phone_number_capabilities_with_invalid_number.json index e98d337b33f2..ee1a10fcab82 100644 --- a/sdk/communication/azure-communication-phonenumbers/test/recordings/test_phone_number_administration_client.pyTestPhoneNumbersClienttest_update_phone_number_capabilities_with_invalid_number.json +++ b/sdk/communication/azure-communication-phonenumbers/test/recordings/test_phone_number_administration_client.pyTestPhoneNumbersClienttest_update_phone_number_capabilities_with_invalid_number.json @@ -1,7 +1,7 @@ { "Entries": [ { - "RequestUri": "https://sanitized.communication.azure.com/phoneNumbers/invalid_phone_number/capabilities?api-version=2022-01-11-preview2", + "RequestUri": "https://sanitized.communication.azure.com/phoneNumbers/invalid_phone_number/capabilities?api-version=2022-12-01", "RequestMethod": "PATCH", "RequestHeaders": { "Accept": "application/json", @@ -9,7 +9,7 @@ "Connection": "keep-alive", "Content-Length": "49", "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.11.0 (Windows-10-10.0.22621-SP0)", + "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b4 Python/3.10.10 (Windows-10-10.0.22621-SP0)", "x-ms-content-sha256": "sanitized", "x-ms-date": "sanitized", "x-ms-return-client-request-id": "true" @@ -18,9 +18,9 @@ "calling": "inbound", "sms": "inbound\u002Boutbound" }, - "StatusCode": 404, + "StatusCode": 403, "ResponseHeaders": { - "api-supported-versions": "2021-03-07, 2022-01-11-preview2, 2022-06-01-preview, 2022-12-01", + "api-supported-versions": "2021-03-07, 2022-01-11-preview2, 2022-06-01-preview, 2022-12-01, 2022-12-02-preview2", "Content-Type": "application/json", "Date": "sanitized", "MS-CV": "sanitized", @@ -28,12 +28,12 @@ "Transfer-Encoding": "chunked", "X-Azure-Ref": "sanitized", "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "75ms" + "X-Processing-Time": "49ms" }, "ResponseBody": { "error": { - "code": "InternalError", - "message": "The server encountered an internal error." + "code": "InsufficientPermissions", + "message": "Phone number not owned by this resource." } } } diff --git a/sdk/communication/azure-communication-phonenumbers/test/recordings/test_phone_number_administration_client.pyTestPhoneNumbersClienttest_update_phone_number_capabilities_with_unauthorized_number.json b/sdk/communication/azure-communication-phonenumbers/test/recordings/test_phone_number_administration_client.pyTestPhoneNumbersClienttest_update_phone_number_capabilities_with_unauthorized_number.json index 02db5c7efd33..36533965b83e 100644 --- a/sdk/communication/azure-communication-phonenumbers/test/recordings/test_phone_number_administration_client.pyTestPhoneNumbersClienttest_update_phone_number_capabilities_with_unauthorized_number.json +++ b/sdk/communication/azure-communication-phonenumbers/test/recordings/test_phone_number_administration_client.pyTestPhoneNumbersClienttest_update_phone_number_capabilities_with_unauthorized_number.json @@ -9,7 +9,7 @@ "Connection": "keep-alive", "Content-Length": "49", "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", + "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b4 Python/3.10.10 (Windows-10-10.0.22621-SP0)", "x-ms-content-sha256": "sanitized", "x-ms-date": "sanitized", "x-ms-return-client-request-id": "true" @@ -18,9 +18,9 @@ "calling": "inbound", "sms": "inbound\u002Boutbound" }, - "StatusCode": 404, + "StatusCode": 403, "ResponseHeaders": { - "api-supported-versions": "2021-03-07, 2022-01-11-preview2, 2022-06-01-preview, 2022-12-01", + "api-supported-versions": "2021-03-07, 2022-01-11-preview2, 2022-06-01-preview, 2022-12-01, 2022-12-02-preview2", "Content-Type": "application/json", "Date": "sanitized", "MS-CV": "sanitized", @@ -28,12 +28,12 @@ "Transfer-Encoding": "chunked", "X-Azure-Ref": "sanitized", "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "257ms" + "X-Processing-Time": "93ms" }, "ResponseBody": { "error": { - "code": "InternalError", - "message": "The server encountered an internal error." + "code": "InsufficientPermissions", + "message": "Phone number not owned by this resource." } } } diff --git a/sdk/communication/azure-communication-phonenumbers/test/recordings/test_phone_number_administration_client_async.pyTestPhoneNumbersClientAsynctest_update_phone_number_capabilities_with_invalid_number.json b/sdk/communication/azure-communication-phonenumbers/test/recordings/test_phone_number_administration_client_async.pyTestPhoneNumbersClientAsynctest_update_phone_number_capabilities_with_invalid_number.json index 30770ae60bc6..387b8300ba47 100644 --- a/sdk/communication/azure-communication-phonenumbers/test/recordings/test_phone_number_administration_client_async.pyTestPhoneNumbersClientAsynctest_update_phone_number_capabilities_with_invalid_number.json +++ b/sdk/communication/azure-communication-phonenumbers/test/recordings/test_phone_number_administration_client_async.pyTestPhoneNumbersClientAsynctest_update_phone_number_capabilities_with_invalid_number.json @@ -1,14 +1,14 @@ { "Entries": [ { - "RequestUri": "https://sanitized.communication.azure.com/phoneNumbers/invalid_phone_number/capabilities?api-version=2022-01-11-preview2", + "RequestUri": "https://sanitized.communication.azure.com/phoneNumbers/invalid_phone_number/capabilities?api-version=2022-12-01", "RequestMethod": "PATCH", "RequestHeaders": { "Accept": "application/json", "Accept-Encoding": "gzip, deflate", "Content-Length": "49", "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.11.0 (Windows-10-10.0.22621-SP0)", + "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b4 Python/3.10.10 (Windows-10-10.0.22621-SP0)", "x-ms-content-sha256": "sanitized", "x-ms-date": "sanitized", "x-ms-return-client-request-id": "true" @@ -17,9 +17,9 @@ "calling": "inbound", "sms": "inbound\u002Boutbound" }, - "StatusCode": 404, + "StatusCode": 403, "ResponseHeaders": { - "api-supported-versions": "2021-03-07, 2022-01-11-preview2, 2022-06-01-preview, 2022-12-01", + "api-supported-versions": "2021-03-07, 2022-01-11-preview2, 2022-06-01-preview, 2022-12-01, 2022-12-02-preview2", "Content-Type": "application/json", "Date": "sanitized", "MS-CV": "sanitized", @@ -27,12 +27,12 @@ "Transfer-Encoding": "chunked", "X-Azure-Ref": "sanitized", "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "78ms" + "X-Processing-Time": "320ms" }, "ResponseBody": { "error": { - "code": "InternalError", - "message": "The server encountered an internal error." + "code": "InsufficientPermissions", + "message": "Phone number not owned by this resource." } } } diff --git a/sdk/communication/azure-communication-phonenumbers/test/recordings/test_phone_number_administration_client_async.pyTestPhoneNumbersClientAsynctest_update_phone_number_capabilities_with_unauthorized_number.json b/sdk/communication/azure-communication-phonenumbers/test/recordings/test_phone_number_administration_client_async.pyTestPhoneNumbersClientAsynctest_update_phone_number_capabilities_with_unauthorized_number.json index b8912bd6d86e..a35b36d136be 100644 --- a/sdk/communication/azure-communication-phonenumbers/test/recordings/test_phone_number_administration_client_async.pyTestPhoneNumbersClientAsynctest_update_phone_number_capabilities_with_unauthorized_number.json +++ b/sdk/communication/azure-communication-phonenumbers/test/recordings/test_phone_number_administration_client_async.pyTestPhoneNumbersClientAsynctest_update_phone_number_capabilities_with_unauthorized_number.json @@ -8,7 +8,7 @@ "Accept-Encoding": "gzip, deflate", "Content-Length": "49", "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", + "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b4 Python/3.10.10 (Windows-10-10.0.22621-SP0)", "x-ms-content-sha256": "sanitized", "x-ms-date": "sanitized", "x-ms-return-client-request-id": "true" @@ -17,9 +17,9 @@ "calling": "inbound", "sms": "inbound\u002Boutbound" }, - "StatusCode": 404, + "StatusCode": 403, "ResponseHeaders": { - "api-supported-versions": "2021-03-07, 2022-01-11-preview2, 2022-06-01-preview, 2022-12-01", + "api-supported-versions": "2021-03-07, 2022-01-11-preview2, 2022-06-01-preview, 2022-12-01, 2022-12-02-preview2", "Content-Type": "application/json", "Date": "sanitized", "MS-CV": "sanitized", @@ -27,12 +27,12 @@ "Transfer-Encoding": "chunked", "X-Azure-Ref": "sanitized", "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "79ms" + "X-Processing-Time": "46ms" }, "ResponseBody": { "error": { - "code": "InternalError", - "message": "The server encountered an internal error." + "code": "InsufficientPermissions", + "message": "Phone number not owned by this resource." } } } diff --git a/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e.pyTestSipRoutingClientE2Etest_add_trunk.json b/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e.pyTestSipRoutingClientE2Etest_add_trunk.json index 158fc0942ef8..a53c95dde3da 100644 --- a/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e.pyTestSipRoutingClientE2Etest_add_trunk.json +++ b/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e.pyTestSipRoutingClientE2Etest_add_trunk.json @@ -1,127 +1,7 @@ { "Entries": [ { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "PATCH", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Connection": "keep-alive", - "Content-Length": "14", - "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": { - "routes": [] - }, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "175ms" - }, - "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "GET", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Connection": "keep-alive", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": null, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "317ms" - }, - "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "PATCH", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Connection": "keep-alive", - "Content-Length": "112", - "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - } - }, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "613ms" - }, - "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", + "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2023-03-01", "RequestMethod": "PATCH", "RequestHeaders": { "Accept": "application/json", @@ -129,7 +9,7 @@ "Connection": "keep-alive", "Content-Length": "62", "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", + "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b4 Python/3.11.0 (Windows-10-10.0.22621-SP0)", "x-ms-content-sha256": "sanitized", "x-ms-date": "sanitized", "x-ms-return-client-request-id": "true" @@ -143,15 +23,15 @@ }, "StatusCode": 200, "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", + "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview, 2023-01-01-preview, 2023-03-01", + "Content-Length": "165", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "MS-CV": "sanitized", "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", "X-Azure-Ref": "sanitized", "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "613ms" + "X-Processing-Time": "1163ms" }, "ResponseBody": { "trunks": { @@ -169,13 +49,13 @@ } }, { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", + "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2023-03-01", "RequestMethod": "GET", "RequestHeaders": { "Accept": "application/json", "Accept-Encoding": "gzip, deflate", "Connection": "keep-alive", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", + "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b4 Python/3.11.0 (Windows-10-10.0.22621-SP0)", "x-ms-content-sha256": "sanitized", "x-ms-date": "sanitized", "x-ms-return-client-request-id": "true" @@ -183,15 +63,15 @@ "RequestBody": null, "StatusCode": 200, "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", + "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview, 2023-01-01-preview, 2023-03-01", + "Content-Length": "165", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "MS-CV": "sanitized", "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", "X-Azure-Ref": "sanitized", "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "106ms" + "X-Processing-Time": "173ms" }, "ResponseBody": { "trunks": { diff --git a/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e.pyTestSipRoutingClientE2Etest_add_trunk_from_managed_identity.json b/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e.pyTestSipRoutingClientE2Etest_add_trunk_from_managed_identity.json index 9d2a43c7cb08..3874683f2fa1 100644 --- a/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e.pyTestSipRoutingClientE2Etest_add_trunk_from_managed_identity.json +++ b/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e.pyTestSipRoutingClientE2Etest_add_trunk_from_managed_identity.json @@ -1,146 +1,43 @@ { "Entries": [ { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "PATCH", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Connection": "keep-alive", - "Content-Length": "14", - "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": { - "routes": [] - }, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "180ms" - }, - "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - }, - "sbs3.sanitized.com": { - "sipSignalingPort": 2222 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", + "RequestUri": "https://login.microsoftonline.com/common/discovery/instance?authorization_endpoint=https://login.windows-ppe.net/sanitized/oauth2/v2.0/authorize\u0026api-version=1.0", "RequestMethod": "GET", "RequestHeaders": { - "Accept": "application/json", + "Accept": "*/*", "Accept-Encoding": "gzip, deflate", "Connection": "keep-alive", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" + "User-Agent": "azsdk-python-identity/1.12.0 Python/3.11.0 (Windows-10-10.0.22621-SP0)" }, "RequestBody": null, "StatusCode": 200, "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "118ms" - }, - "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - }, - "sbs3.sanitized.com": { - "sipSignalingPort": 2222 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "PATCH", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Connection": "keep-alive", - "Content-Length": "140", - "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - }, - "sbs3.sanitized.com": null - } - }, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", + "Access-Control-Allow-Methods": "GET, OPTIONS", + "Access-Control-Allow-Origin": "*", + "Cache-Control": "max-age=86400, private", + "Content-Length": "109", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "401ms" + "P3P": "sanitized", + "Set-Cookie": "sanitized", + "Strict-Transport-Security": "max-age=31536000; includeSubDomains", + "X-Content-Type-Options": "nosniff", + "x-ms-ests-server": "sanitized", + "X-XSS-Protection": "0" }, "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - }, - "routes": [] + "tenant_discovery_endpoint": "https://login.windows-ppe.net/sanitized/v2.0/.well-known/openid-configuration" } }, { - "RequestUri": "https://login.microsoftonline.com/sanitized/v2.0/.well-known/openid-configuration", + "RequestUri": "https://login.windows-ppe.net/sanitized/v2.0/.well-known/openid-configuration", "RequestMethod": "GET", "RequestHeaders": { "Accept": "*/*", "Accept-Encoding": "gzip, deflate", "Connection": "keep-alive", - "User-Agent": "azsdk-python-identity/1.13.0b1 Python/3.10.9 (Windows-10-10.0.22621-SP0)" + "Cookie": "sanitized", + "User-Agent": "azsdk-python-identity/1.12.0 Python/3.11.0 (Windows-10-10.0.22621-SP0)" }, "RequestBody": null, "StatusCode": 200, @@ -148,7 +45,7 @@ "Access-Control-Allow-Methods": "GET, OPTIONS", "Access-Control-Allow-Origin": "*", "Cache-Control": "max-age=86400, private", - "Content-Length": "1564", + "Content-Length": "1548", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "P3P": "sanitized", @@ -160,13 +57,13 @@ "X-XSS-Protection": "0" }, "ResponseBody": { - "token_endpoint": "https://login.microsoftonline.com/sanitized/oauth2/v2.0/token", + "token_endpoint": "https://login.windows-ppe.net/sanitized/oauth2/v2.0/token", "token_endpoint_auth_methods_supported": [ "client_secret_post", "private_key_jwt", "client_secret_basic" ], - "jwks_uri": "https://login.microsoftonline.com/sanitized/discovery/v2.0/keys", + "jwks_uri": "https://login.windows-ppe.net/sanitized/discovery/v2.0/keys", "response_modes_supported": [ "query", "fragment", @@ -190,14 +87,14 @@ "email", "offline_access" ], - "issuer": "https://login.microsoftonline.com/sanitized/v2.0", + "issuer": "https://login.windows-ppe.net/sanitized/v2.0", "request_uri_parameter_supported": false, - "userinfo_endpoint": "https://graph.microsoft.com/oidc/userinfo", - "authorization_endpoint": "https://login.microsoftonline.com/sanitized/oauth2/v2.0/authorize", - "device_authorization_endpoint": "https://login.microsoftonline.com/sanitized/oauth2/v2.0/devicecode", + "userinfo_endpoint": "https://graph.microsoft-ppe.com/oidc/userinfo", + "authorization_endpoint": "https://login.windows-ppe.net/sanitized/oauth2/v2.0/authorize", + "device_authorization_endpoint": "https://login.windows-ppe.net/sanitized/oauth2/v2.0/devicecode", "http_logout_supported": true, "frontchannel_logout_supported": true, - "end_session_endpoint": "https://login.microsoftonline.com/sanitized/oauth2/v2.0/logout", + "end_session_endpoint": "https://login.windows-ppe.net/sanitized/oauth2/v2.0/logout", "claims_supported": [ "sub", "iss", @@ -219,12 +116,12 @@ "c_hash", "email" ], - "kerberos_endpoint": "https://login.microsoftonline.com/sanitized/kerberos", - "tenant_region_scope": "WW", - "cloud_instance_name": "microsoftonline.com", - "cloud_graph_host_name": "graph.windows.net", - "msgraph_host": "graph.microsoft.com", - "rbac_url": "https://pas.windows.net" + "kerberos_endpoint": "https://login.windows-ppe.net/sanitized/kerberos", + "tenant_region_scope": "NA", + "cloud_instance_name": "windows-ppe.net", + "cloud_graph_host_name": "graph.ppe.windows.net", + "msgraph_host": "graph.microsoft-ppe.com", + "rbac_url": "https://pas.windows-ppe.net" } }, { @@ -235,7 +132,7 @@ "Accept-Encoding": "gzip, deflate", "Connection": "keep-alive", "Cookie": "sanitized", - "User-Agent": "azsdk-python-identity/1.13.0b1 Python/3.10.9 (Windows-10-10.0.22621-SP0)" + "User-Agent": "azsdk-python-identity/1.12.0 Python/3.11.0 (Windows-10-10.0.22621-SP0)" }, "RequestBody": null, "StatusCode": 200, @@ -251,7 +148,6 @@ "Strict-Transport-Security": "max-age=31536000; includeSubDomains", "X-Content-Type-Options": "nosniff", "x-ms-ests-server": "sanitized", - "x-ms-httpver": "1.1", "X-XSS-Protection": "0" }, "ResponseBody": { @@ -302,7 +198,7 @@ } }, { - "RequestUri": "https://login.microsoftonline.com/sanitized/oauth2/v2.0/token", + "RequestUri": "https://login.windows-ppe.net/sanitized/oauth2/v2.0/token", "RequestMethod": "POST", "RequestHeaders": { "Accept": "application/json", @@ -312,13 +208,13 @@ "Content-Length": "240", "Content-Type": "application/x-www-form-urlencoded", "Cookie": "sanitized", - "User-Agent": "azsdk-python-identity/1.13.0b1 Python/3.10.9 (Windows-10-10.0.22621-SP0)", + "User-Agent": "azsdk-python-identity/1.12.0 Python/3.11.0 (Windows-10-10.0.22621-SP0)", "x-client-cpu": "x64", "x-client-current-telemetry": "4|730,0|", "x-client-last-telemetry": "4|0|||", "x-client-os": "win32", "x-client-sku": "MSAL.Python", - "x-client-ver": "1.20.0", + "x-client-ver": "1.21.0", "x-ms-lib-capability": "retry-after, h429" }, "RequestBody": "client_id=sanitized\u0026grant_type=client_credentials\u0026client_info=1\u0026client_secret=sanitized\u0026claims=%7B%22access_token%22%3A\u002B%7B%22xms_cc%22%3A\u002B%7B%22values%22%3A\u002B%5B%22CP1%22%5D%7D%7D%7D\u0026scope=https%3A%2F%2Fcommunication.azure.com%2F%2F.default", @@ -326,7 +222,7 @@ "ResponseHeaders": { "Cache-Control": "no-store, no-cache", "client-request-id": "sanitized", - "Content-Length": "111", + "Content-Length": "90", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "Expires": "-1", @@ -342,14 +238,13 @@ }, "ResponseBody": { "token_type": "Bearer", - "expires_in": 86399, - "ext_expires_in": 86399, - "refresh_in": 43199, + "expires_in": 3599, + "ext_expires_in": 3599, "access_token": "Sanitized" } }, { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", + "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2023-03-01", "RequestMethod": "PATCH", "RequestHeaders": { "Accept": "application/json", @@ -357,7 +252,7 @@ "Connection": "keep-alive", "Content-Length": "62", "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)" + "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b4 Python/3.11.0 (Windows-10-10.0.22621-SP0)" }, "RequestBody": { "trunks": { @@ -368,15 +263,15 @@ }, "StatusCode": 200, "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", + "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview, 2023-01-01-preview, 2023-03-01", + "Content-Length": "165", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "MS-CV": "sanitized", "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", "X-Azure-Ref": "sanitized", "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "623ms" + "X-Processing-Time": "1146ms" }, "ResponseBody": { "trunks": { @@ -394,26 +289,26 @@ } }, { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", + "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2023-03-01", "RequestMethod": "GET", "RequestHeaders": { "Accept": "application/json", "Accept-Encoding": "gzip, deflate", "Connection": "keep-alive", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)" + "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b4 Python/3.11.0 (Windows-10-10.0.22621-SP0)" }, "RequestBody": null, "StatusCode": 200, "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", + "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview, 2023-01-01-preview, 2023-03-01", + "Content-Length": "165", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "MS-CV": "sanitized", "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", "X-Azure-Ref": "sanitized", "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "125ms" + "X-Processing-Time": "174ms" }, "ResponseBody": { "trunks": { diff --git a/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e.pyTestSipRoutingClientE2Etest_delete_trunk.json b/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e.pyTestSipRoutingClientE2Etest_delete_trunk.json index c167c5490b3f..52841b3f6ed4 100644 --- a/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e.pyTestSipRoutingClientE2Etest_delete_trunk.json +++ b/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e.pyTestSipRoutingClientE2Etest_delete_trunk.json @@ -1,133 +1,7 @@ { "Entries": [ { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "PATCH", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Connection": "keep-alive", - "Content-Length": "14", - "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": { - "routes": [] - }, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "191ms" - }, - "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "GET", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Connection": "keep-alive", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": null, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "101ms" - }, - "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "PATCH", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Connection": "keep-alive", - "Content-Length": "112", - "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - } - }, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "667ms" - }, - "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", + "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2023-03-01", "RequestMethod": "PATCH", "RequestHeaders": { "Accept": "application/json", @@ -135,7 +9,7 @@ "Connection": "keep-alive", "Content-Length": "40", "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", + "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b4 Python/3.11.0 (Windows-10-10.0.22621-SP0)", "x-ms-content-sha256": "sanitized", "x-ms-date": "sanitized", "x-ms-return-client-request-id": "true" @@ -147,15 +21,15 @@ }, "StatusCode": 200, "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", + "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview, 2023-01-01-preview, 2023-03-01", + "Content-Length": "71", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "MS-CV": "sanitized", "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", "X-Azure-Ref": "sanitized", "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "649ms" + "X-Processing-Time": "434ms" }, "ResponseBody": { "trunks": { @@ -167,13 +41,13 @@ } }, { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", + "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2023-03-01", "RequestMethod": "GET", "RequestHeaders": { "Accept": "application/json", "Accept-Encoding": "gzip, deflate", "Connection": "keep-alive", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", + "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b4 Python/3.11.0 (Windows-10-10.0.22621-SP0)", "x-ms-content-sha256": "sanitized", "x-ms-date": "sanitized", "x-ms-return-client-request-id": "true" @@ -181,15 +55,15 @@ "RequestBody": null, "StatusCode": 200, "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", + "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview, 2023-01-01-preview, 2023-03-01", + "Content-Length": "71", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "MS-CV": "sanitized", "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", "X-Azure-Ref": "sanitized", "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "130ms" + "X-Processing-Time": "167ms" }, "ResponseBody": { "trunks": { diff --git a/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e.pyTestSipRoutingClientE2Etest_delete_trunk_from_managed_identity.json b/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e.pyTestSipRoutingClientE2Etest_delete_trunk_from_managed_identity.json index 2b7570264aea..68bde578b8ca 100644 --- a/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e.pyTestSipRoutingClientE2Etest_delete_trunk_from_managed_identity.json +++ b/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e.pyTestSipRoutingClientE2Etest_delete_trunk_from_managed_identity.json @@ -1,133 +1,43 @@ { "Entries": [ { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "PATCH", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Connection": "keep-alive", - "Content-Length": "14", - "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": { - "routes": [] - }, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "180ms" - }, - "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", + "RequestUri": "https://login.microsoftonline.com/common/discovery/instance?authorization_endpoint=https://login.windows-ppe.net/sanitized/oauth2/v2.0/authorize\u0026api-version=1.0", "RequestMethod": "GET", "RequestHeaders": { - "Accept": "application/json", + "Accept": "*/*", "Accept-Encoding": "gzip, deflate", "Connection": "keep-alive", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" + "User-Agent": "azsdk-python-identity/1.12.0 Python/3.11.0 (Windows-10-10.0.22621-SP0)" }, "RequestBody": null, "StatusCode": 200, "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "321ms" - }, - "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "PATCH", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Connection": "keep-alive", - "Content-Length": "112", - "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - } - }, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", + "Access-Control-Allow-Methods": "GET, OPTIONS", + "Access-Control-Allow-Origin": "*", + "Cache-Control": "max-age=86400, private", + "Content-Length": "109", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "617ms" + "P3P": "sanitized", + "Set-Cookie": "sanitized", + "Strict-Transport-Security": "max-age=31536000; includeSubDomains", + "X-Content-Type-Options": "nosniff", + "x-ms-ests-server": "sanitized", + "X-XSS-Protection": "0" }, "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - }, - "routes": [] + "tenant_discovery_endpoint": "https://login.windows-ppe.net/sanitized/v2.0/.well-known/openid-configuration" } }, { - "RequestUri": "https://login.microsoftonline.com/sanitized/v2.0/.well-known/openid-configuration", + "RequestUri": "https://login.windows-ppe.net/sanitized/v2.0/.well-known/openid-configuration", "RequestMethod": "GET", "RequestHeaders": { "Accept": "*/*", "Accept-Encoding": "gzip, deflate", "Connection": "keep-alive", - "User-Agent": "azsdk-python-identity/1.13.0b1 Python/3.10.9 (Windows-10-10.0.22621-SP0)" + "Cookie": "sanitized", + "User-Agent": "azsdk-python-identity/1.12.0 Python/3.11.0 (Windows-10-10.0.22621-SP0)" }, "RequestBody": null, "StatusCode": 200, @@ -135,7 +45,7 @@ "Access-Control-Allow-Methods": "GET, OPTIONS", "Access-Control-Allow-Origin": "*", "Cache-Control": "max-age=86400, private", - "Content-Length": "1564", + "Content-Length": "1548", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "P3P": "sanitized", @@ -147,13 +57,13 @@ "X-XSS-Protection": "0" }, "ResponseBody": { - "token_endpoint": "https://login.microsoftonline.com/sanitized/oauth2/v2.0/token", + "token_endpoint": "https://login.windows-ppe.net/sanitized/oauth2/v2.0/token", "token_endpoint_auth_methods_supported": [ "client_secret_post", "private_key_jwt", "client_secret_basic" ], - "jwks_uri": "https://login.microsoftonline.com/sanitized/discovery/v2.0/keys", + "jwks_uri": "https://login.windows-ppe.net/sanitized/discovery/v2.0/keys", "response_modes_supported": [ "query", "fragment", @@ -177,14 +87,14 @@ "email", "offline_access" ], - "issuer": "https://login.microsoftonline.com/sanitized/v2.0", + "issuer": "https://login.windows-ppe.net/sanitized/v2.0", "request_uri_parameter_supported": false, - "userinfo_endpoint": "https://graph.microsoft.com/oidc/userinfo", - "authorization_endpoint": "https://login.microsoftonline.com/sanitized/oauth2/v2.0/authorize", - "device_authorization_endpoint": "https://login.microsoftonline.com/sanitized/oauth2/v2.0/devicecode", + "userinfo_endpoint": "https://graph.microsoft-ppe.com/oidc/userinfo", + "authorization_endpoint": "https://login.windows-ppe.net/sanitized/oauth2/v2.0/authorize", + "device_authorization_endpoint": "https://login.windows-ppe.net/sanitized/oauth2/v2.0/devicecode", "http_logout_supported": true, "frontchannel_logout_supported": true, - "end_session_endpoint": "https://login.microsoftonline.com/sanitized/oauth2/v2.0/logout", + "end_session_endpoint": "https://login.windows-ppe.net/sanitized/oauth2/v2.0/logout", "claims_supported": [ "sub", "iss", @@ -206,12 +116,12 @@ "c_hash", "email" ], - "kerberos_endpoint": "https://login.microsoftonline.com/sanitized/kerberos", - "tenant_region_scope": "WW", - "cloud_instance_name": "microsoftonline.com", - "cloud_graph_host_name": "graph.windows.net", - "msgraph_host": "graph.microsoft.com", - "rbac_url": "https://pas.windows.net" + "kerberos_endpoint": "https://login.windows-ppe.net/sanitized/kerberos", + "tenant_region_scope": "NA", + "cloud_instance_name": "windows-ppe.net", + "cloud_graph_host_name": "graph.ppe.windows.net", + "msgraph_host": "graph.microsoft-ppe.com", + "rbac_url": "https://pas.windows-ppe.net" } }, { @@ -222,7 +132,7 @@ "Accept-Encoding": "gzip, deflate", "Connection": "keep-alive", "Cookie": "sanitized", - "User-Agent": "azsdk-python-identity/1.13.0b1 Python/3.10.9 (Windows-10-10.0.22621-SP0)" + "User-Agent": "azsdk-python-identity/1.12.0 Python/3.11.0 (Windows-10-10.0.22621-SP0)" }, "RequestBody": null, "StatusCode": 200, @@ -238,7 +148,6 @@ "Strict-Transport-Security": "max-age=31536000; includeSubDomains", "X-Content-Type-Options": "nosniff", "x-ms-ests-server": "sanitized", - "x-ms-httpver": "1.1", "X-XSS-Protection": "0" }, "ResponseBody": { @@ -289,7 +198,7 @@ } }, { - "RequestUri": "https://login.microsoftonline.com/sanitized/oauth2/v2.0/token", + "RequestUri": "https://login.windows-ppe.net/sanitized/oauth2/v2.0/token", "RequestMethod": "POST", "RequestHeaders": { "Accept": "application/json", @@ -299,13 +208,13 @@ "Content-Length": "240", "Content-Type": "application/x-www-form-urlencoded", "Cookie": "sanitized", - "User-Agent": "azsdk-python-identity/1.13.0b1 Python/3.10.9 (Windows-10-10.0.22621-SP0)", + "User-Agent": "azsdk-python-identity/1.12.0 Python/3.11.0 (Windows-10-10.0.22621-SP0)", "x-client-cpu": "x64", "x-client-current-telemetry": "4|730,0|", "x-client-last-telemetry": "4|0|||", "x-client-os": "win32", "x-client-sku": "MSAL.Python", - "x-client-ver": "1.20.0", + "x-client-ver": "1.21.0", "x-ms-lib-capability": "retry-after, h429" }, "RequestBody": "client_id=sanitized\u0026grant_type=client_credentials\u0026client_info=1\u0026client_secret=sanitized\u0026claims=%7B%22access_token%22%3A\u002B%7B%22xms_cc%22%3A\u002B%7B%22values%22%3A\u002B%5B%22CP1%22%5D%7D%7D%7D\u0026scope=https%3A%2F%2Fcommunication.azure.com%2F%2F.default", @@ -313,7 +222,7 @@ "ResponseHeaders": { "Cache-Control": "no-store, no-cache", "client-request-id": "sanitized", - "Content-Length": "111", + "Content-Length": "90", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "Expires": "-1", @@ -329,14 +238,13 @@ }, "ResponseBody": { "token_type": "Bearer", - "expires_in": 86399, - "ext_expires_in": 86399, - "refresh_in": 43199, + "expires_in": 3599, + "ext_expires_in": 3599, "access_token": "Sanitized" } }, { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", + "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2023-03-01", "RequestMethod": "PATCH", "RequestHeaders": { "Accept": "application/json", @@ -344,7 +252,7 @@ "Connection": "keep-alive", "Content-Length": "40", "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)" + "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b4 Python/3.11.0 (Windows-10-10.0.22621-SP0)" }, "RequestBody": { "trunks": { @@ -353,15 +261,15 @@ }, "StatusCode": 200, "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", + "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview, 2023-01-01-preview, 2023-03-01", + "Content-Length": "71", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "MS-CV": "sanitized", "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", "X-Azure-Ref": "sanitized", "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "284ms" + "X-Processing-Time": "398ms" }, "ResponseBody": { "trunks": { @@ -373,26 +281,26 @@ } }, { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", + "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2023-03-01", "RequestMethod": "GET", "RequestHeaders": { "Accept": "application/json", "Accept-Encoding": "gzip, deflate", "Connection": "keep-alive", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)" + "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b4 Python/3.11.0 (Windows-10-10.0.22621-SP0)" }, "RequestBody": null, "StatusCode": 200, "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", + "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview, 2023-01-01-preview, 2023-03-01", + "Content-Length": "71", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "MS-CV": "sanitized", "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", "X-Azure-Ref": "sanitized", "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "107ms" + "X-Processing-Time": "176ms" }, "ResponseBody": { "trunks": { diff --git a/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e.pyTestSipRoutingClientE2Etest_get_routes.json b/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e.pyTestSipRoutingClientE2Etest_get_routes.json index 1de6e02a7424..8a14d55a96b3 100644 --- a/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e.pyTestSipRoutingClientE2Etest_get_routes.json +++ b/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e.pyTestSipRoutingClientE2Etest_get_routes.json @@ -1,141 +1,15 @@ { "Entries": [ { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", + "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2023-03-01", "RequestMethod": "PATCH", "RequestHeaders": { "Accept": "application/json", "Accept-Encoding": "gzip, deflate", "Connection": "keep-alive", - "Content-Length": "14", + "Content-Length": "137", "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": { - "routes": [] - }, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "172ms" - }, - "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "GET", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Connection": "keep-alive", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": null, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "116ms" - }, - "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "PATCH", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Connection": "keep-alive", - "Content-Length": "112", - "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - } - }, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "298ms" - }, - "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "PATCH", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Connection": "keep-alive", - "Content-Length": "157", - "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", + "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b4 Python/3.11.0 (Windows-10-10.0.22621-SP0)", "x-ms-content-sha256": "sanitized", "x-ms-date": "sanitized", "x-ms-return-client-request-id": "true" @@ -146,23 +20,21 @@ "description": "Handle numbers starting with \u0027\u002B123\u0027", "name": "First rule", "numberPattern": "\\\u002B123[0-9]\u002B", - "trunks": [ - "sbs1.sanitized.com" - ] + "trunks": [] } ] }, "StatusCode": 200, "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", + "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview, 2023-01-01-preview, 2023-03-01", + "Content-Length": "234", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "MS-CV": "sanitized", "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", "X-Azure-Ref": "sanitized", "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "182ms" + "X-Processing-Time": "306ms" }, "ResponseBody": { "trunks": { @@ -178,21 +50,19 @@ "description": "Handle numbers starting with \u0027\u002B123\u0027", "name": "First rule", "numberPattern": "\\\u002B123[0-9]\u002B", - "trunks": [ - "sbs1.sanitized.com" - ] + "trunks": [] } ] } }, { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", + "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2023-03-01", "RequestMethod": "GET", "RequestHeaders": { "Accept": "application/json", "Accept-Encoding": "gzip, deflate", "Connection": "keep-alive", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", + "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b4 Python/3.11.0 (Windows-10-10.0.22621-SP0)", "x-ms-content-sha256": "sanitized", "x-ms-date": "sanitized", "x-ms-return-client-request-id": "true" @@ -200,15 +70,15 @@ "RequestBody": null, "StatusCode": 200, "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", + "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview, 2023-01-01-preview, 2023-03-01", + "Content-Length": "234", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "MS-CV": "sanitized", "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", "X-Azure-Ref": "sanitized", "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "635ms" + "X-Processing-Time": "165ms" }, "ResponseBody": { "trunks": { @@ -224,9 +94,7 @@ "description": "Handle numbers starting with \u0027\u002B123\u0027", "name": "First rule", "numberPattern": "\\\u002B123[0-9]\u002B", - "trunks": [ - "sbs1.sanitized.com" - ] + "trunks": [] } ] } diff --git a/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e.pyTestSipRoutingClientE2Etest_get_routes_from_managed_identity.json b/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e.pyTestSipRoutingClientE2Etest_get_routes_from_managed_identity.json index 8a8866213fec..c6db844f6a0d 100644 --- a/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e.pyTestSipRoutingClientE2Etest_get_routes_from_managed_identity.json +++ b/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e.pyTestSipRoutingClientE2Etest_get_routes_from_managed_identity.json @@ -1,139 +1,43 @@ { "Entries": [ { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "PATCH", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Connection": "keep-alive", - "Content-Length": "14", - "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": { - "routes": [] - }, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "191ms" - }, - "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", + "RequestUri": "https://login.microsoftonline.com/common/discovery/instance?authorization_endpoint=https://login.windows-ppe.net/sanitized/oauth2/v2.0/authorize\u0026api-version=1.0", "RequestMethod": "GET", "RequestHeaders": { - "Accept": "application/json", + "Accept": "*/*", "Accept-Encoding": "gzip, deflate", "Connection": "keep-alive", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" + "User-Agent": "azsdk-python-identity/1.12.0 Python/3.11.0 (Windows-10-10.0.22621-SP0)" }, "RequestBody": null, "StatusCode": 200, "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "123ms" - }, - "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "PATCH", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Connection": "keep-alive", - "Content-Length": "112", - "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - } - }, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", + "Access-Control-Allow-Methods": "GET, OPTIONS", + "Access-Control-Allow-Origin": "*", + "Cache-Control": "max-age=86400, private", + "Content-Length": "109", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "311ms" + "P3P": "sanitized", + "Set-Cookie": "sanitized", + "Strict-Transport-Security": "max-age=31536000; includeSubDomains", + "X-Content-Type-Options": "nosniff", + "x-ms-ests-server": "sanitized", + "X-XSS-Protection": "0" }, "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - }, - "routes": [] + "tenant_discovery_endpoint": "https://login.windows-ppe.net/sanitized/v2.0/.well-known/openid-configuration" } }, { - "RequestUri": "https://login.microsoftonline.com/sanitized/v2.0/.well-known/openid-configuration", + "RequestUri": "https://login.windows-ppe.net/sanitized/v2.0/.well-known/openid-configuration", "RequestMethod": "GET", "RequestHeaders": { "Accept": "*/*", "Accept-Encoding": "gzip, deflate", "Connection": "keep-alive", - "User-Agent": "azsdk-python-identity/1.13.0b1 Python/3.10.9 (Windows-10-10.0.22621-SP0)" + "Cookie": "sanitized", + "User-Agent": "azsdk-python-identity/1.12.0 Python/3.11.0 (Windows-10-10.0.22621-SP0)" }, "RequestBody": null, "StatusCode": 200, @@ -141,7 +45,7 @@ "Access-Control-Allow-Methods": "GET, OPTIONS", "Access-Control-Allow-Origin": "*", "Cache-Control": "max-age=86400, private", - "Content-Length": "1564", + "Content-Length": "1548", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "P3P": "sanitized", @@ -153,13 +57,13 @@ "X-XSS-Protection": "0" }, "ResponseBody": { - "token_endpoint": "https://login.microsoftonline.com/sanitized/oauth2/v2.0/token", + "token_endpoint": "https://login.windows-ppe.net/sanitized/oauth2/v2.0/token", "token_endpoint_auth_methods_supported": [ "client_secret_post", "private_key_jwt", "client_secret_basic" ], - "jwks_uri": "https://login.microsoftonline.com/sanitized/discovery/v2.0/keys", + "jwks_uri": "https://login.windows-ppe.net/sanitized/discovery/v2.0/keys", "response_modes_supported": [ "query", "fragment", @@ -183,14 +87,14 @@ "email", "offline_access" ], - "issuer": "https://login.microsoftonline.com/sanitized/v2.0", + "issuer": "https://login.windows-ppe.net/sanitized/v2.0", "request_uri_parameter_supported": false, - "userinfo_endpoint": "https://graph.microsoft.com/oidc/userinfo", - "authorization_endpoint": "https://login.microsoftonline.com/sanitized/oauth2/v2.0/authorize", - "device_authorization_endpoint": "https://login.microsoftonline.com/sanitized/oauth2/v2.0/devicecode", + "userinfo_endpoint": "https://graph.microsoft-ppe.com/oidc/userinfo", + "authorization_endpoint": "https://login.windows-ppe.net/sanitized/oauth2/v2.0/authorize", + "device_authorization_endpoint": "https://login.windows-ppe.net/sanitized/oauth2/v2.0/devicecode", "http_logout_supported": true, "frontchannel_logout_supported": true, - "end_session_endpoint": "https://login.microsoftonline.com/sanitized/oauth2/v2.0/logout", + "end_session_endpoint": "https://login.windows-ppe.net/sanitized/oauth2/v2.0/logout", "claims_supported": [ "sub", "iss", @@ -212,12 +116,12 @@ "c_hash", "email" ], - "kerberos_endpoint": "https://login.microsoftonline.com/sanitized/kerberos", - "tenant_region_scope": "WW", - "cloud_instance_name": "microsoftonline.com", - "cloud_graph_host_name": "graph.windows.net", - "msgraph_host": "graph.microsoft.com", - "rbac_url": "https://pas.windows.net" + "kerberos_endpoint": "https://login.windows-ppe.net/sanitized/kerberos", + "tenant_region_scope": "NA", + "cloud_instance_name": "windows-ppe.net", + "cloud_graph_host_name": "graph.ppe.windows.net", + "msgraph_host": "graph.microsoft-ppe.com", + "rbac_url": "https://pas.windows-ppe.net" } }, { @@ -228,7 +132,7 @@ "Accept-Encoding": "gzip, deflate", "Connection": "keep-alive", "Cookie": "sanitized", - "User-Agent": "azsdk-python-identity/1.13.0b1 Python/3.10.9 (Windows-10-10.0.22621-SP0)" + "User-Agent": "azsdk-python-identity/1.12.0 Python/3.11.0 (Windows-10-10.0.22621-SP0)" }, "RequestBody": null, "StatusCode": 200, @@ -244,7 +148,6 @@ "Strict-Transport-Security": "max-age=31536000; includeSubDomains", "X-Content-Type-Options": "nosniff", "x-ms-ests-server": "sanitized", - "x-ms-httpver": "1.1", "X-XSS-Protection": "0" }, "ResponseBody": { @@ -295,7 +198,7 @@ } }, { - "RequestUri": "https://login.microsoftonline.com/sanitized/oauth2/v2.0/token", + "RequestUri": "https://login.windows-ppe.net/sanitized/oauth2/v2.0/token", "RequestMethod": "POST", "RequestHeaders": { "Accept": "application/json", @@ -305,13 +208,13 @@ "Content-Length": "240", "Content-Type": "application/x-www-form-urlencoded", "Cookie": "sanitized", - "User-Agent": "azsdk-python-identity/1.13.0b1 Python/3.10.9 (Windows-10-10.0.22621-SP0)", + "User-Agent": "azsdk-python-identity/1.12.0 Python/3.11.0 (Windows-10-10.0.22621-SP0)", "x-client-cpu": "x64", "x-client-current-telemetry": "4|730,0|", "x-client-last-telemetry": "4|0|||", "x-client-os": "win32", "x-client-sku": "MSAL.Python", - "x-client-ver": "1.20.0", + "x-client-ver": "1.21.0", "x-ms-lib-capability": "retry-after, h429" }, "RequestBody": "client_id=sanitized\u0026grant_type=client_credentials\u0026client_info=1\u0026client_secret=sanitized\u0026claims=%7B%22access_token%22%3A\u002B%7B%22xms_cc%22%3A\u002B%7B%22values%22%3A\u002B%5B%22CP1%22%5D%7D%7D%7D\u0026scope=https%3A%2F%2Fcommunication.azure.com%2F%2F.default", @@ -319,7 +222,7 @@ "ResponseHeaders": { "Cache-Control": "no-store, no-cache", "client-request-id": "sanitized", - "Content-Length": "111", + "Content-Length": "90", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "Expires": "-1", @@ -335,22 +238,21 @@ }, "ResponseBody": { "token_type": "Bearer", - "expires_in": 86399, - "ext_expires_in": 86399, - "refresh_in": 43199, + "expires_in": 3599, + "ext_expires_in": 3599, "access_token": "Sanitized" } }, { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", + "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2023-03-01", "RequestMethod": "PATCH", "RequestHeaders": { "Accept": "application/json", "Accept-Encoding": "gzip, deflate", "Connection": "keep-alive", - "Content-Length": "157", + "Content-Length": "137", "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)" + "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b4 Python/3.11.0 (Windows-10-10.0.22621-SP0)" }, "RequestBody": { "routes": [ @@ -358,23 +260,21 @@ "description": "Handle numbers starting with \u0027\u002B123\u0027", "name": "First rule", "numberPattern": "\\\u002B123[0-9]\u002B", - "trunks": [ - "sbs1.sanitized.com" - ] + "trunks": [] } ] }, "StatusCode": 200, "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", + "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview, 2023-01-01-preview, 2023-03-01", + "Content-Length": "234", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "MS-CV": "sanitized", "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", "X-Azure-Ref": "sanitized", "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "189ms" + "X-Processing-Time": "580ms" }, "ResponseBody": { "trunks": { @@ -390,34 +290,32 @@ "description": "Handle numbers starting with \u0027\u002B123\u0027", "name": "First rule", "numberPattern": "\\\u002B123[0-9]\u002B", - "trunks": [ - "sbs1.sanitized.com" - ] + "trunks": [] } ] } }, { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", + "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2023-03-01", "RequestMethod": "GET", "RequestHeaders": { "Accept": "application/json", "Accept-Encoding": "gzip, deflate", "Connection": "keep-alive", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)" + "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b4 Python/3.11.0 (Windows-10-10.0.22621-SP0)" }, "RequestBody": null, "StatusCode": 200, "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", + "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview, 2023-01-01-preview, 2023-03-01", + "Content-Length": "234", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "MS-CV": "sanitized", "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", "X-Azure-Ref": "sanitized", "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "130ms" + "X-Processing-Time": "172ms" }, "ResponseBody": { "trunks": { @@ -433,9 +331,7 @@ "description": "Handle numbers starting with \u0027\u002B123\u0027", "name": "First rule", "numberPattern": "\\\u002B123[0-9]\u002B", - "trunks": [ - "sbs1.sanitized.com" - ] + "trunks": [] } ] } diff --git a/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e.pyTestSipRoutingClientE2Etest_get_trunk.json b/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e.pyTestSipRoutingClientE2Etest_get_trunk.json index 2848b125e2f5..f1bbd4957b56 100644 --- a/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e.pyTestSipRoutingClientE2Etest_get_trunk.json +++ b/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e.pyTestSipRoutingClientE2Etest_get_trunk.json @@ -1,146 +1,13 @@ { "Entries": [ { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "PATCH", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Connection": "keep-alive", - "Content-Length": "14", - "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": { - "routes": [] - }, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "186ms" - }, - "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - }, - "sbs3.sanitized.com": { - "sipSignalingPort": 2222 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "GET", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Connection": "keep-alive", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": null, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "352ms" - }, - "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - }, - "sbs3.sanitized.com": { - "sipSignalingPort": 2222 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "PATCH", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Connection": "keep-alive", - "Content-Length": "140", - "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - }, - "sbs3.sanitized.com": null - } - }, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "409ms" - }, - "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", + "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2023-03-01", "RequestMethod": "GET", "RequestHeaders": { "Accept": "application/json", "Accept-Encoding": "gzip, deflate", "Connection": "keep-alive", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", + "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b4 Python/3.11.0 (Windows-10-10.0.22621-SP0)", "x-ms-content-sha256": "sanitized", "x-ms-date": "sanitized", "x-ms-return-client-request-id": "true" @@ -148,15 +15,15 @@ "RequestBody": null, "StatusCode": 200, "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", + "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview, 2023-01-01-preview, 2023-03-01", + "Content-Length": "118", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "MS-CV": "sanitized", "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", "X-Azure-Ref": "sanitized", "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "105ms" + "X-Processing-Time": "165ms" }, "ResponseBody": { "trunks": { diff --git a/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e.pyTestSipRoutingClientE2Etest_get_trunk_from_managed_identity.json b/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e.pyTestSipRoutingClientE2Etest_get_trunk_from_managed_identity.json index 813429fcd0a4..abeaf7e8bdc5 100644 --- a/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e.pyTestSipRoutingClientE2Etest_get_trunk_from_managed_identity.json +++ b/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e.pyTestSipRoutingClientE2Etest_get_trunk_from_managed_identity.json @@ -1,139 +1,43 @@ { "Entries": [ { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "PATCH", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Connection": "keep-alive", - "Content-Length": "14", - "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": { - "routes": [] - }, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "193ms" - }, - "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", + "RequestUri": "https://login.microsoftonline.com/common/discovery/instance?authorization_endpoint=https://login.windows-ppe.net/sanitized/oauth2/v2.0/authorize\u0026api-version=1.0", "RequestMethod": "GET", "RequestHeaders": { - "Accept": "application/json", + "Accept": "*/*", "Accept-Encoding": "gzip, deflate", "Connection": "keep-alive", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" + "User-Agent": "azsdk-python-identity/1.12.0 Python/3.11.0 (Windows-10-10.0.22621-SP0)" }, "RequestBody": null, "StatusCode": 200, "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "107ms" - }, - "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "PATCH", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Connection": "keep-alive", - "Content-Length": "112", - "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - } - }, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", + "Access-Control-Allow-Methods": "GET, OPTIONS", + "Access-Control-Allow-Origin": "*", + "Cache-Control": "max-age=86400, private", + "Content-Length": "109", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "309ms" + "P3P": "sanitized", + "Set-Cookie": "sanitized", + "Strict-Transport-Security": "max-age=31536000; includeSubDomains", + "X-Content-Type-Options": "nosniff", + "x-ms-ests-server": "sanitized", + "X-XSS-Protection": "0" }, "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - }, - "routes": [] + "tenant_discovery_endpoint": "https://login.windows-ppe.net/sanitized/v2.0/.well-known/openid-configuration" } }, { - "RequestUri": "https://login.microsoftonline.com/sanitized/v2.0/.well-known/openid-configuration", + "RequestUri": "https://login.windows-ppe.net/sanitized/v2.0/.well-known/openid-configuration", "RequestMethod": "GET", "RequestHeaders": { "Accept": "*/*", "Accept-Encoding": "gzip, deflate", "Connection": "keep-alive", - "User-Agent": "azsdk-python-identity/1.13.0b1 Python/3.10.9 (Windows-10-10.0.22621-SP0)" + "Cookie": "sanitized", + "User-Agent": "azsdk-python-identity/1.12.0 Python/3.11.0 (Windows-10-10.0.22621-SP0)" }, "RequestBody": null, "StatusCode": 200, @@ -141,7 +45,7 @@ "Access-Control-Allow-Methods": "GET, OPTIONS", "Access-Control-Allow-Origin": "*", "Cache-Control": "max-age=86400, private", - "Content-Length": "1564", + "Content-Length": "1548", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "P3P": "sanitized", @@ -153,13 +57,13 @@ "X-XSS-Protection": "0" }, "ResponseBody": { - "token_endpoint": "https://login.microsoftonline.com/sanitized/oauth2/v2.0/token", + "token_endpoint": "https://login.windows-ppe.net/sanitized/oauth2/v2.0/token", "token_endpoint_auth_methods_supported": [ "client_secret_post", "private_key_jwt", "client_secret_basic" ], - "jwks_uri": "https://login.microsoftonline.com/sanitized/discovery/v2.0/keys", + "jwks_uri": "https://login.windows-ppe.net/sanitized/discovery/v2.0/keys", "response_modes_supported": [ "query", "fragment", @@ -183,14 +87,14 @@ "email", "offline_access" ], - "issuer": "https://login.microsoftonline.com/sanitized/v2.0", + "issuer": "https://login.windows-ppe.net/sanitized/v2.0", "request_uri_parameter_supported": false, - "userinfo_endpoint": "https://graph.microsoft.com/oidc/userinfo", - "authorization_endpoint": "https://login.microsoftonline.com/sanitized/oauth2/v2.0/authorize", - "device_authorization_endpoint": "https://login.microsoftonline.com/sanitized/oauth2/v2.0/devicecode", + "userinfo_endpoint": "https://graph.microsoft-ppe.com/oidc/userinfo", + "authorization_endpoint": "https://login.windows-ppe.net/sanitized/oauth2/v2.0/authorize", + "device_authorization_endpoint": "https://login.windows-ppe.net/sanitized/oauth2/v2.0/devicecode", "http_logout_supported": true, "frontchannel_logout_supported": true, - "end_session_endpoint": "https://login.microsoftonline.com/sanitized/oauth2/v2.0/logout", + "end_session_endpoint": "https://login.windows-ppe.net/sanitized/oauth2/v2.0/logout", "claims_supported": [ "sub", "iss", @@ -212,12 +116,12 @@ "c_hash", "email" ], - "kerberos_endpoint": "https://login.microsoftonline.com/sanitized/kerberos", - "tenant_region_scope": "WW", - "cloud_instance_name": "microsoftonline.com", - "cloud_graph_host_name": "graph.windows.net", - "msgraph_host": "graph.microsoft.com", - "rbac_url": "https://pas.windows.net" + "kerberos_endpoint": "https://login.windows-ppe.net/sanitized/kerberos", + "tenant_region_scope": "NA", + "cloud_instance_name": "windows-ppe.net", + "cloud_graph_host_name": "graph.ppe.windows.net", + "msgraph_host": "graph.microsoft-ppe.com", + "rbac_url": "https://pas.windows-ppe.net" } }, { @@ -228,7 +132,7 @@ "Accept-Encoding": "gzip, deflate", "Connection": "keep-alive", "Cookie": "sanitized", - "User-Agent": "azsdk-python-identity/1.13.0b1 Python/3.10.9 (Windows-10-10.0.22621-SP0)" + "User-Agent": "azsdk-python-identity/1.12.0 Python/3.11.0 (Windows-10-10.0.22621-SP0)" }, "RequestBody": null, "StatusCode": 200, @@ -244,7 +148,6 @@ "Strict-Transport-Security": "max-age=31536000; includeSubDomains", "X-Content-Type-Options": "nosniff", "x-ms-ests-server": "sanitized", - "x-ms-httpver": "1.1", "X-XSS-Protection": "0" }, "ResponseBody": { @@ -295,7 +198,7 @@ } }, { - "RequestUri": "https://login.microsoftonline.com/sanitized/oauth2/v2.0/token", + "RequestUri": "https://login.windows-ppe.net/sanitized/oauth2/v2.0/token", "RequestMethod": "POST", "RequestHeaders": { "Accept": "application/json", @@ -305,13 +208,13 @@ "Content-Length": "240", "Content-Type": "application/x-www-form-urlencoded", "Cookie": "sanitized", - "User-Agent": "azsdk-python-identity/1.13.0b1 Python/3.10.9 (Windows-10-10.0.22621-SP0)", + "User-Agent": "azsdk-python-identity/1.12.0 Python/3.11.0 (Windows-10-10.0.22621-SP0)", "x-client-cpu": "x64", "x-client-current-telemetry": "4|730,0|", "x-client-last-telemetry": "4|0|||", "x-client-os": "win32", "x-client-sku": "MSAL.Python", - "x-client-ver": "1.20.0", + "x-client-ver": "1.21.0", "x-ms-lib-capability": "retry-after, h429" }, "RequestBody": "client_id=sanitized\u0026grant_type=client_credentials\u0026client_info=1\u0026client_secret=sanitized\u0026claims=%7B%22access_token%22%3A\u002B%7B%22xms_cc%22%3A\u002B%7B%22values%22%3A\u002B%5B%22CP1%22%5D%7D%7D%7D\u0026scope=https%3A%2F%2Fcommunication.azure.com%2F%2F.default", @@ -319,7 +222,7 @@ "ResponseHeaders": { "Cache-Control": "no-store, no-cache", "client-request-id": "sanitized", - "Content-Length": "111", + "Content-Length": "90", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "Expires": "-1", @@ -335,33 +238,32 @@ }, "ResponseBody": { "token_type": "Bearer", - "expires_in": 86399, - "ext_expires_in": 86399, - "refresh_in": 43199, + "expires_in": 3599, + "ext_expires_in": 3599, "access_token": "Sanitized" } }, { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", + "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2023-03-01", "RequestMethod": "GET", "RequestHeaders": { "Accept": "application/json", "Accept-Encoding": "gzip, deflate", "Connection": "keep-alive", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)" + "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b4 Python/3.11.0 (Windows-10-10.0.22621-SP0)" }, "RequestBody": null, "StatusCode": 200, "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", + "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview, 2023-01-01-preview, 2023-03-01", + "Content-Length": "118", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "MS-CV": "sanitized", "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", "X-Azure-Ref": "sanitized", "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "129ms" + "X-Processing-Time": "172ms" }, "ResponseBody": { "trunks": { diff --git a/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e.pyTestSipRoutingClientE2Etest_get_trunk_not_existing_throws.json b/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e.pyTestSipRoutingClientE2Etest_get_trunk_not_existing_throws.json new file mode 100644 index 000000000000..7528838267e9 --- /dev/null +++ b/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e.pyTestSipRoutingClientE2Etest_get_trunk_not_existing_throws.json @@ -0,0 +1,42 @@ +{ + "Entries": [ + { + "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2023-03-01", + "RequestMethod": "GET", + "RequestHeaders": { + "Accept": "application/json", + "Accept-Encoding": "gzip, deflate", + "Connection": "keep-alive", + "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b4 Python/3.11.0 (Windows-10-10.0.22621-SP0)", + "x-ms-content-sha256": "sanitized", + "x-ms-date": "sanitized", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 200, + "ResponseHeaders": { + "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview, 2023-01-01-preview, 2023-03-01", + "Content-Length": "118", + "Content-Type": "application/json; charset=utf-8", + "Date": "sanitized", + "MS-CV": "sanitized", + "Strict-Transport-Security": "max-age=2592000", + "X-Azure-Ref": "sanitized", + "X-Cache": "CONFIG_NOCACHE", + "X-Processing-Time": "674ms" + }, + "ResponseBody": { + "trunks": { + "sbs1.sanitized.com": { + "sipSignalingPort": 1122 + }, + "sbs2.sanitized.com": { + "sipSignalingPort": 1123 + } + }, + "routes": [] + } + } + ], + "Variables": {} +} diff --git a/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e.pyTestSipRoutingClientE2Etest_get_trunks.json b/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e.pyTestSipRoutingClientE2Etest_get_trunks.json index 9c48999dbb83..e10b51c62d8c 100644 --- a/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e.pyTestSipRoutingClientE2Etest_get_trunks.json +++ b/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e.pyTestSipRoutingClientE2Etest_get_trunks.json @@ -1,139 +1,13 @@ { "Entries": [ { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "PATCH", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Connection": "keep-alive", - "Content-Length": "14", - "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": { - "routes": [] - }, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "1307ms" - }, - "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 7777 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "GET", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Connection": "keep-alive", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": null, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "104ms" - }, - "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 7777 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "PATCH", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Connection": "keep-alive", - "Content-Length": "168", - "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - } - }, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "642ms" - }, - "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", + "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2023-03-01", "RequestMethod": "GET", "RequestHeaders": { "Accept": "application/json", "Accept-Encoding": "gzip, deflate", "Connection": "keep-alive", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", + "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b4 Python/3.11.0 (Windows-10-10.0.22621-SP0)", "x-ms-content-sha256": "sanitized", "x-ms-date": "sanitized", "x-ms-return-client-request-id": "true" @@ -141,15 +15,15 @@ "RequestBody": null, "StatusCode": 200, "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", + "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview, 2023-01-01-preview, 2023-03-01", + "Content-Length": "118", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "MS-CV": "sanitized", "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", "X-Azure-Ref": "sanitized", "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "104ms" + "X-Processing-Time": "183ms" }, "ResponseBody": { "trunks": { diff --git a/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e.pyTestSipRoutingClientE2Etest_get_trunks_from_managed_identity.json b/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e.pyTestSipRoutingClientE2Etest_get_trunks_from_managed_identity.json index 90965b323912..ca87e951ae3f 100644 --- a/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e.pyTestSipRoutingClientE2Etest_get_trunks_from_managed_identity.json +++ b/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e.pyTestSipRoutingClientE2Etest_get_trunks_from_managed_identity.json @@ -1,139 +1,43 @@ { "Entries": [ { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "PATCH", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Connection": "keep-alive", - "Content-Length": "14", - "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": { - "routes": [] - }, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "1514ms" - }, - "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", + "RequestUri": "https://login.microsoftonline.com/common/discovery/instance?authorization_endpoint=https://login.windows-ppe.net/sanitized/oauth2/v2.0/authorize\u0026api-version=1.0", "RequestMethod": "GET", "RequestHeaders": { - "Accept": "application/json", + "Accept": "*/*", "Accept-Encoding": "gzip, deflate", "Connection": "keep-alive", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" + "User-Agent": "azsdk-python-identity/1.12.0 Python/3.11.0 (Windows-10-10.0.22621-SP0)" }, "RequestBody": null, "StatusCode": 200, "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "113ms" - }, - "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "PATCH", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Connection": "keep-alive", - "Content-Length": "112", - "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - } - }, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", + "Access-Control-Allow-Methods": "GET, OPTIONS", + "Access-Control-Allow-Origin": "*", + "Cache-Control": "max-age=86400, private", + "Content-Length": "109", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "294ms" + "P3P": "sanitized", + "Set-Cookie": "sanitized", + "Strict-Transport-Security": "max-age=31536000; includeSubDomains", + "X-Content-Type-Options": "nosniff", + "x-ms-ests-server": "sanitized", + "X-XSS-Protection": "0" }, "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - }, - "routes": [] + "tenant_discovery_endpoint": "https://login.windows-ppe.net/sanitized/v2.0/.well-known/openid-configuration" } }, { - "RequestUri": "https://login.microsoftonline.com/sanitized/v2.0/.well-known/openid-configuration", + "RequestUri": "https://login.windows-ppe.net/sanitized/v2.0/.well-known/openid-configuration", "RequestMethod": "GET", "RequestHeaders": { "Accept": "*/*", "Accept-Encoding": "gzip, deflate", "Connection": "keep-alive", - "User-Agent": "azsdk-python-identity/1.13.0b1 Python/3.10.9 (Windows-10-10.0.22621-SP0)" + "Cookie": "sanitized", + "User-Agent": "azsdk-python-identity/1.12.0 Python/3.11.0 (Windows-10-10.0.22621-SP0)" }, "RequestBody": null, "StatusCode": 200, @@ -141,7 +45,7 @@ "Access-Control-Allow-Methods": "GET, OPTIONS", "Access-Control-Allow-Origin": "*", "Cache-Control": "max-age=86400, private", - "Content-Length": "1564", + "Content-Length": "1548", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "P3P": "sanitized", @@ -153,13 +57,13 @@ "X-XSS-Protection": "0" }, "ResponseBody": { - "token_endpoint": "https://login.microsoftonline.com/sanitized/oauth2/v2.0/token", + "token_endpoint": "https://login.windows-ppe.net/sanitized/oauth2/v2.0/token", "token_endpoint_auth_methods_supported": [ "client_secret_post", "private_key_jwt", "client_secret_basic" ], - "jwks_uri": "https://login.microsoftonline.com/sanitized/discovery/v2.0/keys", + "jwks_uri": "https://login.windows-ppe.net/sanitized/discovery/v2.0/keys", "response_modes_supported": [ "query", "fragment", @@ -183,14 +87,14 @@ "email", "offline_access" ], - "issuer": "https://login.microsoftonline.com/sanitized/v2.0", + "issuer": "https://login.windows-ppe.net/sanitized/v2.0", "request_uri_parameter_supported": false, - "userinfo_endpoint": "https://graph.microsoft.com/oidc/userinfo", - "authorization_endpoint": "https://login.microsoftonline.com/sanitized/oauth2/v2.0/authorize", - "device_authorization_endpoint": "https://login.microsoftonline.com/sanitized/oauth2/v2.0/devicecode", + "userinfo_endpoint": "https://graph.microsoft-ppe.com/oidc/userinfo", + "authorization_endpoint": "https://login.windows-ppe.net/sanitized/oauth2/v2.0/authorize", + "device_authorization_endpoint": "https://login.windows-ppe.net/sanitized/oauth2/v2.0/devicecode", "http_logout_supported": true, "frontchannel_logout_supported": true, - "end_session_endpoint": "https://login.microsoftonline.com/sanitized/oauth2/v2.0/logout", + "end_session_endpoint": "https://login.windows-ppe.net/sanitized/oauth2/v2.0/logout", "claims_supported": [ "sub", "iss", @@ -212,12 +116,12 @@ "c_hash", "email" ], - "kerberos_endpoint": "https://login.microsoftonline.com/sanitized/kerberos", - "tenant_region_scope": "WW", - "cloud_instance_name": "microsoftonline.com", - "cloud_graph_host_name": "graph.windows.net", - "msgraph_host": "graph.microsoft.com", - "rbac_url": "https://pas.windows.net" + "kerberos_endpoint": "https://login.windows-ppe.net/sanitized/kerberos", + "tenant_region_scope": "NA", + "cloud_instance_name": "windows-ppe.net", + "cloud_graph_host_name": "graph.ppe.windows.net", + "msgraph_host": "graph.microsoft-ppe.com", + "rbac_url": "https://pas.windows-ppe.net" } }, { @@ -228,7 +132,7 @@ "Accept-Encoding": "gzip, deflate", "Connection": "keep-alive", "Cookie": "sanitized", - "User-Agent": "azsdk-python-identity/1.13.0b1 Python/3.10.9 (Windows-10-10.0.22621-SP0)" + "User-Agent": "azsdk-python-identity/1.12.0 Python/3.11.0 (Windows-10-10.0.22621-SP0)" }, "RequestBody": null, "StatusCode": 200, @@ -244,7 +148,6 @@ "Strict-Transport-Security": "max-age=31536000; includeSubDomains", "X-Content-Type-Options": "nosniff", "x-ms-ests-server": "sanitized", - "x-ms-httpver": "1.1", "X-XSS-Protection": "0" }, "ResponseBody": { @@ -295,7 +198,7 @@ } }, { - "RequestUri": "https://login.microsoftonline.com/sanitized/oauth2/v2.0/token", + "RequestUri": "https://login.windows-ppe.net/sanitized/oauth2/v2.0/token", "RequestMethod": "POST", "RequestHeaders": { "Accept": "application/json", @@ -305,13 +208,13 @@ "Content-Length": "240", "Content-Type": "application/x-www-form-urlencoded", "Cookie": "sanitized", - "User-Agent": "azsdk-python-identity/1.13.0b1 Python/3.10.9 (Windows-10-10.0.22621-SP0)", + "User-Agent": "azsdk-python-identity/1.12.0 Python/3.11.0 (Windows-10-10.0.22621-SP0)", "x-client-cpu": "x64", "x-client-current-telemetry": "4|730,0|", "x-client-last-telemetry": "4|0|||", "x-client-os": "win32", "x-client-sku": "MSAL.Python", - "x-client-ver": "1.20.0", + "x-client-ver": "1.21.0", "x-ms-lib-capability": "retry-after, h429" }, "RequestBody": "client_id=sanitized\u0026grant_type=client_credentials\u0026client_info=1\u0026client_secret=sanitized\u0026claims=%7B%22access_token%22%3A\u002B%7B%22xms_cc%22%3A\u002B%7B%22values%22%3A\u002B%5B%22CP1%22%5D%7D%7D%7D\u0026scope=https%3A%2F%2Fcommunication.azure.com%2F%2F.default", @@ -319,7 +222,7 @@ "ResponseHeaders": { "Cache-Control": "no-store, no-cache", "client-request-id": "sanitized", - "Content-Length": "111", + "Content-Length": "90", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "Expires": "-1", @@ -335,33 +238,32 @@ }, "ResponseBody": { "token_type": "Bearer", - "expires_in": 86399, - "ext_expires_in": 86399, - "refresh_in": 43199, + "expires_in": 3599, + "ext_expires_in": 3599, "access_token": "Sanitized" } }, { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", + "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2023-03-01", "RequestMethod": "GET", "RequestHeaders": { "Accept": "application/json", "Accept-Encoding": "gzip, deflate", "Connection": "keep-alive", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)" + "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b4 Python/3.11.0 (Windows-10-10.0.22621-SP0)" }, "RequestBody": null, "StatusCode": 200, "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", + "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview, 2023-01-01-preview, 2023-03-01", + "Content-Length": "118", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "MS-CV": "sanitized", "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", "X-Azure-Ref": "sanitized", "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "115ms" + "X-Processing-Time": "528ms" }, "ResponseBody": { "trunks": { diff --git a/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e.pyTestSipRoutingClientE2Etest_set_routes.json b/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e.pyTestSipRoutingClientE2Etest_set_routes.json index c299d5cc606c..7afdc55f6cda 100644 --- a/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e.pyTestSipRoutingClientE2Etest_set_routes.json +++ b/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e.pyTestSipRoutingClientE2Etest_set_routes.json @@ -1,127 +1,15 @@ { "Entries": [ { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", + "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2023-03-01", "RequestMethod": "PATCH", "RequestHeaders": { "Accept": "application/json", "Accept-Encoding": "gzip, deflate", "Connection": "keep-alive", - "Content-Length": "14", + "Content-Length": "137", "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": { - "routes": [] - }, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "189ms" - }, - "ResponseBody": { - "trunks": {}, - "routes": [] - } - }, - { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "GET", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Connection": "keep-alive", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": null, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "271ms" - }, - "ResponseBody": { - "trunks": {}, - "routes": [] - } - }, - { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "PATCH", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Connection": "keep-alive", - "Content-Length": "112", - "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - } - }, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "719ms" - }, - "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "PATCH", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Connection": "keep-alive", - "Content-Length": "157", - "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", + "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b4 Python/3.11.0 (Windows-10-10.0.22621-SP0)", "x-ms-content-sha256": "sanitized", "x-ms-date": "sanitized", "x-ms-return-client-request-id": "true" @@ -132,23 +20,21 @@ "description": "Handle numbers starting with \u0027\u002B123\u0027", "name": "First rule", "numberPattern": "\\\u002B123[0-9]\u002B", - "trunks": [ - "sbs1.sanitized.com" - ] + "trunks": [] } ] }, "StatusCode": 200, "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", + "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview, 2023-01-01-preview, 2023-03-01", + "Content-Length": "234", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "MS-CV": "sanitized", "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", "X-Azure-Ref": "sanitized", "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "176ms" + "X-Processing-Time": "328ms" }, "ResponseBody": { "trunks": { @@ -164,23 +50,21 @@ "description": "Handle numbers starting with \u0027\u002B123\u0027", "name": "First rule", "numberPattern": "\\\u002B123[0-9]\u002B", - "trunks": [ - "sbs1.sanitized.com" - ] + "trunks": [] } ] } }, { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", + "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2023-03-01", "RequestMethod": "PATCH", "RequestHeaders": { "Accept": "application/json", "Accept-Encoding": "gzip, deflate", "Connection": "keep-alive", - "Content-Length": "163", + "Content-Length": "143", "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", + "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b4 Python/3.11.0 (Windows-10-10.0.22621-SP0)", "x-ms-content-sha256": "sanitized", "x-ms-date": "sanitized", "x-ms-return-client-request-id": "true" @@ -191,23 +75,21 @@ "description": "Handle numbers starting with \u0027\u002B999\u0027", "name": "Alternative rule", "numberPattern": "\\\u002B999[0-9]\u002B", - "trunks": [ - "sbs2.sanitized.com" - ] + "trunks": [] } ] }, "StatusCode": 200, "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", + "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview, 2023-01-01-preview, 2023-03-01", + "Content-Length": "240", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "MS-CV": "sanitized", "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", "X-Azure-Ref": "sanitized", "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "322ms" + "X-Processing-Time": "314ms" }, "ResponseBody": { "trunks": { @@ -223,21 +105,19 @@ "description": "Handle numbers starting with \u0027\u002B999\u0027", "name": "Alternative rule", "numberPattern": "\\\u002B999[0-9]\u002B", - "trunks": [ - "sbs2.sanitized.com" - ] + "trunks": [] } ] } }, { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", + "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2023-03-01", "RequestMethod": "GET", "RequestHeaders": { "Accept": "application/json", "Accept-Encoding": "gzip, deflate", "Connection": "keep-alive", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", + "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b4 Python/3.11.0 (Windows-10-10.0.22621-SP0)", "x-ms-content-sha256": "sanitized", "x-ms-date": "sanitized", "x-ms-return-client-request-id": "true" @@ -245,15 +125,15 @@ "RequestBody": null, "StatusCode": 200, "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", + "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview, 2023-01-01-preview, 2023-03-01", + "Content-Length": "240", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "MS-CV": "sanitized", "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", "X-Azure-Ref": "sanitized", "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "124ms" + "X-Processing-Time": "172ms" }, "ResponseBody": { "trunks": { @@ -269,9 +149,7 @@ "description": "Handle numbers starting with \u0027\u002B999\u0027", "name": "Alternative rule", "numberPattern": "\\\u002B999[0-9]\u002B", - "trunks": [ - "sbs2.sanitized.com" - ] + "trunks": [] } ] } diff --git a/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e.pyTestSipRoutingClientE2Etest_set_routes_from_managed_identity.json b/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e.pyTestSipRoutingClientE2Etest_set_routes_from_managed_identity.json index 2ae4f32936d9..952953ccea52 100644 --- a/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e.pyTestSipRoutingClientE2Etest_set_routes_from_managed_identity.json +++ b/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e.pyTestSipRoutingClientE2Etest_set_routes_from_managed_identity.json @@ -1,139 +1,43 @@ { "Entries": [ { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "PATCH", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Connection": "keep-alive", - "Content-Length": "14", - "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": { - "routes": [] - }, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "208ms" - }, - "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", + "RequestUri": "https://login.microsoftonline.com/common/discovery/instance?authorization_endpoint=https://login.windows-ppe.net/sanitized/oauth2/v2.0/authorize\u0026api-version=1.0", "RequestMethod": "GET", "RequestHeaders": { - "Accept": "application/json", + "Accept": "*/*", "Accept-Encoding": "gzip, deflate", "Connection": "keep-alive", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" + "User-Agent": "azsdk-python-identity/1.12.0 Python/3.11.0 (Windows-10-10.0.22621-SP0)" }, "RequestBody": null, "StatusCode": 200, "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "107ms" - }, - "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "PATCH", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Connection": "keep-alive", - "Content-Length": "112", - "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - } - }, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", + "Access-Control-Allow-Methods": "GET, OPTIONS", + "Access-Control-Allow-Origin": "*", + "Cache-Control": "max-age=86400, private", + "Content-Length": "109", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "285ms" + "P3P": "sanitized", + "Set-Cookie": "sanitized", + "Strict-Transport-Security": "max-age=31536000; includeSubDomains", + "X-Content-Type-Options": "nosniff", + "x-ms-ests-server": "sanitized", + "X-XSS-Protection": "0" }, "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - }, - "routes": [] + "tenant_discovery_endpoint": "https://login.windows-ppe.net/sanitized/v2.0/.well-known/openid-configuration" } }, { - "RequestUri": "https://login.microsoftonline.com/sanitized/v2.0/.well-known/openid-configuration", + "RequestUri": "https://login.windows-ppe.net/sanitized/v2.0/.well-known/openid-configuration", "RequestMethod": "GET", "RequestHeaders": { "Accept": "*/*", "Accept-Encoding": "gzip, deflate", "Connection": "keep-alive", - "User-Agent": "azsdk-python-identity/1.13.0b1 Python/3.10.9 (Windows-10-10.0.22621-SP0)" + "Cookie": "sanitized", + "User-Agent": "azsdk-python-identity/1.12.0 Python/3.11.0 (Windows-10-10.0.22621-SP0)" }, "RequestBody": null, "StatusCode": 200, @@ -141,7 +45,7 @@ "Access-Control-Allow-Methods": "GET, OPTIONS", "Access-Control-Allow-Origin": "*", "Cache-Control": "max-age=86400, private", - "Content-Length": "1564", + "Content-Length": "1548", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "P3P": "sanitized", @@ -153,13 +57,13 @@ "X-XSS-Protection": "0" }, "ResponseBody": { - "token_endpoint": "https://login.microsoftonline.com/sanitized/oauth2/v2.0/token", + "token_endpoint": "https://login.windows-ppe.net/sanitized/oauth2/v2.0/token", "token_endpoint_auth_methods_supported": [ "client_secret_post", "private_key_jwt", "client_secret_basic" ], - "jwks_uri": "https://login.microsoftonline.com/sanitized/discovery/v2.0/keys", + "jwks_uri": "https://login.windows-ppe.net/sanitized/discovery/v2.0/keys", "response_modes_supported": [ "query", "fragment", @@ -183,14 +87,14 @@ "email", "offline_access" ], - "issuer": "https://login.microsoftonline.com/sanitized/v2.0", + "issuer": "https://login.windows-ppe.net/sanitized/v2.0", "request_uri_parameter_supported": false, - "userinfo_endpoint": "https://graph.microsoft.com/oidc/userinfo", - "authorization_endpoint": "https://login.microsoftonline.com/sanitized/oauth2/v2.0/authorize", - "device_authorization_endpoint": "https://login.microsoftonline.com/sanitized/oauth2/v2.0/devicecode", + "userinfo_endpoint": "https://graph.microsoft-ppe.com/oidc/userinfo", + "authorization_endpoint": "https://login.windows-ppe.net/sanitized/oauth2/v2.0/authorize", + "device_authorization_endpoint": "https://login.windows-ppe.net/sanitized/oauth2/v2.0/devicecode", "http_logout_supported": true, "frontchannel_logout_supported": true, - "end_session_endpoint": "https://login.microsoftonline.com/sanitized/oauth2/v2.0/logout", + "end_session_endpoint": "https://login.windows-ppe.net/sanitized/oauth2/v2.0/logout", "claims_supported": [ "sub", "iss", @@ -212,12 +116,12 @@ "c_hash", "email" ], - "kerberos_endpoint": "https://login.microsoftonline.com/sanitized/kerberos", - "tenant_region_scope": "WW", - "cloud_instance_name": "microsoftonline.com", - "cloud_graph_host_name": "graph.windows.net", - "msgraph_host": "graph.microsoft.com", - "rbac_url": "https://pas.windows.net" + "kerberos_endpoint": "https://login.windows-ppe.net/sanitized/kerberos", + "tenant_region_scope": "NA", + "cloud_instance_name": "windows-ppe.net", + "cloud_graph_host_name": "graph.ppe.windows.net", + "msgraph_host": "graph.microsoft-ppe.com", + "rbac_url": "https://pas.windows-ppe.net" } }, { @@ -228,7 +132,7 @@ "Accept-Encoding": "gzip, deflate", "Connection": "keep-alive", "Cookie": "sanitized", - "User-Agent": "azsdk-python-identity/1.13.0b1 Python/3.10.9 (Windows-10-10.0.22621-SP0)" + "User-Agent": "azsdk-python-identity/1.12.0 Python/3.11.0 (Windows-10-10.0.22621-SP0)" }, "RequestBody": null, "StatusCode": 200, @@ -244,7 +148,6 @@ "Strict-Transport-Security": "max-age=31536000; includeSubDomains", "X-Content-Type-Options": "nosniff", "x-ms-ests-server": "sanitized", - "x-ms-httpver": "1.1", "X-XSS-Protection": "0" }, "ResponseBody": { @@ -295,7 +198,7 @@ } }, { - "RequestUri": "https://login.microsoftonline.com/sanitized/oauth2/v2.0/token", + "RequestUri": "https://login.windows-ppe.net/sanitized/oauth2/v2.0/token", "RequestMethod": "POST", "RequestHeaders": { "Accept": "application/json", @@ -305,13 +208,13 @@ "Content-Length": "240", "Content-Type": "application/x-www-form-urlencoded", "Cookie": "sanitized", - "User-Agent": "azsdk-python-identity/1.13.0b1 Python/3.10.9 (Windows-10-10.0.22621-SP0)", + "User-Agent": "azsdk-python-identity/1.12.0 Python/3.11.0 (Windows-10-10.0.22621-SP0)", "x-client-cpu": "x64", "x-client-current-telemetry": "4|730,0|", "x-client-last-telemetry": "4|0|||", "x-client-os": "win32", "x-client-sku": "MSAL.Python", - "x-client-ver": "1.20.0", + "x-client-ver": "1.21.0", "x-ms-lib-capability": "retry-after, h429" }, "RequestBody": "client_id=sanitized\u0026grant_type=client_credentials\u0026client_info=1\u0026client_secret=sanitized\u0026claims=%7B%22access_token%22%3A\u002B%7B%22xms_cc%22%3A\u002B%7B%22values%22%3A\u002B%5B%22CP1%22%5D%7D%7D%7D\u0026scope=https%3A%2F%2Fcommunication.azure.com%2F%2F.default", @@ -319,7 +222,7 @@ "ResponseHeaders": { "Cache-Control": "no-store, no-cache", "client-request-id": "sanitized", - "Content-Length": "111", + "Content-Length": "90", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "Expires": "-1", @@ -335,22 +238,21 @@ }, "ResponseBody": { "token_type": "Bearer", - "expires_in": 86399, - "ext_expires_in": 86399, - "refresh_in": 43199, + "expires_in": 3599, + "ext_expires_in": 3599, "access_token": "Sanitized" } }, { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", + "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2023-03-01", "RequestMethod": "PATCH", "RequestHeaders": { "Accept": "application/json", "Accept-Encoding": "gzip, deflate", "Connection": "keep-alive", - "Content-Length": "157", + "Content-Length": "137", "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)" + "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b4 Python/3.11.0 (Windows-10-10.0.22621-SP0)" }, "RequestBody": { "routes": [ @@ -358,23 +260,21 @@ "description": "Handle numbers starting with \u0027\u002B123\u0027", "name": "First rule", "numberPattern": "\\\u002B123[0-9]\u002B", - "trunks": [ - "sbs1.sanitized.com" - ] + "trunks": [] } ] }, "StatusCode": 200, "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", + "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview, 2023-01-01-preview, 2023-03-01", + "Content-Length": "234", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "MS-CV": "sanitized", "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", "X-Azure-Ref": "sanitized", "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "789ms" + "X-Processing-Time": "313ms" }, "ResponseBody": { "trunks": { @@ -390,23 +290,21 @@ "description": "Handle numbers starting with \u0027\u002B123\u0027", "name": "First rule", "numberPattern": "\\\u002B123[0-9]\u002B", - "trunks": [ - "sbs1.sanitized.com" - ] + "trunks": [] } ] } }, { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", + "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2023-03-01", "RequestMethod": "PATCH", "RequestHeaders": { "Accept": "application/json", "Accept-Encoding": "gzip, deflate", "Connection": "keep-alive", - "Content-Length": "163", + "Content-Length": "143", "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)" + "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b4 Python/3.11.0 (Windows-10-10.0.22621-SP0)" }, "RequestBody": { "routes": [ @@ -414,23 +312,21 @@ "description": "Handle numbers starting with \u0027\u002B999\u0027", "name": "Alternative rule", "numberPattern": "\\\u002B999[0-9]\u002B", - "trunks": [ - "sbs2.sanitized.com" - ] + "trunks": [] } ] }, "StatusCode": 200, "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", + "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview, 2023-01-01-preview, 2023-03-01", + "Content-Length": "240", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "MS-CV": "sanitized", "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", "X-Azure-Ref": "sanitized", "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "192ms" + "X-Processing-Time": "314ms" }, "ResponseBody": { "trunks": { @@ -446,34 +342,32 @@ "description": "Handle numbers starting with \u0027\u002B999\u0027", "name": "Alternative rule", "numberPattern": "\\\u002B999[0-9]\u002B", - "trunks": [ - "sbs2.sanitized.com" - ] + "trunks": [] } ] } }, { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", + "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2023-03-01", "RequestMethod": "GET", "RequestHeaders": { "Accept": "application/json", "Accept-Encoding": "gzip, deflate", "Connection": "keep-alive", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)" + "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b4 Python/3.11.0 (Windows-10-10.0.22621-SP0)" }, "RequestBody": null, "StatusCode": 200, "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", + "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview, 2023-01-01-preview, 2023-03-01", + "Content-Length": "240", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "MS-CV": "sanitized", "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", "X-Azure-Ref": "sanitized", "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "184ms" + "X-Processing-Time": "165ms" }, "ResponseBody": { "trunks": { @@ -489,9 +383,7 @@ "description": "Handle numbers starting with \u0027\u002B999\u0027", "name": "Alternative rule", "numberPattern": "\\\u002B999[0-9]\u002B", - "trunks": [ - "sbs2.sanitized.com" - ] + "trunks": [] } ] } diff --git a/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e.pyTestSipRoutingClientE2Etest_set_trunk.json b/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e.pyTestSipRoutingClientE2Etest_set_trunk.json index 0ba6cc6a68d3..a64dd0342eac 100644 --- a/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e.pyTestSipRoutingClientE2Etest_set_trunk.json +++ b/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e.pyTestSipRoutingClientE2Etest_set_trunk.json @@ -1,133 +1,7 @@ { "Entries": [ { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "PATCH", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Connection": "keep-alive", - "Content-Length": "14", - "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": { - "routes": [] - }, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "138ms" - }, - "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "GET", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Connection": "keep-alive", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": null, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "64ms" - }, - "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "PATCH", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Connection": "keep-alive", - "Content-Length": "112", - "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - } - }, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "222ms" - }, - "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", + "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2023-03-01", "RequestMethod": "PATCH", "RequestHeaders": { "Accept": "application/json", @@ -135,7 +9,7 @@ "Connection": "keep-alive", "Content-Length": "62", "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", + "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b4 Python/3.11.0 (Windows-10-10.0.22621-SP0)", "x-ms-content-sha256": "sanitized", "x-ms-date": "sanitized", "x-ms-return-client-request-id": "true" @@ -149,15 +23,15 @@ }, "StatusCode": 200, "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", + "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview, 2023-01-01-preview, 2023-03-01", + "Content-Length": "118", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "MS-CV": "sanitized", "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", "X-Azure-Ref": "sanitized", "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "131ms" + "X-Processing-Time": "441ms" }, "ResponseBody": { "trunks": { @@ -172,13 +46,13 @@ } }, { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", + "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2023-03-01", "RequestMethod": "GET", "RequestHeaders": { "Accept": "application/json", "Accept-Encoding": "gzip, deflate", "Connection": "keep-alive", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", + "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b4 Python/3.11.0 (Windows-10-10.0.22621-SP0)", "x-ms-content-sha256": "sanitized", "x-ms-date": "sanitized", "x-ms-return-client-request-id": "true" @@ -186,15 +60,15 @@ "RequestBody": null, "StatusCode": 200, "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", + "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview, 2023-01-01-preview, 2023-03-01", + "Content-Length": "118", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "MS-CV": "sanitized", "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", "X-Azure-Ref": "sanitized", "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "52ms" + "X-Processing-Time": "169ms" }, "ResponseBody": { "trunks": { diff --git a/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e.pyTestSipRoutingClientE2Etest_set_trunk_from_managed_identity.json b/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e.pyTestSipRoutingClientE2Etest_set_trunk_from_managed_identity.json index cf4389c4ba86..f79c60f12ff1 100644 --- a/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e.pyTestSipRoutingClientE2Etest_set_trunk_from_managed_identity.json +++ b/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e.pyTestSipRoutingClientE2Etest_set_trunk_from_managed_identity.json @@ -1,139 +1,43 @@ { "Entries": [ { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "PATCH", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Connection": "keep-alive", - "Content-Length": "14", - "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": { - "routes": [] - }, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "83ms" - }, - "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 7777 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", + "RequestUri": "https://login.microsoftonline.com/common/discovery/instance?authorization_endpoint=https://login.windows-ppe.net/sanitized/oauth2/v2.0/authorize\u0026api-version=1.0", "RequestMethod": "GET", "RequestHeaders": { - "Accept": "application/json", + "Accept": "*/*", "Accept-Encoding": "gzip, deflate", "Connection": "keep-alive", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" + "User-Agent": "azsdk-python-identity/1.12.0 Python/3.11.0 (Windows-10-10.0.22621-SP0)" }, "RequestBody": null, "StatusCode": 200, "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "53ms" - }, - "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 7777 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "PATCH", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Connection": "keep-alive", - "Content-Length": "112", - "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - } - }, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", + "Access-Control-Allow-Methods": "GET, OPTIONS", + "Access-Control-Allow-Origin": "*", + "Cache-Control": "max-age=86400, private", + "Content-Length": "109", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "120ms" + "P3P": "sanitized", + "Set-Cookie": "sanitized", + "Strict-Transport-Security": "max-age=31536000; includeSubDomains", + "X-Content-Type-Options": "nosniff", + "x-ms-ests-server": "sanitized", + "X-XSS-Protection": "0" }, "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - }, - "routes": [] + "tenant_discovery_endpoint": "https://login.windows-ppe.net/sanitized/v2.0/.well-known/openid-configuration" } }, { - "RequestUri": "https://login.microsoftonline.com/sanitized/v2.0/.well-known/openid-configuration", + "RequestUri": "https://login.windows-ppe.net/sanitized/v2.0/.well-known/openid-configuration", "RequestMethod": "GET", "RequestHeaders": { "Accept": "*/*", "Accept-Encoding": "gzip, deflate", "Connection": "keep-alive", - "User-Agent": "azsdk-python-identity/1.13.0b1 Python/3.10.9 (Windows-10-10.0.22621-SP0)" + "Cookie": "sanitized", + "User-Agent": "azsdk-python-identity/1.12.0 Python/3.11.0 (Windows-10-10.0.22621-SP0)" }, "RequestBody": null, "StatusCode": 200, @@ -141,7 +45,7 @@ "Access-Control-Allow-Methods": "GET, OPTIONS", "Access-Control-Allow-Origin": "*", "Cache-Control": "max-age=86400, private", - "Content-Length": "1564", + "Content-Length": "1548", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "P3P": "sanitized", @@ -153,13 +57,13 @@ "X-XSS-Protection": "0" }, "ResponseBody": { - "token_endpoint": "https://login.microsoftonline.com/sanitized/oauth2/v2.0/token", + "token_endpoint": "https://login.windows-ppe.net/sanitized/oauth2/v2.0/token", "token_endpoint_auth_methods_supported": [ "client_secret_post", "private_key_jwt", "client_secret_basic" ], - "jwks_uri": "https://login.microsoftonline.com/sanitized/discovery/v2.0/keys", + "jwks_uri": "https://login.windows-ppe.net/sanitized/discovery/v2.0/keys", "response_modes_supported": [ "query", "fragment", @@ -183,14 +87,14 @@ "email", "offline_access" ], - "issuer": "https://login.microsoftonline.com/sanitized/v2.0", + "issuer": "https://login.windows-ppe.net/sanitized/v2.0", "request_uri_parameter_supported": false, - "userinfo_endpoint": "https://graph.microsoft.com/oidc/userinfo", - "authorization_endpoint": "https://login.microsoftonline.com/sanitized/oauth2/v2.0/authorize", - "device_authorization_endpoint": "https://login.microsoftonline.com/sanitized/oauth2/v2.0/devicecode", + "userinfo_endpoint": "https://graph.microsoft-ppe.com/oidc/userinfo", + "authorization_endpoint": "https://login.windows-ppe.net/sanitized/oauth2/v2.0/authorize", + "device_authorization_endpoint": "https://login.windows-ppe.net/sanitized/oauth2/v2.0/devicecode", "http_logout_supported": true, "frontchannel_logout_supported": true, - "end_session_endpoint": "https://login.microsoftonline.com/sanitized/oauth2/v2.0/logout", + "end_session_endpoint": "https://login.windows-ppe.net/sanitized/oauth2/v2.0/logout", "claims_supported": [ "sub", "iss", @@ -212,12 +116,12 @@ "c_hash", "email" ], - "kerberos_endpoint": "https://login.microsoftonline.com/sanitized/kerberos", - "tenant_region_scope": "WW", - "cloud_instance_name": "microsoftonline.com", - "cloud_graph_host_name": "graph.windows.net", - "msgraph_host": "graph.microsoft.com", - "rbac_url": "https://pas.windows.net" + "kerberos_endpoint": "https://login.windows-ppe.net/sanitized/kerberos", + "tenant_region_scope": "NA", + "cloud_instance_name": "windows-ppe.net", + "cloud_graph_host_name": "graph.ppe.windows.net", + "msgraph_host": "graph.microsoft-ppe.com", + "rbac_url": "https://pas.windows-ppe.net" } }, { @@ -228,7 +132,7 @@ "Accept-Encoding": "gzip, deflate", "Connection": "keep-alive", "Cookie": "sanitized", - "User-Agent": "azsdk-python-identity/1.13.0b1 Python/3.10.9 (Windows-10-10.0.22621-SP0)" + "User-Agent": "azsdk-python-identity/1.12.0 Python/3.11.0 (Windows-10-10.0.22621-SP0)" }, "RequestBody": null, "StatusCode": 200, @@ -244,7 +148,6 @@ "Strict-Transport-Security": "max-age=31536000; includeSubDomains", "X-Content-Type-Options": "nosniff", "x-ms-ests-server": "sanitized", - "x-ms-httpver": "1.1", "X-XSS-Protection": "0" }, "ResponseBody": { @@ -295,7 +198,7 @@ } }, { - "RequestUri": "https://login.microsoftonline.com/sanitized/oauth2/v2.0/token", + "RequestUri": "https://login.windows-ppe.net/sanitized/oauth2/v2.0/token", "RequestMethod": "POST", "RequestHeaders": { "Accept": "application/json", @@ -305,13 +208,13 @@ "Content-Length": "240", "Content-Type": "application/x-www-form-urlencoded", "Cookie": "sanitized", - "User-Agent": "azsdk-python-identity/1.13.0b1 Python/3.10.9 (Windows-10-10.0.22621-SP0)", + "User-Agent": "azsdk-python-identity/1.12.0 Python/3.11.0 (Windows-10-10.0.22621-SP0)", "x-client-cpu": "x64", "x-client-current-telemetry": "4|730,0|", "x-client-last-telemetry": "4|0|||", "x-client-os": "win32", "x-client-sku": "MSAL.Python", - "x-client-ver": "1.20.0", + "x-client-ver": "1.21.0", "x-ms-lib-capability": "retry-after, h429" }, "RequestBody": "client_id=sanitized\u0026grant_type=client_credentials\u0026client_info=1\u0026client_secret=sanitized\u0026claims=%7B%22access_token%22%3A\u002B%7B%22xms_cc%22%3A\u002B%7B%22values%22%3A\u002B%5B%22CP1%22%5D%7D%7D%7D\u0026scope=https%3A%2F%2Fcommunication.azure.com%2F%2F.default", @@ -319,7 +222,7 @@ "ResponseHeaders": { "Cache-Control": "no-store, no-cache", "client-request-id": "sanitized", - "Content-Length": "111", + "Content-Length": "90", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "Expires": "-1", @@ -335,14 +238,13 @@ }, "ResponseBody": { "token_type": "Bearer", - "expires_in": 86399, - "ext_expires_in": 86399, - "refresh_in": 43199, + "expires_in": 3599, + "ext_expires_in": 3599, "access_token": "Sanitized" } }, { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", + "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2023-03-01", "RequestMethod": "PATCH", "RequestHeaders": { "Accept": "application/json", @@ -350,7 +252,7 @@ "Connection": "keep-alive", "Content-Length": "62", "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)" + "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b4 Python/3.11.0 (Windows-10-10.0.22621-SP0)" }, "RequestBody": { "trunks": { @@ -361,15 +263,15 @@ }, "StatusCode": 200, "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", + "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview, 2023-01-01-preview, 2023-03-01", + "Content-Length": "118", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "MS-CV": "sanitized", "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", "X-Azure-Ref": "sanitized", "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "410ms" + "X-Processing-Time": "470ms" }, "ResponseBody": { "trunks": { @@ -384,26 +286,26 @@ } }, { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", + "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2023-03-01", "RequestMethod": "GET", "RequestHeaders": { "Accept": "application/json", "Accept-Encoding": "gzip, deflate", "Connection": "keep-alive", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)" + "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b4 Python/3.11.0 (Windows-10-10.0.22621-SP0)" }, "RequestBody": null, "StatusCode": 200, "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", + "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview, 2023-01-01-preview, 2023-03-01", + "Content-Length": "118", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "MS-CV": "sanitized", "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", "X-Azure-Ref": "sanitized", "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "119ms" + "X-Processing-Time": "162ms" }, "ResponseBody": { "trunks": { diff --git a/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e.pyTestSipRoutingClientE2Etest_set_trunks.json b/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e.pyTestSipRoutingClientE2Etest_set_trunks.json index 76400ecaf4e7..0af1f01c846e 100644 --- a/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e.pyTestSipRoutingClientE2Etest_set_trunks.json +++ b/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e.pyTestSipRoutingClientE2Etest_set_trunks.json @@ -1,139 +1,13 @@ { "Entries": [ { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "PATCH", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Connection": "keep-alive", - "Content-Length": "14", - "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": { - "routes": [] - }, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "448ms" - }, - "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "GET", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Connection": "keep-alive", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": null, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "106ms" - }, - "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "PATCH", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Connection": "keep-alive", - "Content-Length": "112", - "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - } - }, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "486ms" - }, - "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", + "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2023-03-01", "RequestMethod": "GET", "RequestHeaders": { "Accept": "application/json", "Accept-Encoding": "gzip, deflate", "Connection": "keep-alive", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", + "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b4 Python/3.11.0 (Windows-10-10.0.22621-SP0)", "x-ms-content-sha256": "sanitized", "x-ms-date": "sanitized", "x-ms-return-client-request-id": "true" @@ -141,15 +15,15 @@ "RequestBody": null, "StatusCode": 200, "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", + "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview, 2023-01-01-preview, 2023-03-01", + "Content-Length": "118", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "MS-CV": "sanitized", "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", "X-Azure-Ref": "sanitized", "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "119ms" + "X-Processing-Time": "165ms" }, "ResponseBody": { "trunks": { @@ -164,7 +38,7 @@ } }, { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", + "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2023-03-01", "RequestMethod": "PATCH", "RequestHeaders": { "Accept": "application/json", @@ -172,7 +46,7 @@ "Connection": "keep-alive", "Content-Length": "118", "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", + "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b4 Python/3.11.0 (Windows-10-10.0.22621-SP0)", "x-ms-content-sha256": "sanitized", "x-ms-date": "sanitized", "x-ms-return-client-request-id": "true" @@ -188,15 +62,15 @@ }, "StatusCode": 200, "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", + "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview, 2023-01-01-preview, 2023-03-01", + "Content-Length": "71", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "MS-CV": "sanitized", "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", "X-Azure-Ref": "sanitized", "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "991ms" + "X-Processing-Time": "1066ms" }, "ResponseBody": { "trunks": { @@ -208,13 +82,13 @@ } }, { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", + "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2023-03-01", "RequestMethod": "GET", "RequestHeaders": { "Accept": "application/json", "Accept-Encoding": "gzip, deflate", "Connection": "keep-alive", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", + "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b4 Python/3.11.0 (Windows-10-10.0.22621-SP0)", "x-ms-content-sha256": "sanitized", "x-ms-date": "sanitized", "x-ms-return-client-request-id": "true" @@ -222,15 +96,15 @@ "RequestBody": null, "StatusCode": 200, "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", + "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview, 2023-01-01-preview, 2023-03-01", + "Content-Length": "71", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "MS-CV": "sanitized", "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", "X-Azure-Ref": "sanitized", "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "105ms" + "X-Processing-Time": "166ms" }, "ResponseBody": { "trunks": { diff --git a/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e.pyTestSipRoutingClientE2Etest_set_trunks_empty_list.json b/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e.pyTestSipRoutingClientE2Etest_set_trunks_empty_list.json index cd86efa61e0e..78fcd5b0a520 100644 --- a/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e.pyTestSipRoutingClientE2Etest_set_trunks_empty_list.json +++ b/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e.pyTestSipRoutingClientE2Etest_set_trunks_empty_list.json @@ -1,13 +1,13 @@ { "Entries": [ { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", + "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2023-03-01", "RequestMethod": "GET", "RequestHeaders": { "Accept": "application/json", "Accept-Encoding": "gzip, deflate", "Connection": "keep-alive", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", + "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b4 Python/3.11.0 (Windows-10-10.0.22621-SP0)", "x-ms-content-sha256": "sanitized", "x-ms-date": "sanitized", "x-ms-return-client-request-id": "true" @@ -15,55 +15,59 @@ "RequestBody": null, "StatusCode": 200, "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", + "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview, 2023-01-01-preview, 2023-03-01", + "Content-Length": "118", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "MS-CV": "sanitized", "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", "X-Azure-Ref": "sanitized", "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "1432ms" + "X-Processing-Time": "164ms" }, "ResponseBody": { "trunks": { - "sbs3.sanitized.com": { - "sipSignalingPort": 2222 + "sbs1.sanitized.com": { + "sipSignalingPort": 1122 + }, + "sbs2.sanitized.com": { + "sipSignalingPort": 1123 } }, "routes": [] } }, { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", + "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2023-03-01", "RequestMethod": "PATCH", "RequestHeaders": { "Accept": "application/json", "Accept-Encoding": "gzip, deflate", "Connection": "keep-alive", - "Content-Length": "40", + "Content-Length": "68", "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", + "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b4 Python/3.11.0 (Windows-10-10.0.22621-SP0)", "x-ms-content-sha256": "sanitized", "x-ms-date": "sanitized", "x-ms-return-client-request-id": "true" }, "RequestBody": { "trunks": { - "sbs3.sanitized.com": null + "sbs1.sanitized.com": null, + "sbs2.sanitized.com": null } }, "StatusCode": 200, "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", + "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview, 2023-01-01-preview, 2023-03-01", + "Content-Length": "25", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "MS-CV": "sanitized", "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", "X-Azure-Ref": "sanitized", "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "286ms" + "X-Processing-Time": "390ms" }, "ResponseBody": { "trunks": {}, @@ -71,13 +75,13 @@ } }, { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", + "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2023-03-01", "RequestMethod": "GET", "RequestHeaders": { "Accept": "application/json", "Accept-Encoding": "gzip, deflate", "Connection": "keep-alive", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", + "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b4 Python/3.11.0 (Windows-10-10.0.22621-SP0)", "x-ms-content-sha256": "sanitized", "x-ms-date": "sanitized", "x-ms-return-client-request-id": "true" @@ -85,15 +89,15 @@ "RequestBody": null, "StatusCode": 200, "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", + "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview, 2023-01-01-preview, 2023-03-01", + "Content-Length": "25", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "MS-CV": "sanitized", "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", "X-Azure-Ref": "sanitized", "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "4792ms" + "X-Processing-Time": "169ms" }, "ResponseBody": { "trunks": {}, diff --git a/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e.pyTestSipRoutingClientE2Etest_set_trunks_from_managed_identity.json b/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e.pyTestSipRoutingClientE2Etest_set_trunks_from_managed_identity.json index 2f9ccca2e0a4..22a065d15bd4 100644 --- a/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e.pyTestSipRoutingClientE2Etest_set_trunks_from_managed_identity.json +++ b/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e.pyTestSipRoutingClientE2Etest_set_trunks_from_managed_identity.json @@ -1,134 +1,43 @@ { "Entries": [ { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "PATCH", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Connection": "keep-alive", - "Content-Length": "14", - "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": { - "routes": [] - }, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "189ms" - }, - "ResponseBody": { - "trunks": { - "sbs3.sanitized.com": { - "sipSignalingPort": 2222 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", + "RequestUri": "https://login.microsoftonline.com/common/discovery/instance?authorization_endpoint=https://login.windows-ppe.net/sanitized/oauth2/v2.0/authorize\u0026api-version=1.0", "RequestMethod": "GET", "RequestHeaders": { - "Accept": "application/json", + "Accept": "*/*", "Accept-Encoding": "gzip, deflate", "Connection": "keep-alive", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" + "User-Agent": "azsdk-python-identity/1.12.0 Python/3.11.0 (Windows-10-10.0.22621-SP0)" }, "RequestBody": null, "StatusCode": 200, "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "107ms" - }, - "ResponseBody": { - "trunks": { - "sbs3.sanitized.com": { - "sipSignalingPort": 2222 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "PATCH", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Connection": "keep-alive", - "Content-Length": "140", - "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - }, - "sbs3.sanitized.com": null - } - }, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", + "Access-Control-Allow-Methods": "GET, OPTIONS", + "Access-Control-Allow-Origin": "*", + "Cache-Control": "max-age=86400, private", + "Content-Length": "109", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "712ms" + "P3P": "sanitized", + "Set-Cookie": "sanitized", + "Strict-Transport-Security": "max-age=31536000; includeSubDomains", + "X-Content-Type-Options": "nosniff", + "x-ms-ests-server": "sanitized", + "X-XSS-Protection": "0" }, "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - }, - "routes": [] + "tenant_discovery_endpoint": "https://login.windows-ppe.net/sanitized/v2.0/.well-known/openid-configuration" } }, { - "RequestUri": "https://login.microsoftonline.com/sanitized/v2.0/.well-known/openid-configuration", + "RequestUri": "https://login.windows-ppe.net/sanitized/v2.0/.well-known/openid-configuration", "RequestMethod": "GET", "RequestHeaders": { "Accept": "*/*", "Accept-Encoding": "gzip, deflate", "Connection": "keep-alive", - "User-Agent": "azsdk-python-identity/1.13.0b1 Python/3.10.9 (Windows-10-10.0.22621-SP0)" + "Cookie": "sanitized", + "User-Agent": "azsdk-python-identity/1.12.0 Python/3.11.0 (Windows-10-10.0.22621-SP0)" }, "RequestBody": null, "StatusCode": 200, @@ -136,7 +45,7 @@ "Access-Control-Allow-Methods": "GET, OPTIONS", "Access-Control-Allow-Origin": "*", "Cache-Control": "max-age=86400, private", - "Content-Length": "1564", + "Content-Length": "1548", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "P3P": "sanitized", @@ -148,13 +57,13 @@ "X-XSS-Protection": "0" }, "ResponseBody": { - "token_endpoint": "https://login.microsoftonline.com/sanitized/oauth2/v2.0/token", + "token_endpoint": "https://login.windows-ppe.net/sanitized/oauth2/v2.0/token", "token_endpoint_auth_methods_supported": [ "client_secret_post", "private_key_jwt", "client_secret_basic" ], - "jwks_uri": "https://login.microsoftonline.com/sanitized/discovery/v2.0/keys", + "jwks_uri": "https://login.windows-ppe.net/sanitized/discovery/v2.0/keys", "response_modes_supported": [ "query", "fragment", @@ -178,14 +87,14 @@ "email", "offline_access" ], - "issuer": "https://login.microsoftonline.com/sanitized/v2.0", + "issuer": "https://login.windows-ppe.net/sanitized/v2.0", "request_uri_parameter_supported": false, - "userinfo_endpoint": "https://graph.microsoft.com/oidc/userinfo", - "authorization_endpoint": "https://login.microsoftonline.com/sanitized/oauth2/v2.0/authorize", - "device_authorization_endpoint": "https://login.microsoftonline.com/sanitized/oauth2/v2.0/devicecode", + "userinfo_endpoint": "https://graph.microsoft-ppe.com/oidc/userinfo", + "authorization_endpoint": "https://login.windows-ppe.net/sanitized/oauth2/v2.0/authorize", + "device_authorization_endpoint": "https://login.windows-ppe.net/sanitized/oauth2/v2.0/devicecode", "http_logout_supported": true, "frontchannel_logout_supported": true, - "end_session_endpoint": "https://login.microsoftonline.com/sanitized/oauth2/v2.0/logout", + "end_session_endpoint": "https://login.windows-ppe.net/sanitized/oauth2/v2.0/logout", "claims_supported": [ "sub", "iss", @@ -207,12 +116,12 @@ "c_hash", "email" ], - "kerberos_endpoint": "https://login.microsoftonline.com/sanitized/kerberos", - "tenant_region_scope": "WW", - "cloud_instance_name": "microsoftonline.com", - "cloud_graph_host_name": "graph.windows.net", - "msgraph_host": "graph.microsoft.com", - "rbac_url": "https://pas.windows.net" + "kerberos_endpoint": "https://login.windows-ppe.net/sanitized/kerberos", + "tenant_region_scope": "NA", + "cloud_instance_name": "windows-ppe.net", + "cloud_graph_host_name": "graph.ppe.windows.net", + "msgraph_host": "graph.microsoft-ppe.com", + "rbac_url": "https://pas.windows-ppe.net" } }, { @@ -223,7 +132,7 @@ "Accept-Encoding": "gzip, deflate", "Connection": "keep-alive", "Cookie": "sanitized", - "User-Agent": "azsdk-python-identity/1.13.0b1 Python/3.10.9 (Windows-10-10.0.22621-SP0)" + "User-Agent": "azsdk-python-identity/1.12.0 Python/3.11.0 (Windows-10-10.0.22621-SP0)" }, "RequestBody": null, "StatusCode": 200, @@ -239,7 +148,6 @@ "Strict-Transport-Security": "max-age=31536000; includeSubDomains", "X-Content-Type-Options": "nosniff", "x-ms-ests-server": "sanitized", - "x-ms-httpver": "1.1", "X-XSS-Protection": "0" }, "ResponseBody": { @@ -290,7 +198,7 @@ } }, { - "RequestUri": "https://login.microsoftonline.com/sanitized/oauth2/v2.0/token", + "RequestUri": "https://login.windows-ppe.net/sanitized/oauth2/v2.0/token", "RequestMethod": "POST", "RequestHeaders": { "Accept": "application/json", @@ -300,13 +208,13 @@ "Content-Length": "240", "Content-Type": "application/x-www-form-urlencoded", "Cookie": "sanitized", - "User-Agent": "azsdk-python-identity/1.13.0b1 Python/3.10.9 (Windows-10-10.0.22621-SP0)", + "User-Agent": "azsdk-python-identity/1.12.0 Python/3.11.0 (Windows-10-10.0.22621-SP0)", "x-client-cpu": "x64", "x-client-current-telemetry": "4|730,0|", "x-client-last-telemetry": "4|0|||", "x-client-os": "win32", "x-client-sku": "MSAL.Python", - "x-client-ver": "1.20.0", + "x-client-ver": "1.21.0", "x-ms-lib-capability": "retry-after, h429" }, "RequestBody": "client_id=sanitized\u0026grant_type=client_credentials\u0026client_info=1\u0026client_secret=sanitized\u0026claims=%7B%22access_token%22%3A\u002B%7B%22xms_cc%22%3A\u002B%7B%22values%22%3A\u002B%5B%22CP1%22%5D%7D%7D%7D\u0026scope=https%3A%2F%2Fcommunication.azure.com%2F%2F.default", @@ -314,7 +222,7 @@ "ResponseHeaders": { "Cache-Control": "no-store, no-cache", "client-request-id": "sanitized", - "Content-Length": "111", + "Content-Length": "90", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "Expires": "-1", @@ -330,33 +238,32 @@ }, "ResponseBody": { "token_type": "Bearer", - "expires_in": 86399, - "ext_expires_in": 86399, - "refresh_in": 43199, + "expires_in": 3598, + "ext_expires_in": 3598, "access_token": "Sanitized" } }, { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", + "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2023-03-01", "RequestMethod": "GET", "RequestHeaders": { "Accept": "application/json", "Accept-Encoding": "gzip, deflate", "Connection": "keep-alive", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)" + "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b4 Python/3.11.0 (Windows-10-10.0.22621-SP0)" }, "RequestBody": null, "StatusCode": 200, "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", + "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview, 2023-01-01-preview, 2023-03-01", + "Content-Length": "118", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "MS-CV": "sanitized", "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", "X-Azure-Ref": "sanitized", "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "99ms" + "X-Processing-Time": "166ms" }, "ResponseBody": { "trunks": { @@ -371,7 +278,7 @@ } }, { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", + "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2023-03-01", "RequestMethod": "PATCH", "RequestHeaders": { "Accept": "application/json", @@ -379,7 +286,7 @@ "Connection": "keep-alive", "Content-Length": "118", "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)" + "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b4 Python/3.11.0 (Windows-10-10.0.22621-SP0)" }, "RequestBody": { "trunks": { @@ -392,15 +299,15 @@ }, "StatusCode": 200, "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", + "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview, 2023-01-01-preview, 2023-03-01", + "Content-Length": "71", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "MS-CV": "sanitized", "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", "X-Azure-Ref": "sanitized", "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "818ms" + "X-Processing-Time": "1144ms" }, "ResponseBody": { "trunks": { @@ -412,26 +319,26 @@ } }, { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", + "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2023-03-01", "RequestMethod": "GET", "RequestHeaders": { "Accept": "application/json", "Accept-Encoding": "gzip, deflate", "Connection": "keep-alive", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)" + "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b4 Python/3.11.0 (Windows-10-10.0.22621-SP0)" }, "RequestBody": null, "StatusCode": 200, "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", + "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview, 2023-01-01-preview, 2023-03-01", + "Content-Length": "71", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "MS-CV": "sanitized", "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", "X-Azure-Ref": "sanitized", "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "107ms" + "X-Processing-Time": "169ms" }, "ResponseBody": { "trunks": { diff --git a/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e_async.pyTestSipRoutingClientE2EAsynctest_add_trunk.json b/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e_async.pyTestSipRoutingClientE2EAsynctest_add_trunk.json index 994f1e1458f8..01a3af2baa02 100644 --- a/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e_async.pyTestSipRoutingClientE2EAsynctest_add_trunk.json +++ b/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e_async.pyTestSipRoutingClientE2EAsynctest_add_trunk.json @@ -1,132 +1,14 @@ { "Entries": [ { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "PATCH", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Content-Length": "14", - "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": { - "routes": [] - }, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "185ms" - }, - "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "GET", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Content-Length": "0", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": null, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "117ms" - }, - "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "PATCH", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Content-Length": "112", - "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - } - }, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "2380ms" - }, - "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", + "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2023-03-01", "RequestMethod": "PATCH", "RequestHeaders": { "Accept": "application/json", "Accept-Encoding": "gzip, deflate", "Content-Length": "62", "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", + "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b4 Python/3.11.0 (Windows-10-10.0.22621-SP0)", "x-ms-content-sha256": "sanitized", "x-ms-date": "sanitized", "x-ms-return-client-request-id": "true" @@ -140,15 +22,15 @@ }, "StatusCode": 200, "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", + "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview, 2023-01-01-preview, 2023-03-01", + "Content-Length": "165", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "MS-CV": "sanitized", "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", "X-Azure-Ref": "sanitized", "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "1198ms" + "X-Processing-Time": "1079ms" }, "ResponseBody": { "trunks": { @@ -166,13 +48,13 @@ } }, { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", + "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2023-03-01", "RequestMethod": "GET", "RequestHeaders": { "Accept": "application/json", "Accept-Encoding": "gzip, deflate", "Content-Length": "0", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", + "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b4 Python/3.11.0 (Windows-10-10.0.22621-SP0)", "x-ms-content-sha256": "sanitized", "x-ms-date": "sanitized", "x-ms-return-client-request-id": "true" @@ -180,15 +62,15 @@ "RequestBody": null, "StatusCode": 200, "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", + "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview, 2023-01-01-preview, 2023-03-01", + "Content-Length": "165", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "MS-CV": "sanitized", "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", "X-Azure-Ref": "sanitized", "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "192ms" + "X-Processing-Time": "169ms" }, "ResponseBody": { "trunks": { diff --git a/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e_async.pyTestSipRoutingClientE2EAsynctest_add_trunk_from_managed_identity.json b/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e_async.pyTestSipRoutingClientE2EAsynctest_add_trunk_from_managed_identity.json index 6b3af21bc851..92fec60bd7b6 100644 --- a/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e_async.pyTestSipRoutingClientE2EAsynctest_add_trunk_from_managed_identity.json +++ b/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e_async.pyTestSipRoutingClientE2EAsynctest_add_trunk_from_managed_identity.json @@ -1,151 +1,20 @@ { "Entries": [ { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "PATCH", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Content-Length": "14", - "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": { - "routes": [] - }, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "204ms" - }, - "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - }, - "sbs3.sanitized.com": { - "sipSignalingPort": 2222 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "GET", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Content-Length": "0", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": null, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "767ms" - }, - "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - }, - "sbs3.sanitized.com": { - "sipSignalingPort": 2222 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "PATCH", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Content-Length": "140", - "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - }, - "sbs3.sanitized.com": null - } - }, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "456ms" - }, - "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://login.microsoftonline.com/sanitized/oauth2/v2.0/token", + "RequestUri": "https://login.windows-ppe.net/sanitized/oauth2/v2.0/token", "RequestMethod": "POST", "RequestHeaders": { "Accept": "*/*", "Accept-Encoding": "gzip, deflate", "Content-Length": "131", "Content-Type": "application/x-www-form-urlencoded", - "User-Agent": "azsdk-python-identity/1.13.0b1 Python/3.10.9 (Windows-10-10.0.22621-SP0)" + "User-Agent": "azsdk-python-identity/1.12.0 Python/3.11.0 (Windows-10-10.0.22621-SP0)" }, "RequestBody": "client_id=sanitized\u0026client_secret=sanitized\u0026grant_type=client_credentials\u0026scope=https%3A%2F%2Fcommunication.azure.com%2F%2F.default", "StatusCode": 200, "ResponseHeaders": { "Cache-Control": "no-store, no-cache", - "Content-Length": "92", + "Content-Length": "90", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "Expires": "-1", @@ -160,20 +29,20 @@ }, "ResponseBody": { "token_type": "Bearer", - "expires_in": 86399, - "ext_expires_in": 86399, + "expires_in": 3599, + "ext_expires_in": 3599, "access_token": "Sanitized" } }, { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", + "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2023-03-01", "RequestMethod": "PATCH", "RequestHeaders": { "Accept": "application/json", "Accept-Encoding": "gzip, deflate", "Content-Length": "62", "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)" + "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b4 Python/3.11.0 (Windows-10-10.0.22621-SP0)" }, "RequestBody": { "trunks": { @@ -184,15 +53,15 @@ }, "StatusCode": 200, "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", + "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview, 2023-01-01-preview, 2023-03-01", + "Content-Length": "165", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "MS-CV": "sanitized", "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", "X-Azure-Ref": "sanitized", "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "554ms" + "X-Processing-Time": "950ms" }, "ResponseBody": { "trunks": { @@ -210,25 +79,25 @@ } }, { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", + "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2023-03-01", "RequestMethod": "GET", "RequestHeaders": { "Accept": "application/json", "Accept-Encoding": "gzip, deflate", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)" + "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b4 Python/3.11.0 (Windows-10-10.0.22621-SP0)" }, "RequestBody": null, "StatusCode": 200, "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", + "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview, 2023-01-01-preview, 2023-03-01", + "Content-Length": "165", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "MS-CV": "sanitized", "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", "X-Azure-Ref": "sanitized", "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "119ms" + "X-Processing-Time": "168ms" }, "ResponseBody": { "trunks": { diff --git a/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e_async.pyTestSipRoutingClientE2EAsynctest_delete_trunk.json b/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e_async.pyTestSipRoutingClientE2EAsynctest_delete_trunk.json index 4cfccee0ffdc..93835df14075 100644 --- a/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e_async.pyTestSipRoutingClientE2EAsynctest_delete_trunk.json +++ b/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e_async.pyTestSipRoutingClientE2EAsynctest_delete_trunk.json @@ -1,138 +1,14 @@ { "Entries": [ { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "PATCH", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Content-Length": "14", - "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": { - "routes": [] - }, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "190ms" - }, - "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "GET", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Content-Length": "0", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": null, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "1176ms" - }, - "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "PATCH", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Content-Length": "112", - "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - } - }, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "334ms" - }, - "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", + "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2023-03-01", "RequestMethod": "PATCH", "RequestHeaders": { "Accept": "application/json", "Accept-Encoding": "gzip, deflate", "Content-Length": "40", "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", + "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b4 Python/3.11.0 (Windows-10-10.0.22621-SP0)", "x-ms-content-sha256": "sanitized", "x-ms-date": "sanitized", "x-ms-return-client-request-id": "true" @@ -144,15 +20,15 @@ }, "StatusCode": 200, "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", + "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview, 2023-01-01-preview, 2023-03-01", + "Content-Length": "71", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "MS-CV": "sanitized", "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", "X-Azure-Ref": "sanitized", "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "280ms" + "X-Processing-Time": "390ms" }, "ResponseBody": { "trunks": { @@ -164,13 +40,13 @@ } }, { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", + "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2023-03-01", "RequestMethod": "GET", "RequestHeaders": { "Accept": "application/json", "Accept-Encoding": "gzip, deflate", "Content-Length": "0", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", + "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b4 Python/3.11.0 (Windows-10-10.0.22621-SP0)", "x-ms-content-sha256": "sanitized", "x-ms-date": "sanitized", "x-ms-return-client-request-id": "true" @@ -178,15 +54,15 @@ "RequestBody": null, "StatusCode": 200, "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", + "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview, 2023-01-01-preview, 2023-03-01", + "Content-Length": "71", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "MS-CV": "sanitized", "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", "X-Azure-Ref": "sanitized", "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "118ms" + "X-Processing-Time": "169ms" }, "ResponseBody": { "trunks": { diff --git a/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e_async.pyTestSipRoutingClientE2EAsynctest_delete_trunk_from_managed_identity.json b/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e_async.pyTestSipRoutingClientE2EAsynctest_delete_trunk_from_managed_identity.json index 3a6f7da5fc50..8ea969d6d38a 100644 --- a/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e_async.pyTestSipRoutingClientE2EAsynctest_delete_trunk_from_managed_identity.json +++ b/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e_async.pyTestSipRoutingClientE2EAsynctest_delete_trunk_from_managed_identity.json @@ -1,138 +1,20 @@ { "Entries": [ { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "PATCH", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Content-Length": "14", - "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": { - "routes": [] - }, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "927ms" - }, - "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "GET", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Content-Length": "0", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": null, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "105ms" - }, - "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "PATCH", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Content-Length": "112", - "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - } - }, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "1353ms" - }, - "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://login.microsoftonline.com/sanitized/oauth2/v2.0/token", + "RequestUri": "https://login.windows-ppe.net/sanitized/oauth2/v2.0/token", "RequestMethod": "POST", "RequestHeaders": { "Accept": "*/*", "Accept-Encoding": "gzip, deflate", "Content-Length": "131", "Content-Type": "application/x-www-form-urlencoded", - "User-Agent": "azsdk-python-identity/1.13.0b1 Python/3.10.9 (Windows-10-10.0.22621-SP0)" + "User-Agent": "azsdk-python-identity/1.12.0 Python/3.11.0 (Windows-10-10.0.22621-SP0)" }, "RequestBody": "client_id=sanitized\u0026client_secret=sanitized\u0026grant_type=client_credentials\u0026scope=https%3A%2F%2Fcommunication.azure.com%2F%2F.default", "StatusCode": 200, "ResponseHeaders": { "Cache-Control": "no-store, no-cache", - "Content-Length": "92", + "Content-Length": "90", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "Expires": "-1", @@ -147,20 +29,20 @@ }, "ResponseBody": { "token_type": "Bearer", - "expires_in": 86399, - "ext_expires_in": 86399, + "expires_in": 3599, + "ext_expires_in": 3599, "access_token": "Sanitized" } }, { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", + "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2023-03-01", "RequestMethod": "PATCH", "RequestHeaders": { "Accept": "application/json", "Accept-Encoding": "gzip, deflate", "Content-Length": "40", "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)" + "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b4 Python/3.11.0 (Windows-10-10.0.22621-SP0)" }, "RequestBody": { "trunks": { @@ -169,15 +51,15 @@ }, "StatusCode": 200, "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", + "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview, 2023-01-01-preview, 2023-03-01", + "Content-Length": "71", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "MS-CV": "sanitized", "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", "X-Azure-Ref": "sanitized", "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "297ms" + "X-Processing-Time": "1143ms" }, "ResponseBody": { "trunks": { @@ -189,25 +71,25 @@ } }, { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", + "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2023-03-01", "RequestMethod": "GET", "RequestHeaders": { "Accept": "application/json", "Accept-Encoding": "gzip, deflate", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)" + "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b4 Python/3.11.0 (Windows-10-10.0.22621-SP0)" }, "RequestBody": null, "StatusCode": 200, "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", + "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview, 2023-01-01-preview, 2023-03-01", + "Content-Length": "71", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "MS-CV": "sanitized", "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", "X-Azure-Ref": "sanitized", "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "100ms" + "X-Processing-Time": "169ms" }, "ResponseBody": { "trunks": { diff --git a/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e_async.pyTestSipRoutingClientE2EAsynctest_get_routes.json b/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e_async.pyTestSipRoutingClientE2EAsynctest_get_routes.json index 78a9d5a580f3..c76551c309c5 100644 --- a/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e_async.pyTestSipRoutingClientE2EAsynctest_get_routes.json +++ b/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e_async.pyTestSipRoutingClientE2EAsynctest_get_routes.json @@ -1,138 +1,14 @@ { "Entries": [ { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", + "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2023-03-01", "RequestMethod": "PATCH", "RequestHeaders": { "Accept": "application/json", "Accept-Encoding": "gzip, deflate", - "Content-Length": "14", + "Content-Length": "137", "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": { - "routes": [] - }, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "573ms" - }, - "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "GET", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Content-Length": "0", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": null, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "119ms" - }, - "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "PATCH", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Content-Length": "112", - "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - } - }, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "975ms" - }, - "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "PATCH", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Content-Length": "157", - "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", + "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b4 Python/3.11.0 (Windows-10-10.0.22621-SP0)", "x-ms-content-sha256": "sanitized", "x-ms-date": "sanitized", "x-ms-return-client-request-id": "true" @@ -143,23 +19,21 @@ "description": "Handle numbers starting with \u0027\u002B123\u0027", "name": "First rule", "numberPattern": "\\\u002B123[0-9]\u002B", - "trunks": [ - "sbs1.sanitized.com" - ] + "trunks": [] } ] }, "StatusCode": 200, "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", + "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview, 2023-01-01-preview, 2023-03-01", + "Content-Length": "234", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "MS-CV": "sanitized", "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", "X-Azure-Ref": "sanitized", "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "197ms" + "X-Processing-Time": "313ms" }, "ResponseBody": { "trunks": { @@ -175,21 +49,19 @@ "description": "Handle numbers starting with \u0027\u002B123\u0027", "name": "First rule", "numberPattern": "\\\u002B123[0-9]\u002B", - "trunks": [ - "sbs1.sanitized.com" - ] + "trunks": [] } ] } }, { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", + "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2023-03-01", "RequestMethod": "GET", "RequestHeaders": { "Accept": "application/json", "Accept-Encoding": "gzip, deflate", "Content-Length": "0", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", + "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b4 Python/3.11.0 (Windows-10-10.0.22621-SP0)", "x-ms-content-sha256": "sanitized", "x-ms-date": "sanitized", "x-ms-return-client-request-id": "true" @@ -197,15 +69,15 @@ "RequestBody": null, "StatusCode": 200, "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", + "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview, 2023-01-01-preview, 2023-03-01", + "Content-Length": "234", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "MS-CV": "sanitized", "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", "X-Azure-Ref": "sanitized", "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "1076ms" + "X-Processing-Time": "176ms" }, "ResponseBody": { "trunks": { @@ -221,9 +93,7 @@ "description": "Handle numbers starting with \u0027\u002B123\u0027", "name": "First rule", "numberPattern": "\\\u002B123[0-9]\u002B", - "trunks": [ - "sbs1.sanitized.com" - ] + "trunks": [] } ] } diff --git a/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e_async.pyTestSipRoutingClientE2EAsynctest_get_routes_from_managed_identity.json b/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e_async.pyTestSipRoutingClientE2EAsynctest_get_routes_from_managed_identity.json index 0fe66664d1cd..4b74d8407e28 100644 --- a/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e_async.pyTestSipRoutingClientE2EAsynctest_get_routes_from_managed_identity.json +++ b/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e_async.pyTestSipRoutingClientE2EAsynctest_get_routes_from_managed_identity.json @@ -1,144 +1,20 @@ { "Entries": [ { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "PATCH", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Content-Length": "14", - "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": { - "routes": [] - }, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "197ms" - }, - "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "GET", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Content-Length": "0", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": null, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "117ms" - }, - "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "PATCH", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Content-Length": "112", - "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - } - }, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "1237ms" - }, - "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://login.microsoftonline.com/sanitized/oauth2/v2.0/token", + "RequestUri": "https://login.windows-ppe.net/sanitized/oauth2/v2.0/token", "RequestMethod": "POST", "RequestHeaders": { "Accept": "*/*", "Accept-Encoding": "gzip, deflate", "Content-Length": "131", "Content-Type": "application/x-www-form-urlencoded", - "User-Agent": "azsdk-python-identity/1.13.0b1 Python/3.10.9 (Windows-10-10.0.22621-SP0)" + "User-Agent": "azsdk-python-identity/1.12.0 Python/3.11.0 (Windows-10-10.0.22621-SP0)" }, "RequestBody": "client_id=sanitized\u0026client_secret=sanitized\u0026grant_type=client_credentials\u0026scope=https%3A%2F%2Fcommunication.azure.com%2F%2F.default", "StatusCode": 200, "ResponseHeaders": { "Cache-Control": "no-store, no-cache", - "Content-Length": "92", + "Content-Length": "90", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "Expires": "-1", @@ -153,20 +29,20 @@ }, "ResponseBody": { "token_type": "Bearer", - "expires_in": 86399, - "ext_expires_in": 86399, + "expires_in": 3599, + "ext_expires_in": 3599, "access_token": "Sanitized" } }, { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", + "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2023-03-01", "RequestMethod": "PATCH", "RequestHeaders": { "Accept": "application/json", "Accept-Encoding": "gzip, deflate", - "Content-Length": "157", + "Content-Length": "137", "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)" + "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b4 Python/3.11.0 (Windows-10-10.0.22621-SP0)" }, "RequestBody": { "routes": [ @@ -174,23 +50,21 @@ "description": "Handle numbers starting with \u0027\u002B123\u0027", "name": "First rule", "numberPattern": "\\\u002B123[0-9]\u002B", - "trunks": [ - "sbs1.sanitized.com" - ] + "trunks": [] } ] }, "StatusCode": 200, "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", + "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview, 2023-01-01-preview, 2023-03-01", + "Content-Length": "234", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "MS-CV": "sanitized", "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", "X-Azure-Ref": "sanitized", "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "271ms" + "X-Processing-Time": "388ms" }, "ResponseBody": { "trunks": { @@ -206,33 +80,31 @@ "description": "Handle numbers starting with \u0027\u002B123\u0027", "name": "First rule", "numberPattern": "\\\u002B123[0-9]\u002B", - "trunks": [ - "sbs1.sanitized.com" - ] + "trunks": [] } ] } }, { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", + "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2023-03-01", "RequestMethod": "GET", "RequestHeaders": { "Accept": "application/json", "Accept-Encoding": "gzip, deflate", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)" + "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b4 Python/3.11.0 (Windows-10-10.0.22621-SP0)" }, "RequestBody": null, "StatusCode": 200, "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", + "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview, 2023-01-01-preview, 2023-03-01", + "Content-Length": "234", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "MS-CV": "sanitized", "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", "X-Azure-Ref": "sanitized", "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "120ms" + "X-Processing-Time": "167ms" }, "ResponseBody": { "trunks": { @@ -248,9 +120,7 @@ "description": "Handle numbers starting with \u0027\u002B123\u0027", "name": "First rule", "numberPattern": "\\\u002B123[0-9]\u002B", - "trunks": [ - "sbs1.sanitized.com" - ] + "trunks": [] } ] } diff --git a/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e_async.pyTestSipRoutingClientE2EAsynctest_get_trunk.json b/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e_async.pyTestSipRoutingClientE2EAsynctest_get_trunk.json index 195cf20132b5..f0fd6849ff65 100644 --- a/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e_async.pyTestSipRoutingClientE2EAsynctest_get_trunk.json +++ b/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e_async.pyTestSipRoutingClientE2EAsynctest_get_trunk.json @@ -1,144 +1,13 @@ { "Entries": [ { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "PATCH", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Content-Length": "14", - "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": { - "routes": [] - }, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "211ms" - }, - "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - }, - "sbs3.sanitized.com": { - "sipSignalingPort": 2222 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "GET", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Content-Length": "0", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": null, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "138ms" - }, - "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - }, - "sbs3.sanitized.com": { - "sipSignalingPort": 2222 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "PATCH", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Content-Length": "140", - "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - }, - "sbs3.sanitized.com": null - } - }, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "506ms" - }, - "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", + "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2023-03-01", "RequestMethod": "GET", "RequestHeaders": { "Accept": "application/json", "Accept-Encoding": "gzip, deflate", "Content-Length": "0", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", + "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b4 Python/3.11.0 (Windows-10-10.0.22621-SP0)", "x-ms-content-sha256": "sanitized", "x-ms-date": "sanitized", "x-ms-return-client-request-id": "true" @@ -146,15 +15,15 @@ "RequestBody": null, "StatusCode": 200, "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", + "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview, 2023-01-01-preview, 2023-03-01", + "Content-Length": "118", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "MS-CV": "sanitized", "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", "X-Azure-Ref": "sanitized", "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "134ms" + "X-Processing-Time": "168ms" }, "ResponseBody": { "trunks": { diff --git a/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e_async.pyTestSipRoutingClientE2EAsynctest_get_trunk_from_managed_identity.json b/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e_async.pyTestSipRoutingClientE2EAsynctest_get_trunk_from_managed_identity.json index 3c331f271246..b8f42b27d83d 100644 --- a/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e_async.pyTestSipRoutingClientE2EAsynctest_get_trunk_from_managed_identity.json +++ b/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e_async.pyTestSipRoutingClientE2EAsynctest_get_trunk_from_managed_identity.json @@ -1,144 +1,20 @@ { "Entries": [ { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "PATCH", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Content-Length": "14", - "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": { - "routes": [] - }, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "201ms" - }, - "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "GET", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Content-Length": "0", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": null, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "120ms" - }, - "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "PATCH", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Content-Length": "112", - "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - } - }, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "319ms" - }, - "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://login.microsoftonline.com/sanitized/oauth2/v2.0/token", + "RequestUri": "https://login.windows-ppe.net/sanitized/oauth2/v2.0/token", "RequestMethod": "POST", "RequestHeaders": { "Accept": "*/*", "Accept-Encoding": "gzip, deflate", "Content-Length": "131", "Content-Type": "application/x-www-form-urlencoded", - "User-Agent": "azsdk-python-identity/1.13.0b1 Python/3.10.9 (Windows-10-10.0.22621-SP0)" + "User-Agent": "azsdk-python-identity/1.12.0 Python/3.11.0 (Windows-10-10.0.22621-SP0)" }, "RequestBody": "client_id=sanitized\u0026client_secret=sanitized\u0026grant_type=client_credentials\u0026scope=https%3A%2F%2Fcommunication.azure.com%2F%2F.default", "StatusCode": 200, "ResponseHeaders": { "Cache-Control": "no-store, no-cache", - "Content-Length": "92", + "Content-Length": "90", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "Expires": "-1", @@ -153,31 +29,31 @@ }, "ResponseBody": { "token_type": "Bearer", - "expires_in": 86399, - "ext_expires_in": 86399, + "expires_in": 3599, + "ext_expires_in": 3599, "access_token": "Sanitized" } }, { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", + "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2023-03-01", "RequestMethod": "GET", "RequestHeaders": { "Accept": "application/json", "Accept-Encoding": "gzip, deflate", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)" + "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b4 Python/3.11.0 (Windows-10-10.0.22621-SP0)" }, "RequestBody": null, "StatusCode": 200, "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", + "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview, 2023-01-01-preview, 2023-03-01", + "Content-Length": "118", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "MS-CV": "sanitized", "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", "X-Azure-Ref": "sanitized", "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "108ms" + "X-Processing-Time": "165ms" }, "ResponseBody": { "trunks": { diff --git a/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e_async.pyTestSipRoutingClientE2EAsynctest_get_trunk_not_existing_throws.json b/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e_async.pyTestSipRoutingClientE2EAsynctest_get_trunk_not_existing_throws.json new file mode 100644 index 000000000000..06f0d0d3ce59 --- /dev/null +++ b/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e_async.pyTestSipRoutingClientE2EAsynctest_get_trunk_not_existing_throws.json @@ -0,0 +1,42 @@ +{ + "Entries": [ + { + "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2023-03-01", + "RequestMethod": "GET", + "RequestHeaders": { + "Accept": "application/json", + "Accept-Encoding": "gzip, deflate", + "Content-Length": "0", + "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b4 Python/3.11.0 (Windows-10-10.0.22621-SP0)", + "x-ms-content-sha256": "sanitized", + "x-ms-date": "sanitized", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 200, + "ResponseHeaders": { + "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview, 2023-01-01-preview, 2023-03-01", + "Content-Length": "118", + "Content-Type": "application/json; charset=utf-8", + "Date": "sanitized", + "MS-CV": "sanitized", + "Strict-Transport-Security": "max-age=2592000", + "X-Azure-Ref": "sanitized", + "X-Cache": "CONFIG_NOCACHE", + "X-Processing-Time": "736ms" + }, + "ResponseBody": { + "trunks": { + "sbs1.sanitized.com": { + "sipSignalingPort": 1122 + }, + "sbs2.sanitized.com": { + "sipSignalingPort": 1123 + } + }, + "routes": [] + } + } + ], + "Variables": {} +} diff --git a/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e_async.pyTestSipRoutingClientE2EAsynctest_get_trunks.json b/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e_async.pyTestSipRoutingClientE2EAsynctest_get_trunks.json index 23a50694d03d..14e331ea6b68 100644 --- a/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e_async.pyTestSipRoutingClientE2EAsynctest_get_trunks.json +++ b/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e_async.pyTestSipRoutingClientE2EAsynctest_get_trunks.json @@ -1,137 +1,13 @@ { "Entries": [ { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "PATCH", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Content-Length": "14", - "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": { - "routes": [] - }, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "205ms" - }, - "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 7777 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "GET", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Content-Length": "0", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": null, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "114ms" - }, - "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 7777 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "PATCH", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Content-Length": "168", - "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - } - }, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "669ms" - }, - "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", + "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2023-03-01", "RequestMethod": "GET", "RequestHeaders": { "Accept": "application/json", "Accept-Encoding": "gzip, deflate", "Content-Length": "0", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", + "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b4 Python/3.11.0 (Windows-10-10.0.22621-SP0)", "x-ms-content-sha256": "sanitized", "x-ms-date": "sanitized", "x-ms-return-client-request-id": "true" @@ -139,15 +15,15 @@ "RequestBody": null, "StatusCode": 200, "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", + "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview, 2023-01-01-preview, 2023-03-01", + "Content-Length": "118", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "MS-CV": "sanitized", "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", "X-Azure-Ref": "sanitized", "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "122ms" + "X-Processing-Time": "165ms" }, "ResponseBody": { "trunks": { diff --git a/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e_async.pyTestSipRoutingClientE2EAsynctest_get_trunks_from_managed_identity.json b/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e_async.pyTestSipRoutingClientE2EAsynctest_get_trunks_from_managed_identity.json index 888462d7b3dc..56da260e0781 100644 --- a/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e_async.pyTestSipRoutingClientE2EAsynctest_get_trunks_from_managed_identity.json +++ b/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e_async.pyTestSipRoutingClientE2EAsynctest_get_trunks_from_managed_identity.json @@ -1,144 +1,20 @@ { "Entries": [ { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "PATCH", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Content-Length": "14", - "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": { - "routes": [] - }, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "209ms" - }, - "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "GET", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Content-Length": "0", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": null, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "122ms" - }, - "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "PATCH", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Content-Length": "112", - "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - } - }, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "300ms" - }, - "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://login.microsoftonline.com/sanitized/oauth2/v2.0/token", + "RequestUri": "https://login.windows-ppe.net/sanitized/oauth2/v2.0/token", "RequestMethod": "POST", "RequestHeaders": { "Accept": "*/*", "Accept-Encoding": "gzip, deflate", "Content-Length": "131", "Content-Type": "application/x-www-form-urlencoded", - "User-Agent": "azsdk-python-identity/1.13.0b1 Python/3.10.9 (Windows-10-10.0.22621-SP0)" + "User-Agent": "azsdk-python-identity/1.12.0 Python/3.11.0 (Windows-10-10.0.22621-SP0)" }, "RequestBody": "client_id=sanitized\u0026client_secret=sanitized\u0026grant_type=client_credentials\u0026scope=https%3A%2F%2Fcommunication.azure.com%2F%2F.default", "StatusCode": 200, "ResponseHeaders": { "Cache-Control": "no-store, no-cache", - "Content-Length": "92", + "Content-Length": "90", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "Expires": "-1", @@ -153,31 +29,31 @@ }, "ResponseBody": { "token_type": "Bearer", - "expires_in": 86399, - "ext_expires_in": 86399, + "expires_in": 3599, + "ext_expires_in": 3599, "access_token": "Sanitized" } }, { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", + "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2023-03-01", "RequestMethod": "GET", "RequestHeaders": { "Accept": "application/json", "Accept-Encoding": "gzip, deflate", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)" + "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b4 Python/3.11.0 (Windows-10-10.0.22621-SP0)" }, "RequestBody": null, "StatusCode": 200, "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", + "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview, 2023-01-01-preview, 2023-03-01", + "Content-Length": "118", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "MS-CV": "sanitized", "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", "X-Azure-Ref": "sanitized", "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "201ms" + "X-Processing-Time": "166ms" }, "ResponseBody": { "trunks": { diff --git a/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e_async.pyTestSipRoutingClientE2EAsynctest_set_routes.json b/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e_async.pyTestSipRoutingClientE2EAsynctest_set_routes.json index afe4ba26d1d9..8f1575c93c18 100644 --- a/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e_async.pyTestSipRoutingClientE2EAsynctest_set_routes.json +++ b/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e_async.pyTestSipRoutingClientE2EAsynctest_set_routes.json @@ -1,124 +1,14 @@ { "Entries": [ { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", + "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2023-03-01", "RequestMethod": "PATCH", "RequestHeaders": { "Accept": "application/json", "Accept-Encoding": "gzip, deflate", - "Content-Length": "14", + "Content-Length": "137", "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": { - "routes": [] - }, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "187ms" - }, - "ResponseBody": { - "trunks": {}, - "routes": [] - } - }, - { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "GET", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Content-Length": "0", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": null, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "103ms" - }, - "ResponseBody": { - "trunks": {}, - "routes": [] - } - }, - { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "PATCH", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Content-Length": "112", - "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - } - }, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "512ms" - }, - "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "PATCH", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Content-Length": "157", - "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", + "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b4 Python/3.11.0 (Windows-10-10.0.22621-SP0)", "x-ms-content-sha256": "sanitized", "x-ms-date": "sanitized", "x-ms-return-client-request-id": "true" @@ -129,23 +19,21 @@ "description": "Handle numbers starting with \u0027\u002B123\u0027", "name": "First rule", "numberPattern": "\\\u002B123[0-9]\u002B", - "trunks": [ - "sbs1.sanitized.com" - ] + "trunks": [] } ] }, "StatusCode": 200, "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", + "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview, 2023-01-01-preview, 2023-03-01", + "Content-Length": "234", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "MS-CV": "sanitized", "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", "X-Azure-Ref": "sanitized", "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "194ms" + "X-Processing-Time": "324ms" }, "ResponseBody": { "trunks": { @@ -161,22 +49,20 @@ "description": "Handle numbers starting with \u0027\u002B123\u0027", "name": "First rule", "numberPattern": "\\\u002B123[0-9]\u002B", - "trunks": [ - "sbs1.sanitized.com" - ] + "trunks": [] } ] } }, { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", + "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2023-03-01", "RequestMethod": "PATCH", "RequestHeaders": { "Accept": "application/json", "Accept-Encoding": "gzip, deflate", - "Content-Length": "163", + "Content-Length": "143", "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", + "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b4 Python/3.11.0 (Windows-10-10.0.22621-SP0)", "x-ms-content-sha256": "sanitized", "x-ms-date": "sanitized", "x-ms-return-client-request-id": "true" @@ -187,23 +73,21 @@ "description": "Handle numbers starting with \u0027\u002B999\u0027", "name": "Alternative rule", "numberPattern": "\\\u002B999[0-9]\u002B", - "trunks": [ - "sbs2.sanitized.com" - ] + "trunks": [] } ] }, "StatusCode": 200, "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", + "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview, 2023-01-01-preview, 2023-03-01", + "Content-Length": "240", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "MS-CV": "sanitized", "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", "X-Azure-Ref": "sanitized", "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "188ms" + "X-Processing-Time": "318ms" }, "ResponseBody": { "trunks": { @@ -219,21 +103,19 @@ "description": "Handle numbers starting with \u0027\u002B999\u0027", "name": "Alternative rule", "numberPattern": "\\\u002B999[0-9]\u002B", - "trunks": [ - "sbs2.sanitized.com" - ] + "trunks": [] } ] } }, { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", + "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2023-03-01", "RequestMethod": "GET", "RequestHeaders": { "Accept": "application/json", "Accept-Encoding": "gzip, deflate", "Content-Length": "0", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", + "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b4 Python/3.11.0 (Windows-10-10.0.22621-SP0)", "x-ms-content-sha256": "sanitized", "x-ms-date": "sanitized", "x-ms-return-client-request-id": "true" @@ -241,15 +123,15 @@ "RequestBody": null, "StatusCode": 200, "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", + "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview, 2023-01-01-preview, 2023-03-01", + "Content-Length": "240", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "MS-CV": "sanitized", "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", "X-Azure-Ref": "sanitized", "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "114ms" + "X-Processing-Time": "173ms" }, "ResponseBody": { "trunks": { @@ -265,9 +147,7 @@ "description": "Handle numbers starting with \u0027\u002B999\u0027", "name": "Alternative rule", "numberPattern": "\\\u002B999[0-9]\u002B", - "trunks": [ - "sbs2.sanitized.com" - ] + "trunks": [] } ] } diff --git a/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e_async.pyTestSipRoutingClientE2EAsynctest_set_routes_from_managed_identity.json b/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e_async.pyTestSipRoutingClientE2EAsynctest_set_routes_from_managed_identity.json index 8a5bfd53bf5a..67f0767ec8f7 100644 --- a/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e_async.pyTestSipRoutingClientE2EAsynctest_set_routes_from_managed_identity.json +++ b/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e_async.pyTestSipRoutingClientE2EAsynctest_set_routes_from_managed_identity.json @@ -1,144 +1,20 @@ { "Entries": [ { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "PATCH", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Content-Length": "14", - "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": { - "routes": [] - }, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "188ms" - }, - "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "GET", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Content-Length": "0", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": null, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "122ms" - }, - "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "PATCH", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Content-Length": "112", - "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - } - }, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "299ms" - }, - "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://login.microsoftonline.com/sanitized/oauth2/v2.0/token", + "RequestUri": "https://login.windows-ppe.net/sanitized/oauth2/v2.0/token", "RequestMethod": "POST", "RequestHeaders": { "Accept": "*/*", "Accept-Encoding": "gzip, deflate", "Content-Length": "131", "Content-Type": "application/x-www-form-urlencoded", - "User-Agent": "azsdk-python-identity/1.13.0b1 Python/3.10.9 (Windows-10-10.0.22621-SP0)" + "User-Agent": "azsdk-python-identity/1.12.0 Python/3.11.0 (Windows-10-10.0.22621-SP0)" }, "RequestBody": "client_id=sanitized\u0026client_secret=sanitized\u0026grant_type=client_credentials\u0026scope=https%3A%2F%2Fcommunication.azure.com%2F%2F.default", "StatusCode": 200, "ResponseHeaders": { "Cache-Control": "no-store, no-cache", - "Content-Length": "92", + "Content-Length": "90", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "Expires": "-1", @@ -153,20 +29,20 @@ }, "ResponseBody": { "token_type": "Bearer", - "expires_in": 86399, - "ext_expires_in": 86399, + "expires_in": 3599, + "ext_expires_in": 3599, "access_token": "Sanitized" } }, { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", + "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2023-03-01", "RequestMethod": "PATCH", "RequestHeaders": { "Accept": "application/json", "Accept-Encoding": "gzip, deflate", - "Content-Length": "157", + "Content-Length": "137", "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)" + "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b4 Python/3.11.0 (Windows-10-10.0.22621-SP0)" }, "RequestBody": { "routes": [ @@ -174,23 +50,21 @@ "description": "Handle numbers starting with \u0027\u002B123\u0027", "name": "First rule", "numberPattern": "\\\u002B123[0-9]\u002B", - "trunks": [ - "sbs1.sanitized.com" - ] + "trunks": [] } ] }, "StatusCode": 200, "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", + "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview, 2023-01-01-preview, 2023-03-01", + "Content-Length": "234", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "MS-CV": "sanitized", "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", "X-Azure-Ref": "sanitized", "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "206ms" + "X-Processing-Time": "744ms" }, "ResponseBody": { "trunks": { @@ -206,22 +80,20 @@ "description": "Handle numbers starting with \u0027\u002B123\u0027", "name": "First rule", "numberPattern": "\\\u002B123[0-9]\u002B", - "trunks": [ - "sbs1.sanitized.com" - ] + "trunks": [] } ] } }, { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", + "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2023-03-01", "RequestMethod": "PATCH", "RequestHeaders": { "Accept": "application/json", "Accept-Encoding": "gzip, deflate", - "Content-Length": "163", + "Content-Length": "143", "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)" + "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b4 Python/3.11.0 (Windows-10-10.0.22621-SP0)" }, "RequestBody": { "routes": [ @@ -229,23 +101,21 @@ "description": "Handle numbers starting with \u0027\u002B999\u0027", "name": "Alternative rule", "numberPattern": "\\\u002B999[0-9]\u002B", - "trunks": [ - "sbs2.sanitized.com" - ] + "trunks": [] } ] }, "StatusCode": 200, "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", + "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview, 2023-01-01-preview, 2023-03-01", + "Content-Length": "240", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "MS-CV": "sanitized", "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", "X-Azure-Ref": "sanitized", "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "219ms" + "X-Processing-Time": "306ms" }, "ResponseBody": { "trunks": { @@ -261,33 +131,31 @@ "description": "Handle numbers starting with \u0027\u002B999\u0027", "name": "Alternative rule", "numberPattern": "\\\u002B999[0-9]\u002B", - "trunks": [ - "sbs2.sanitized.com" - ] + "trunks": [] } ] } }, { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", + "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2023-03-01", "RequestMethod": "GET", "RequestHeaders": { "Accept": "application/json", "Accept-Encoding": "gzip, deflate", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)" + "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b4 Python/3.11.0 (Windows-10-10.0.22621-SP0)" }, "RequestBody": null, "StatusCode": 200, "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", + "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview, 2023-01-01-preview, 2023-03-01", + "Content-Length": "240", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "MS-CV": "sanitized", "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", "X-Azure-Ref": "sanitized", "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "102ms" + "X-Processing-Time": "484ms" }, "ResponseBody": { "trunks": { @@ -303,9 +171,7 @@ "description": "Handle numbers starting with \u0027\u002B999\u0027", "name": "Alternative rule", "numberPattern": "\\\u002B999[0-9]\u002B", - "trunks": [ - "sbs2.sanitized.com" - ] + "trunks": [] } ] } diff --git a/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e_async.pyTestSipRoutingClientE2EAsynctest_set_trunk.json b/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e_async.pyTestSipRoutingClientE2EAsynctest_set_trunk.json index 6d9820064235..98979d170dde 100644 --- a/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e_async.pyTestSipRoutingClientE2EAsynctest_set_trunk.json +++ b/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e_async.pyTestSipRoutingClientE2EAsynctest_set_trunk.json @@ -1,138 +1,14 @@ { "Entries": [ { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "PATCH", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Content-Length": "14", - "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": { - "routes": [] - }, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "179ms" - }, - "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "GET", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Content-Length": "0", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": null, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "110ms" - }, - "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "PATCH", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Content-Length": "112", - "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - } - }, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "309ms" - }, - "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", + "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2023-03-01", "RequestMethod": "PATCH", "RequestHeaders": { "Accept": "application/json", "Accept-Encoding": "gzip, deflate", "Content-Length": "62", "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", + "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b4 Python/3.11.0 (Windows-10-10.0.22621-SP0)", "x-ms-content-sha256": "sanitized", "x-ms-date": "sanitized", "x-ms-return-client-request-id": "true" @@ -146,15 +22,15 @@ }, "StatusCode": 200, "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", + "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview, 2023-01-01-preview, 2023-03-01", + "Content-Length": "118", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "MS-CV": "sanitized", "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", "X-Azure-Ref": "sanitized", "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "281ms" + "X-Processing-Time": "449ms" }, "ResponseBody": { "trunks": { @@ -169,13 +45,13 @@ } }, { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", + "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2023-03-01", "RequestMethod": "GET", "RequestHeaders": { "Accept": "application/json", "Accept-Encoding": "gzip, deflate", "Content-Length": "0", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", + "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b4 Python/3.11.0 (Windows-10-10.0.22621-SP0)", "x-ms-content-sha256": "sanitized", "x-ms-date": "sanitized", "x-ms-return-client-request-id": "true" @@ -183,15 +59,15 @@ "RequestBody": null, "StatusCode": 200, "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", + "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview, 2023-01-01-preview, 2023-03-01", + "Content-Length": "118", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "MS-CV": "sanitized", "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", "X-Azure-Ref": "sanitized", "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "102ms" + "X-Processing-Time": "882ms" }, "ResponseBody": { "trunks": { diff --git a/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e_async.pyTestSipRoutingClientE2EAsynctest_set_trunk_from_managed_identity.json b/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e_async.pyTestSipRoutingClientE2EAsynctest_set_trunk_from_managed_identity.json index 9d9731800e70..d91517d4add1 100644 --- a/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e_async.pyTestSipRoutingClientE2EAsynctest_set_trunk_from_managed_identity.json +++ b/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e_async.pyTestSipRoutingClientE2EAsynctest_set_trunk_from_managed_identity.json @@ -1,144 +1,20 @@ { "Entries": [ { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "PATCH", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Content-Length": "14", - "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": { - "routes": [] - }, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "185ms" - }, - "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 7777 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "GET", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Content-Length": "0", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": null, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "101ms" - }, - "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 7777 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "PATCH", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Content-Length": "112", - "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - } - }, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "291ms" - }, - "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://login.microsoftonline.com/sanitized/oauth2/v2.0/token", + "RequestUri": "https://login.windows-ppe.net/sanitized/oauth2/v2.0/token", "RequestMethod": "POST", "RequestHeaders": { "Accept": "*/*", "Accept-Encoding": "gzip, deflate", "Content-Length": "131", "Content-Type": "application/x-www-form-urlencoded", - "User-Agent": "azsdk-python-identity/1.13.0b1 Python/3.10.9 (Windows-10-10.0.22621-SP0)" + "User-Agent": "azsdk-python-identity/1.12.0 Python/3.11.0 (Windows-10-10.0.22621-SP0)" }, "RequestBody": "client_id=sanitized\u0026client_secret=sanitized\u0026grant_type=client_credentials\u0026scope=https%3A%2F%2Fcommunication.azure.com%2F%2F.default", "StatusCode": 200, "ResponseHeaders": { "Cache-Control": "no-store, no-cache", - "Content-Length": "92", + "Content-Length": "90", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "Expires": "-1", @@ -153,20 +29,20 @@ }, "ResponseBody": { "token_type": "Bearer", - "expires_in": 86399, - "ext_expires_in": 86399, + "expires_in": 3599, + "ext_expires_in": 3599, "access_token": "Sanitized" } }, { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", + "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2023-03-01", "RequestMethod": "PATCH", "RequestHeaders": { "Accept": "application/json", "Accept-Encoding": "gzip, deflate", "Content-Length": "62", "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)" + "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b4 Python/3.11.0 (Windows-10-10.0.22621-SP0)" }, "RequestBody": { "trunks": { @@ -177,15 +53,15 @@ }, "StatusCode": 200, "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", + "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview, 2023-01-01-preview, 2023-03-01", + "Content-Length": "118", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "MS-CV": "sanitized", "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", "X-Azure-Ref": "sanitized", "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "289ms" + "X-Processing-Time": "431ms" }, "ResponseBody": { "trunks": { @@ -200,25 +76,25 @@ } }, { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", + "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2023-03-01", "RequestMethod": "GET", "RequestHeaders": { "Accept": "application/json", "Accept-Encoding": "gzip, deflate", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)" + "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b4 Python/3.11.0 (Windows-10-10.0.22621-SP0)" }, "RequestBody": null, "StatusCode": 200, "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", + "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview, 2023-01-01-preview, 2023-03-01", + "Content-Length": "118", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "MS-CV": "sanitized", "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", "X-Azure-Ref": "sanitized", "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "132ms" + "X-Processing-Time": "216ms" }, "ResponseBody": { "trunks": { diff --git a/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e_async.pyTestSipRoutingClientE2EAsynctest_set_trunks.json b/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e_async.pyTestSipRoutingClientE2EAsynctest_set_trunks.json index 42ac8c30a0ef..04f1e9f233a2 100644 --- a/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e_async.pyTestSipRoutingClientE2EAsynctest_set_trunks.json +++ b/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e_async.pyTestSipRoutingClientE2EAsynctest_set_trunks.json @@ -1,137 +1,13 @@ { "Entries": [ { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "PATCH", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Content-Length": "14", - "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": { - "routes": [] - }, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "195ms" - }, - "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "GET", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Content-Length": "0", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": null, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "133ms" - }, - "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "PATCH", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Content-Length": "112", - "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - } - }, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "2157ms" - }, - "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", + "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2023-03-01", "RequestMethod": "GET", "RequestHeaders": { "Accept": "application/json", "Accept-Encoding": "gzip, deflate", "Content-Length": "0", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", + "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b4 Python/3.11.0 (Windows-10-10.0.22621-SP0)", "x-ms-content-sha256": "sanitized", "x-ms-date": "sanitized", "x-ms-return-client-request-id": "true" @@ -139,15 +15,15 @@ "RequestBody": null, "StatusCode": 200, "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", + "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview, 2023-01-01-preview, 2023-03-01", + "Content-Length": "118", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "MS-CV": "sanitized", "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", "X-Azure-Ref": "sanitized", "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "116ms" + "X-Processing-Time": "165ms" }, "ResponseBody": { "trunks": { @@ -162,14 +38,14 @@ } }, { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", + "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2023-03-01", "RequestMethod": "PATCH", "RequestHeaders": { "Accept": "application/json", "Accept-Encoding": "gzip, deflate", "Content-Length": "118", "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", + "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b4 Python/3.11.0 (Windows-10-10.0.22621-SP0)", "x-ms-content-sha256": "sanitized", "x-ms-date": "sanitized", "x-ms-return-client-request-id": "true" @@ -185,15 +61,15 @@ }, "StatusCode": 200, "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", + "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview, 2023-01-01-preview, 2023-03-01", + "Content-Length": "71", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "MS-CV": "sanitized", "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", "X-Azure-Ref": "sanitized", "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "698ms" + "X-Processing-Time": "1308ms" }, "ResponseBody": { "trunks": { @@ -205,13 +81,13 @@ } }, { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", + "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2023-03-01", "RequestMethod": "GET", "RequestHeaders": { "Accept": "application/json", "Accept-Encoding": "gzip, deflate", "Content-Length": "0", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", + "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b4 Python/3.11.0 (Windows-10-10.0.22621-SP0)", "x-ms-content-sha256": "sanitized", "x-ms-date": "sanitized", "x-ms-return-client-request-id": "true" @@ -219,15 +95,15 @@ "RequestBody": null, "StatusCode": 200, "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", + "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview, 2023-01-01-preview, 2023-03-01", + "Content-Length": "71", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "MS-CV": "sanitized", "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", "X-Azure-Ref": "sanitized", "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "111ms" + "X-Processing-Time": "349ms" }, "ResponseBody": { "trunks": { diff --git a/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e_async.pyTestSipRoutingClientE2EAsynctest_set_trunks_empty_list.json b/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e_async.pyTestSipRoutingClientE2EAsynctest_set_trunks_empty_list.json index f1e00f760e27..e0111e4fca81 100644 --- a/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e_async.pyTestSipRoutingClientE2EAsynctest_set_trunks_empty_list.json +++ b/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e_async.pyTestSipRoutingClientE2EAsynctest_set_trunks_empty_list.json @@ -1,13 +1,13 @@ { "Entries": [ { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", + "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2023-03-01", "RequestMethod": "GET", "RequestHeaders": { "Accept": "application/json", "Accept-Encoding": "gzip, deflate", "Content-Length": "0", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", + "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b4 Python/3.11.0 (Windows-10-10.0.22621-SP0)", "x-ms-content-sha256": "sanitized", "x-ms-date": "sanitized", "x-ms-return-client-request-id": "true" @@ -15,54 +15,58 @@ "RequestBody": null, "StatusCode": 200, "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", + "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview, 2023-01-01-preview, 2023-03-01", + "Content-Length": "118", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "MS-CV": "sanitized", "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", "X-Azure-Ref": "sanitized", "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "109ms" + "X-Processing-Time": "273ms" }, "ResponseBody": { "trunks": { - "sbs3.sanitized.com": { - "sipSignalingPort": 2222 + "sbs1.sanitized.com": { + "sipSignalingPort": 1122 + }, + "sbs2.sanitized.com": { + "sipSignalingPort": 1123 } }, "routes": [] } }, { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", + "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2023-03-01", "RequestMethod": "PATCH", "RequestHeaders": { "Accept": "application/json", "Accept-Encoding": "gzip, deflate", - "Content-Length": "40", + "Content-Length": "68", "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", + "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b4 Python/3.11.0 (Windows-10-10.0.22621-SP0)", "x-ms-content-sha256": "sanitized", "x-ms-date": "sanitized", "x-ms-return-client-request-id": "true" }, "RequestBody": { "trunks": { - "sbs3.sanitized.com": null + "sbs1.sanitized.com": null, + "sbs2.sanitized.com": null } }, "StatusCode": 200, "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", + "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview, 2023-01-01-preview, 2023-03-01", + "Content-Length": "25", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "MS-CV": "sanitized", "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", "X-Azure-Ref": "sanitized", "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "489ms" + "X-Processing-Time": "405ms" }, "ResponseBody": { "trunks": {}, @@ -70,13 +74,13 @@ } }, { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", + "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2023-03-01", "RequestMethod": "GET", "RequestHeaders": { "Accept": "application/json", "Accept-Encoding": "gzip, deflate", "Content-Length": "0", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", + "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b4 Python/3.11.0 (Windows-10-10.0.22621-SP0)", "x-ms-content-sha256": "sanitized", "x-ms-date": "sanitized", "x-ms-return-client-request-id": "true" @@ -84,15 +88,15 @@ "RequestBody": null, "StatusCode": 200, "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", + "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview, 2023-01-01-preview, 2023-03-01", + "Content-Length": "25", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "MS-CV": "sanitized", "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", "X-Azure-Ref": "sanitized", "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "133ms" + "X-Processing-Time": "165ms" }, "ResponseBody": { "trunks": {}, diff --git a/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e_async.pyTestSipRoutingClientE2EAsynctest_set_trunks_from_managed_identity.json b/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e_async.pyTestSipRoutingClientE2EAsynctest_set_trunks_from_managed_identity.json index e1fedcf27ab4..654c5332697f 100644 --- a/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e_async.pyTestSipRoutingClientE2EAsynctest_set_trunks_from_managed_identity.json +++ b/sdk/communication/azure-communication-phonenumbers/test/recordings/test_sip_routing_client_e2e_async.pyTestSipRoutingClientE2EAsynctest_set_trunks_from_managed_identity.json @@ -1,139 +1,20 @@ { "Entries": [ { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "PATCH", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Content-Length": "14", - "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": { - "routes": [] - }, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "202ms" - }, - "ResponseBody": { - "trunks": { - "sbs3.sanitized.com": { - "sipSignalingPort": 2222 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "GET", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Content-Length": "0", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": null, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "135ms" - }, - "ResponseBody": { - "trunks": { - "sbs3.sanitized.com": { - "sipSignalingPort": 2222 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", - "RequestMethod": "PATCH", - "RequestHeaders": { - "Accept": "application/json", - "Accept-Encoding": "gzip, deflate", - "Content-Length": "140", - "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)", - "x-ms-content-sha256": "sanitized", - "x-ms-date": "sanitized", - "x-ms-return-client-request-id": "true" - }, - "RequestBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - }, - "sbs3.sanitized.com": null - } - }, - "StatusCode": 200, - "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", - "Content-Type": "application/json; charset=utf-8", - "Date": "sanitized", - "MS-CV": "sanitized", - "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", - "X-Azure-Ref": "sanitized", - "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "692ms" - }, - "ResponseBody": { - "trunks": { - "sbs1.sanitized.com": { - "sipSignalingPort": 1122 - }, - "sbs2.sanitized.com": { - "sipSignalingPort": 1123 - } - }, - "routes": [] - } - }, - { - "RequestUri": "https://login.microsoftonline.com/sanitized/oauth2/v2.0/token", + "RequestUri": "https://login.windows-ppe.net/sanitized/oauth2/v2.0/token", "RequestMethod": "POST", "RequestHeaders": { "Accept": "*/*", "Accept-Encoding": "gzip, deflate", "Content-Length": "131", "Content-Type": "application/x-www-form-urlencoded", - "User-Agent": "azsdk-python-identity/1.13.0b1 Python/3.10.9 (Windows-10-10.0.22621-SP0)" + "User-Agent": "azsdk-python-identity/1.12.0 Python/3.11.0 (Windows-10-10.0.22621-SP0)" }, "RequestBody": "client_id=sanitized\u0026client_secret=sanitized\u0026grant_type=client_credentials\u0026scope=https%3A%2F%2Fcommunication.azure.com%2F%2F.default", "StatusCode": 200, "ResponseHeaders": { "Cache-Control": "no-store, no-cache", - "Content-Length": "92", + "Content-Length": "90", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "Expires": "-1", @@ -148,31 +29,31 @@ }, "ResponseBody": { "token_type": "Bearer", - "expires_in": 86399, - "ext_expires_in": 86399, + "expires_in": 3599, + "ext_expires_in": 3599, "access_token": "Sanitized" } }, { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", + "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2023-03-01", "RequestMethod": "GET", "RequestHeaders": { "Accept": "application/json", "Accept-Encoding": "gzip, deflate", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)" + "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b4 Python/3.11.0 (Windows-10-10.0.22621-SP0)" }, "RequestBody": null, "StatusCode": 200, "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", + "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview, 2023-01-01-preview, 2023-03-01", + "Content-Length": "118", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "MS-CV": "sanitized", "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", "X-Azure-Ref": "sanitized", "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "113ms" + "X-Processing-Time": "163ms" }, "ResponseBody": { "trunks": { @@ -187,14 +68,14 @@ } }, { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", + "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2023-03-01", "RequestMethod": "PATCH", "RequestHeaders": { "Accept": "application/json", "Accept-Encoding": "gzip, deflate", "Content-Length": "118", "Content-Type": "application/merge-patch\u002Bjson", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)" + "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b4 Python/3.11.0 (Windows-10-10.0.22621-SP0)" }, "RequestBody": { "trunks": { @@ -207,15 +88,15 @@ }, "StatusCode": 200, "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", + "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview, 2023-01-01-preview, 2023-03-01", + "Content-Length": "71", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "MS-CV": "sanitized", "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", "X-Azure-Ref": "sanitized", "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "580ms" + "X-Processing-Time": "1257ms" }, "ResponseBody": { "trunks": { @@ -227,25 +108,25 @@ } }, { - "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2021-05-01-preview", + "RequestUri": "https://sanitized.communication.azure.com/sip?api-version=2023-03-01", "RequestMethod": "GET", "RequestHeaders": { "Accept": "application/json", "Accept-Encoding": "gzip, deflate", - "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b3 Python/3.10.9 (Windows-10-10.0.22621-SP0)" + "User-Agent": "azsdk-python-communication-phonenumbers/1.1.0b4 Python/3.11.0 (Windows-10-10.0.22621-SP0)" }, "RequestBody": null, "StatusCode": 200, "ResponseHeaders": { - "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview", + "api-supported-versions": "2021-05-01-preview, 2022-09-01-preview, 2023-01-01-preview, 2023-03-01", + "Content-Length": "71", "Content-Type": "application/json; charset=utf-8", "Date": "sanitized", "MS-CV": "sanitized", "Strict-Transport-Security": "max-age=2592000", - "Transfer-Encoding": "chunked", "X-Azure-Ref": "sanitized", "X-Cache": "CONFIG_NOCACHE", - "X-Processing-Time": "139ms" + "X-Processing-Time": "172ms" }, "ResponseBody": { "trunks": { diff --git a/sdk/communication/azure-communication-phonenumbers/test/sip_routing_helper.py b/sdk/communication/azure-communication-phonenumbers/test/sip_routing_helper.py index 0031d97e802c..cbb219ef298a 100644 --- a/sdk/communication/azure-communication-phonenumbers/test/sip_routing_helper.py +++ b/sdk/communication/azure-communication-phonenumbers/test/sip_routing_helper.py @@ -5,13 +5,16 @@ # ------------------------------------------------------------------------- import uuid +import os +from azure.communication.phonenumbers.siprouting import SipRoutingClient +from _shared.utils import get_http_logging_policy from devtools_testutils import is_live -def get_user_domain(): +def get_unique_fqdn(trunkId): if(is_live()): - return uuid.uuid4().hex + ".com" - return "sanitized.com" + return trunkId + "-" + uuid.uuid4().hex + "." + _get_root_domain() + return trunkId + ".sanitized.com" def assert_trunks_are_equal(response_trunks, request_trunks): assert len(response_trunks) == len(request_trunks), "Length of trunk list doesn't match." @@ -34,3 +37,13 @@ def assert_routes_are_equal(response_routes, request_routes): assert len(request_routes[k].trunks) == len(response_routes[k].trunks), "Trunk lists length doesn't match." for m in range(len(request_routes[k].trunks)): assert request_routes[k].trunks[m] == response_routes[k].trunks[m] , "Trunk lists don't match." + +def setup_configuration(connection_str,trunks=[],routes=[]): + if is_live(): + client = SipRoutingClient.from_connection_string(connection_str, http_logging_policy=get_http_logging_policy()) + client.set_routes(routes) + client.set_trunks(trunks) + +def _get_root_domain(): + return os.getenv("AZURE_TEST_DOMAIN","testdomain.com") + diff --git a/sdk/communication/azure-communication-phonenumbers/test/test_phone_number_administration_client.py b/sdk/communication/azure-communication-phonenumbers/test/test_phone_number_administration_client.py index fd3247aadf7e..6e0f605ca012 100644 --- a/sdk/communication/azure-communication-phonenumbers/test/test_phone_number_administration_client.py +++ b/sdk/communication/azure-communication-phonenumbers/test/test_phone_number_administration_client.py @@ -39,6 +39,12 @@ def _get_test_phone_number(): return os.environ["AZURE_PHONE_NUMBER_" + test_agent] +def is_client_error_status_code( + status_code # type: int +): + return status_code >= 400 and status_code < 500 + + class TestPhoneNumbersClient(PhoneNumbersTestCase): def setup_method(self): super(TestPhoneNumbersClient, self).setUp(use_dynamic_resource=False) @@ -220,7 +226,8 @@ def test_get_purchased_phone_number_with_invalid_phone_number(self, **kwargs): with pytest.raises(Exception) as ex: self.phone_number_client.get_purchased_phone_number(phone_number) - assert str(ex.value.status_code) == "404" # type: ignore + assert is_client_error_status_code( + ex.value.status_code) is True, 'Status code {ex.value.status_code} does not indicate a client error' # type: ignore assert ex.value.message is not None # type: ignore @recorded_by_proxy @@ -253,7 +260,8 @@ def test_update_phone_number_capabilities_with_unauthorized_number(self, **kwarg PhoneNumberCapabilityType.INBOUND, polling=True ) - assert str(ex.value.status_code) == "404" # type: ignore + assert is_client_error_status_code( + ex.value.status_code) is True, 'Status code {ex.value.status_code} does not indicate a client error' # type: ignore assert ex.value.message is not None # type: ignore @recorded_by_proxy @@ -270,7 +278,8 @@ def test_update_phone_number_capabilities_with_invalid_number(self, **kwargs): PhoneNumberCapabilityType.INBOUND, polling=True ) - assert str(ex.value.status_code) == "404" # type: ignore + assert is_client_error_status_code( + ex.value.status_code) is True, 'Status code {ex.value.status_code} does not indicate a client error' # type: ignore assert ex.value.message is not None # type: ignore @recorded_by_proxy @@ -292,21 +301,22 @@ def test_update_phone_number_capabilities_with_empty_number(self, **kwargs): def test_list_toll_free_area_codes_from_managed_identity(self): phone_number_client = self._get_managed_identity_phone_number_client() area_codes = phone_number_client.list_available_area_codes( - "US", PhoneNumberType.TOLL_FREE, PhoneNumberAssignmentType.APPLICATION) + "US", PhoneNumberType.TOLL_FREE, assignment_type=PhoneNumberAssignmentType.APPLICATION) assert area_codes.next() @recorded_by_proxy def test_list_toll_free_area_codes(self): area_codes = self.phone_number_client.list_available_area_codes( - "US", PhoneNumberType.TOLL_FREE, PhoneNumberAssignmentType.APPLICATION) + "US", PhoneNumberType.TOLL_FREE, assignment_type=PhoneNumberAssignmentType.APPLICATION) assert area_codes.next() @recorded_by_proxy def test_list_geographic_area_codes_from_managed_identity(self): phone_number_client = self._get_managed_identity_phone_number_client() - first_locality = phone_number_client.list_available_localities("US").next() + first_locality = phone_number_client.list_available_localities( + "US").next() area_codes = self.phone_number_client.list_available_area_codes( - "US", PhoneNumberType.GEOGRAPHIC, PhoneNumberAssignmentType.PERSON, first_locality.localized_name, administrative_division=first_locality.administrative_division.abbreviated_name) + "US", PhoneNumberType.GEOGRAPHIC, assignment_type=PhoneNumberAssignmentType.PERSON, locality=first_locality.localized_name, administrative_division=first_locality.administrative_division.abbreviated_name) assert area_codes.next() @recorded_by_proxy @@ -314,7 +324,7 @@ def test_list_geographic_area_codes(self): first_locality = self.phone_number_client.list_available_localities( "US").next() area_codes = self.phone_number_client.list_available_area_codes( - "US", PhoneNumberType.GEOGRAPHIC, PhoneNumberAssignmentType.PERSON, first_locality.localized_name, administrative_division=first_locality.administrative_division.abbreviated_name) + "US", PhoneNumberType.GEOGRAPHIC, assignment_type=PhoneNumberAssignmentType.PERSON, locality=first_locality.localized_name, administrative_division=first_locality.administrative_division.abbreviated_name) assert area_codes.next() @recorded_by_proxy diff --git a/sdk/communication/azure-communication-phonenumbers/test/test_phone_number_administration_client_async.py b/sdk/communication/azure-communication-phonenumbers/test/test_phone_number_administration_client_async.py index 7434cb130ef3..9a119142606f 100644 --- a/sdk/communication/azure-communication-phonenumbers/test/test_phone_number_administration_client_async.py +++ b/sdk/communication/azure-communication-phonenumbers/test/test_phone_number_administration_client_async.py @@ -30,6 +30,7 @@ "COMMUNICATION_SKIP_CAPABILITIES_LIVE_TEST", "false") == "true" SKIP_UPDATE_CAPABILITIES_TESTS_REASON = "Phone number capabilities are skipped." + def _get_test_phone_number(): if SKIP_UPDATE_CAPABILITIES_TESTS: return os.environ["AZURE_PHONE_NUMBER"] @@ -38,6 +39,12 @@ def _get_test_phone_number(): return os.environ["AZURE_PHONE_NUMBER_" + test_agent] +def is_client_error_status_code( + status_code # type: int +): + return status_code >= 400 and status_code < 500 + + @pytest.mark.asyncio class TestPhoneNumbersClientAsync(PhoneNumbersTestCase): def setup_method(self): @@ -235,7 +242,8 @@ async def test_get_purchased_phone_number_with_invalid_phone_number(self): async with self.phone_number_client: await self.phone_number_client.get_purchased_phone_number(phone_number) - assert str(ex.value.status_code) == "404" # type: ignore + assert is_client_error_status_code( + ex.value.status_code) is True, 'Status code {ex.value.status_code} does not indicate a client error' # type: ignore assert ex.value.message is not None # type: ignore @recorded_by_proxy_async @@ -271,7 +279,8 @@ async def test_update_phone_number_capabilities_with_unauthorized_number(self): polling=True ) - assert str(ex.value.status_code) == "404" # type: ignore + assert is_client_error_status_code( + ex.value.status_code) is True, 'Status code {ex.value.status_code} does not indicate a client error' # type: ignore assert ex.value.message is not None # type: ignore @recorded_by_proxy_async @@ -290,7 +299,8 @@ async def test_update_phone_number_capabilities_with_invalid_number(self): polling=True ) - assert str(ex.value.status_code) == "404" # type: ignore + assert is_client_error_status_code( + ex.value.status_code) is True, 'Status code {ex.value.status_code} does not indicate a client error' # type: ignore assert ex.value.message is not None # type: ignore @recorded_by_proxy_async @@ -314,7 +324,7 @@ async def test_list_toll_free_area_codes_with_managed_identity(self): phone_number_client = self._get_managed_identity_phone_number_client() async with phone_number_client: area_codes = phone_number_client.list_available_area_codes( - "US", PhoneNumberType.TOLL_FREE, PhoneNumberAssignmentType.APPLICATION) + "US", PhoneNumberType.TOLL_FREE, assignment_type=PhoneNumberAssignmentType.APPLICATION) items = [] async for item in area_codes: items.append(item) @@ -324,7 +334,7 @@ async def test_list_toll_free_area_codes_with_managed_identity(self): async def test_list_toll_free_area_codes(self): async with self.phone_number_client: area_codes = self.phone_number_client.list_available_area_codes( - "US", PhoneNumberType.TOLL_FREE, PhoneNumberAssignmentType.APPLICATION) + "US", PhoneNumberType.TOLL_FREE, assignment_type=PhoneNumberAssignmentType.APPLICATION) items = [] async for item in area_codes: items.append(item) @@ -337,7 +347,7 @@ async def test_list_geographic_area_codes_with_managed_identity(self): localities = phone_number_client.list_available_localities("US") async for first_locality in localities: area_codes = self.phone_number_client.list_available_area_codes( - "US", PhoneNumberType.GEOGRAPHIC, PhoneNumberAssignmentType.PERSON, first_locality.localized_name, administrative_division=first_locality.administrative_division.abbreviated_name) + "US", PhoneNumberType.GEOGRAPHIC, assignment_type=PhoneNumberAssignmentType.PERSON, locality=first_locality.localized_name, administrative_division=first_locality.administrative_division.abbreviated_name) items = [] async for item in area_codes: items.append(item) @@ -351,7 +361,7 @@ async def test_list_geographic_area_codes(self): "US") async for first_locality in localities: area_codes = self.phone_number_client.list_available_area_codes( - "US", PhoneNumberType.GEOGRAPHIC, PhoneNumberAssignmentType.PERSON, first_locality.localized_name, administrative_division=first_locality.administrative_division.abbreviated_name) + "US", PhoneNumberType.GEOGRAPHIC, assignment_type=PhoneNumberAssignmentType.PERSON, locality=first_locality.localized_name, administrative_division=first_locality.administrative_division.abbreviated_name) items = [] async for item in area_codes: items.append(item) diff --git a/sdk/communication/azure-communication-phonenumbers/test/test_sip_routing_client_e2e.py b/sdk/communication/azure-communication-phonenumbers/test/test_sip_routing_client_e2e.py index 0ace3f93d333..7f13cb0b70eb 100644 --- a/sdk/communication/azure-communication-phonenumbers/test/test_sip_routing_client_e2e.py +++ b/sdk/communication/azure-communication-phonenumbers/test/test_sip_routing_client_e2e.py @@ -4,42 +4,37 @@ # license information. # -------------------------------------------------------------------------- from azure.core.exceptions import HttpResponseError +import pytest from phone_numbers_testcase import PhoneNumbersTestCase from _shared.utils import create_token_credential, get_http_logging_policy -from sip_routing_helper import get_user_domain, assert_trunks_are_equal, assert_routes_are_equal +from sip_routing_helper import get_unique_fqdn, assert_trunks_are_equal, assert_routes_are_equal, setup_configuration from devtools_testutils import recorded_by_proxy from azure.communication.phonenumbers.siprouting import SipRoutingClient, SipTrunk, SipTrunkRoute from azure.communication.phonenumbers._shared.utils import parse_connection_str -class TestSipRoutingClientE2E(PhoneNumbersTestCase): - user_domain = get_user_domain() - first_trunk = SipTrunk(fqdn="sbs1." + user_domain, sip_signaling_port=1122) - second_trunk = SipTrunk(fqdn="sbs2." + user_domain, sip_signaling_port=1123) - additional_trunk = SipTrunk(fqdn="sbs3." + user_domain, sip_signaling_port=2222) - first_route = SipTrunkRoute(name="First rule", description="Handle numbers starting with '+123'", number_pattern="\\+123[0-9]+", trunks=["sbs1." + user_domain]) +class TestSipRoutingClientE2E(PhoneNumbersTestCase): + first_trunk = SipTrunk(fqdn=get_unique_fqdn("sbs1"), sip_signaling_port=1122) + second_trunk = SipTrunk(fqdn=get_unique_fqdn("sbs2"), sip_signaling_port=1123) + additional_trunk = SipTrunk(fqdn=get_unique_fqdn("sbs3"), sip_signaling_port=2222) + first_route = SipTrunkRoute(name="First rule", description="Handle numbers starting with '+123'", number_pattern="\\+123[0-9]+", trunks=[]) def setup_method(self): super(TestSipRoutingClientE2E, self).setUp(use_dynamic_resource = True) self._sip_routing_client = SipRoutingClient.from_connection_string( self.connection_str, http_logging_policy=get_http_logging_policy() ) - - def _prepare_test(self): - self._sip_routing_client.set_routes([]) - self._sip_routing_client.set_trunks([self.first_trunk,self.second_trunk]) + setup_configuration(self.connection_str,trunks=[self.first_trunk, self.second_trunk]) @recorded_by_proxy def test_get_trunks(self, **kwargs): - self._prepare_test() trunks = self._sip_routing_client.list_trunks() assert trunks is not None, "No trunks were returned." assert_trunks_are_equal(trunks,[self.first_trunk,self.second_trunk]) @recorded_by_proxy def test_get_trunks_from_managed_identity(self, **kwargs): - self._prepare_test() client = self._get_sip_client_managed_identity() trunks = client.list_trunks() assert trunks is not None, "No trunks were returned." @@ -47,7 +42,6 @@ def test_get_trunks_from_managed_identity(self, **kwargs): @recorded_by_proxy def test_get_routes(self, **kwargs): - self._prepare_test() self._sip_routing_client.set_routes([self.first_route]) routes = self._sip_routing_client.list_routes() assert routes is not None, "No routes were returned." @@ -55,7 +49,6 @@ def test_get_routes(self, **kwargs): @recorded_by_proxy def test_get_routes_from_managed_identity(self, **kwargs): - self._prepare_test() client = self._get_sip_client_managed_identity() client.set_routes([self.first_route]) routes = client.list_routes() @@ -64,7 +57,6 @@ def test_get_routes_from_managed_identity(self, **kwargs): @recorded_by_proxy def test_set_trunks(self, **kwargs): - self._prepare_test() self._sip_routing_client.set_trunks([self.additional_trunk]) result_trunks = self._sip_routing_client.list_trunks() assert result_trunks is not None, "No trunks were returned." @@ -72,7 +64,6 @@ def test_set_trunks(self, **kwargs): @recorded_by_proxy def test_set_trunks_from_managed_identity(self, **kwargs): - self._prepare_test() client = self._get_sip_client_managed_identity() client.set_trunks([self.additional_trunk]) result_trunks = client.list_trunks() @@ -91,8 +82,7 @@ def test_set_trunks_empty_list(self, **kwargs): @recorded_by_proxy def test_set_routes(self, **kwargs): - self._prepare_test() - new_routes = [SipTrunkRoute(name="Alternative rule", description="Handle numbers starting with '+999'", number_pattern="\\+999[0-9]+", trunks=[self.second_trunk.fqdn])] + new_routes = [SipTrunkRoute(name="Alternative rule", description="Handle numbers starting with '+999'", number_pattern="\\+999[0-9]+", trunks=[])] self._sip_routing_client.set_routes([self.first_route]) self._sip_routing_client.set_routes(new_routes) result_routes = self._sip_routing_client.list_routes() @@ -101,8 +91,7 @@ def test_set_routes(self, **kwargs): @recorded_by_proxy def test_set_routes_from_managed_identity(self, **kwargs): - self._prepare_test() - new_routes = [SipTrunkRoute(name="Alternative rule", description="Handle numbers starting with '+999'", number_pattern="\\+999[0-9]+", trunks=[self.second_trunk.fqdn])] + new_routes = [SipTrunkRoute(name="Alternative rule", description="Handle numbers starting with '+999'", number_pattern="\\+999[0-9]+", trunks=[])] client = self._get_sip_client_managed_identity() client.set_routes([self.first_route]) client.set_routes(new_routes) @@ -112,7 +101,6 @@ def test_set_routes_from_managed_identity(self, **kwargs): @recorded_by_proxy def test_delete_trunk(self, **kwargs): - self._prepare_test() trunk_to_delete = self.second_trunk.fqdn self._sip_routing_client.delete_trunk(trunk_to_delete) new_trunks = self._sip_routing_client.list_trunks() @@ -120,7 +108,6 @@ def test_delete_trunk(self, **kwargs): @recorded_by_proxy def test_delete_trunk_from_managed_identity(self, **kwargs): - self._prepare_test() trunk_to_delete = self.second_trunk.fqdn client = self._get_sip_client_managed_identity() client.delete_trunk(trunk_to_delete) @@ -129,14 +116,12 @@ def test_delete_trunk_from_managed_identity(self, **kwargs): @recorded_by_proxy def test_add_trunk(self, **kwargs): - self._prepare_test() self._sip_routing_client.set_trunk(self.additional_trunk) new_trunks = self._sip_routing_client.list_trunks() assert_trunks_are_equal(new_trunks,[self.first_trunk,self.second_trunk,self.additional_trunk]) @recorded_by_proxy def test_add_trunk_from_managed_identity(self, **kwargs): - self._prepare_test() client = self._get_sip_client_managed_identity() client.set_trunk(self.additional_trunk) new_trunks = client.list_trunks() @@ -144,22 +129,24 @@ def test_add_trunk_from_managed_identity(self, **kwargs): @recorded_by_proxy def test_get_trunk(self, **kwargs): - self._prepare_test() trunk = self._sip_routing_client.get_trunk(self.first_trunk.fqdn) assert trunk is not None, "No trunk was returned." trunk == self.first_trunk @recorded_by_proxy def test_get_trunk_from_managed_identity(self, **kwargs): - self._prepare_test() client = self._get_sip_client_managed_identity() trunk = client.get_trunk(self.first_trunk.fqdn) assert trunk is not None, "No trunk was returned." trunk == self.first_trunk + @recorded_by_proxy + def test_get_trunk_not_existing_throws(self, **kwargs): + with pytest.raises(KeyError): + self._sip_routing_client.get_trunk("non-existing.fqdn.test") + @recorded_by_proxy def test_set_trunk(self, **kwargs): - self._prepare_test() modified_trunk = SipTrunk(fqdn=self.second_trunk.fqdn,sip_signaling_port=7777) self._sip_routing_client.set_trunk(modified_trunk) new_trunks = self._sip_routing_client.list_trunks() @@ -167,7 +154,6 @@ def test_set_trunk(self, **kwargs): @recorded_by_proxy def test_set_trunk_from_managed_identity(self, **kwargs): - self._prepare_test() modified_trunk = SipTrunk(fqdn=self.second_trunk.fqdn,sip_signaling_port=7777) client = self._get_sip_client_managed_identity() client.set_trunk(modified_trunk) diff --git a/sdk/communication/azure-communication-phonenumbers/test/test_sip_routing_client_e2e_async.py b/sdk/communication/azure-communication-phonenumbers/test/test_sip_routing_client_e2e_async.py index d8b3c589054e..348c05df0f97 100644 --- a/sdk/communication/azure-communication-phonenumbers/test/test_sip_routing_client_e2e_async.py +++ b/sdk/communication/azure-communication-phonenumbers/test/test_sip_routing_client_e2e_async.py @@ -8,35 +8,30 @@ from phone_numbers_testcase import PhoneNumbersTestCase from devtools_testutils.aio import recorded_by_proxy_async from _shared.utils import async_create_token_credential, get_http_logging_policy -from sip_routing_helper import get_user_domain, assert_trunks_are_equal, assert_routes_are_equal +from sip_routing_helper import get_unique_fqdn, assert_trunks_are_equal, assert_routes_are_equal, setup_configuration from azure.communication.phonenumbers.siprouting.aio import SipRoutingClient -from azure.communication.phonenumbers.siprouting._generated.models import SipTrunkRoute -from azure.communication.phonenumbers.siprouting._models import SipTrunk +from azure.communication.phonenumbers.siprouting._models import SipTrunk, SipTrunkRoute from azure.communication.phonenumbers._shared.utils import parse_connection_str + @pytest.mark.asyncio -class TestSipRoutingClientE2EAsync(PhoneNumbersTestCase): - user_domain = get_user_domain() +class TestSipRoutingClientE2EAsync(PhoneNumbersTestCase): - first_trunk = SipTrunk(fqdn="sbs1." + user_domain, sip_signaling_port=1122) - second_trunk = SipTrunk(fqdn="sbs2." + user_domain, sip_signaling_port=1123) - additional_trunk = SipTrunk(fqdn="sbs3." + user_domain, sip_signaling_port=2222) - first_route = SipTrunkRoute(name="First rule", description="Handle numbers starting with '+123'", number_pattern="\\+123[0-9]+", trunks=["sbs1." + user_domain]) + first_trunk = SipTrunk(fqdn=get_unique_fqdn("sbs1"), sip_signaling_port=1122) + second_trunk = SipTrunk(fqdn=get_unique_fqdn("sbs2"), sip_signaling_port=1123) + additional_trunk = SipTrunk(fqdn=get_unique_fqdn("sbs3"), sip_signaling_port=2222) + first_route = SipTrunkRoute(name="First rule", description="Handle numbers starting with '+123'", number_pattern="\\+123[0-9]+", trunks=[]) def setup_method(self): - super(TestSipRoutingClientE2EAsync, self).setUp(use_dynamic_resource=True) + super(TestSipRoutingClientE2EAsync, self).setUp(use_dynamic_resource = True) self._sip_routing_client = SipRoutingClient.from_connection_string( self.connection_str, http_logging_policy=get_http_logging_policy() ) - - async def _prepare_test(self): - await self._sip_routing_client.set_routes([]) - await self._sip_routing_client.set_trunks([self.first_trunk, self.second_trunk]) + setup_configuration(self.connection_str,trunks=[self.first_trunk, self.second_trunk]) @recorded_by_proxy_async async def test_get_trunks(self): - await self._prepare_test() async with self._sip_routing_client: trunks = await self._sip_routing_client.list_trunks() assert trunks is not None, "No trunks were returned." @@ -44,7 +39,6 @@ async def test_get_trunks(self): @recorded_by_proxy_async async def test_get_trunks_from_managed_identity(self): - await self._prepare_test() self._sip_routing_client = self._get_sip_client_managed_identity() async with self._sip_routing_client: trunks = await self._sip_routing_client.list_trunks() @@ -53,7 +47,6 @@ async def test_get_trunks_from_managed_identity(self): @recorded_by_proxy_async async def test_get_routes(self): - await self._prepare_test() async with self._sip_routing_client: await self._sip_routing_client.set_routes([self.first_route]) routes = await self._sip_routing_client.list_routes() @@ -62,7 +55,6 @@ async def test_get_routes(self): @recorded_by_proxy_async async def test_get_routes_from_managed_identity(self): - await self._prepare_test() self._sip_routing_client = self._get_sip_client_managed_identity() async with self._sip_routing_client: await self._sip_routing_client.set_routes([self.first_route]) @@ -72,7 +64,6 @@ async def test_get_routes_from_managed_identity(self): @recorded_by_proxy_async async def test_set_trunks(self): - await self._prepare_test() async with self._sip_routing_client: await self._sip_routing_client.set_trunks([self.additional_trunk]) result_trunks = await self._sip_routing_client.list_trunks() @@ -81,7 +72,6 @@ async def test_set_trunks(self): @recorded_by_proxy_async async def test_set_trunks_from_managed_identity(self): - await self._prepare_test() self._sip_routing_client = self._get_sip_client_managed_identity() async with self._sip_routing_client: await self._sip_routing_client.set_trunks([self.additional_trunk]) @@ -102,8 +92,7 @@ async def test_set_trunks_empty_list(self): @recorded_by_proxy_async async def test_set_routes(self): - await self._prepare_test() - new_routes = [SipTrunkRoute(name="Alternative rule", description="Handle numbers starting with '+999'", number_pattern="\\+999[0-9]+", trunks=[self.second_trunk.fqdn])] + new_routes = [SipTrunkRoute(name="Alternative rule", description="Handle numbers starting with '+999'", number_pattern="\\+999[0-9]+", trunks=[])] async with self._sip_routing_client: await self._sip_routing_client.set_routes([self.first_route]) await self._sip_routing_client.set_routes(new_routes) @@ -113,8 +102,7 @@ async def test_set_routes(self): @recorded_by_proxy_async async def test_set_routes_from_managed_identity(self): - await self._prepare_test() - new_routes = [SipTrunkRoute(name="Alternative rule", description="Handle numbers starting with '+999'", number_pattern="\\+999[0-9]+", trunks=[self.second_trunk.fqdn])] + new_routes = [SipTrunkRoute(name="Alternative rule", description="Handle numbers starting with '+999'", number_pattern="\\+999[0-9]+", trunks=[])] self._sip_routing_client = self._get_sip_client_managed_identity() async with self._sip_routing_client: await self._sip_routing_client.set_routes([self.first_route]) @@ -125,7 +113,6 @@ async def test_set_routes_from_managed_identity(self): @recorded_by_proxy_async async def test_delete_trunk(self): - await self._prepare_test() trunk_to_delete = self.second_trunk.fqdn async with self._sip_routing_client: await self._sip_routing_client.delete_trunk(trunk_to_delete) @@ -134,7 +121,6 @@ async def test_delete_trunk(self): @recorded_by_proxy_async async def test_delete_trunk_from_managed_identity(self): - await self._prepare_test() trunk_to_delete = self.second_trunk.fqdn self._sip_routing_client = self._get_sip_client_managed_identity() async with self._sip_routing_client: @@ -144,7 +130,6 @@ async def test_delete_trunk_from_managed_identity(self): @recorded_by_proxy_async async def test_add_trunk(self): - await self._prepare_test() async with self._sip_routing_client: await self._sip_routing_client.set_trunk(self.additional_trunk) new_trunks = await self._sip_routing_client.list_trunks() @@ -152,7 +137,6 @@ async def test_add_trunk(self): @recorded_by_proxy_async async def test_add_trunk_from_managed_identity(self): - await self._prepare_test() self._sip_routing_client = self._get_sip_client_managed_identity() async with self._sip_routing_client: await self._sip_routing_client.set_trunk(self.additional_trunk) @@ -161,7 +145,6 @@ async def test_add_trunk_from_managed_identity(self): @recorded_by_proxy_async async def test_get_trunk(self): - await self._prepare_test() async with self._sip_routing_client: trunk = await self._sip_routing_client.get_trunk(self.first_trunk.fqdn) assert trunk is not None, "No trunk was returned." @@ -169,16 +152,19 @@ async def test_get_trunk(self): @recorded_by_proxy_async async def test_get_trunk_from_managed_identity(self): - await self._prepare_test() self._sip_routing_client = self._get_sip_client_managed_identity() async with self._sip_routing_client: trunk = await self._sip_routing_client.get_trunk(self.first_trunk.fqdn) assert trunk is not None, "No trunk was returned." assert_trunks_are_equal([trunk],[self.first_trunk]), "Returned trunk does not match the required trunk." + + @recorded_by_proxy_async + async def test_get_trunk_not_existing_throws(self, **kwargs): + with pytest.raises(KeyError): + await self._sip_routing_client.get_trunk("non-existing.fqdn.test") @recorded_by_proxy_async async def test_set_trunk(self): - await self._prepare_test() modified_trunk = SipTrunk(fqdn=self.second_trunk.fqdn,sip_signaling_port=7777) async with self._sip_routing_client: await self._sip_routing_client.set_trunk(modified_trunk) @@ -187,7 +173,6 @@ async def test_set_trunk(self): @recorded_by_proxy_async async def test_set_trunk_from_managed_identity(self): - await self._prepare_test() modified_trunk = SipTrunk(fqdn=self.second_trunk.fqdn,sip_signaling_port=7777) self._sip_routing_client = self._get_sip_client_managed_identity() async with self._sip_routing_client: diff --git a/sdk/communication/azure-communication-phonenumbers/tests.yml b/sdk/communication/azure-communication-phonenumbers/tests.yml index 1cb8d45b4fea..5c5523f88a1c 100644 --- a/sdk/communication/azure-communication-phonenumbers/tests.yml +++ b/sdk/communication/azure-communication-phonenumbers/tests.yml @@ -29,3 +29,5 @@ stages: Path: sdk/communication/azure-communication-phonenumbers/phonenumbers-livetest-matrix.json Selection: sparse GenerateVMJobs: true + TestResourceDirectories: + - communication/test-resources/ diff --git a/sdk/communication/azure-communication-rooms/tests.yml b/sdk/communication/azure-communication-rooms/tests.yml index 1c24dc4cab2b..18d27a3eb811 100644 --- a/sdk/communication/azure-communication-rooms/tests.yml +++ b/sdk/communication/azure-communication-rooms/tests.yml @@ -20,4 +20,6 @@ stages: - $(sub-config-communication-int-test-resources-common) - $(sub-config-communication-int-test-resources-python) Clouds: Public,Int + TestResourceDirectories: + - communication/test-resources/ diff --git a/sdk/communication/azure-communication-sms/README.md b/sdk/communication/azure-communication-sms/README.md index 977e0640921f..e677308013d3 100644 --- a/sdk/communication/azure-communication-sms/README.md +++ b/sdk/communication/azure-communication-sms/README.md @@ -3,7 +3,11 @@ This package contains a Python SDK for Azure Communication Services for SMS. Read more about Azure Communication Services [here](https://docs.microsoft.com/azure/communication-services/overview) -[Source code](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/communication/azure-communication-sms) | [Package (Pypi)](https://pypi.org/project/azure-communication-sms/) | [API reference documentation](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/communication/azure-communication-sms) | [Product documentation](https://docs.microsoft.com/azure/communication-services/quickstarts/telephony-sms/send?pivots=programming-language-python) +[Source code](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/communication/azure-communication-sms) +| [Package (Pypi)](https://pypi.org/project/azure-communication-sms/) +| [Package (Conda)](https://anaconda.org/microsoft/azure-communication/) +| [API reference documentation](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/communication/azure-communication-sms) +| [Product documentation](https://docs.microsoft.com/azure/communication-services/quickstarts/telephony-sms/send?pivots=programming-language-python) ## _Disclaimer_ diff --git a/sdk/communication/azure-communication-sms/tests.yml b/sdk/communication/azure-communication-sms/tests.yml index 939a126afc54..978a2dbec0d5 100644 --- a/sdk/communication/azure-communication-sms/tests.yml +++ b/sdk/communication/azure-communication-sms/tests.yml @@ -18,3 +18,5 @@ stages: EnvVars: AZURE_SKIP_LIVE_RECORDING: 'True' AZURE_TEST_RUN_LIVE: 'True' + TestResourceDirectories: + - communication/test-resources/ diff --git a/sdk/communication/ci.yml b/sdk/communication/ci.yml index 5135ab78eac5..2c0acd5ed7df 100644 --- a/sdk/communication/ci.yml +++ b/sdk/communication/ci.yml @@ -50,3 +50,5 @@ extends: safeName: azurecommunicationrooms - name: azure-communication-jobrouter safeName: azurecommunicationjobrouter + - name: azure-communication-callautomation + safeName: azurecommunicationcallautomation \ No newline at end of file diff --git a/sdk/communication/cspell.json b/sdk/communication/cspell.json index 9bd2f530bf09..48bea1944b0b 100644 --- a/sdk/communication/cspell.json +++ b/sdk/communication/cspell.json @@ -1,6 +1,12 @@ { "version": "0.2", "ignoreWords": [ - "orgid" + "orgid", + "dtmf", + "Dtmf", + "DTMF", + "pstn", + "PSTN", + "unmuted" ] } \ No newline at end of file diff --git a/sdk/communication/test-resources/test-resources.json b/sdk/communication/test-resources/test-resources.json new file mode 100644 index 000000000000..b2d8f7539581 --- /dev/null +++ b/sdk/communication/test-resources/test-resources.json @@ -0,0 +1,100 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "baseName": { + "type": "string", + "defaultValue": "[resourceGroup().name]", + "metadata": { + "description": "The base resource name." + } + }, + "endpointPrefix": { + "defaultValue": "communication", + "type": "string" + }, + "communicationServicesEndpointSuffix": { + "defaultValue": ".communication.azure.com", + "type": "string" + }, + "testApplicationOid": { + "type": "string", + "metadata": { + "description": "The client OID to grant access to test resources." + } + }, + "tenantId": { + "type": "String", + "metadata": { + "description": "The tenant id to which the application and resources belong." + } + }, + "testApplicationId": { + "type": "String", + "metadata": { + "description": "The application client id used to run tests." + } + }, + "testApplicationSecret": { + "type": "String", + "metadata": { + "description": "The application client secret used to run tests." + } + } + }, + "variables": { + "uniqueSubDomainName": "[format('{0}-{1}', parameters('baseName'), parameters('endpointPrefix'))]", + "contributorRoleId": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + "resources": [ + { + "type": "Microsoft.Communication/CommunicationServices", + "apiVersion": "2020-08-20-preview", + "name": "[variables('uniqueSubDomainName')]", + "location": "global", + "properties": { + "dataLocation": "UnitedStates" + } + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2019-04-01-preview", + "name": "[guid(resourceGroup().id, deployment().name, parameters('baseName'), variables('contributorRoleId'))]", + "properties": { + "roleDefinitionId": "[resourceId('Microsoft.Authorization/roleDefinitions', variables('contributorRoleId'))]", + "principalId": "[parameters('testApplicationOid')]", + "scope": "[resourceGroup().id]" + } + } + ], + "outputs": { + "AZURE_TENANT_ID": { + "type": "String", + "value": "[parameters('tenantId')]" + }, + "AZURE_CLIENT_ID": { + "type": "String", + "value": "[parameters('testApplicationId')]" + }, + "AZURE_CLIENT_SECRET": { + "type": "String", + "value": "[parameters('testApplicationSecret')]" + }, + "COMMUNICATION_LIVETEST_DYNAMIC_CONNECTION_STRING": { + "type": "string", + "value": "[listKeys(resourceId('Microsoft.Communication/CommunicationServices',variables('uniqueSubDomainName')), '2021-10-01-preview').primaryConnectionString]" + }, + "COMMUNICATION_SERVICE_ENDPOINT": { + "type": "string", + "value": "[concat('https://', parameters('baseName'), '-', parameters('endpointPrefix'), parameters('communicationServicesEndpointSuffix'))]" + }, + "COMMUNICATION_SERVICE_ACCESS_KEY": { + "type": "string", + "value": "[listKeys(resourceId('Microsoft.Communication/CommunicationServices',variables('uniqueSubDomainName')), '2021-10-01-preview').primaryKey]" + }, + "RESOURCE_GROUP_NAME": { + "type": "string", + "value": "[resourceGroup().Name]" + } + } +} diff --git a/sdk/communication/tests.yml b/sdk/communication/tests.yml index 4ccf33189988..d1e74bdb1d26 100644 --- a/sdk/communication/tests.yml +++ b/sdk/communication/tests.yml @@ -12,6 +12,11 @@ parameters: - azure-communication-rooms - azure-communication-sms - azure-communication-jobrouter + - azure-communication-callautomation + - name: TestResourceDirectories + type: object + default: + - communication/test-resources/ stages: - ${{ each service in parameters.Services }}: @@ -22,6 +27,7 @@ stages: # All 5 service stages run in parallel, and with no parallel limits the tests may get throttled. MaxParallel: 2 ServiceDirectory: communication + TestResourceDirectories: ${{ parameters.TestResourceDirectories }} ${{ if contains(service, 'phonenumbers') }}: CloudConfig: diff --git a/sdk/confidentialledger/azure-confidentialledger/README.md b/sdk/confidentialledger/azure-confidentialledger/README.md index 956c87d9c9ea..a81efabd09e0 100644 --- a/sdk/confidentialledger/azure-confidentialledger/README.md +++ b/sdk/confidentialledger/azure-confidentialledger/README.md @@ -2,7 +2,11 @@ Azure Confidential Ledger provides a service for logging to an immutable, tamper-proof ledger. As part of the [Azure Confidential Computing][azure_confidential_computing] portfolio, Azure Confidential Ledger runs in secure, hardware-based trusted execution environments, also known as enclaves. It is built on Microsoft Research's [Confidential Consortium Framework][ccf]. -[Source code][confidential_ledger_client_src] | [Package (PyPI)][pypi_package_confidential_ledger] | [API reference documentation][reference_docs] | [Product documentation][confidential_ledger_docs] +[Source code][confidential_ledger_client_src] +| [Package (PyPI)][pypi_package_confidential_ledger] +| [Package (Conda)](https://anaconda.org/microsoft/azure-confidentialledger/) +| [API reference documentation][reference_docs] +| [Product documentation][confidential_ledger_docs] ## Getting started ### Install packages diff --git a/sdk/containerregistry/azure-containerregistry/README.md b/sdk/containerregistry/azure-containerregistry/README.md index d2f633c55452..7a8589605dc6 100644 --- a/sdk/containerregistry/azure-containerregistry/README.md +++ b/sdk/containerregistry/azure-containerregistry/README.md @@ -9,7 +9,12 @@ Use the client library for Azure Container Registry to: - Set read/write/delete properties on registry items - Delete images and artifacts, repositories and tags -[Source code][source] | [Package (Pypi)][package] | [API reference documentation][docs] | [REST API documentation][rest_docs] | [Product documentation][product_docs] +[Source code][source] +| [Package (Pypi)][package] +| [Package (Conda)](https://anaconda.org/microsoft/azure-containerregistry/) +| [API reference documentation][docs] +| [REST API documentation][rest_docs] +| [Product documentation][product_docs] ## _Disclaimer_ diff --git a/sdk/containerregistry/azure-containerregistry/assets.json b/sdk/containerregistry/azure-containerregistry/assets.json index 88b918f2083c..90394b9890c4 100644 --- a/sdk/containerregistry/azure-containerregistry/assets.json +++ b/sdk/containerregistry/azure-containerregistry/assets.json @@ -2,5 +2,5 @@ "AssetsRepo": "Azure/azure-sdk-assets", "AssetsRepoPrefixPath": "python", "TagPrefix": "python/containerregistry/azure-containerregistry", - "Tag": "python/containerregistry/azure-containerregistry_a2d3792ebb" + "Tag": "python/containerregistry/azure-containerregistry_448865ae2e" } diff --git a/sdk/containerregistry/azure-containerregistry/azure/containerregistry/_container_registry_client.py b/sdk/containerregistry/azure-containerregistry/azure/containerregistry/_container_registry_client.py index 5daec513a37a..6a5bbc3bb943 100644 --- a/sdk/containerregistry/azure-containerregistry/azure/containerregistry/_container_registry_client.py +++ b/sdk/containerregistry/azure-containerregistry/azure/containerregistry/_container_registry_client.py @@ -42,9 +42,6 @@ def _return_response_and_deserialized(pipeline_response, deserialized, _): return pipeline_response, deserialized -def _return_deserialized(_, deserialized, __): - return deserialized - def _return_response_headers(_, __, response_headers): return response_headers @@ -799,15 +796,13 @@ def upload_manifest( cls=_return_response_headers, **kwargs ) - digest = response_headers['Docker-Content-Digest'] + if not _validate_digest(data, digest): + raise ValueError("The digest in the response does not match the digest of the uploaded manifest.") except ValueError: if repository is None or manifest is None: raise ValueError("The parameter repository and manifest cannot be None.") - if not _validate_digest(data, digest): - raise ValueError("The digest in the response does not match the digest of the uploaded manifest.") raise - return digest @distributed_trace @@ -855,6 +850,8 @@ def download_manifest(self, repository, tag_or_digest, **kwargs): :param str repository: Name of the repository :param str tag_or_digest: The tag or digest of the manifest to download. + When digest is provided, will use this digest to compare with the one calculated by the response payload. + When tag is provided, will use the digest in response headers to compare. :returns: DownloadManifestResult :rtype: ~azure.containerregistry.models.DownloadManifestResult :raises ValueError: If the parameter repository or tag_or_digest is None. @@ -872,16 +869,18 @@ def download_manifest(self, repository, tag_or_digest, **kwargs): **kwargs ) ) - digest = response.http_response.headers['Docker-Content-Digest'] manifest = OCIManifest.deserialize(cast(ManifestWrapper, manifest_wrapper).serialize()) manifest_stream = _serialize_manifest(manifest) + if tag_or_digest.startswith("sha256:"): + digest = tag_or_digest + else: + digest = response.http_response.headers['Docker-Content-Digest'] + if not _validate_digest(manifest_stream, digest): + raise ValueError("The requested digest does not match the digest of the received manifest.") except ValueError: if repository is None or tag_or_digest is None: raise ValueError("The parameter repository and tag_or_digest cannot be None.") - if not _validate_digest(manifest_stream, digest): - raise ValueError("The requested digest does not match the digest of the received manifest.") raise - return DownloadManifestResult(digest=digest, data=manifest_stream, manifest=manifest) @distributed_trace @@ -896,9 +895,7 @@ def download_blob(self, repository, digest, **kwargs): :raises ValueError: If the parameter repository or digest is None. """ try: - deserialized = self._client.container_registry_blob.get_blob( # type: ignore - repository, digest, cls=_return_deserialized, **kwargs - ) + deserialized = self._client.container_registry_blob.get_blob(repository, digest, **kwargs) except ValueError: if repository is None or digest is None: raise ValueError("The parameter repository and digest cannot be None.") diff --git a/sdk/containerregistry/azure-containerregistry/tests/test_container_registry_client.py b/sdk/containerregistry/azure-containerregistry/tests/test_container_registry_client.py index 5547f6bbba8e..8384a10b9418 100644 --- a/sdk/containerregistry/azure-containerregistry/tests/test_container_registry_client.py +++ b/sdk/containerregistry/azure-containerregistry/tests/test_container_registry_client.py @@ -16,7 +16,7 @@ ArtifactTagOrder, ContainerRegistryClient, ) -from azure.containerregistry._helpers import _deserialize_manifest +from azure.containerregistry._helpers import _deserialize_manifest, _serialize_manifest from azure.core.exceptions import ResourceNotFoundError, ClientAuthenticationError from azure.core.paging import ItemPaged from azure.identity import AzureAuthorityHosts @@ -461,7 +461,6 @@ def test_upload_oci_manifest(self, containerregistry_endpoint): # Assert response = client.download_manifest(repo, digest) - assert response.digest == digest assert response.data.tell() == 0 self.assert_manifest(response.manifest, manifest) @@ -472,9 +471,8 @@ def test_upload_oci_manifest(self, containerregistry_endpoint): @recorded_by_proxy def test_upload_oci_manifest_stream(self, containerregistry_endpoint): repo = self.get_resource_name("repo") - base_path = os.path.join(self.get_test_directory(), "data", "oci_artifact") - manifest_stream = open(os.path.join(base_path, "manifest.json"), "rb") - manifest = _deserialize_manifest(manifest_stream) + manifest = self.create_oci_manifest() + manifest_stream = _serialize_manifest(manifest) with self.create_registry_client(containerregistry_endpoint) as client: self.upload_manifest_prerequisites(repo, client) @@ -483,7 +481,6 @@ def test_upload_oci_manifest_stream(self, containerregistry_endpoint): # Assert response = client.download_manifest(repo, digest) - assert response.digest == digest assert response.data.tell() == 0 self.assert_manifest(response.manifest, manifest) @@ -494,10 +491,9 @@ def test_upload_oci_manifest_stream(self, containerregistry_endpoint): @recorded_by_proxy def test_upload_oci_manifest_with_tag(self, containerregistry_endpoint): repo = self.get_resource_name("repo") + tag = "v1" manifest = self.create_oci_manifest() with self.create_registry_client(containerregistry_endpoint) as client: - tag = "v1" - self.upload_manifest_prerequisites(repo, client) # Act @@ -505,7 +501,6 @@ def test_upload_oci_manifest_with_tag(self, containerregistry_endpoint): # Assert response = client.download_manifest(repo, digest) - assert response.digest == digest assert response.data.tell() == 0 self.assert_manifest(response.manifest, manifest) @@ -525,12 +520,10 @@ def test_upload_oci_manifest_with_tag(self, containerregistry_endpoint): @recorded_by_proxy def test_upload_oci_manifest_stream_with_tag(self, containerregistry_endpoint): repo = self.get_resource_name("repo") - base_path = os.path.join(self.get_test_directory(), "data", "oci_artifact") - manifest_stream = open(os.path.join(base_path, "manifest.json"), "rb") - manifest = _deserialize_manifest(manifest_stream) + tag = "v1" + manifest = self.create_oci_manifest() + manifest_stream = _serialize_manifest(manifest) with self.create_registry_client(containerregistry_endpoint) as client: - tag = "v1" - self.upload_manifest_prerequisites(repo, client) # Act @@ -538,7 +531,6 @@ def test_upload_oci_manifest_stream_with_tag(self, containerregistry_endpoint): # Assert response = client.download_manifest(repo, digest) - assert response.digest == digest assert response.data.tell() == 0 self.assert_manifest(response.manifest, manifest) diff --git a/sdk/core/azure-core-tracing-opentelemetry/README.md b/sdk/core/azure-core-tracing-opentelemetry/README.md index f063405ed1b9..2f739ede4cc4 100644 --- a/sdk/core/azure-core-tracing-opentelemetry/README.md +++ b/sdk/core/azure-core-tracing-opentelemetry/README.md @@ -6,25 +6,31 @@ ### Install the package -Install the opentelemetry python for Python with [pip](https://pypi.org/project/pip/): +Install the Azure Core OpenTelemetry Tracing plugin for Python with [pip](https://pypi.org/project/pip/): ```bash pip install azure-core-tracing-opentelemetry ``` -Now you can use opentelemetry for Python as usual with any SDKs that are compatible +Now you can use OpenTelemetry for Python as usual with any SDKs that are compatible with azure-core tracing. This includes (not exhaustive list), azure-storage-blob, azure-keyvault-secrets, azure-eventhub, etc. ## Key concepts * You don't need to pass any context, SDK will get it for you -* Those lines are the only ones you need to enable tracing +* These lines are the only ones you need to enable tracing ``` python from azure.core.settings import settings from azure.core.tracing.ext.opentelemetry_span import OpenTelemetrySpan settings.tracing_implementation = OpenTelemetrySpan ``` +* Alternatively, if you have the latest version of `azure-core` installed, you can also set the following environment variable to + enable tracing with OpenTelemetry: + + ```bash + AZURE_SDK_TRACING_IMPLEMENTATION=opentelemetry + ``` ## Examples @@ -41,11 +47,11 @@ from azure.core.tracing.ext.opentelemetry_span import OpenTelemetrySpan settings.tracing_implementation = OpenTelemetrySpan # In the below example, we use a simple console exporter, uncomment these lines to use -# the Azure Monitor Exporter. -# Example of Azure Monitor exporter, but you can use anything OpenTelemetry supports -# from azure_monitor import AzureMonitorSpanExporter -# exporter = AzureMonitorSpanExporter( -# instrumentation_key="uuid of the instrumentation key (see your Azure Monitor account)" +# the OpenTelemetry exporter for Azure Monitor. +# Example of a trace exporter for Azure Monitor, but you can use anything OpenTelemetry supports +# from azure.monitor.opentelemetry.exporter import AzureMonitorTraceExporter +# exporter = AzureMonitorTraceExporter( +# connection_string="the connection string used for your Application Insights resource" # ) # Regular open telemetry usage from here, see https://github.com/open-telemetry/opentelemetry-python @@ -73,12 +79,12 @@ with tracer.start_as_current_span(name="MyApplication"): client.create_container('my_container') # Call will be traced ``` -Azure Exporter can be found in the [package](https://pypi.org/project/opentelemetry-azure-monitor-exporter/) `opentelemetry-azure-monitor-exporter` +The Azure Monitor OpenTelemetry Exporter can be found in the [package](https://pypi.org/project/azure-monitor-opentelemetry-exporter/) `opentelemetry-azure-monitor-exporter` ## Troubleshooting -This client raises exceptions defined in [Azure Core](https://docs.microsoft.com/python/api/azure-core/azure.core.exceptions?view=azure-python). +This client raises exceptions defined in [Azure Core](https://learn.microsoft.com/python/api/azure-core/azure.core.exceptions?view=azure-python). ## Next steps diff --git a/sdk/core/azure-core-tracing-opentelemetry/azure/core/tracing/ext/opentelemetry_span/__init__.py b/sdk/core/azure-core-tracing-opentelemetry/azure/core/tracing/ext/opentelemetry_span/__init__.py index da1db4dd3f43..1949cd1461c2 100644 --- a/sdk/core/azure-core-tracing-opentelemetry/azure/core/tracing/ext/opentelemetry_span/__init__.py +++ b/sdk/core/azure-core-tracing-opentelemetry/azure/core/tracing/ext/opentelemetry_span/__init__.py @@ -3,39 +3,32 @@ # Licensed under the MIT License. # ------------------------------------ """Implements azure.core.tracing.AbstractSpan to wrap OpenTelemetry spans.""" - +from typing import Any, ContextManager, Dict, Optional, Union, Callable, Sequence import warnings + from opentelemetry import trace from opentelemetry.trace import Span, Tracer, SpanKind as OpenTelemetrySpanKind, Link as OpenTelemetryLink -from opentelemetry.context import attach, detach, get_current -from opentelemetry.propagate import extract, inject -from opentelemetry.trace.propagation import get_current_span as get_span_from_context +from opentelemetry.context import attach, detach, get_current # type: ignore[attr-defined] +from opentelemetry.propagate import extract, inject # type: ignore[attr-defined] +from opentelemetry.trace.propagation import get_current_span as get_span_from_context # type: ignore[attr-defined] -from azure.core.tracing import SpanKind, HttpSpanMixin # pylint: disable=no-name-in-module +from azure.core.tracing import SpanKind, HttpSpanMixin # type: ignore[attr-defined] # pylint: disable=no-name-in-module +from ._schema import OpenTelemetrySchema from ._version import VERSION -try: - from typing import TYPE_CHECKING, ContextManager -except ImportError: - TYPE_CHECKING = False - -if TYPE_CHECKING: - from typing import Any, Mapping, Dict, Optional, Union, Callable, Sequence - from azure.core.pipeline.transport import HttpRequest, HttpResponse - - AttributeValue = Union[ - str, - bool, - int, - float, - Sequence[str], - Sequence[bool], - Sequence[int], - Sequence[float], - ] - Attributes = Optional[Dict[str, AttributeValue]] +AttributeValue = Union[ + str, + bool, + int, + float, + Sequence[str], + Sequence[bool], + Sequence[int], + Sequence[float], +] +Attributes = Optional[Dict[str, AttributeValue]] __version__ = VERSION @@ -47,15 +40,19 @@ class OpenTelemetrySpan(HttpSpanMixin, object): :type span: ~OpenTelemetry.trace.Span :param name: The name of the OpenTelemetry span to create if a new span is needed :type name: str - :keyword SpanKind kind: The span kind of this span. + :keyword kind: The span kind of this span. + :paramtype kind: ~azure.core.tracing.SpanKind :keyword links: The list of links to be added to the span. :paramtype links: list[~azure.core.tracing.Link] """ - def __init__(self, span=None, name="span", **kwargs): - # type: (Optional[Span], Optional[str], Any) -> None + def __init__(self, span: Optional[Span] = None, name: str = "span", **kwargs: Any) -> None: current_tracer = self.get_current_tracer() + # TODO: Once we have additional supported versions, we should add a way to specify the version. + self._schema_version = OpenTelemetrySchema.get_latest_version() + self._attribute_mappings = OpenTelemetrySchema.get_attribute_mappings(self._schema_version) + ## kind value = kwargs.pop("kind", None) kind = ( @@ -72,7 +69,7 @@ def __init__(self, span=None, name="span", **kwargs): else OpenTelemetrySpanKind.INTERNAL if value == SpanKind.UNSPECIFIED else None - ) # type: SpanKind + ) if value and kind is None: raise ValueError("Kind {} is not supported in OpenTelemetry".format(value)) @@ -86,27 +83,26 @@ def __init__(self, span=None, name="span", **kwargs): ot_links.append(OpenTelemetryLink(span_ctx, link.attributes)) kwargs.setdefault("links", ot_links) except AttributeError: - # we will just send the links as is if it's not ~azure.core.tracing.Link without any validation + # We will just send the links as is if it's not ~azure.core.tracing.Link without any validation # assuming user knows what they are doing. kwargs.setdefault("links", links) - self._span_instance = span or current_tracer.start_span(name=name, kind=kind, **kwargs) - self._current_ctxt_manager = None + self._span_instance = span or current_tracer.start_span(name=name, kind=kind, **kwargs) # type: ignore + self._current_ctxt_manager: Optional[ContextManager[Span]] = None @property - def span_instance(self): - # type: () -> Span + def span_instance(self) -> Span: """ :return: The OpenTelemetry span that is being wrapped. """ return self._span_instance - def span(self, name="span", **kwargs): - # type: (Optional[str], Any) -> OpenTelemetrySpan + def span(self, name: str = "span", **kwargs: Any) -> "OpenTelemetrySpan": """ Create a child span for the current span and append it to the child spans list in the span instance. :param name: Name of the child span :type name: str - :keyword SpanKind kind: The span kind of this span. + :keyword kind: The span kind of this span. + :paramtype kind: ~azure.core.tracing.SpanKind :keyword links: The list of links to be added to the span. :paramtype links: list[Link] :return: The OpenTelemetrySpan that is wrapping the child span instance @@ -114,10 +110,9 @@ def span(self, name="span", **kwargs): return self.__class__(name=name, **kwargs) @property - def kind(self): - # type: () -> Optional[SpanKind] + def kind(self) -> Optional[SpanKind]: """Get the span kind of this span.""" - value = self.span_instance.kind + value = self.span_instance.kind # type: ignore[attr-defined] return ( SpanKind.CLIENT if value == OpenTelemetrySpanKind.CLIENT @@ -133,8 +128,7 @@ def kind(self): ) @kind.setter - def kind(self, value): - # type: (SpanKind) -> None + def kind(self, value: SpanKind) -> None: """Set the span kind of this span.""" kind = ( OpenTelemetrySpanKind.CLIENT @@ -154,7 +148,7 @@ def kind(self, value): if kind is None: raise ValueError("Kind {} is not supported in OpenTelemetry".format(value)) try: - self._span_instance._kind = kind # pylint: disable=protected-access + self._span_instance._kind = kind # type: ignore[attr-defined] # pylint: disable=protected-access except AttributeError: warnings.warn( """Kind must be set while creating the span for OpenTelemetry. It might be possible @@ -162,51 +156,50 @@ def kind(self, value): Try updating the azure packages to the latest versions.""" ) - def __enter__(self): + def __enter__(self) -> "OpenTelemetrySpan": """Start a span.""" self._current_ctxt_manager = trace.use_span(self._span_instance, end_on_exit=True) - self._current_ctxt_manager.__enter__() # pylint: disable=no-member + if self._current_ctxt_manager: + self._current_ctxt_manager.__enter__() # pylint: disable=no-member return self - def __exit__(self, exception_type, exception_value, traceback): + def __exit__(self, exception_type, exception_value, traceback) -> None: """Finish a span.""" if self._current_ctxt_manager: self._current_ctxt_manager.__exit__(exception_type, exception_value, traceback) # pylint: disable=no-member self._current_ctxt_manager = None - def start(self): - # Spans are automatically started at their creation with OpenTelemetry + def start(self) -> None: + # Spans are automatically started at their creation with OpenTelemetry. pass - def finish(self): - # type: () -> None + def finish(self) -> None: """Set the end time for a span.""" self.span_instance.end() - def to_header(self): # pylint: disable=no-self-use - # type: () -> Dict[str, str] + def to_header(self) -> Dict[str, str]: # pylint: disable=no-self-use """ Returns a dictionary with the header labels and values. :return: A key value pair dictionary + :rtype: dict[str, str] """ - temp_headers = {} # type: Dict[str, str] + temp_headers: Dict[str, str] = {} inject(temp_headers) return temp_headers - def add_attribute(self, key, value): - # type: (str, Union[str, int]) -> None + def add_attribute(self, key: str, value: Union[str, int]) -> None: """ Add attribute (key value pair) to the current span. :param key: The key of the key value pair :type key: str :param value: The value of the key value pair - :type value: str + :type value: Union[str, int] """ + key = self._attribute_mappings.get(key, key) self.span_instance.set_attribute(key, value) - def get_trace_parent(self): - # type: () -> str + def get_trace_parent(self) -> str: """Return traceparent string as defined in W3C trace context specification. Example: @@ -222,8 +215,7 @@ def get_trace_parent(self): return self.to_header()["traceparent"] @classmethod - def link(cls, traceparent, attributes=None): - # type: (str, Attributes) -> None + def link(cls, traceparent: str, attributes: Attributes = None) -> None: """ Links the context to the current tracer. @@ -233,8 +225,7 @@ def link(cls, traceparent, attributes=None): cls.link_from_headers({"traceparent": traceparent}, attributes) @classmethod - def link_from_headers(cls, headers, attributes=None): - # type: (Dict[str, str], Attributes) -> None + def link_from_headers(cls, headers: Dict[str, str], attributes: Attributes = None): """ Given a dictionary, extracts the context and links the context to the current tracer. @@ -245,7 +236,7 @@ def link_from_headers(cls, headers, attributes=None): span_ctx = get_span_from_context(ctx).get_span_context() current_span = cls.get_current_span() try: - current_span._links.append(OpenTelemetryLink(span_ctx, attributes)) # pylint: disable=protected-access + current_span._links.append(OpenTelemetryLink(span_ctx, attributes)) # type: ignore # pylint: disable=protected-access except AttributeError: warnings.warn( """Link must be added while creating the span for OpenTelemetry. It might be possible @@ -254,48 +245,42 @@ def link_from_headers(cls, headers, attributes=None): ) @classmethod - def get_current_span(cls): - # type: () -> Span + def get_current_span(cls) -> Span: """ - Get the current span from the execution context. Return None otherwise. + Get the current span from the execution context. """ return get_span_from_context() @classmethod - def get_current_tracer(cls): - # type: () -> Tracer + def get_current_tracer(cls) -> Tracer: """ - Get the current tracer from the execution context. Return None otherwise. + Get the current tracer from the execution context. """ return trace.get_tracer(__name__, __version__) @classmethod - def change_context(cls, span): - # type: (Span) -> ContextManager + def change_context(cls, span: Span) -> ContextManager: """Change the context for the life of this context manager.""" return trace.use_span(span, end_on_exit=False) @classmethod - def set_current_span(cls, span): - # type: (Span) -> None + def set_current_span(cls, span: Span) -> None: """Not supported by OpenTelemetry.""" raise NotImplementedError( "set_current_span is not supported by OpenTelemetry plugin. Use change_context instead." ) @classmethod - def set_current_tracer(cls, _): - # type: (Tracer) -> None - """ - Set the given tracer as the current tracer in the execution context. + def set_current_tracer(cls, _: Tracer) -> None: + """Set the given tracer as the current tracer in the execution context. + :param tracer: The tracer to set the current tracer as :type tracer: :class: OpenTelemetry.trace.Tracer """ # Do nothing, if you're able to get two tracer with OpenTelemetry that's a surprise! @classmethod - def with_current_context(cls, func): - # type: (Callable) -> Callable + def with_current_context(cls, func: Callable) -> Callable: """Passes the current spans to the new context the function will be run in. :param func: The function that will be run in the new context diff --git a/sdk/core/azure-core-tracing-opentelemetry/azure/core/tracing/ext/opentelemetry_span/_schema.py b/sdk/core/azure-core-tracing-opentelemetry/azure/core/tracing/ext/opentelemetry_span/_schema.py new file mode 100644 index 000000000000..4e8bb137869a --- /dev/null +++ b/sdk/core/azure-core-tracing-opentelemetry/azure/core/tracing/ext/opentelemetry_span/_schema.py @@ -0,0 +1,42 @@ +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ +from enum import Enum +from typing import Dict + +from azure.core import CaseInsensitiveEnumMeta # type: ignore[attr-defined] + + +class OpenTelemetrySchemaVersion( + str, Enum, metaclass=CaseInsensitiveEnumMeta +): # pylint: disable=enum-must-inherit-case-insensitive-enum-meta + + V1_19_0 = "1.19.0" + + +class OpenTelemetrySchema: + + SUPPORTED_VERSIONS = [ + OpenTelemetrySchemaVersion.V1_19_0, + ] + + # Mappings of attributes potentially reported by Azure SDKs to corresponding ones that follow + # OpenTelemetry semantic conventions. + _ATTRIBUTE_MAPPINGS = { + OpenTelemetrySchemaVersion.V1_19_0: { + "x-ms-client-request-id": "az.client_request_id", + "x-ms-request-id": "az.service_request_id", + "http.user_agent": "user_agent.original", + "messaging_bus.destination": "messaging.destination.name", + "peer.address": "net.peer.name", + } + } + + @classmethod + def get_latest_version(cls) -> OpenTelemetrySchemaVersion: + return OpenTelemetrySchemaVersion(cls.SUPPORTED_VERSIONS[-1]) + + @classmethod + def get_attribute_mappings(cls, version: OpenTelemetrySchemaVersion) -> Dict[str, str]: + return cls._ATTRIBUTE_MAPPINGS[version] diff --git a/sdk/core/azure-core-tracing-opentelemetry/pyproject.toml b/sdk/core/azure-core-tracing-opentelemetry/pyproject.toml index 4010cf355786..e68e9286f132 100644 --- a/sdk/core/azure-core-tracing-opentelemetry/pyproject.toml +++ b/sdk/core/azure-core-tracing-opentelemetry/pyproject.toml @@ -2,4 +2,3 @@ type_check_samples = false verifytypes = false pyright = false -mypy = false \ No newline at end of file diff --git a/sdk/core/azure-core-tracing-opentelemetry/samples/sample_eventgrid.py b/sdk/core/azure-core-tracing-opentelemetry/samples/sample_eventgrid.py index b31cbfe6e726..aeeb54e72db1 100644 --- a/sdk/core/azure-core-tracing-opentelemetry/samples/sample_eventgrid.py +++ b/sdk/core/azure-core-tracing-opentelemetry/samples/sample_eventgrid.py @@ -5,8 +5,8 @@ This example traces calls for publishing cloud data and exports it using the ConsoleSpanExporter. -An alternative path to export using AzureMonitor is also mentioned in the sample. Please take -a look at the commented code. +An alternative path to export using the OpenTelemetry exporter for Azure Monitor +is also mentioned in the sample. Please take a look at the commented code. """ # Declare OpenTelemetry as enabled tracing plugin for Azure SDKs @@ -16,13 +16,15 @@ settings.tracing_implementation = OpenTelemetrySpan # In the below example, we use a simple console exporter, uncomment these lines to use -# the Azure Monitor Exporter. It can be installed from https://pypi.org/project/opentelemetry-azure-monitor/ -# Example of Azure Monitor exporter, but you can use anything OpenTelemetry supports -# from azure_monitor import AzureMonitorSpanExporter -# exporter = AzureMonitorSpanExporter( -# instrumentation_key="uuid of the instrumentation key (see your Azure Monitor account)" +# the OpenTelemetry exporter for Azure MonitorOpenTelemetry exporter for Azure Monitor. +# Example of a trace exporter for Azure Monitor, but you can use anything OpenTelemetry supports. + +# from azure.monitor.opentelemetry.exporter import AzureMonitorTraceExporter +# exporter = AzureMonitorTraceExporter( +# connection_string="the connection string used for your Application Insights resource" # ) + # Regular open telemetry usage from here, see https://github.com/open-telemetry/opentelemetry-python # for details from opentelemetry import trace diff --git a/sdk/core/azure-core-tracing-opentelemetry/samples/sample_eventhubs.py b/sdk/core/azure-core-tracing-opentelemetry/samples/sample_eventhubs.py index e4db96f1c3ee..a43470d819c1 100644 --- a/sdk/core/azure-core-tracing-opentelemetry/samples/sample_eventhubs.py +++ b/sdk/core/azure-core-tracing-opentelemetry/samples/sample_eventhubs.py @@ -4,8 +4,8 @@ This example traces calls for sending a batch to eventhub. -An alternative path to export using AzureMonitor is also mentioned in the sample. Please take -a look at the commented code. +An alternative path to export using the OpenTelemetry exporter for Azure Monitor +is also mentioned in the sample. Please take a look at the commented code. """ # Declare OpenTelemetry as enabled tracing plugin for Azure SDKs @@ -15,11 +15,12 @@ settings.tracing_implementation = OpenTelemetrySpan # In the below example, we use a simple console exporter, uncomment these lines to use -# the Azure Monitor Exporter. It can be installed from https://pypi.org/project/opentelemetry-azure-monitor/ -# Example of Azure Monitor exporter, but you can use anything OpenTelemetry supports -# from azure_monitor import AzureMonitorSpanExporter -# exporter = AzureMonitorSpanExporter( -# instrumentation_key="uuid of the instrumentation key (see your Azure Monitor account)" +# the OpenTelemetry exporter for Azure Monitor. +# Example of a trace exporter for Azure Monitor, but you can use anything OpenTelemetry supports. + +# from azure.monitor.opentelemetry.exporter import AzureMonitorTraceExporter +# exporter = AzureMonitorTraceExporter( +# connection_string="the connection string used for your Application Insights resource" # ) # Regular open telemetry usage from here, see https://github.com/open-telemetry/opentelemetry-python diff --git a/sdk/core/azure-core-tracing-opentelemetry/samples/sample_receive_eh.py b/sdk/core/azure-core-tracing-opentelemetry/samples/sample_receive_eh.py index 7661bd819e9a..0ca8a9cb4823 100644 --- a/sdk/core/azure-core-tracing-opentelemetry/samples/sample_receive_eh.py +++ b/sdk/core/azure-core-tracing-opentelemetry/samples/sample_receive_eh.py @@ -4,8 +4,8 @@ This example traces calls for sending a batch to eventhub. -An alternative path to export using AzureMonitor is also mentioned in the sample. Please take -a look at the commented code. +An alternative path to export using the OpenTelemetry exporter for Azure Monitor +is also mentioned in the sample. Please take a look at the commented code. """ # Declare OpenTelemetry as enabled tracing plugin for Azure SDKs @@ -15,13 +15,15 @@ settings.tracing_implementation = OpenTelemetrySpan # In the below example, we use a simple console exporter, uncomment these lines to use -# the Azure Monitor Exporter. It can be installed from https://pypi.org/project/opentelemetry-azure-monitor/ -# Example of Azure Monitor exporter, but you can use anything OpenTelemetry supports -# from azure_monitor import AzureMonitorSpanExporter -# exporter = AzureMonitorSpanExporter( -# instrumentation_key="uuid of the instrumentation key (see your Azure Monitor account)" +# the OpenTelemetry exporter for Azure Monitor. +# Example of a trace exporter for Azure Monitor, but you can use anything OpenTelemetry supports. + +# from azure.monitor.opentelemetry.exporter import AzureMonitorTraceExporter +# exporter = AzureMonitorTraceExporter( +# connection_string="the connection string used for your Application Insights resource" # ) + # Regular open telemetry usage from here, see https://github.com/open-telemetry/opentelemetry-python # for details from opentelemetry import trace diff --git a/sdk/core/azure-core-tracing-opentelemetry/samples/sample_receive_sb.py b/sdk/core/azure-core-tracing-opentelemetry/samples/sample_receive_sb.py index 79b0e988506d..cb2041e7c364 100644 --- a/sdk/core/azure-core-tracing-opentelemetry/samples/sample_receive_sb.py +++ b/sdk/core/azure-core-tracing-opentelemetry/samples/sample_receive_sb.py @@ -4,8 +4,8 @@ This example traces calls for receiving messages from the servicebus queue. -The telemetry will be collected automatically and sent to Application -Insights via the AzureMonitorTraceExporter +An alternative path to export using the OpenTelemetry exporter for Azure Monitor +is also mentioned in the sample. Please take a look at the commented code. """ import os @@ -16,6 +16,16 @@ settings.tracing_implementation = OpenTelemetrySpan +# In the below example, we use a simple console exporter, uncomment these lines to use +# the OpenTelemetry exporter for Azure Monitor. +# Example of a trace exporter for Azure Monitor, but you can use anything OpenTelemetry supports. + +# from azure.monitor.opentelemetry.exporter import AzureMonitorTraceExporter +# exporter = AzureMonitorTraceExporter( +# connection_string="the connection string used for your Application Insights resource" +# ) + + # Regular open telemetry usage from here, see https://github.com/open-telemetry/opentelemetry-python # for details from opentelemetry import trace diff --git a/sdk/core/azure-core-tracing-opentelemetry/samples/sample_servicebus.py b/sdk/core/azure-core-tracing-opentelemetry/samples/sample_servicebus.py index 84a1bb50d6a5..ff3dfc09cff8 100644 --- a/sdk/core/azure-core-tracing-opentelemetry/samples/sample_servicebus.py +++ b/sdk/core/azure-core-tracing-opentelemetry/samples/sample_servicebus.py @@ -4,8 +4,8 @@ This example traces calls for sending messages to the servicebus queue. -An alternative path to export using AzureMonitor is also mentioned in the sample. Please take -a look at the commented code. +An alternative path to export using the OpenTelemetry exporter for Azure Monitor +is also mentioned in the sample. Please take a look at the commented code. """ # Declare OpenTelemetry as enabled tracing plugin for Azure SDKs @@ -15,13 +15,15 @@ settings.tracing_implementation = OpenTelemetrySpan # In the below example, we use a simple console exporter, uncomment these lines to use -# the Azure Monitor Exporter. It can be installed from https://pypi.org/project/opentelemetry-azure-monitor/ -# Example of Azure Monitor exporter, but you can use anything OpenTelemetry supports -# from azure_monitor import AzureMonitorSpanExporter -# exporter = AzureMonitorSpanExporter( -# instrumentation_key="uuid of the instrumentation key (see your Azure Monitor account)" +# the OpenTelemetry exporter for Azure Monitor. +# Example of a trace exporter for Azure Monitor, but you can use anything OpenTelemetry supports. + +# from azure.monitor.opentelemetry.exporter import AzureMonitorTraceExporter +# exporter = AzureMonitorTraceExporter( +# connection_string="the connection string used for your Application Insights resource" # ) + # Regular open telemetry usage from here, see https://github.com/open-telemetry/opentelemetry-python # for details from opentelemetry import trace diff --git a/sdk/core/azure-core-tracing-opentelemetry/samples/sample_storage.py b/sdk/core/azure-core-tracing-opentelemetry/samples/sample_storage.py index 39655accd674..d029cf71b5ef 100644 --- a/sdk/core/azure-core-tracing-opentelemetry/samples/sample_storage.py +++ b/sdk/core/azure-core-tracing-opentelemetry/samples/sample_storage.py @@ -5,8 +5,8 @@ This example traces calls for creating a container in storage and exports it using the ConsoleSpanExporter. -An alternative path to export using AzureMonitor is also mentioned in the sample. Please take -a look at the commented code. +An alternative path to export using the OpenTelemetry exporter for Azure Monitor +is also mentioned in the sample. Please take a look at the commented code. """ # Declare OpenTelemetry as enabled tracing plugin for Azure SDKs @@ -16,11 +16,12 @@ settings.tracing_implementation = OpenTelemetrySpan # In the below example, we use a simple console exporter, uncomment these lines to use -# the Azure Monitor Exporter. It can be installed from https://pypi.org/project/opentelemetry-azure-monitor/ -# Example of Azure Monitor exporter, but you can use anything OpenTelemetry supports -# from azure_monitor import AzureMonitorSpanExporter -# exporter = AzureMonitorSpanExporter( -# instrumentation_key="uuid of the instrumentation key (see your Azure Monitor account)" +# the OpenTelemetry exporter for Azure Monitor. +# Example of a trace exporter for Azure Monitor, but you can use anything OpenTelemetry supports. + +# from azure.monitor.opentelemetry.exporter import AzureMonitorTraceExporter +# exporter = AzureMonitorTraceExporter( +# connection_string="the connection string used for your Application Insights resource" # ) # Regular open telemetry usage from here, see https://github.com/open-telemetry/opentelemetry-python diff --git a/sdk/core/azure-core-tracing-opentelemetry/setup.py b/sdk/core/azure-core-tracing-opentelemetry/setup.py index 8293cebe9faa..aa9bcb2f4da5 100644 --- a/sdk/core/azure-core-tracing-opentelemetry/setup.py +++ b/sdk/core/azure-core-tracing-opentelemetry/setup.py @@ -44,11 +44,11 @@ "Programming Language :: Python", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", "License :: OSI Approved :: MIT License", ], zip_safe=False, @@ -59,7 +59,7 @@ package_data={ "pytyped": ["py.typed"], }, - python_requires=">=3.6", + python_requires=">=3.7", install_requires=[ "opentelemetry-api<2.0.0,>=1.0.0", "azure-core<2.0.0,>=1.13.0", diff --git a/sdk/core/azure-core-tracing-opentelemetry/tests/test_schema.py b/sdk/core/azure-core-tracing-opentelemetry/tests/test_schema.py new file mode 100644 index 000000000000..20b84a819d5f --- /dev/null +++ b/sdk/core/azure-core-tracing-opentelemetry/tests/test_schema.py @@ -0,0 +1,31 @@ +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ +import uuid + +from opentelemetry.trace import SpanKind as OpenTelemetrySpanKind + +from azure.core.tracing.ext.opentelemetry_span import OpenTelemetrySpan +from azure.core.tracing.ext.opentelemetry_span._schema import OpenTelemetrySchema + + +class TestOpenTelemetrySchema: + def test_latest_schema_attributes_renamed(self, tracer): + with tracer.start_as_current_span("Root", kind=OpenTelemetrySpanKind.CLIENT) as parent: + wrapped_class = OpenTelemetrySpan(span=parent) + schema_version = OpenTelemetrySchema.get_latest_version() + attribute_mappings = OpenTelemetrySchema.get_attribute_mappings(schema_version) + attribute_values = {} + for key, value in attribute_mappings.items(): + attribute_values[value] = uuid.uuid4().hex + # Add attribute using key that is not following OpenTelemetry semantic conventions. + wrapped_class.add_attribute(key, attribute_values[value]) + + for attribute, expected_value in attribute_values.items(): + # Check that expected renamed attribute is present with the correct value. + assert wrapped_class.span_instance.attributes.get(attribute) == expected_value + + for key in attribute_mappings: + # Check that original attribute is not present. + assert wrapped_class.span_instance.attributes.get(key) is None diff --git a/sdk/core/azure-core-tracing-opentelemetry/tests/test_tracing_implementations.py b/sdk/core/azure-core-tracing-opentelemetry/tests/test_tracing_implementations.py index df6cf33bb7d7..53b9504e2f1e 100644 --- a/sdk/core/azure-core-tracing-opentelemetry/tests/test_tracing_implementations.py +++ b/sdk/core/azure-core-tracing-opentelemetry/tests/test_tracing_implementations.py @@ -2,23 +2,15 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. # ------------------------------------ -"""The tests for opencensus_span.py""" - -import unittest - -try: - from unittest import mock -except ImportError: - import mock +"""The tests for opentelemetry_span.py""" +from unittest import mock from opentelemetry import trace from opentelemetry.trace import SpanKind as OpenTelemetrySpanKind +import pytest from azure.core.tracing.ext.opentelemetry_span import OpenTelemetrySpan from azure.core.tracing import SpanKind -import os - -import pytest class TestOpentelemetryWrapper: @@ -142,7 +134,7 @@ def test_set_http_attributes(self, tracer): wrapped_class = OpenTelemetrySpan(span=parent) request = mock.Mock() setattr(request, "method", "GET") - setattr(request, "url", "some url") + setattr(request, "url", "https://foo.bar/path") response = mock.Mock() setattr(request, "headers", {}) setattr(response, "status_code", 200) @@ -152,11 +144,19 @@ def test_set_http_attributes(self, tracer): assert wrapped_class.span_instance.attributes.get("component") == "http" assert wrapped_class.span_instance.attributes.get("http.url") == request.url assert wrapped_class.span_instance.attributes.get("http.status_code") == 504 - assert wrapped_class.span_instance.attributes.get("http.user_agent") is None + assert wrapped_class.span_instance.attributes.get("user_agent.original") is None + request.headers["User-Agent"] = "some user agent" + request.url = "http://foo.bar:8080/path" wrapped_class.set_http_attributes(request, response) assert wrapped_class.span_instance.attributes.get("http.status_code") == response.status_code - assert wrapped_class.span_instance.attributes.get("http.user_agent") == request.headers.get("User-Agent") + assert wrapped_class.span_instance.attributes.get("user_agent.original") == request.headers.get( + "User-Agent" + ) + + if wrapped_class.span_instance.attributes.get("net.peer.name"): + assert wrapped_class.span_instance.attributes.get("net.peer.name") == "foo.bar" + assert wrapped_class.span_instance.attributes.get("net.peer.port") == 8080 def test_span_kind(self, tracer): with tracer.start_as_current_span("Root") as parent: diff --git a/sdk/core/azure-core/CLIENT_LIBRARY_DEVELOPER.md b/sdk/core/azure-core/CLIENT_LIBRARY_DEVELOPER.md index c2469f8d886f..ba4eff375eca 100644 --- a/sdk/core/azure-core/CLIENT_LIBRARY_DEVELOPER.md +++ b/sdk/core/azure-core/CLIENT_LIBRARY_DEVELOPER.md @@ -600,6 +600,9 @@ manager, with `__aenter__`, `__aexit__`, and `close` methods. | --- | --- | | Key Vault ([example][kv_tenant_id]) | Request access in a tenant that was discovered as part of an authentication challenge +## Long-running operation (LRO) customization + +See [doc/dev/customize_long_running_operation.md](https://github.com/Azure/azure-sdk-for-python/blob/main/doc/dev/customize_long_running_operation.md) for more information. [cae_doc]: https://docs.microsoft.com/azure/active-directory/conditional-access/concept-continuous-access-evaluation [custom_creds_sample]: https://github.com/Azure/azure-sdk-for-python/blob/fc95f8d3d84d076ffea158116ca1bf6912689c70/sdk/identity/azure-identity/samples/custom_credentials.py diff --git a/sdk/core/azure-core/README.md b/sdk/core/azure-core/README.md index 828c45f0ac8a..c9f4bd32715f 100644 --- a/sdk/core/azure-core/README.md +++ b/sdk/core/azure-core/README.md @@ -6,7 +6,10 @@ These libraries follow the [Azure SDK Design Guidelines for Python](https://azur If you are a client library developer, please reference [client library developer reference](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/core/azure-core/CLIENT_LIBRARY_DEVELOPER.md) for more information. -[Source code](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/core/azure-core/) | [Package (Pypi)][package] | [API reference documentation](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/core/azure-core/) +[Source code](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/core/azure-core/) +| [Package (Pypi)][package] +| [Package (Conda)](https://anaconda.org/microsoft/azure-core/) +| [API reference documentation](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/core/azure-core/) ## _Disclaimer_ diff --git a/sdk/core/azure-core/azure/core/pipeline/transport/_base.py b/sdk/core/azure-core/azure/core/pipeline/transport/_base.py index 77c286abb1e2..d33485c82361 100644 --- a/sdk/core/azure-core/azure/core/pipeline/transport/_base.py +++ b/sdk/core/azure-core/azure/core/pipeline/transport/_base.py @@ -429,6 +429,7 @@ def stream_download(self, pipeline: PipelineType, **kwargs) -> Iterator[bytes]: :rtype: iterator[bytes] """ + raise NotImplementedError("stream_download is not implemented.") def parts(self) -> Iterator["HttpResponse"]: """Assuming the content-type is multipart/mixed, will return the parts as an iterator. @@ -462,7 +463,7 @@ def body(self): return self.data -class HttpClientTransportResponse(_HttpClientTransportResponse, HttpResponse): +class HttpClientTransportResponse(_HttpClientTransportResponse, HttpResponse): # pylint: disable=abstract-method """Create a HTTPResponse from an http.client response. Body will NOT be read by the constructor. Call "body()" to load the body in memory if necessary. diff --git a/sdk/core/azure-core/azure/core/pipeline/transport/_base_async.py b/sdk/core/azure-core/azure/core/pipeline/transport/_base_async.py index aa1c61837cf0..543e5977020f 100644 --- a/sdk/core/azure-core/azure/core/pipeline/transport/_base_async.py +++ b/sdk/core/azure-core/azure/core/pipeline/transport/_base_async.py @@ -72,6 +72,7 @@ def stream_download(self, pipeline, **kwargs) -> AsyncIteratorType[bytes]: :keyword bool decompress: If True which is default, will attempt to decode the body based on the *content-encoding* header. """ + raise NotImplementedError("stream_download is not implemented.") def parts(self) -> AsyncIterator: """Assuming the content-type is multipart/mixed, will return the parts as an async iterator. @@ -85,7 +86,9 @@ def parts(self) -> AsyncIterator: return _PartGenerator(self, default_http_response_type=AsyncHttpClientTransportResponse) -class AsyncHttpClientTransportResponse(_HttpClientTransportResponse, AsyncHttpResponse): +class AsyncHttpClientTransportResponse( # pylint: disable=abstract-method + _HttpClientTransportResponse, AsyncHttpResponse +): """Create a HTTPResponse from an http.client response. Body will NOT be read by the constructor. Call "body()" to load the body in memory if necessary. diff --git a/sdk/core/azure-core/azure/core/settings.py b/sdk/core/azure-core/azure/core/settings.py index 2f078e9f9729..a0e970a1c367 100644 --- a/sdk/core/azure-core/azure/core/settings.py +++ b/sdk/core/azure-core/azure/core/settings.py @@ -31,17 +31,9 @@ import logging import os import sys -from typing import Type, Optional, Callable, cast, Union, Dict, TYPE_CHECKING +from typing import Type, Optional, Callable, cast, Union, Dict from azure.core.tracing import AbstractSpan -if TYPE_CHECKING: - try: - # pylint:disable=unused-import - from azure.core.tracing.ext.opencensus_span import ( - OpenCensusSpan, - ) # pylint:disable=redefined-outer-name - except ImportError: - pass __all__ = ("settings", "Settings") @@ -115,8 +107,8 @@ def convert_logging(value: Union[str, int]) -> int: return level -def get_opencensus_span() -> Optional[Type[AbstractSpan]]: - """Returns the OpenCensusSpan if opencensus is installed else returns None""" +def _get_opencensus_span() -> Optional[Type[AbstractSpan]]: + """Returns the OpenCensusSpan if the opencensus tracing plugin is installed else returns None""" try: from azure.core.tracing.ext.opencensus_span import ( # pylint:disable=redefined-outer-name OpenCensusSpan, @@ -127,14 +119,33 @@ def get_opencensus_span() -> Optional[Type[AbstractSpan]]: return None -def get_opencensus_span_if_opencensus_is_imported() -> Optional[Type[AbstractSpan]]: +def _get_opentelemetry_span() -> Optional[Type[AbstractSpan]]: + """Returns the OpenTelemetrySpan if the opentelemetry tracing plugin is installed else returns None""" + try: + from azure.core.tracing.ext.opentelemetry_span import ( # pylint:disable=redefined-outer-name + OpenTelemetrySpan, + ) + + return OpenTelemetrySpan + except ImportError: + return None + + +def _get_opencensus_span_if_opencensus_is_imported() -> Optional[Type[AbstractSpan]]: if "opencensus" not in sys.modules: return None - return get_opencensus_span() + return _get_opencensus_span() + + +def _get_opentelemetry_span_if_opentelemetry_is_imported() -> Optional[Type[AbstractSpan]]: + if "opentelemetry" not in sys.modules: + return None + return _get_opentelemetry_span() _tracing_implementation_dict: Dict[str, Callable[[], Optional[Type[AbstractSpan]]]] = { - "opencensus": get_opencensus_span + "opencensus": _get_opencensus_span, + "opentelemetry": _get_opentelemetry_span, } @@ -145,6 +156,7 @@ def convert_tracing_impl(value: Union[str, Type[AbstractSpan]]) -> Optional[Type understands the following strings, ignoring case: * "opencensus" + * "opentelemetry" :param value: the value to convert :type value: string @@ -153,7 +165,9 @@ def convert_tracing_impl(value: Union[str, Type[AbstractSpan]]) -> Optional[Type """ if value is None: - return get_opencensus_span_if_opencensus_is_imported() + return ( + _get_opentelemetry_span_if_opentelemetry_is_imported() or _get_opencensus_span_if_opencensus_is_imported() + ) if not isinstance(value, str): value = cast(Type[AbstractSpan], value) diff --git a/sdk/core/azure-core/azure/core/tracing/_abstract_span.py b/sdk/core/azure-core/azure/core/tracing/_abstract_span.py index b29103dbcb23..ddbe78b1ae86 100644 --- a/sdk/core/azure-core/azure/core/tracing/_abstract_span.py +++ b/sdk/core/azure-core/azure/core/tracing/_abstract_span.py @@ -4,6 +4,8 @@ # ------------------------------------ """Protocol that defines what functions wrappers of tracing libraries should implement.""" from enum import Enum +from urllib.parse import urlparse + from typing import ( TYPE_CHECKING, Any, @@ -102,7 +104,7 @@ def add_attribute(self, key: str, value: Union[str, int]) -> None: :param key: The key of the key value pair :type key: str :param value: The value of the key value pair - :type value: str + :type value: Union[str, int] """ def set_http_attributes(self, request: "HttpRequest", response: Optional["HttpResponseType"] = None) -> None: @@ -202,6 +204,8 @@ class HttpSpanMixin(_MIXIN_BASE): _HTTP_METHOD = "http.method" _HTTP_URL = "http.url" _HTTP_STATUS_CODE = "http.status_code" + _NET_PEER_NAME = "net.peer.name" + _NET_PEER_PORT = "net.peer.port" def set_http_attributes(self, request: "HttpRequest", response: Optional["HttpResponseType"] = None) -> None: """ @@ -209,13 +213,20 @@ def set_http_attributes(self, request: "HttpRequest", response: Optional["HttpRe :param request: The request made :type request: HttpRequest - :param response: The response received by the server. Is None if no response received. + :param response: The response received from the server. Is None if no response received. :type response: ~azure.core.pipeline.transport.HttpResponse or ~azure.core.pipeline.transport.AsyncHttpResponse """ self.kind = SpanKind.CLIENT self.add_attribute(self._SPAN_COMPONENT, "http") self.add_attribute(self._HTTP_METHOD, request.method) self.add_attribute(self._HTTP_URL, request.url) + + parsed_url = urlparse(request.url) + if parsed_url.hostname: + self.add_attribute(self._NET_PEER_NAME, parsed_url.hostname) + if parsed_url.port and parsed_url.port not in [80, 443]: + self.add_attribute(self._NET_PEER_PORT, parsed_url.port) + user_agent = request.headers.get("User-Agent") if user_agent: self.add_attribute(self._HTTP_USER_AGENT, user_agent) diff --git a/sdk/core/azure-core/azure/core/tracing/decorator.py b/sdk/core/azure-core/azure/core/tracing/decorator.py index 02b1bcc0099b..95a7394ec129 100644 --- a/sdk/core/azure-core/azure/core/tracing/decorator.py +++ b/sdk/core/azure-core/azure/core/tracing/decorator.py @@ -27,7 +27,7 @@ import functools -from typing import Callable, Any, TypeVar, overload +from typing import Callable, Any, TypeVar, overload, Optional from typing_extensions import ParamSpec from .common import change_context, get_function_and_class_name from . import SpanKind as _SpanKind @@ -50,7 +50,7 @@ def distributed_trace( # pylint:disable=function-redefined pass -def distributed_trace(__func: Callable[P, T] = None, **kwargs: Any): # pylint:disable=function-redefined +def distributed_trace(__func: Optional[Callable[P, T]] = None, **kwargs: Any): # pylint:disable=function-redefined """Decorator to apply to function to get traced automatically. Span will use the func name or "name_of_span". diff --git a/sdk/core/azure-core/azure/core/tracing/decorator_async.py b/sdk/core/azure-core/azure/core/tracing/decorator_async.py index ed82bdf09cb6..a24b1e98137f 100644 --- a/sdk/core/azure-core/azure/core/tracing/decorator_async.py +++ b/sdk/core/azure-core/azure/core/tracing/decorator_async.py @@ -27,7 +27,7 @@ import functools -from typing import Awaitable, Callable, Any, TypeVar, overload +from typing import Awaitable, Callable, Any, TypeVar, overload, Optional from typing_extensions import ParamSpec from .common import change_context, get_function_and_class_name from . import SpanKind as _SpanKind @@ -50,7 +50,7 @@ def distributed_trace_async( # pylint:disable=function-redefined def distributed_trace_async( # pylint:disable=function-redefined - __func: Callable[P, Awaitable[T]] = None, **kwargs: Any + __func: Optional[Callable[P, Awaitable[T]]] = None, **kwargs: Any ): """Decorator to apply to function to get traced automatically. diff --git a/sdk/core/azure-core/samples/README.md b/sdk/core/azure-core/samples/README.md index d13d6d0f24fb..0dbdd60b7622 100644 --- a/sdk/core/azure-core/samples/README.md +++ b/sdk/core/azure-core/samples/README.md @@ -6,14 +6,21 @@ products: - azure --- -# Azure Core Library Python Samples +# Azure Core Library Python Developer Samples These are some code snippets that show the way in which you can set up some functionalities used in new SDKs such as logging, pipelines, etc. -They are not intended to be ran as standalone application, but show you how these functionalities can be configured. +They are not intended to be run as standalone application, but show you how these functionalities can be configured. [test_example_sync.py](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/core/azure-core/samples/test_example_sync.py) - samples of how to create a sync pipeline [test_example_async.py](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/core/azure-core/samples/test_example_async.py) - samples of how to create an async pipeline [test_example_sansio.py](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/core/azure-core/samples/test_example_sansio.py) - samples of how to config policies + +# Azure Core Library Python End User Samples + +These are some code snippets that show the way in which end users can customize the behavior. + +[shared_transport.py](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/core/azure-core/samples/example_shared_transport.py) - samples of how to use a shared sync transport +[shared_transport_async.py](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/core/azure-core/samples/example_shared_transport_async.py) - samples of how to use a shared async transport diff --git a/sdk/core/azure-core/samples/example_shared_transport.py b/sdk/core/azure-core/samples/example_shared_transport.py new file mode 100644 index 000000000000..0781282e971b --- /dev/null +++ b/sdk/core/azure-core/samples/example_shared_transport.py @@ -0,0 +1,77 @@ +# coding: utf-8 + +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- + +""" +FILE: example_shared_transport.py + +DESCRIPTION: + This sample demonstrates how to share transport connections between multiple clients. + +USAGE: + python example_shared_transport.py + + Set the environment variables with your own values before running the sample: + 1) AZURE_STORAGE_CONNECTION_STRING - the endpoint of your Azure Metrics Advisor service +""" + +import os +from azure.core.pipeline.transport import RequestsTransport +from azure.storage.blob import BlobServiceClient + +connection_string = os.getenv("AZURE_STORAGE_CONNECTION_STRING") + + +def shared_transport(): + # [START shared_transport] + shared_transport = RequestsTransport() + with shared_transport: + blob_service_client1 = BlobServiceClient.from_connection_string( + connection_string, + transport=shared_transport, + session_owner=False, # here we set session_owner to False to indicate that we don't want to close the session when the client is closed + ) + blob_service_client2 = BlobServiceClient.from_connection_string( + connection_string, transport=shared_transport, session_owner=False + ) + containers1 = blob_service_client1.list_containers() + for contain in containers1: + print(contain.name) + containers2 = blob_service_client2.list_containers() + for contain in containers2: + print(contain.name) + # [END shared_transport] + + +def shared_transport_with_pooling(): + # [START shared_transport_with_pooling] + import requests + + session = requests.Session() + adapter = requests.adapters.HTTPAdapter(pool_connections=100, pool_maxsize=100) + session.mount("http://", adapter) + session.mount("https://", adapter) + shared_transport = RequestsTransport(session=session) + with shared_transport: + blob_service_client1 = BlobServiceClient.from_connection_string( + connection_string, transport=shared_transport, session_owner=False + ) + blob_service_client2 = BlobServiceClient.from_connection_string( + connection_string, transport=shared_transport, session_owner=False + ) + containers1 = blob_service_client1.list_containers() + for contain in containers1: + print(contain.name) + containers2 = blob_service_client2.list_containers() + for contain in containers2: + print(contain.name) + # [END shared_transport_with_pooling] + + +if __name__ == "__main__": + shared_transport() + shared_transport_with_pooling() diff --git a/sdk/core/azure-core/samples/example_shared_transport_async.py b/sdk/core/azure-core/samples/example_shared_transport_async.py new file mode 100644 index 000000000000..cc59548e8139 --- /dev/null +++ b/sdk/core/azure-core/samples/example_shared_transport_async.py @@ -0,0 +1,76 @@ +# coding: utf-8 + +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- + +""" +FILE: example_shared_transport_async.py + +DESCRIPTION: + This sample demonstrates how to share transport connections between multiple async clients. + +USAGE: + python example_shared_transport_async.py + + Set the environment variables with your own values before running the sample: + 1) AZURE_STORAGE_CONNECTION_STRING - the endpoint of your Azure Metrics Advisor service +""" + +import os +import asyncio +from azure.core.pipeline.transport import AioHttpTransport +from azure.storage.blob.aio import BlobServiceClient + +connection_string = os.getenv("AZURE_STORAGE_CONNECTION_STRING") + + +async def shared_transport_async(): + # [START shared_transport_async] + shared_transport = AioHttpTransport() + async with shared_transport: + blob_service_client1 = BlobServiceClient.from_connection_string( + connection_string, + transport=shared_transport, + session_owner=False, # here we set session_owner to False to indicate that we don't want to close the session when the client is closed + ) + blob_service_client2 = BlobServiceClient.from_connection_string( + connection_string, transport=shared_transport, session_owner=False + ) + containers1 = blob_service_client1.list_containers() + async for contain in containers1: + print(contain.name) + containers2 = blob_service_client2.list_containers() + async for contain in containers2: + print(contain.name) + # [END shared_transport_async] + + +async def shared_transport_async_with_pooling(): + # [START shared_transport_async_with_pooling] + import aiohttp + + conn = aiohttp.TCPConnector(limit=100) + session = aiohttp.ClientSession(connector=conn) + shared_transport = AioHttpTransport(session=session) + async with shared_transport: + blob_service_client1 = BlobServiceClient.from_connection_string( + connection_string, transport=shared_transport, session_owner=False + ) + blob_service_client2 = BlobServiceClient.from_connection_string( + connection_string, transport=shared_transport, session_owner=False + ) + containers1 = blob_service_client1.list_containers() + async for contain in containers1: + print(contain.name) + containers2 = blob_service_client2.list_containers() + async for contain in containers2: + print(contain.name) + # [END shared_transport_async_with_pooling] + + +if __name__ == "__main__": + asyncio.run(shared_transport_async()) + asyncio.run(shared_transport_async_with_pooling()) diff --git a/sdk/cosmos/azure-cosmos/README.md b/sdk/cosmos/azure-cosmos/README.md index 30cba2249de5..d41b8c9cb210 100644 --- a/sdk/cosmos/azure-cosmos/README.md +++ b/sdk/cosmos/azure-cosmos/README.md @@ -12,7 +12,12 @@ Use the Azure Cosmos DB SQL API SDK for Python to manage databases and the JSON * Create, read, update, and delete the **items** (JSON documents) in your containers * Query the documents in your database using **SQL-like syntax** -[SDK source code][source_code] | [Package (PyPI)][cosmos_pypi] | [API reference documentation][ref_cosmos_sdk] | [Product documentation][cosmos_docs] | [Samples][cosmos_samples] +[SDK source code][source_code] +| [Package (PyPI)][cosmos_pypi] +| [Package (Conda)](https://anaconda.org/microsoft/azure-cosmos/) +| [API reference documentation][ref_cosmos_sdk] +| [Product documentation][cosmos_docs] +| [Samples][cosmos_samples] > This SDK is used for the [SQL API](https://docs.microsoft.com/azure/cosmos-db/sql-query-getting-started). For all other APIs, please check the [Azure Cosmos DB documentation](https://docs.microsoft.com/azure/cosmos-db/introduction) to evaluate the best SDK for your project. diff --git a/sdk/cosmos/azure-cosmos/azure/cosmos/_retry_utility.py b/sdk/cosmos/azure-cosmos/azure/cosmos/_retry_utility.py index 2868599205d9..b5c6aebb2bea 100644 --- a/sdk/cosmos/azure-cosmos/azure/cosmos/_retry_utility.py +++ b/sdk/cosmos/azure-cosmos/azure/cosmos/_retry_utility.py @@ -96,7 +96,8 @@ def Execute(client, global_endpoint_manager, function, *args, **kwargs): return result except exceptions.CosmosHttpResponseError as e: - retry_policy = None + retry_policy = defaultRetry_policy + # Re-assign retry policy based on error code if e.status_code == StatusCodes.FORBIDDEN and e.sub_status == SubStatusCodes.WRITE_FORBIDDEN: retry_policy = endpointDiscovery_retry_policy elif e.status_code == StatusCodes.TOO_MANY_REQUESTS: @@ -111,8 +112,6 @@ def Execute(client, global_endpoint_manager, function, *args, **kwargs): retry_policy = partition_key_range_gone_retry_policy elif e.status_code == StatusCodes.REQUEST_TIMEOUT or e.status_code == StatusCodes.SERVICE_UNAVAILABLE: retry_policy = timeout_failover_retry_policy - else: - retry_policy = defaultRetry_policy # If none of the retry policies applies or there is no retry needed, set the # throttle related response headers and re-throw the exception back arg[0] diff --git a/sdk/cosmos/azure-cosmos/azure/cosmos/aio/_retry_utility_async.py b/sdk/cosmos/azure-cosmos/azure/cosmos/aio/_retry_utility_async.py index bfb54cf49dfd..0d17679b39f0 100644 --- a/sdk/cosmos/azure-cosmos/azure/cosmos/aio/_retry_utility_async.py +++ b/sdk/cosmos/azure-cosmos/azure/cosmos/aio/_retry_utility_async.py @@ -36,6 +36,7 @@ from .. import _default_retry_policy from .. import _session_retry_policy from .. import _gone_retry_policy +from .. import _timeout_failover_retry_policy # pylint: disable=protected-access @@ -70,6 +71,9 @@ async def ExecuteAsync(client, global_endpoint_manager, function, *args, **kwarg client.connection_policy.EnableEndpointDiscovery, global_endpoint_manager, *args ) partition_key_range_gone_retry_policy = _gone_retry_policy.PartitionKeyRangeGoneRetryPolicy(client, *args) + timeout_failover_retry_policy = _timeout_failover_retry_policy._TimeoutFailoverRetryPolicy( + client.connection_policy, global_endpoint_manager, *args + ) while True: try: @@ -105,6 +109,8 @@ async def ExecuteAsync(client, global_endpoint_manager, function, *args, **kwarg retry_policy = sessionRetry_policy elif exceptions._partition_range_is_gone(e): retry_policy = partition_key_range_gone_retry_policy + elif e.status_code == StatusCodes.REQUEST_TIMEOUT or e.status_code == StatusCodes.SERVICE_UNAVAILABLE: + retry_policy = timeout_failover_retry_policy else: retry_policy = defaultRetry_policy diff --git a/sdk/cosmos/azure-cosmos/docs/ErrorCodesAndRetries.md b/sdk/cosmos/azure-cosmos/docs/ErrorCodesAndRetries.md new file mode 100644 index 000000000000..ca78b7ebe568 --- /dev/null +++ b/sdk/cosmos/azure-cosmos/docs/ErrorCodesAndRetries.md @@ -0,0 +1,18 @@ +## Cosmos DB Python SDK – Detailing Exceptions and Retries + +The Cosmos DB Python SDK has several default policies that will deal with retrying certain errors and exceptions. More information on these can be found below. + +| Status code | Cause of exception and retry behavior | +| :--- |:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| 400 | For all operations:
  • This exception is encountered when the request is invalid, which could be for any of the following reasons:
    • Syntax error in query text
    • Malformed JSON document for a write request
    • Incorrectly formatted REST API request body etc.
  • The client does NOT retry the request when a Bad Request (400) exception is thrown by the server.
| +| 401 | For all operations:
  • This is an unauthorized exception due to invalid auth tokens being used for the request. The client does NOT retry requests when this exception is encountered.
| +| 403 |