diff --git a/sdk/deviceupdate/azure-iot-deviceupdate/CHANGELOG.md b/sdk/deviceupdate/azure-iot-deviceupdate/CHANGELOG.md index a2b359c6c82b..7f2e8882217d 100644 --- a/sdk/deviceupdate/azure-iot-deviceupdate/CHANGELOG.md +++ b/sdk/deviceupdate/azure-iot-deviceupdate/CHANGELOG.md @@ -1,5 +1,9 @@ # Release History +## 1.1.0 (2026-06-15) + +skip changelog generation for data-plane package and please add changelog manually. + ## 1.0.1 (Unreleased) ### Features Added diff --git a/sdk/deviceupdate/azure-iot-deviceupdate/MANIFEST.in b/sdk/deviceupdate/azure-iot-deviceupdate/MANIFEST.in index a6db34baa849..3a7efa566a2f 100644 --- a/sdk/deviceupdate/azure-iot-deviceupdate/MANIFEST.in +++ b/sdk/deviceupdate/azure-iot-deviceupdate/MANIFEST.in @@ -1,7 +1,7 @@ +include *.md +include LICENSE +include azure/iot/deviceupdate/py.typed recursive-include tests *.py recursive-include samples *.py *.md -include LICENSE -include *.md include azure/__init__.py include azure/iot/__init__.py -include azure/iot/deviceupdate/py.typed diff --git a/sdk/deviceupdate/azure-iot-deviceupdate/_metadata.json b/sdk/deviceupdate/azure-iot-deviceupdate/_metadata.json new file mode 100644 index 000000000000..614a01ddd585 --- /dev/null +++ b/sdk/deviceupdate/azure-iot-deviceupdate/_metadata.json @@ -0,0 +1,11 @@ +{ + "apiVersion": "2026-06-01", + "apiVersions": { + "DeviceUpdateClient": "2026-06-01" + }, + "commit": "292231b1131ff9fd070377372a0647c6ac7a6ce2", + "repository_url": "https://github.com/Azure/azure-rest-api-specs", + "typespec_src": "specification/deviceupdate/data-plane/duiothub", + "emitterVersion": "0.63.1", + "httpClientPythonVersion": "^0.31.1" +} \ No newline at end of file diff --git a/sdk/deviceupdate/azure-iot-deviceupdate/apiview-properties.json b/sdk/deviceupdate/azure-iot-deviceupdate/apiview-properties.json new file mode 100644 index 000000000000..5d72b7c26227 --- /dev/null +++ b/sdk/deviceupdate/azure-iot-deviceupdate/apiview-properties.json @@ -0,0 +1,156 @@ +{ + "CrossLanguagePackageId": "DeviceUpdateClient", + "CrossLanguageDefinitionId": { + "azure.iot.deviceupdate.models.CloudInitiatedRollbackPolicy": "DeviceUpdateClient.CloudInitiatedRollbackPolicy", + "azure.iot.deviceupdate.models.CloudInitiatedRollbackPolicyFailure": "DeviceUpdateClient.CloudInitiatedRollbackPolicyFailure", + "azure.iot.deviceupdate.models.Compatibility": "DeviceUpdateClient.Compatibility", + "azure.iot.deviceupdate.models.ContractModel": "DeviceUpdateClient.ContractModel", + "azure.iot.deviceupdate.models.Deployment": "DeviceUpdateClient.Deployment", + "azure.iot.deviceupdate.models.DeploymentDeviceState": "DeviceUpdateClient.DeploymentDeviceState", + "azure.iot.deviceupdate.models.DeploymentStatus": "DeviceUpdateClient.DeploymentStatus", + "azure.iot.deviceupdate.models.Device": "DeviceUpdateClient.Device", + "azure.iot.deviceupdate.models.DeviceClass": "DeviceUpdateClient.DeviceClass", + "azure.iot.deviceupdate.models.DeviceClassProperties": "DeviceUpdateClient.DeviceClassProperties", + "azure.iot.deviceupdate.models.DeviceClassSubgroup": "DeviceUpdateClient.DeviceClassSubgroup", + "azure.iot.deviceupdate.models.DeviceClassSubgroupDeploymentStatus": "DeviceUpdateClient.DeviceClassSubgroupDeploymentStatus", + "azure.iot.deviceupdate.models.DeviceClassSubgroupUpdatableDevices": "DeviceUpdateClient.DeviceClassSubgroupUpdatableDevices", + "azure.iot.deviceupdate.models.DeviceHealth": "DeviceUpdateClient.DeviceHealth", + "azure.iot.deviceupdate.models.DeviceOperation": "DeviceUpdateClient.DeviceOperation", + "azure.iot.deviceupdate.models.DeviceUpdateAgentId": "DeviceUpdateClient.DeviceUpdateAgentId", + "azure.iot.deviceupdate.models.Error": "DeviceUpdateClient.Error", + "azure.iot.deviceupdate.models.ErrorResponse": "DeviceUpdateClient.ErrorResponse", + "azure.iot.deviceupdate.models.FileImportMetadata": "DeviceUpdateClient.FileImportMetadata", + "azure.iot.deviceupdate.models.Group": "DeviceUpdateClient.Group", + "azure.iot.deviceupdate.models.HealthCheck": "DeviceUpdateClient.HealthCheck", + "azure.iot.deviceupdate.models.ImportManifestMetadata": "DeviceUpdateClient.ImportManifestMetadata", + "azure.iot.deviceupdate.models.ImportUpdateInputItem": "DeviceUpdateClient.ImportUpdateInputItem", + "azure.iot.deviceupdate.models.InnerError": "DeviceUpdateClient.InnerError", + "azure.iot.deviceupdate.models.InstallResult": "DeviceUpdateClient.InstallResult", + "azure.iot.deviceupdate.models.Instructions": "DeviceUpdateClient.Instructions", + "azure.iot.deviceupdate.models.LogCollection": "DeviceUpdateClient.LogCollection", + "azure.iot.deviceupdate.models.LogCollectionOperationDetailedStatus": "DeviceUpdateClient.LogCollectionOperationDetailedStatus", + "azure.iot.deviceupdate.models.LogCollectionOperationDeviceStatus": "DeviceUpdateClient.LogCollectionOperationDeviceStatus", + "azure.iot.deviceupdate.models.PatchBody": "DeviceUpdateClient.PatchBody", + "azure.iot.deviceupdate.models.Step": "DeviceUpdateClient.Step", + "azure.iot.deviceupdate.models.StepResult": "DeviceUpdateClient.StepResult", + "azure.iot.deviceupdate.models.Update": "DeviceUpdateClient.Update", + "azure.iot.deviceupdate.models.UpdateCompliance": "DeviceUpdateClient.UpdateCompliance", + "azure.iot.deviceupdate.models.UpdateFileBase": "DeviceUpdateClient.UpdateFileBase", + "azure.iot.deviceupdate.models.UpdateFile": "DeviceUpdateClient.UpdateFile", + "azure.iot.deviceupdate.models.UpdateFileDownloadHandler": "DeviceUpdateClient.UpdateFileDownloadHandler", + "azure.iot.deviceupdate.models.UpdateId": "DeviceUpdateClient.UpdateId", + "azure.iot.deviceupdate.models.UpdateInfo": "DeviceUpdateClient.UpdateInfo", + "azure.iot.deviceupdate.models.UpdateOperation": "DeviceUpdateClient.UpdateOperation", + "azure.iot.deviceupdate.models.StepType": "DeviceUpdateClient.StepType", + "azure.iot.deviceupdate.models.OperationStatus": "DeviceUpdateClient.OperationStatus", + "azure.iot.deviceupdate.models.DeviceDeploymentState": "DeviceUpdateClient.DeviceDeploymentState", + "azure.iot.deviceupdate.models.ImportType": "DeviceUpdateClient.ImportType", + "azure.iot.deviceupdate.models.GroupType": "DeviceUpdateClient.GroupType", + "azure.iot.deviceupdate.models.DownloadSecurity": "DeviceUpdateClient.DownloadSecurity", + "azure.iot.deviceupdate.models.DeploymentState": "DeviceUpdateClient.DeploymentState", + "azure.iot.deviceupdate.models.DeviceClassSubgroupDeploymentState": "DeviceUpdateClient.DeviceClassSubgroupDeploymentState", + "azure.iot.deviceupdate.models.DeviceHealthState": "DeviceUpdateClient.DeviceHealthState", + "azure.iot.deviceupdate.models.HealthCheckResult": "DeviceUpdateClient.HealthCheckResult", + "azure.iot.deviceupdate.operations.DeviceUpdateOperations.list_updates": "DeviceUpdateClient.DeviceUpdateOperationGroup.listUpdates", + "azure.iot.deviceupdate.aio.operations.DeviceUpdateOperations.list_updates": "DeviceUpdateClient.DeviceUpdateOperationGroup.listUpdates", + "azure.iot.deviceupdate.operations.DeviceUpdateOperations.begin_import_update": "DeviceUpdateClient.DeviceUpdateOperationGroup.importUpdate", + "azure.iot.deviceupdate.aio.operations.DeviceUpdateOperations.begin_import_update": "DeviceUpdateClient.DeviceUpdateOperationGroup.importUpdate", + "azure.iot.deviceupdate.operations.DeviceUpdateOperations.get_update": "DeviceUpdateClient.DeviceUpdateOperationGroup.getUpdate", + "azure.iot.deviceupdate.aio.operations.DeviceUpdateOperations.get_update": "DeviceUpdateClient.DeviceUpdateOperationGroup.getUpdate", + "azure.iot.deviceupdate.operations.DeviceUpdateOperations.begin_delete_update": "DeviceUpdateClient.DeviceUpdateOperationGroup.deleteUpdate", + "azure.iot.deviceupdate.aio.operations.DeviceUpdateOperations.begin_delete_update": "DeviceUpdateClient.DeviceUpdateOperationGroup.deleteUpdate", + "azure.iot.deviceupdate.operations.DeviceUpdateOperations.list_providers": "DeviceUpdateClient.DeviceUpdateOperationGroup.listProviders", + "azure.iot.deviceupdate.aio.operations.DeviceUpdateOperations.list_providers": "DeviceUpdateClient.DeviceUpdateOperationGroup.listProviders", + "azure.iot.deviceupdate.operations.DeviceUpdateOperations.list_names": "DeviceUpdateClient.DeviceUpdateOperationGroup.listNames", + "azure.iot.deviceupdate.aio.operations.DeviceUpdateOperations.list_names": "DeviceUpdateClient.DeviceUpdateOperationGroup.listNames", + "azure.iot.deviceupdate.operations.DeviceUpdateOperations.list_versions": "DeviceUpdateClient.DeviceUpdateOperationGroup.listVersions", + "azure.iot.deviceupdate.aio.operations.DeviceUpdateOperations.list_versions": "DeviceUpdateClient.DeviceUpdateOperationGroup.listVersions", + "azure.iot.deviceupdate.operations.DeviceUpdateOperations.list_files": "DeviceUpdateClient.DeviceUpdateOperationGroup.listFiles", + "azure.iot.deviceupdate.aio.operations.DeviceUpdateOperations.list_files": "DeviceUpdateClient.DeviceUpdateOperationGroup.listFiles", + "azure.iot.deviceupdate.operations.DeviceUpdateOperations.get_file": "DeviceUpdateClient.DeviceUpdateOperationGroup.getFile", + "azure.iot.deviceupdate.aio.operations.DeviceUpdateOperations.get_file": "DeviceUpdateClient.DeviceUpdateOperationGroup.getFile", + "azure.iot.deviceupdate.operations.DeviceUpdateOperations.list_operation_statuses": "DeviceUpdateClient.DeviceUpdateOperationGroup.listOperationStatuses", + "azure.iot.deviceupdate.aio.operations.DeviceUpdateOperations.list_operation_statuses": "DeviceUpdateClient.DeviceUpdateOperationGroup.listOperationStatuses", + "azure.iot.deviceupdate.operations.DeviceUpdateOperations.get_operation_status": "DeviceUpdateClient.DeviceUpdateOperationGroup.getOperationStatus", + "azure.iot.deviceupdate.aio.operations.DeviceUpdateOperations.get_operation_status": "DeviceUpdateClient.DeviceUpdateOperationGroup.getOperationStatus", + "azure.iot.deviceupdate.operations.DeviceManagementOperations.list_device_classes": "DeviceUpdateClient.DeviceManagementOperationGroup.listDeviceClasses", + "azure.iot.deviceupdate.aio.operations.DeviceManagementOperations.list_device_classes": "DeviceUpdateClient.DeviceManagementOperationGroup.listDeviceClasses", + "azure.iot.deviceupdate.operations.DeviceManagementOperations.get_device_class": "DeviceUpdateClient.DeviceManagementOperationGroup.getDeviceClass", + "azure.iot.deviceupdate.aio.operations.DeviceManagementOperations.get_device_class": "DeviceUpdateClient.DeviceManagementOperationGroup.getDeviceClass", + "azure.iot.deviceupdate.operations.DeviceManagementOperations.update_device_class": "DeviceUpdateClient.DeviceManagementOperationGroup.updateDeviceClass", + "azure.iot.deviceupdate.aio.operations.DeviceManagementOperations.update_device_class": "DeviceUpdateClient.DeviceManagementOperationGroup.updateDeviceClass", + "azure.iot.deviceupdate.operations.DeviceManagementOperations.delete_device_class": "DeviceUpdateClient.DeviceManagementOperationGroup.deleteDeviceClass", + "azure.iot.deviceupdate.aio.operations.DeviceManagementOperations.delete_device_class": "DeviceUpdateClient.DeviceManagementOperationGroup.deleteDeviceClass", + "azure.iot.deviceupdate.operations.DeviceManagementOperations.list_installable_updates_for_device_class": "DeviceUpdateClient.DeviceManagementOperationGroup.listInstallableUpdatesForDeviceClass", + "azure.iot.deviceupdate.aio.operations.DeviceManagementOperations.list_installable_updates_for_device_class": "DeviceUpdateClient.DeviceManagementOperationGroup.listInstallableUpdatesForDeviceClass", + "azure.iot.deviceupdate.operations.DeviceManagementOperations.list_devices": "DeviceUpdateClient.DeviceManagementOperationGroup.listDevices", + "azure.iot.deviceupdate.aio.operations.DeviceManagementOperations.list_devices": "DeviceUpdateClient.DeviceManagementOperationGroup.listDevices", + "azure.iot.deviceupdate.operations.DeviceManagementOperations.begin_import_devices": "DeviceUpdateClient.DeviceManagementOperationGroup.importDevices", + "azure.iot.deviceupdate.aio.operations.DeviceManagementOperations.begin_import_devices": "DeviceUpdateClient.DeviceManagementOperationGroup.importDevices", + "azure.iot.deviceupdate.operations.DeviceManagementOperations.get_device": "DeviceUpdateClient.DeviceManagementOperationGroup.getDevice", + "azure.iot.deviceupdate.aio.operations.DeviceManagementOperations.get_device": "DeviceUpdateClient.DeviceManagementOperationGroup.getDevice", + "azure.iot.deviceupdate.operations.DeviceManagementOperations.get_device_module": "DeviceUpdateClient.DeviceManagementOperationGroup.getDeviceModule", + "azure.iot.deviceupdate.aio.operations.DeviceManagementOperations.get_device_module": "DeviceUpdateClient.DeviceManagementOperationGroup.getDeviceModule", + "azure.iot.deviceupdate.operations.DeviceManagementOperations.get_update_compliance": "DeviceUpdateClient.DeviceManagementOperationGroup.getUpdateCompliance", + "azure.iot.deviceupdate.aio.operations.DeviceManagementOperations.get_update_compliance": "DeviceUpdateClient.DeviceManagementOperationGroup.getUpdateCompliance", + "azure.iot.deviceupdate.operations.DeviceManagementOperations.list_groups": "DeviceUpdateClient.DeviceManagementOperationGroup.listGroups", + "azure.iot.deviceupdate.aio.operations.DeviceManagementOperations.list_groups": "DeviceUpdateClient.DeviceManagementOperationGroup.listGroups", + "azure.iot.deviceupdate.operations.DeviceManagementOperations.get_group": "DeviceUpdateClient.DeviceManagementOperationGroup.getGroup", + "azure.iot.deviceupdate.aio.operations.DeviceManagementOperations.get_group": "DeviceUpdateClient.DeviceManagementOperationGroup.getGroup", + "azure.iot.deviceupdate.operations.DeviceManagementOperations.delete_group": "DeviceUpdateClient.DeviceManagementOperationGroup.deleteGroup", + "azure.iot.deviceupdate.aio.operations.DeviceManagementOperations.delete_group": "DeviceUpdateClient.DeviceManagementOperationGroup.deleteGroup", + "azure.iot.deviceupdate.operations.DeviceManagementOperations.get_update_compliance_for_group": "DeviceUpdateClient.DeviceManagementOperationGroup.getUpdateComplianceForGroup", + "azure.iot.deviceupdate.aio.operations.DeviceManagementOperations.get_update_compliance_for_group": "DeviceUpdateClient.DeviceManagementOperationGroup.getUpdateComplianceForGroup", + "azure.iot.deviceupdate.operations.DeviceManagementOperations.list_best_updates_for_group": "DeviceUpdateClient.DeviceManagementOperationGroup.listBestUpdatesForGroup", + "azure.iot.deviceupdate.aio.operations.DeviceManagementOperations.list_best_updates_for_group": "DeviceUpdateClient.DeviceManagementOperationGroup.listBestUpdatesForGroup", + "azure.iot.deviceupdate.operations.DeviceManagementOperations.list_deployments_for_group": "DeviceUpdateClient.DeviceManagementOperationGroup.listDeploymentsForGroup", + "azure.iot.deviceupdate.aio.operations.DeviceManagementOperations.list_deployments_for_group": "DeviceUpdateClient.DeviceManagementOperationGroup.listDeploymentsForGroup", + "azure.iot.deviceupdate.operations.DeviceManagementOperations.get_deployment": "DeviceUpdateClient.DeviceManagementOperationGroup.getDeployment", + "azure.iot.deviceupdate.aio.operations.DeviceManagementOperations.get_deployment": "DeviceUpdateClient.DeviceManagementOperationGroup.getDeployment", + "azure.iot.deviceupdate.operations.DeviceManagementOperations.create_or_update_deployment": "DeviceUpdateClient.DeviceManagementOperationGroup.createOrUpdateDeployment", + "azure.iot.deviceupdate.aio.operations.DeviceManagementOperations.create_or_update_deployment": "DeviceUpdateClient.DeviceManagementOperationGroup.createOrUpdateDeployment", + "azure.iot.deviceupdate.operations.DeviceManagementOperations.get_deployment_status": "DeviceUpdateClient.DeviceManagementOperationGroup.getDeploymentStatus", + "azure.iot.deviceupdate.aio.operations.DeviceManagementOperations.get_deployment_status": "DeviceUpdateClient.DeviceManagementOperationGroup.getDeploymentStatus", + "azure.iot.deviceupdate.operations.DeviceManagementOperations.list_device_class_subgroups_for_group": "DeviceUpdateClient.DeviceManagementOperationGroup.listDeviceClassSubgroupsForGroup", + "azure.iot.deviceupdate.aio.operations.DeviceManagementOperations.list_device_class_subgroups_for_group": "DeviceUpdateClient.DeviceManagementOperationGroup.listDeviceClassSubgroupsForGroup", + "azure.iot.deviceupdate.operations.DeviceManagementOperations.get_device_class_subgroup": "DeviceUpdateClient.DeviceManagementOperationGroup.getDeviceClassSubgroup", + "azure.iot.deviceupdate.aio.operations.DeviceManagementOperations.get_device_class_subgroup": "DeviceUpdateClient.DeviceManagementOperationGroup.getDeviceClassSubgroup", + "azure.iot.deviceupdate.operations.DeviceManagementOperations.delete_device_class_subgroup": "DeviceUpdateClient.DeviceManagementOperationGroup.deleteDeviceClassSubgroup", + "azure.iot.deviceupdate.aio.operations.DeviceManagementOperations.delete_device_class_subgroup": "DeviceUpdateClient.DeviceManagementOperationGroup.deleteDeviceClassSubgroup", + "azure.iot.deviceupdate.operations.DeviceManagementOperations.get_device_class_subgroup_update_compliance": "DeviceUpdateClient.DeviceManagementOperationGroup.getDeviceClassSubgroupUpdateCompliance", + "azure.iot.deviceupdate.aio.operations.DeviceManagementOperations.get_device_class_subgroup_update_compliance": "DeviceUpdateClient.DeviceManagementOperationGroup.getDeviceClassSubgroupUpdateCompliance", + "azure.iot.deviceupdate.operations.DeviceManagementOperations.get_best_updates_for_device_class_subgroup": "DeviceUpdateClient.DeviceManagementOperationGroup.getBestUpdatesForDeviceClassSubgroup", + "azure.iot.deviceupdate.aio.operations.DeviceManagementOperations.get_best_updates_for_device_class_subgroup": "DeviceUpdateClient.DeviceManagementOperationGroup.getBestUpdatesForDeviceClassSubgroup", + "azure.iot.deviceupdate.operations.DeviceManagementOperations.list_deployments_for_device_class_subgroup": "DeviceUpdateClient.DeviceManagementOperationGroup.listDeploymentsForDeviceClassSubgroup", + "azure.iot.deviceupdate.aio.operations.DeviceManagementOperations.list_deployments_for_device_class_subgroup": "DeviceUpdateClient.DeviceManagementOperationGroup.listDeploymentsForDeviceClassSubgroup", + "azure.iot.deviceupdate.operations.DeviceManagementOperations.get_deployment_for_device_class_subgroup": "DeviceUpdateClient.DeviceManagementOperationGroup.getDeploymentForDeviceClassSubgroup", + "azure.iot.deviceupdate.aio.operations.DeviceManagementOperations.get_deployment_for_device_class_subgroup": "DeviceUpdateClient.DeviceManagementOperationGroup.getDeploymentForDeviceClassSubgroup", + "azure.iot.deviceupdate.operations.DeviceManagementOperations.stop_deployment": "DeviceUpdateClient.DeviceManagementOperationGroup.stopDeployment", + "azure.iot.deviceupdate.aio.operations.DeviceManagementOperations.stop_deployment": "DeviceUpdateClient.DeviceManagementOperationGroup.stopDeployment", + "azure.iot.deviceupdate.operations.DeviceManagementOperations.retry_deployment": "DeviceUpdateClient.DeviceManagementOperationGroup.retryDeployment", + "azure.iot.deviceupdate.aio.operations.DeviceManagementOperations.retry_deployment": "DeviceUpdateClient.DeviceManagementOperationGroup.retryDeployment", + "azure.iot.deviceupdate.operations.DeviceManagementOperations.get_device_class_subgroup_deployment_status": "DeviceUpdateClient.DeviceManagementOperationGroup.getDeviceClassSubgroupDeploymentStatus", + "azure.iot.deviceupdate.aio.operations.DeviceManagementOperations.get_device_class_subgroup_deployment_status": "DeviceUpdateClient.DeviceManagementOperationGroup.getDeviceClassSubgroupDeploymentStatus", + "azure.iot.deviceupdate.operations.DeviceManagementOperations.list_device_states_for_device_class_subgroup_deployment": "DeviceUpdateClient.DeviceManagementOperationGroup.listDeviceStatesForDeviceClassSubgroupDeployment", + "azure.iot.deviceupdate.aio.operations.DeviceManagementOperations.list_device_states_for_device_class_subgroup_deployment": "DeviceUpdateClient.DeviceManagementOperationGroup.listDeviceStatesForDeviceClassSubgroupDeployment", + "azure.iot.deviceupdate.operations.DeviceManagementOperations.get_operation_status": "DeviceUpdateClient.DeviceManagementOperationGroup.getOperationStatus", + "azure.iot.deviceupdate.aio.operations.DeviceManagementOperations.get_operation_status": "DeviceUpdateClient.DeviceManagementOperationGroup.getOperationStatus", + "azure.iot.deviceupdate.operations.DeviceManagementOperations.list_operation_statuses": "DeviceUpdateClient.DeviceManagementOperationGroup.listOperationStatuses", + "azure.iot.deviceupdate.aio.operations.DeviceManagementOperations.list_operation_statuses": "DeviceUpdateClient.DeviceManagementOperationGroup.listOperationStatuses", + "azure.iot.deviceupdate.operations.DeviceManagementOperations.start_log_collection": "DeviceUpdateClient.DeviceManagementOperationGroup.startLogCollection", + "azure.iot.deviceupdate.aio.operations.DeviceManagementOperations.start_log_collection": "DeviceUpdateClient.DeviceManagementOperationGroup.startLogCollection", + "azure.iot.deviceupdate.operations.DeviceManagementOperations.get_log_collection": "DeviceUpdateClient.DeviceManagementOperationGroup.getLogCollection", + "azure.iot.deviceupdate.aio.operations.DeviceManagementOperations.get_log_collection": "DeviceUpdateClient.DeviceManagementOperationGroup.getLogCollection", + "azure.iot.deviceupdate.operations.DeviceManagementOperations.list_log_collections": "DeviceUpdateClient.DeviceManagementOperationGroup.listLogCollections", + "azure.iot.deviceupdate.aio.operations.DeviceManagementOperations.list_log_collections": "DeviceUpdateClient.DeviceManagementOperationGroup.listLogCollections", + "azure.iot.deviceupdate.operations.DeviceManagementOperations.get_log_collection_detailed_status": "DeviceUpdateClient.DeviceManagementOperationGroup.getLogCollectionDetailedStatus", + "azure.iot.deviceupdate.aio.operations.DeviceManagementOperations.get_log_collection_detailed_status": "DeviceUpdateClient.DeviceManagementOperationGroup.getLogCollectionDetailedStatus", + "azure.iot.deviceupdate.operations.DeviceManagementOperations.list_health_of_devices": "DeviceUpdateClient.DeviceManagementOperationGroup.listHealthOfDevices", + "azure.iot.deviceupdate.aio.operations.DeviceManagementOperations.list_health_of_devices": "DeviceUpdateClient.DeviceManagementOperationGroup.listHealthOfDevices", + "azure.iot.deviceupdate.operations.DeviceManagementOperations.delete_deployment": "DeviceUpdateClient.DeploymentManagementOperationGroup.deleteDeployment", + "azure.iot.deviceupdate.aio.operations.DeviceManagementOperations.delete_deployment": "DeviceUpdateClient.DeploymentManagementOperationGroup.deleteDeployment", + "azure.iot.deviceupdate.operations.DeviceManagementOperations.delete_deployment_for_device_class_subgroup": "DeviceUpdateClient.DeploymentManagementOperationGroup.deleteDeploymentForDeviceClassSubgroup", + "azure.iot.deviceupdate.aio.operations.DeviceManagementOperations.delete_deployment_for_device_class_subgroup": "DeviceUpdateClient.DeploymentManagementOperationGroup.deleteDeploymentForDeviceClassSubgroup" + }, + "CrossLanguageVersion": "2152dadbc310" +} \ No newline at end of file diff --git a/sdk/deviceupdate/azure-iot-deviceupdate/azure/__init__.py b/sdk/deviceupdate/azure-iot-deviceupdate/azure/__init__.py index 5960c353a898..d55ccad1f573 100644 --- a/sdk/deviceupdate/azure-iot-deviceupdate/azure/__init__.py +++ b/sdk/deviceupdate/azure-iot-deviceupdate/azure/__init__.py @@ -1 +1 @@ -__path__ = __import__('pkgutil').extend_path(__path__, __name__) # type: ignore \ No newline at end of file +__path__ = __import__("pkgutil").extend_path(__path__, __name__) # type: ignore diff --git a/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/__init__.py b/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/__init__.py index 5960c353a898..d55ccad1f573 100644 --- a/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/__init__.py +++ b/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/__init__.py @@ -1 +1 @@ -__path__ = __import__('pkgutil').extend_path(__path__, __name__) # type: ignore \ No newline at end of file +__path__ = __import__("pkgutil").extend_path(__path__, __name__) # type: ignore diff --git a/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/__init__.py b/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/__init__.py index b7913c493f30..a1cfe8bc43b1 100644 --- a/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/__init__.py +++ b/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/__init__.py @@ -2,23 +2,31 @@ # -------------------------------------------------------------------------- # 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. +# Code generated by Microsoft (R) Python Code Generator. # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- +# pylint: disable=wrong-import-position -from ._client import DeviceUpdateClient +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from ._patch import * # pylint: disable=unused-wildcard-import + +from ._client import DeviceUpdateClient # type: ignore from ._version import VERSION __version__ = VERSION try: from ._patch import __all__ as _patch_all - from ._patch import * # type: ignore # pylint: disable=unused-wildcard-import + from ._patch import * except ImportError: _patch_all = [] from ._patch import patch_sdk as _patch_sdk -__all__ = ["DeviceUpdateClient"] -__all__.extend([p for p in _patch_all if p not in __all__]) +__all__ = [ + "DeviceUpdateClient", +] +__all__.extend([p for p in _patch_all if p not in __all__]) # pyright: ignore _patch_sdk() diff --git a/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/_client.py b/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/_client.py index 415df58c5150..0212578004b9 100644 --- a/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/_client.py +++ b/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/_client.py @@ -2,28 +2,32 @@ # -------------------------------------------------------------------------- # 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. +# Code generated by Microsoft (R) Python Code Generator. # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- from copy import deepcopy +import sys from typing import Any, TYPE_CHECKING from azure.core import PipelineClient +from azure.core.pipeline import policies from azure.core.rest import HttpRequest, HttpResponse from ._configuration import DeviceUpdateClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import DeviceManagementOperations, DeviceUpdateOperations -if TYPE_CHECKING: - # pylint: disable=unused-import,ungrouped-imports - from typing import Dict +if sys.version_info >= (3, 11): + from typing import Self +else: + from typing_extensions import Self # type: ignore +if TYPE_CHECKING: from azure.core.credentials import TokenCredential -class DeviceUpdateClient: # pylint: disable=client-accepts-api-version-keyword +class DeviceUpdateClient: """Device Update for IoT Hub is an Azure service that enables customers to publish updates for their IoT devices to the cloud, and then deploy that update to their devices (approve updates to groups of devices managed and provisioned in IoT Hub). It leverages the proven security and @@ -38,23 +42,42 @@ class DeviceUpdateClient: # pylint: disable=client-accepts-api-version-keyword :param endpoint: The Device Update for IoT Hub account endpoint (hostname only, no protocol). Required. :type endpoint: str + :param credential: Credential used to authenticate requests to the service. Required. + :type credential: ~azure.core.credentials.TokenCredential :param instance_id: The Device Update for IoT Hub account instance identifier. Required. :type instance_id: str - :param credential: Credential needed for the client to connect to Azure. Required. - :type credential: ~azure.core.credentials.TokenCredential - :keyword api_version: Api Version. Default value is "2022-10-01". Note that overriding this - default value may result in unsupported behavior. + :keyword api_version: The API version to use for this operation. Known values are "2026-06-01" + and None. Default value is None. If not set, the operation's default API version will be used. + Note that overriding this default value may result in unsupported behavior. :paramtype api_version: str :keyword int polling_interval: Default waiting time between two polls for LRO operations if no Retry-After header is present. """ - def __init__(self, endpoint: str, instance_id: str, credential: "TokenCredential", **kwargs: Any) -> None: + def __init__(self, endpoint: str, credential: "TokenCredential", instance_id: str, **kwargs: Any) -> None: _endpoint = "https://{endpoint}" self._config = DeviceUpdateClientConfiguration( - endpoint=endpoint, instance_id=instance_id, credential=credential, **kwargs + endpoint=endpoint, credential=credential, instance_id=instance_id, **kwargs ) - self._client = PipelineClient(base_url=_endpoint, config=self._config, **kwargs) + + _policies = kwargs.pop("policies", None) + if _policies is None: + _policies = [ + policies.RequestIdPolicy(**kwargs), + self._config.headers_policy, + self._config.user_agent_policy, + self._config.proxy_policy, + policies.ContentDecodePolicy(**kwargs), + self._config.redirect_policy, + self._config.retry_policy, + self._config.authentication_policy, + self._config.custom_hook_policy, + self._config.logging_policy, + policies.DistributedTracingPolicy(**kwargs), + policies.SensitiveHeaderCleanupPolicy(**kwargs) if self._config.redirect_policy else None, + self._config.http_logging_policy, + ] + self._client: PipelineClient = PipelineClient(base_url=_endpoint, policies=_policies, **kwargs) self._serialize = Serializer() self._deserialize = Deserializer() @@ -64,7 +87,7 @@ def __init__(self, endpoint: str, instance_id: str, credential: "TokenCredential self._client, self._config, self._serialize, self._deserialize ) - def send_request(self, request: HttpRequest, **kwargs: Any) -> HttpResponse: + def send_request(self, request: HttpRequest, *, stream: bool = False, **kwargs: Any) -> HttpResponse: """Runs the network request through the client's chained policies. >>> from azure.core.rest import HttpRequest @@ -84,21 +107,18 @@ def send_request(self, request: HttpRequest, **kwargs: Any) -> HttpResponse: 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"), } request_copy.url = self._client.format_url(request_copy.url, **path_format_arguments) - return self._client.send_request(request_copy, **kwargs) + return self._client.send_request(request_copy, stream=stream, **kwargs) # type: ignore - def close(self): - # type: () -> None + def close(self) -> None: self._client.close() - def __enter__(self): - # type: () -> DeviceUpdateClient + def __enter__(self) -> Self: 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/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/_configuration.py b/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/_configuration.py index 148973b69bbd..2431c67afc2c 100644 --- a/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/_configuration.py +++ b/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/_configuration.py @@ -2,23 +2,21 @@ # -------------------------------------------------------------------------- # 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. +# Code generated by Microsoft (R) Python Code Generator. # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- from typing import Any, TYPE_CHECKING -from azure.core.configuration import Configuration from azure.core.pipeline import policies from ._version import VERSION if TYPE_CHECKING: - # pylint: disable=unused-import,ungrouped-imports from azure.core.credentials import TokenCredential -class DeviceUpdateClientConfiguration(Configuration): # pylint: disable=too-many-instance-attributes +class DeviceUpdateClientConfiguration: # pylint: disable=too-many-instance-attributes """Configuration for DeviceUpdateClient. Note that all parameters used to create this instance are saved as instance @@ -27,46 +25,44 @@ class DeviceUpdateClientConfiguration(Configuration): # pylint: disable=too-man :param endpoint: The Device Update for IoT Hub account endpoint (hostname only, no protocol). Required. :type endpoint: str + :param credential: Credential used to authenticate requests to the service. Required. + :type credential: ~azure.core.credentials.TokenCredential :param instance_id: The Device Update for IoT Hub account instance identifier. Required. :type instance_id: str - :param credential: Credential needed for the client to connect to Azure. Required. - :type credential: ~azure.core.credentials.TokenCredential - :keyword api_version: Api Version. Default value is "2022-10-01". Note that overriding this - default value may result in unsupported behavior. + :keyword api_version: The API version to use for this operation. Known values are "2026-06-01" + and None. Default value is None. If not set, the operation's default API version will be used. + Note that overriding this default value may result in unsupported behavior. :paramtype api_version: str """ - def __init__(self, endpoint: str, instance_id: str, credential: "TokenCredential", **kwargs: Any) -> None: - super(DeviceUpdateClientConfiguration, self).__init__(**kwargs) - api_version = kwargs.pop("api_version", "2022-10-01") # type: str + def __init__(self, endpoint: str, credential: "TokenCredential", instance_id: str, **kwargs: Any) -> None: + api_version: str = kwargs.pop("api_version", "2026-06-01") if endpoint is None: raise ValueError("Parameter 'endpoint' must not be None.") - if instance_id is None: - raise ValueError("Parameter 'instance_id' must not be None.") if credential is None: raise ValueError("Parameter 'credential' must not be None.") + if instance_id is None: + raise ValueError("Parameter 'instance_id' must not be None.") self.endpoint = endpoint - self.instance_id = instance_id self.credential = credential + self.instance_id = instance_id self.api_version = api_version self.credential_scopes = kwargs.pop("credential_scopes", ["https://api.adu.microsoft.com/.default"]) kwargs.setdefault("sdk_moniker", "iot-deviceupdate/{}".format(VERSION)) + self.polling_interval = kwargs.get("polling_interval", 30) self._configure(**kwargs) - def _configure( - self, **kwargs # type: Any - ): - # type: (...) -> None + 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.retry_policy = kwargs.get("retry_policy") or policies.RetryPolicy(**kwargs) self.authentication_policy = kwargs.get("authentication_policy") if self.credential and not self.authentication_policy: self.authentication_policy = policies.BearerTokenCredentialPolicy( diff --git a/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/_patch.py b/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/_patch.py index f99e77fef986..87676c65a8f0 100644 --- a/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/_patch.py +++ b/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/_patch.py @@ -1,31 +1,21 @@ # coding=utf-8 # -------------------------------------------------------------------------- -# # 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. -# +# Licensed under the MIT License. See License.txt in the project root for license information. # -------------------------------------------------------------------------- +"""Customize generated code here. + +Follow our quickstart for examples: https://aka.ms/azsdk/python/dpcodegen/python/customize +""" + + +__all__: list[str] = [] # Add all objects you want publicly available to users at this package level + -# 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 + """Do not remove from this file. + + `patch_sdk` is a last resort escape hatch that allows you to do customizations + you can't accomplish using the techniques described in + https://aka.ms/azsdk/python/dpcodegen/python/customize + """ diff --git a/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/_utils/__init__.py b/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/_utils/__init__.py new file mode 100644 index 000000000000..8026245c2abc --- /dev/null +++ b/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# 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) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/_utils/model_base.py b/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/_utils/model_base.py new file mode 100644 index 000000000000..bd5b9caf1022 --- /dev/null +++ b/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/_utils/model_base.py @@ -0,0 +1,1755 @@ +# pylint: disable=line-too-long,useless-suppression,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) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +# pylint: disable=protected-access, broad-except + +import copy +import calendar +import decimal +import functools +import sys +import logging +import base64 +import re +import typing +import enum +import email.utils +from datetime import datetime, date, time, timedelta, timezone +from json import JSONEncoder +import xml.etree.ElementTree as ET +from collections.abc import MutableMapping +import isodate +from azure.core.exceptions import DeserializationError +from azure.core import CaseInsensitiveEnumMeta +from azure.core.pipeline import PipelineResponse +from azure.core.serialization import _Null + +from azure.core.rest import HttpResponse + +if sys.version_info >= (3, 11): + from typing import Self +else: + from typing_extensions import Self + +_LOGGER = logging.getLogger(__name__) + +__all__ = ["SdkJSONEncoder", "Model", "rest_field", "rest_discriminator"] + +TZ_UTC = timezone.utc +_T = typing.TypeVar("_T") +_NONE_TYPE = type(None) + + +def _timedelta_as_isostr(td: timedelta) -> str: + """Converts a datetime.timedelta object into an ISO 8601 formatted string, e.g. 'P4DT12H30M05S' + + Function adapted from the Tin Can Python project: https://github.com/RusticiSoftware/TinCanPython + + :param timedelta td: The timedelta to convert + :rtype: str + :return: ISO8601 version of this timedelta + """ + + # Split seconds to larger units + seconds = td.total_seconds() + minutes, seconds = divmod(seconds, 60) + hours, minutes = divmod(minutes, 60) + days, hours = divmod(hours, 24) + + days, hours, minutes = list(map(int, (days, hours, minutes))) + seconds = round(seconds, 6) + + # Build date + date_str = "" + if days: + date_str = "%sD" % days + + if hours or minutes or seconds: + # Build time + time_str = "T" + + # Hours + bigger_exists = date_str or hours + if bigger_exists: + time_str += "{:02}H".format(hours) + + # Minutes + bigger_exists = bigger_exists or minutes + if bigger_exists: + time_str += "{:02}M".format(minutes) + + # Seconds + try: + if seconds.is_integer(): + seconds_string = "{:02}".format(int(seconds)) + else: + # 9 chars long w/ leading 0, 6 digits after decimal + seconds_string = "%09.6f" % seconds + # Remove trailing zeros + seconds_string = seconds_string.rstrip("0") + except AttributeError: # int.is_integer() raises + seconds_string = "{:02}".format(seconds) + + time_str += "{}S".format(seconds_string) + else: + time_str = "" + + return "P" + date_str + time_str + + +def _serialize_bytes(o, format: typing.Optional[str] = None) -> str: + encoded = base64.b64encode(o).decode() + if format == "base64url": + return encoded.strip("=").replace("+", "-").replace("/", "_") + return encoded + + +def _serialize_datetime(o, format: typing.Optional[str] = None): + if hasattr(o, "year") and hasattr(o, "hour"): + if format == "rfc7231": + return email.utils.format_datetime(o, usegmt=True) + if format == "unix-timestamp": + return int(calendar.timegm(o.utctimetuple())) + + # astimezone() fails for naive times in Python 2.7, so make make sure o is aware (tzinfo is set) + if not o.tzinfo: + iso_formatted = o.replace(tzinfo=TZ_UTC).isoformat() + else: + iso_formatted = o.astimezone(TZ_UTC).isoformat() + # Replace the trailing "+00:00" UTC offset with "Z" (RFC 3339: https://www.ietf.org/rfc/rfc3339.txt) + return iso_formatted.replace("+00:00", "Z") + # Next try datetime.date or datetime.time + return o.isoformat() + + +def _is_readonly(p): + try: + return p._visibility == ["read"] + except AttributeError: + return False + + +class SdkJSONEncoder(JSONEncoder): + """A JSON encoder that's capable of serializing datetime objects and bytes.""" + + def __init__(self, *args, exclude_readonly: bool = False, format: typing.Optional[str] = None, **kwargs): + super().__init__(*args, **kwargs) + self.exclude_readonly = exclude_readonly + self.format = format + + def default(self, o): # pylint: disable=too-many-return-statements + if _is_model(o): + if self.exclude_readonly: + readonly_props = [p._rest_name for p in o._attr_to_rest_field.values() if _is_readonly(p)] + return {k: v for k, v in o.items() if k not in readonly_props} + return dict(o.items()) + try: + return super(SdkJSONEncoder, self).default(o) + except TypeError: + if isinstance(o, _Null): + return None + if isinstance(o, decimal.Decimal): + return float(o) + if isinstance(o, (bytes, bytearray)): + return _serialize_bytes(o, self.format) + try: + # First try datetime.datetime + return _serialize_datetime(o, self.format) + except AttributeError: + pass + # Last, try datetime.timedelta + try: + return _timedelta_as_isostr(o) + except AttributeError: + # This will be raised when it hits value.total_seconds in the method above + pass + return super(SdkJSONEncoder, self).default(o) + + +_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}]?") +_VALID_RFC7231 = re.compile( + r"(Mon|Tue|Wed|Thu|Fri|Sat|Sun),\s\d{2}\s" + r"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s\d{4}\s\d{2}:\d{2}:\d{2}\sGMT" +) + +_ARRAY_ENCODE_MAPPING = { + "pipeDelimited": "|", + "spaceDelimited": " ", + "commaDelimited": ",", + "newlineDelimited": "\n", +} + + +def _deserialize_array_encoded(delimit: str, attr): + if isinstance(attr, str): + if attr == "": + return [] + return attr.split(delimit) + return attr + + +def _deserialize_datetime(attr: typing.Union[str, datetime]) -> datetime: + """Deserialize ISO-8601 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :rtype: ~datetime.datetime + :returns: The datetime object from that input + """ + if isinstance(attr, datetime): + # i'm already deserialized + return attr + attr = attr.upper() + match = _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") + return date_obj # type: ignore[no-any-return] + + +def _deserialize_datetime_rfc7231(attr: typing.Union[str, datetime]) -> datetime: + """Deserialize RFC7231 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :rtype: ~datetime.datetime + :returns: The datetime object from that input + """ + if isinstance(attr, datetime): + # i'm already deserialized + return attr + match = _VALID_RFC7231.match(attr) + if not match: + raise ValueError("Invalid datetime string: " + attr) + + return email.utils.parsedate_to_datetime(attr) + + +def _deserialize_datetime_unix_timestamp(attr: typing.Union[float, datetime]) -> datetime: + """Deserialize unix timestamp into Datetime object. + + :param str attr: response string to be deserialized. + :rtype: ~datetime.datetime + :returns: The datetime object from that input + """ + if isinstance(attr, datetime): + # i'm already deserialized + return attr + return datetime.fromtimestamp(attr, TZ_UTC) + + +def _deserialize_date(attr: typing.Union[str, date]) -> date: + """Deserialize ISO-8601 formatted string into Date object. + :param str attr: response string to be deserialized. + :rtype: date + :returns: The date object from that input + """ + # This must NOT use defaultmonth/defaultday. Using None ensure this raises an exception. + if isinstance(attr, date): + return attr + return isodate.parse_date(attr, defaultmonth=None, defaultday=None) # type: ignore + + +def _deserialize_time(attr: typing.Union[str, time]) -> time: + """Deserialize ISO-8601 formatted string into time object. + + :param str attr: response string to be deserialized. + :rtype: datetime.time + :returns: The time object from that input + """ + if isinstance(attr, time): + return attr + return isodate.parse_time(attr) # type: ignore[no-any-return] + + +def _deserialize_bytes(attr): + if isinstance(attr, (bytes, bytearray)): + return attr + return bytes(base64.b64decode(attr)) + + +def _deserialize_bytes_base64(attr): + if isinstance(attr, (bytes, bytearray)): + return attr + padding = "=" * (3 - (len(attr) + 3) % 4) # type: ignore + attr = attr + padding # type: ignore + encoded = attr.replace("-", "+").replace("_", "/") + return bytes(base64.b64decode(encoded)) + + +def _deserialize_duration(attr): + if isinstance(attr, timedelta): + return attr + return isodate.parse_duration(attr) + + +def _deserialize_decimal(attr): + if isinstance(attr, decimal.Decimal): + return attr + return decimal.Decimal(str(attr)) + + +def _deserialize_int_as_str(attr): + if isinstance(attr, int): + return attr + return int(attr) + + +_DESERIALIZE_MAPPING = { + datetime: _deserialize_datetime, + date: _deserialize_date, + time: _deserialize_time, + bytes: _deserialize_bytes, + bytearray: _deserialize_bytes, + timedelta: _deserialize_duration, + typing.Any: lambda x: x, + decimal.Decimal: _deserialize_decimal, +} + +_DESERIALIZE_MAPPING_WITHFORMAT = { + "rfc3339": _deserialize_datetime, + "rfc7231": _deserialize_datetime_rfc7231, + "unix-timestamp": _deserialize_datetime_unix_timestamp, + "base64": _deserialize_bytes, + "base64url": _deserialize_bytes_base64, +} + + +def get_deserializer(annotation: typing.Any, rf: typing.Optional["_RestField"] = None): + if annotation is int and rf and rf._format == "str": + return _deserialize_int_as_str + if annotation is str and rf and rf._format in _ARRAY_ENCODE_MAPPING: + return functools.partial(_deserialize_array_encoded, _ARRAY_ENCODE_MAPPING[rf._format]) + if rf and rf._format: + return _DESERIALIZE_MAPPING_WITHFORMAT.get(rf._format) + return _DESERIALIZE_MAPPING.get(annotation) # pyright: ignore + + +def _get_type_alias_type(module_name: str, alias_name: str): + types = { + k: v + for k, v in sys.modules[module_name].__dict__.items() + if isinstance(v, typing._GenericAlias) # type: ignore + } + if alias_name not in types: + return alias_name + return types[alias_name] + + +def _get_model(module_name: str, model_name: str): + models = {k: v for k, v in sys.modules[module_name].__dict__.items() if isinstance(v, type)} + module_end = module_name.rsplit(".", 1)[0] + models.update({k: v for k, v in sys.modules[module_end].__dict__.items() if isinstance(v, type)}) + if isinstance(model_name, str): + model_name = model_name.split(".")[-1] + if model_name not in models: + return model_name + return models[model_name] + + +_UNSET = object() + + +class _MyMutableMapping(MutableMapping[str, typing.Any]): + def __init__(self, data: dict[str, typing.Any]) -> None: + self._data = data + + def __contains__(self, key: typing.Any) -> bool: + return key in self._data + + def __getitem__(self, key: str) -> typing.Any: + # If this key has been deserialized (for mutable types), we need to handle serialization + if hasattr(self, "_attr_to_rest_field"): + cache_attr = f"_deserialized_{key}" + if hasattr(self, cache_attr): + rf = _get_rest_field(getattr(self, "_attr_to_rest_field"), key) + if rf: + value = self._data.get(key) + if isinstance(value, (dict, list, set)): + # For mutable types, serialize and return + # But also update _data with serialized form and clear flag + # so mutations via this returned value affect _data + serialized = _serialize(value, rf._format) + # If serialized form is same type (no transformation needed), + # return _data directly so mutations work + if isinstance(serialized, type(value)) and serialized == value: + return self._data.get(key) + # Otherwise return serialized copy and clear flag + try: + object.__delattr__(self, cache_attr) + except AttributeError: + pass + # Store serialized form back + self._data[key] = serialized + return serialized + return self._data.__getitem__(key) + + def __setitem__(self, key: str, value: typing.Any) -> None: + # Clear any cached deserialized value when setting through dictionary access + cache_attr = f"_deserialized_{key}" + try: + object.__delattr__(self, cache_attr) + except AttributeError: + pass + self._data.__setitem__(key, value) + + def __delitem__(self, key: str) -> None: + self._data.__delitem__(key) + + def __iter__(self) -> typing.Iterator[typing.Any]: + return self._data.__iter__() + + def __len__(self) -> int: + return self._data.__len__() + + def __ne__(self, other: typing.Any) -> bool: + return not self.__eq__(other) + + def keys(self) -> typing.KeysView[str]: + """ + :returns: a set-like object providing a view on D's keys + :rtype: ~typing.KeysView + """ + return self._data.keys() + + def values(self) -> typing.ValuesView[typing.Any]: + """ + :returns: an object providing a view on D's values + :rtype: ~typing.ValuesView + """ + return self._data.values() + + def items(self) -> typing.ItemsView[str, typing.Any]: + """ + :returns: set-like object providing a view on D's items + :rtype: ~typing.ItemsView + """ + return self._data.items() + + def get(self, key: str, default: typing.Any = None) -> typing.Any: + """ + Get the value for key if key is in the dictionary, else default. + :param str key: The key to look up. + :param any default: The value to return if key is not in the dictionary. Defaults to None + :returns: D[k] if k in D, else d. + :rtype: any + """ + try: + return self[key] + except KeyError: + return default + + @typing.overload + def pop(self, key: str) -> typing.Any: ... # pylint: disable=arguments-differ + + @typing.overload + def pop(self, key: str, default: _T) -> _T: ... # pylint: disable=signature-differs + + @typing.overload + def pop(self, key: str, default: typing.Any) -> typing.Any: ... # pylint: disable=signature-differs + + def pop(self, key: str, default: typing.Any = _UNSET) -> typing.Any: + """ + Removes specified key and return the corresponding value. + :param str key: The key to pop. + :param any default: The value to return if key is not in the dictionary + :returns: The value corresponding to the key. + :rtype: any + :raises KeyError: If key is not found and default is not given. + """ + if default is _UNSET: + return self._data.pop(key) + return self._data.pop(key, default) + + def popitem(self) -> tuple[str, typing.Any]: + """ + Removes and returns some (key, value) pair + :returns: The (key, value) pair. + :rtype: tuple + :raises KeyError: if D is empty. + """ + return self._data.popitem() + + def clear(self) -> None: + """ + Remove all items from D. + """ + self._data.clear() + + def update(self, *args: typing.Any, **kwargs: typing.Any) -> None: # pylint: disable=arguments-differ + """ + Updates D from mapping/iterable E and F. + :param any args: Either a mapping object or an iterable of key-value pairs. + """ + self._data.update(*args, **kwargs) + + @typing.overload + def setdefault(self, key: str, default: None = None) -> None: ... + + @typing.overload + def setdefault(self, key: str, default: typing.Any) -> typing.Any: ... # pylint: disable=signature-differs + + def setdefault(self, key: str, default: typing.Any = _UNSET) -> typing.Any: + """ + Same as calling D.get(k, d), and setting D[k]=d if k not found + :param str key: The key to look up. + :param any default: The value to set if key is not in the dictionary + :returns: D[k] if k in D, else d. + :rtype: any + """ + if default is _UNSET: + return self._data.setdefault(key) + return self._data.setdefault(key, default) + + def __eq__(self, other: typing.Any) -> bool: + if isinstance(other, _MyMutableMapping): + return self._data == other._data + try: + other_model = self.__class__(other) + except Exception: + return False + return self._data == other_model._data + + def __repr__(self) -> str: + return str(self._data) + + +def _is_model(obj: typing.Any) -> bool: + return getattr(obj, "_is_model", False) + + +def _serialize(o, format: typing.Optional[str] = None): # pylint: disable=too-many-return-statements + if isinstance(o, list): + if format in _ARRAY_ENCODE_MAPPING and all(isinstance(x, str) for x in o): + return _ARRAY_ENCODE_MAPPING[format].join(o) + return [_serialize(x, format) for x in o] + if isinstance(o, dict): + return {k: _serialize(v, format) for k, v in o.items()} + if isinstance(o, set): + return {_serialize(x, format) for x in o} + if isinstance(o, tuple): + return tuple(_serialize(x, format) for x in o) + if isinstance(o, (bytes, bytearray)): + return _serialize_bytes(o, format) + if isinstance(o, decimal.Decimal): + return float(o) + if isinstance(o, enum.Enum): + return o.value + if isinstance(o, int): + if format == "str": + return str(o) + return o + try: + # First try datetime.datetime + return _serialize_datetime(o, format) + except AttributeError: + pass + # Last, try datetime.timedelta + try: + return _timedelta_as_isostr(o) + except AttributeError: + # This will be raised when it hits value.total_seconds in the method above + pass + return o + + +def _get_rest_field(attr_to_rest_field: dict[str, "_RestField"], rest_name: str) -> typing.Optional["_RestField"]: + try: + return next(rf for rf in attr_to_rest_field.values() if rf._rest_name == rest_name) + except StopIteration: + return None + + +def _create_value(rf: typing.Optional["_RestField"], value: typing.Any) -> typing.Any: + if not rf: + return _serialize(value, None) + if rf._is_multipart_file_input: + return value + if rf._is_model: + return _deserialize(rf._type, value) + if isinstance(value, ET.Element): + value = _deserialize(rf._type, value) + return _serialize(value, rf._format) + + +# ============================================================================ +# Fast-path scalar deserializer functions for rest_field(deserializer=...) +# These are referenced from rest_field declarations to bypass the generic +# _deserialize -> _deserialize_with_callable chain. +# Only simple/primitive types — no models or container types. +# ============================================================================ + + +def _xml_deser_str(value): + if isinstance(value, ET.Element): + return value.text or "" + return str(value) if value is not None else None + + +def _xml_deser_int(value): + if isinstance(value, ET.Element): + return int(value.text) if value.text else None + return int(value) if value is not None else None + + +def _xml_deser_float(value): + if isinstance(value, ET.Element): + return float(value.text) if value.text else None + return float(value) if value is not None else None + + +def _xml_deser_bool(value): + if isinstance(value, ET.Element): + text = value.text + else: + text = value + if text is None: + return None + if text in (True, False): + return text + return text.lower() == "true" + + +# pylint: disable=docstring-missing-param +def _xml_deser_bytes(value): + """Deserialize bytes from XML (base64).""" + if isinstance(value, ET.Element): + text = value.text + else: + text = value + if text is None: + return None + return _deserialize_bytes(text) + + +def _xml_deser_bytes_base64url(value): + """Deserialize bytes from XML (base64url).""" + if isinstance(value, ET.Element): + text = value.text + else: + text = value + if text is None: + return None + return _deserialize_bytes_base64(text) + + +def _xml_deser_datetime(value): + """Deserialize a datetime from XML (ISO 8601 / rfc3339).""" + if isinstance(value, ET.Element): + text = value.text + else: + text = value + if text is None: + return None + return _deserialize_datetime(text) + + +def _xml_deser_datetime_rfc7231(value): + """Deserialize a datetime from XML (RFC7231 format).""" + if isinstance(value, ET.Element): + text = value.text + else: + text = value + if text is None: + return None + return _deserialize_datetime_rfc7231(text) + + +def _xml_deser_datetime_unix_timestamp(value): + """Deserialize a datetime from XML (Unix timestamp).""" + if isinstance(value, ET.Element): + text = value.text + else: + text = value + if text is None: + return None + return _deserialize_datetime_unix_timestamp(float(text)) + + +def _xml_deser_date(value): + """Deserialize a date from XML (ISO 8601).""" + if isinstance(value, ET.Element): + text = value.text + else: + text = value + if text is None: + return None + return _deserialize_date(text) + + +def _xml_deser_time(value): + """Deserialize a time from XML (ISO 8601).""" + if isinstance(value, ET.Element): + text = value.text + else: + text = value + if text is None: + return None + return _deserialize_time(text) + + +def _xml_deser_duration(value): + """Deserialize a timedelta from XML (ISO 8601 duration).""" + if isinstance(value, ET.Element): + text = value.text + else: + text = value + if text is None: + return None + return _deserialize_duration(text) + + +def _xml_deser_decimal(value): + """Deserialize a Decimal from XML.""" + if isinstance(value, ET.Element): + text = value.text + else: + text = value + if text is None: + return None + return _deserialize_decimal(text) + + +def _xml_deser_enum_or_str(enum_cls, value): + """Deserialize a Union[EnumType, str] from XML.""" + text = value.text if isinstance(value, ET.Element) else value + if text is None: + return None + try: + return enum_cls(text) + except ValueError: + return text + + +def _extract_xml_model_type(rf_type): + """Extract the concrete Model class from a resolved rf._type partial chain. + + Unwraps ``Optional[Model]`` and ``_deserialize_model(Model, ...)`` + wrappers. Only handles Model and Optional[Model] — other composite + types (List, Dict, Union, etc.) return None and fall through to the + generic ``_deserialize`` path at runtime. + """ + if rf_type is None: + return None + if isinstance(rf_type, type) and _is_model(rf_type): + return rf_type + if not isinstance(rf_type, functools.partial): + return None + func = rf_type.func + args = rf_type.args + if func is _deserialize_with_optional and args: + return _extract_xml_model_type(args[0]) + if func is _deserialize_model and args: + cls = args[0] + return cls if isinstance(cls, type) and _is_model(cls) else None + return None + + +def _build_xml_field_plan( # pylint: disable=docstring-missing-return, docstring-missing-rtype, unused-variable + cls, attr_to_rest_field: dict +) -> list: + """Build a precomputed XML field plan for fast _init_from_xml iteration. + + Called once per model class in __new__. Returns a list of tuples: + (rest_name, xml_name, kind, deser, rf_type, is_optional, items_name) + + kind: 0=wrapped, 1=attribute, 2=unwrapped, 3=text + + For Model and Optional[Model] fields that lack a scalar + ``_deserializer``, this function precomputes the Model class as the + deserializer so ``_init_from_xml`` can call ``ModelClass(element)`` + directly instead of going through the expensive + ``_get_deserialize_callable_from_annotation`` chain at runtime. + """ + model_meta = getattr(cls, "_xml", {}) + model_ns = model_meta.get("ns") or model_meta.get("namespace") + plan = [] + + for rf in attr_to_rest_field.values(): + prop_meta = getattr(rf, "_xml", {}) + deser = rf._deserializer + + xml_name = prop_meta.get("name", rf._rest_name) + xml_ns = _resolve_xml_ns(prop_meta, model_meta) + if xml_ns: + xml_name = "{" + xml_ns + "}" + xml_name + + is_optional = rf._is_optional + + # For Model / Optional[Model] fields without a scalar deserializer, + # precompute the Model class as the deserializer. + if deser is None and rf._type is not None: + model_cls = _extract_xml_model_type(rf._type) + if model_cls is not None: + deser = model_cls + + if prop_meta.get("attribute", False): + plan.append((rf._rest_name, xml_name, 1, deser, rf._type, is_optional, None)) + elif prop_meta.get("unwrapped", False): + items_name = prop_meta.get("itemsName") + if items_name: + items_ns = prop_meta.get("itemsNs") + if items_ns is not None: + xml_ns = items_ns + if xml_ns: + items_name = "{" + xml_ns + "}" + items_name + else: + items_name = xml_name + plan.append((rf._rest_name, xml_name, 2, deser, rf._type, is_optional, items_name)) + elif prop_meta.get("text", False): + plan.append((rf._rest_name, xml_name, 3, deser, rf._type, is_optional, None)) + else: + plan.append((rf._rest_name, xml_name, 0, deser, rf._type, is_optional, None)) + + return plan + + +# pylint: enable=docstring-missing-param +class Model(_MyMutableMapping): + _is_model = True + # label whether current class's _attr_to_rest_field has been calculated + # could not see _attr_to_rest_field directly because subclass inherits it from parent class + _calculated: set[str] = set() + + def __init__(self, *args: typing.Any, **kwargs: typing.Any) -> None: + class_name = self.__class__.__name__ + if len(args) > 1: + raise TypeError(f"{class_name}.__init__() takes 2 positional arguments but {len(args) + 1} were given") + dict_to_pass: dict[str, typing.Any] = {} + if args: + if isinstance(args[0], ET.Element): + dict_to_pass.update(self._init_from_xml(args[0])) + else: + dict_to_pass.update( + {k: _create_value(_get_rest_field(self._attr_to_rest_field, k), v) for k, v in args[0].items()} + ) + else: + non_attr_kwargs = [k for k in kwargs if k not in self._attr_to_rest_field] + if non_attr_kwargs: + # actual type errors only throw the first wrong keyword arg they see, so following that. + raise TypeError(f"{class_name}.__init__() got an unexpected keyword argument '{non_attr_kwargs[0]}'") + dict_to_pass.update( + { + self._attr_to_rest_field[k]._rest_name: _create_value(self._attr_to_rest_field[k], v) + for k, v in kwargs.items() + if v is not None + } + ) + # Apply client default values for fields the caller didn't set so that + # defaults are part of `_data` and therefore included during serialization. + for rf in self._attr_to_rest_field.values(): + if rf._default is _UNSET: + continue + if rf._rest_name in dict_to_pass: + continue + dict_to_pass[rf._rest_name] = _create_value(rf, rf._default) + super().__init__(dict_to_pass) + + def _init_from_xml( # pylint: disable=too-many-branches, too-many-statements + self, element: ET.Element + ) -> dict[str, typing.Any]: + """Deserialize an XML element into a dict mapping rest field names to values. + + :param ET.Element element: The XML element to deserialize from. + :returns: A dictionary of rest_name to deserialized value pairs. + :rtype: dict + """ + result: dict[str, typing.Any] = {} + existed_attr_keys: list[str] = [] + + field_plan = getattr(self, "_xml_field_plan", None) + if field_plan: + for rest_name, xml_name, kind, deser, rf_type, is_optional, items_name in field_plan: + if kind == 0: # wrapped element (most common) + item = element.find(xml_name) + if item is not None: + existed_attr_keys.append(xml_name) + if deser: + result[rest_name] = deser(item) + else: + result[rest_name] = _deserialize(rf_type, item) + elif kind == 1: # attribute + attr_val = element.get(xml_name) + if attr_val is not None: + existed_attr_keys.append(xml_name) + if deser: + result[rest_name] = deser(attr_val) + else: + result[rest_name] = attr_val + elif kind == 2: # unwrapped array + items = element.findall(items_name) # pyright: ignore + if len(items) > 0: + existed_attr_keys.append(items_name) + if deser: + result[rest_name] = deser(items) + else: + result[rest_name] = _deserialize(rf_type, items) + elif not is_optional: + existed_attr_keys.append(items_name) + result[rest_name] = [] + elif kind == 3: # text + if element.text is not None: + if deser: + result[rest_name] = deser(element.text) + else: + result[rest_name] = element.text + else: + model_meta = getattr(self, "_xml", {}) + for rf in self._attr_to_rest_field.values(): + prop_meta = getattr(rf, "_xml", {}) + xml_name = prop_meta.get("name", rf._rest_name) + xml_ns = _resolve_xml_ns(prop_meta, model_meta) + if xml_ns: + xml_name = "{" + xml_ns + "}" + xml_name + + # attribute + if prop_meta.get("attribute", False) and element.get(xml_name) is not None: + existed_attr_keys.append(xml_name) + result[rf._rest_name] = _deserialize(rf._type, element.get(xml_name)) + continue + + # unwrapped element is array + if prop_meta.get("unwrapped", False): + _items_name = prop_meta.get("itemsName") + if _items_name: + xml_name = _items_name + _items_ns = prop_meta.get("itemsNs") + if _items_ns is not None: + xml_ns = _items_ns + if xml_ns: + xml_name = "{" + xml_ns + "}" + xml_name + items = element.findall(xml_name) # pyright: ignore + if len(items) > 0: + existed_attr_keys.append(xml_name) + result[rf._rest_name] = _deserialize(rf._type, items) + elif not rf._is_optional: + existed_attr_keys.append(xml_name) + result[rf._rest_name] = [] + continue + + # text element is primitive type + if prop_meta.get("text", False): + if element.text is not None: + result[rf._rest_name] = _deserialize(rf._type, element.text) + continue + + # wrapped element could be normal property or array + item = element.find(xml_name) + if item is not None: + existed_attr_keys.append(xml_name) + result[rf._rest_name] = _deserialize(rf._type, item) + + # rest thing is additional properties + for e in element: + if e.tag not in existed_attr_keys: + result[e.tag] = _convert_element(e) + + return result + + def copy(self) -> "Model": + return Model(self.__dict__) + + def __new__(cls, *args: typing.Any, **kwargs: typing.Any) -> Self: + if f"{cls.__module__}.{cls.__qualname__}" not in cls._calculated: + # we know the last nine classes in mro are going to be 'Model', '_MyMutableMapping', 'MutableMapping', + # 'Mapping', 'Collection', 'Sized', 'Iterable', 'Container' and 'object' + mros = cls.__mro__[:-9][::-1] # ignore parents, and reverse the mro order + attr_to_rest_field: dict[str, _RestField] = { # map attribute name to rest_field property + k: v for mro_class in mros for k, v in mro_class.__dict__.items() if k[0] != "_" and hasattr(v, "_type") + } + annotations = { + k: v + for mro_class in mros + if hasattr(mro_class, "__annotations__") + for k, v in mro_class.__annotations__.items() + } + for attr, rf in attr_to_rest_field.items(): + rf._module = cls.__module__ + if not rf._type: + rf._type = rf._get_deserialize_callable_from_annotation(annotations.get(attr, None)) + if not rf._rest_name_input: + rf._rest_name_input = attr + cls._attr_to_rest_field: dict[str, _RestField] = dict(attr_to_rest_field.items()) + cls._backcompat_attr_to_rest_field: dict[str, _RestField] = { + Model._get_backcompat_attribute_name(cls._attr_to_rest_field, attr): rf + for attr, rf in cls._attr_to_rest_field.items() + } + # Build XML field plan for fast _init_from_xml (only for XML models) + if getattr(cls, "_xml", None): + cls._xml_field_plan = _build_xml_field_plan(cls, attr_to_rest_field) + cls._calculated.add(f"{cls.__module__}.{cls.__qualname__}") + + return super().__new__(cls) + + def __init_subclass__(cls, discriminator: typing.Optional[str] = None) -> None: + for base in cls.__bases__: + if hasattr(base, "__mapping__"): + base.__mapping__[discriminator or cls.__name__] = cls # type: ignore + + @classmethod + def _get_backcompat_attribute_name(cls, attr_to_rest_field: dict[str, "_RestField"], attr_name: str) -> str: + rest_field_obj = attr_to_rest_field.get(attr_name) # pylint: disable=protected-access + if rest_field_obj is None: + return attr_name + original_tsp_name = getattr(rest_field_obj, "_original_tsp_name", None) # pylint: disable=protected-access + if original_tsp_name: + return original_tsp_name + return attr_name + + @classmethod + def _get_discriminator(cls, exist_discriminators) -> typing.Optional["_RestField"]: + for v in cls.__dict__.values(): + if isinstance(v, _RestField) and v._is_discriminator and v._rest_name not in exist_discriminators: + return v + return None + + @classmethod + def _deserialize(cls, data, exist_discriminators): + if not hasattr(cls, "__mapping__"): + return cls(data) + discriminator = cls._get_discriminator(exist_discriminators) + if discriminator is None: + return cls(data) + exist_discriminators.append(discriminator._rest_name) + if isinstance(data, ET.Element): + model_meta = getattr(cls, "_xml", {}) + prop_meta = getattr(discriminator, "_xml", {}) + xml_name = prop_meta.get("name", discriminator._rest_name) + xml_ns = _resolve_xml_ns(prop_meta, model_meta) + if xml_ns: + xml_name = "{" + xml_ns + "}" + xml_name + + if data.get(xml_name) is not None: + discriminator_value = data.get(xml_name) + else: + discriminator_value = data.find(xml_name).text # pyright: ignore + else: + discriminator_value = data.get(discriminator._rest_name) + mapped_cls = cls.__mapping__.get(discriminator_value, cls) # pyright: ignore # pylint: disable=no-member + return mapped_cls._deserialize(data, exist_discriminators) + + def as_dict(self, *, exclude_readonly: bool = False) -> dict[str, typing.Any]: + """Return a dict that can be turned into json using json.dump. + + :keyword bool exclude_readonly: Whether to remove the readonly properties. + :returns: A dict JSON compatible object + :rtype: dict + """ + + result = {} + readonly_props = [] + if exclude_readonly: + readonly_props = [p._rest_name for p in self._attr_to_rest_field.values() if _is_readonly(p)] + for k, v in self.items(): + if exclude_readonly and k in readonly_props: # pyright: ignore + continue + is_multipart_file_input = False + try: + is_multipart_file_input = next( + rf for rf in self._attr_to_rest_field.values() if rf._rest_name == k + )._is_multipart_file_input + except StopIteration: + pass + result[k] = v if is_multipart_file_input else Model._as_dict_value(v, exclude_readonly=exclude_readonly) + return result + + @staticmethod + def _as_dict_value(v: typing.Any, exclude_readonly: bool = False) -> typing.Any: + if v is None or isinstance(v, _Null): + return None + if isinstance(v, (list, tuple, set)): + return type(v)(Model._as_dict_value(x, exclude_readonly=exclude_readonly) for x in v) + if isinstance(v, dict): + return {dk: Model._as_dict_value(dv, exclude_readonly=exclude_readonly) for dk, dv in v.items()} + return v.as_dict(exclude_readonly=exclude_readonly) if hasattr(v, "as_dict") else v + + +def _deserialize_model(model_deserializer: typing.Optional[typing.Callable], obj): + if _is_model(obj): + return obj + return _deserialize(model_deserializer, obj) + + +def _deserialize_with_optional(if_obj_deserializer: typing.Optional[typing.Callable], obj): + if obj is None: + return obj + return _deserialize_with_callable(if_obj_deserializer, obj) + + +def _deserialize_with_union(deserializers, obj): + for deserializer in deserializers: + try: + return _deserialize(deserializer, obj) + except DeserializationError: + pass + raise DeserializationError() + + +def _deserialize_dict( + value_deserializer: typing.Optional[typing.Callable], + module: typing.Optional[str], + obj: dict[typing.Any, typing.Any], +): + if obj is None: + return obj + if isinstance(obj, ET.Element): + obj = {child.tag: child for child in obj} + return {k: _deserialize(value_deserializer, v, module) for k, v in obj.items()} + + +def _deserialize_multiple_sequence( + entry_deserializers: list[typing.Optional[typing.Callable]], + module: typing.Optional[str], + obj, +): + if obj is None: + return obj + return type(obj)(_deserialize(deserializer, entry, module) for entry, deserializer in zip(obj, entry_deserializers)) + + +def _is_array_encoded_deserializer(deserializer: functools.partial) -> bool: + return ( + isinstance(deserializer, functools.partial) + and isinstance(deserializer.args[0], functools.partial) + and deserializer.args[0].func == _deserialize_array_encoded # pylint: disable=comparison-with-callable + ) + + +def _deserialize_sequence( + deserializer: typing.Optional[typing.Callable], + module: typing.Optional[str], + obj, +): + if obj is None: + return obj + if isinstance(obj, ET.Element): + obj = list(obj) + + # encoded string may be deserialized to sequence + if isinstance(obj, str) and isinstance(deserializer, functools.partial): + # for list[str] + if _is_array_encoded_deserializer(deserializer): + return deserializer(obj) + + # for list[Union[...]] + if isinstance(deserializer.args[0], list): + for sub_deserializer in deserializer.args[0]: + if _is_array_encoded_deserializer(sub_deserializer): + return sub_deserializer(obj) + + return type(obj)(_deserialize(deserializer, entry, module) for entry in obj) + + +def _sorted_annotations(types: list[typing.Any]) -> list[typing.Any]: + return sorted( + types, + key=lambda x: hasattr(x, "__name__") and x.__name__.lower() in ("str", "float", "int", "bool"), + ) + + +def _get_deserialize_callable_from_annotation( # pylint: disable=too-many-return-statements, too-many-statements, too-many-branches + annotation: typing.Any, + module: typing.Optional[str], + rf: typing.Optional["_RestField"] = None, +) -> typing.Optional[typing.Callable[[typing.Any], typing.Any]]: + if not annotation: + return None + + # is it a type alias? + if isinstance(annotation, str): + if module is not None: + annotation = _get_type_alias_type(module, annotation) + + # is it a forward ref / in quotes? + if isinstance(annotation, (str, typing.ForwardRef)): + try: + model_name = annotation.__forward_arg__ # type: ignore + except AttributeError: + model_name = annotation + if module is not None: + annotation = _get_model(module, model_name) # type: ignore + + try: + if module and _is_model(annotation): + if rf: + rf._is_model = True + + return functools.partial(_deserialize_model, annotation) # pyright: ignore + except Exception: + pass + + # is it a literal? + try: + if annotation.__origin__ is typing.Literal: # pyright: ignore + return None + except AttributeError: + pass + + # is it optional? + try: + if any(a is _NONE_TYPE for a in annotation.__args__): # pyright: ignore + if rf: + rf._is_optional = True + if len(annotation.__args__) <= 2: # pyright: ignore + if_obj_deserializer = _get_deserialize_callable_from_annotation( + next(a for a in annotation.__args__ if a is not _NONE_TYPE), module, rf # pyright: ignore + ) + + return functools.partial(_deserialize_with_optional, if_obj_deserializer) + # the type is Optional[Union[...]], we need to remove the None type from the Union + annotation_copy = copy.copy(annotation) + annotation_copy.__args__ = [a for a in annotation_copy.__args__ if a is not _NONE_TYPE] # pyright: ignore + return _get_deserialize_callable_from_annotation(annotation_copy, module, rf) + except AttributeError: + pass + + # is it union? + if getattr(annotation, "__origin__", None) is typing.Union: + # initial ordering is we make `string` the last deserialization option, because it is often them most generic + deserializers = [ + _get_deserialize_callable_from_annotation(arg, module, rf) + for arg in _sorted_annotations(annotation.__args__) # pyright: ignore + ] + + return functools.partial(_deserialize_with_union, deserializers) + + try: + annotation_name = ( + annotation.__name__ if hasattr(annotation, "__name__") else annotation._name # pyright: ignore + ) + if annotation_name.lower() == "dict": + value_deserializer = _get_deserialize_callable_from_annotation( + annotation.__args__[1], module, rf # pyright: ignore + ) + + return functools.partial( + _deserialize_dict, + value_deserializer, + module, + ) + except (AttributeError, IndexError): + pass + try: + annotation_name = ( + annotation.__name__ if hasattr(annotation, "__name__") else annotation._name # pyright: ignore + ) + if annotation_name.lower() in ["list", "set", "tuple", "sequence"]: + if len(annotation.__args__) > 1: # pyright: ignore + entry_deserializers = [ + _get_deserialize_callable_from_annotation(dt, module, rf) + for dt in annotation.__args__ # pyright: ignore + ] + return functools.partial(_deserialize_multiple_sequence, entry_deserializers, module) + deserializer = _get_deserialize_callable_from_annotation( + annotation.__args__[0], module, rf # pyright: ignore + ) + + return functools.partial(_deserialize_sequence, deserializer, module) + except (TypeError, IndexError, AttributeError, SyntaxError): + pass + + def _deserialize_default( + deserializer, + obj, + ): + if obj is None: + return obj + try: + return _deserialize_with_callable(deserializer, obj) + except Exception: + pass + return obj + + if get_deserializer(annotation, rf): + return functools.partial(_deserialize_default, get_deserializer(annotation, rf)) + + return functools.partial(_deserialize_default, annotation) + + +def _deserialize_with_callable( + deserializer: typing.Optional[typing.Callable[[typing.Any], typing.Any]], + value: typing.Any, +): # pylint: disable=too-many-return-statements + try: + if value is None or isinstance(value, _Null): + return None + if isinstance(value, ET.Element): + if deserializer is str: + return value.text or "" + if deserializer is int: + return int(value.text) if value.text else None + if deserializer is float: + return float(value.text) if value.text else None + if deserializer is bool: + return value.text == "true" if value.text else None + if deserializer and deserializer in _DESERIALIZE_MAPPING.values(): + return deserializer(value.text) if value.text else None + if deserializer and deserializer in _DESERIALIZE_MAPPING_WITHFORMAT.values(): + return deserializer(value.text) if value.text else None + if deserializer is None: + return value + if deserializer in [int, float, bool]: + return deserializer(value) + if isinstance(deserializer, CaseInsensitiveEnumMeta): + try: + return deserializer(value.text if isinstance(value, ET.Element) else value) + except ValueError: + # for unknown value, return raw value + return value.text if isinstance(value, ET.Element) else value + if isinstance(deserializer, type) and issubclass(deserializer, Model): + return deserializer._deserialize(value, []) + return typing.cast(typing.Callable[[typing.Any], typing.Any], deserializer)(value) + except Exception as e: + raise DeserializationError() from e + + +def _deserialize( + deserializer: typing.Any, + value: typing.Any, + module: typing.Optional[str] = None, + rf: typing.Optional["_RestField"] = None, + format: typing.Optional[str] = None, +) -> typing.Any: + if isinstance(value, PipelineResponse): + value = value.http_response.json() + if rf is None and format: + rf = _RestField(format=format) + if not isinstance(deserializer, functools.partial): + deserializer = _get_deserialize_callable_from_annotation(deserializer, module, rf) + return _deserialize_with_callable(deserializer, value) + + +def _failsafe_deserialize( + deserializer: typing.Any, + response: HttpResponse, + module: typing.Optional[str] = None, + rf: typing.Optional["_RestField"] = None, + format: typing.Optional[str] = None, +) -> typing.Any: + try: + return _deserialize(deserializer, response.json(), module, rf, format) + except Exception: # pylint: disable=broad-except + _LOGGER.warning( + "Ran into a deserialization error. Ignoring since this is failsafe deserialization", exc_info=True + ) + return None + + +def _failsafe_deserialize_xml( + deserializer: typing.Any, + response: HttpResponse, +) -> typing.Any: + try: + return _deserialize_xml(deserializer, response.text()) + except Exception: # pylint: disable=broad-except + _LOGGER.warning( + "Ran into a deserialization error. Ignoring since this is failsafe deserialization", exc_info=True + ) + return None + + +# pylint: disable=too-many-instance-attributes +class _RestField: + def __init__( + self, + *, + name: typing.Optional[str] = None, + type: typing.Optional[typing.Callable] = None, # pylint: disable=redefined-builtin + is_discriminator: bool = False, + visibility: typing.Optional[list[str]] = None, + default: typing.Any = _UNSET, + format: typing.Optional[str] = None, + is_multipart_file_input: bool = False, + xml: typing.Optional[dict[str, typing.Any]] = None, + deserializer: typing.Optional[typing.Callable] = None, + original_tsp_name: typing.Optional[str] = None, + ): + self._type = type + self._rest_name_input = name + self._module: typing.Optional[str] = None + self._is_discriminator = is_discriminator + self._visibility = visibility + self._is_model = False + self._is_optional = False + self._default = default + self._format = format + self._is_multipart_file_input = is_multipart_file_input + self._xml = xml if xml is not None else {} + self._deserializer = deserializer + self._original_tsp_name = original_tsp_name + + @property + def _class_type(self) -> typing.Any: + result = getattr(self._type, "args", [None])[0] + # type may be wrapped by nested functools.partial so we need to check for that + if isinstance(result, functools.partial): + return getattr(result, "args", [None])[0] + return result + + @property + def _rest_name(self) -> str: + if self._rest_name_input is None: + raise ValueError("Rest name was never set") + return self._rest_name_input + + def __get__(self, obj: Model, type=None): # pylint: disable=redefined-builtin + # by this point, type and rest_name will have a value bc we default + # them in __new__ of the Model class + # Use _data.get() directly to avoid triggering __getitem__ which clears the cache + item = obj._data.get(self._rest_name, _UNSET) + if item is _UNSET: + # Field not set by user; return the client default if one exists, otherwise None + return self._default if self._default is not _UNSET else None + if item is None: + return item + if self._is_model: + return item + + # For mutable types, we want mutations to directly affect _data + # Check if we've already deserialized this value + cache_attr = f"_deserialized_{self._rest_name}" + if hasattr(obj, cache_attr): + # Return the value from _data directly (it's been deserialized in place) + return obj._data.get(self._rest_name) + + # Fast path: use _deserializer directly (avoids _serialize/_deserialize chain) + if self._deserializer: + deserialized = self._deserializer(item) + else: + deserialized = _deserialize(self._type, _serialize(item, self._format), rf=self) + + # For mutable types, store the deserialized value back in _data + # so mutations directly affect _data + if isinstance(deserialized, (dict, list, set)): + obj._data[self._rest_name] = deserialized + object.__setattr__(obj, cache_attr, True) # Mark as deserialized + return deserialized + + return deserialized + + def __set__(self, obj: Model, value) -> None: + # Clear the cached deserialized object when setting a new value + cache_attr = f"_deserialized_{self._rest_name}" + if hasattr(obj, cache_attr): + object.__delattr__(obj, cache_attr) + + if value is None: + # we want to wipe out entries if users set attr to None + try: + obj.__delitem__(self._rest_name) + except KeyError: + pass + return + if self._is_model: + if not _is_model(value): + value = _deserialize(self._type, value) + obj.__setitem__(self._rest_name, value) + return + obj.__setitem__(self._rest_name, _serialize(value, self._format)) + + def _get_deserialize_callable_from_annotation( + self, annotation: typing.Any + ) -> typing.Optional[typing.Callable[[typing.Any], typing.Any]]: + return _get_deserialize_callable_from_annotation(annotation, self._module, self) + + +def rest_field( + *, + name: typing.Optional[str] = None, + type: typing.Optional[typing.Callable] = None, # pylint: disable=redefined-builtin + visibility: typing.Optional[list[str]] = None, + default: typing.Any = _UNSET, + format: typing.Optional[str] = None, + is_multipart_file_input: bool = False, + xml: typing.Optional[dict[str, typing.Any]] = None, + deserializer: typing.Optional[typing.Callable] = None, + original_tsp_name: typing.Optional[str] = None, +) -> typing.Any: + return _RestField( + name=name, + type=type, + visibility=visibility, + default=default, + format=format, + is_multipart_file_input=is_multipart_file_input, + xml=xml, + deserializer=deserializer, + original_tsp_name=original_tsp_name, + ) + + +def rest_discriminator( + *, + name: typing.Optional[str] = None, + type: typing.Optional[typing.Callable] = None, # pylint: disable=redefined-builtin + visibility: typing.Optional[list[str]] = None, + xml: typing.Optional[dict[str, typing.Any]] = None, +) -> typing.Any: + return _RestField(name=name, type=type, is_discriminator=True, visibility=visibility, xml=xml) + + +def serialize_xml(model: Model, exclude_readonly: bool = False) -> str: + """Serialize a model to XML. + + :param Model model: The model to serialize. + :param bool exclude_readonly: Whether to exclude readonly properties. + :returns: The XML representation of the model. + :rtype: str + """ + return ET.tostring(_get_element(model, exclude_readonly), encoding="unicode") # type: ignore + + +def _get_xml_ns(meta: dict[str, typing.Any]) -> typing.Optional[str]: + """Return the XML namespace from a metadata dict, checking both 'ns' (old-style) and 'namespace' (DPG) keys. + + :param dict meta: The metadata dictionary to extract namespace from. + :returns: The namespace string if 'ns' or 'namespace' key is present, None otherwise. + :rtype: str or None + """ + ns = meta.get("ns") + if ns is None: + ns = meta.get("namespace") + return ns + + +def _resolve_xml_ns( + prop_meta: dict[str, typing.Any], model_meta: typing.Optional[dict[str, typing.Any]] = None +) -> typing.Optional[str]: + """Resolve XML namespace for a property, falling back to model namespace when appropriate. + + Checks the property metadata first; if no namespace is found and the model does not declare + an explicit prefix, falls back to the model-level namespace. + + :param dict prop_meta: The property metadata dictionary. + :param dict model_meta: The model metadata dictionary, used as fallback. + :returns: The resolved namespace string, or None. + :rtype: str or None + """ + ns = _get_xml_ns(prop_meta) + if ns is None and model_meta is not None and not model_meta.get("prefix"): + ns = _get_xml_ns(model_meta) + return ns + + +def _set_xml_attribute(element: ET.Element, name: str, value: typing.Any, prop_meta: dict[str, typing.Any]) -> None: + """Set an XML attribute on an element, handling namespace prefix registration. + + :param ET.Element element: The element to set the attribute on. + :param str name: The default attribute name (wire name). + :param any value: The attribute value. + :param dict prop_meta: The property metadata dictionary. + """ + xml_name = prop_meta.get("name", name) + _attr_ns = _get_xml_ns(prop_meta) + if _attr_ns: + _attr_prefix = prop_meta.get("prefix") + if _attr_prefix: + _safe_register_namespace(_attr_prefix, _attr_ns) + xml_name = "{" + _attr_ns + "}" + xml_name + element.set(xml_name, _get_primitive_type_value(value)) + + +def _get_element( + o: typing.Any, + exclude_readonly: bool = False, + parent_meta: typing.Optional[dict[str, typing.Any]] = None, + wrapped_element: typing.Optional[ET.Element] = None, +) -> typing.Union[ET.Element, list[ET.Element]]: + if _is_model(o): + model_meta = getattr(o, "_xml", {}) + + # if prop is a model, then use the prop element directly, else generate a wrapper of model + if wrapped_element is None: + # When serializing as an array item (parent_meta is set), check if the parent has an + # explicit itemsName. This ensures correct element names for unwrapped arrays (where + # the element tag is the property/items name, not the model type name). + _items_name = parent_meta.get("itemsName") if parent_meta is not None else None + element_name = _items_name if _items_name else (model_meta.get("name") or o.__class__.__name__) + _model_ns = _get_xml_ns(model_meta) + wrapped_element = _create_xml_element( + element_name, + model_meta.get("prefix"), + _model_ns, + ) + + readonly_props = [] + if exclude_readonly: + readonly_props = [p._rest_name for p in o._attr_to_rest_field.values() if _is_readonly(p)] + + for k, v in o.items(): + # do not serialize readonly properties + if exclude_readonly and k in readonly_props: + continue + + prop_rest_field = _get_rest_field(o._attr_to_rest_field, k) + if prop_rest_field: + prop_meta = getattr(prop_rest_field, "_xml").copy() + # use the wire name as xml name if no specific name is set + if prop_meta.get("name") is None: + prop_meta["name"] = k + else: + # additional properties will not have rest field, use the wire name as xml name + prop_meta = {"name": k} + + # Propagate model namespace to properties only for old-style "ns"-keyed models. + # DPG-generated models use the "namespace" key and explicitly declare namespace on + # each property that needs it, so propagation is intentionally skipped for them. + if prop_meta.get("ns") is None and model_meta.get("ns"): + prop_meta["ns"] = model_meta.get("ns") + prop_meta["prefix"] = model_meta.get("prefix") + + if prop_meta.get("unwrapped", False): + # unwrapped could only set on array + wrapped_element.extend(_get_element(v, exclude_readonly, prop_meta)) + elif prop_meta.get("text", False): + # text could only set on primitive type + wrapped_element.text = _get_primitive_type_value(v) + elif prop_meta.get("attribute", False): + _set_xml_attribute(wrapped_element, k, v, prop_meta) + else: + # other wrapped prop element + wrapped_element.append(_get_wrapped_element(v, exclude_readonly, prop_meta)) + return wrapped_element + if isinstance(o, list): + return [_get_element(x, exclude_readonly, parent_meta) for x in o] # type: ignore + if isinstance(o, dict): + result = [] + _dict_ns = _get_xml_ns(parent_meta) if parent_meta else None + for k, v in o.items(): + result.append( + _get_wrapped_element( + v, + exclude_readonly, + { + "name": k, + "ns": _dict_ns, + "prefix": parent_meta.get("prefix") if parent_meta else None, + }, + ) + ) + return result + + # primitive case need to create element based on parent_meta + if parent_meta: + _items_ns = parent_meta.get("itemsNs") + if _items_ns is None: + _items_ns = _get_xml_ns(parent_meta) + return _get_wrapped_element( + o, + exclude_readonly, + { + "name": parent_meta.get("itemsName", parent_meta.get("name")), + "prefix": parent_meta.get("itemsPrefix", parent_meta.get("prefix")), + "ns": _items_ns, + }, + ) + + raise ValueError("Could not serialize value into xml: " + o) + + +def _get_wrapped_element( + v: typing.Any, + exclude_readonly: bool, + meta: typing.Optional[dict[str, typing.Any]], +) -> ET.Element: + _meta_ns = _get_xml_ns(meta) if meta else None + wrapped_element = _create_xml_element( + meta.get("name") if meta else None, meta.get("prefix") if meta else None, _meta_ns + ) + if isinstance(v, (dict, list)): + wrapped_element.extend(_get_element(v, exclude_readonly, meta)) + elif _is_model(v): + _get_element(v, exclude_readonly, meta, wrapped_element) + else: + wrapped_element.text = _get_primitive_type_value(v) + return wrapped_element # type: ignore[no-any-return] + + +def _get_primitive_type_value(v) -> str: + if v is True: + return "true" + if v is False: + return "false" + if isinstance(v, _Null): + return "" + return str(v) + + +def _safe_register_namespace(prefix: str, ns: str) -> None: + """Register an XML namespace prefix, handling reserved prefix patterns. + + Some prefixes (e.g. 'ns2') match Python's reserved 'ns\\d+' pattern used for + auto-generated prefixes, causing register_namespace to raise ValueError. + Falls back to directly registering in the internal namespace map. + + :param str prefix: The namespace prefix to register. + :param str ns: The namespace URI. + """ + try: + ET.register_namespace(prefix, ns) + except ValueError: + _ns_map = getattr(ET, "_namespace_map", None) + if _ns_map is not None: + _ns_map[ns] = prefix + + +def _create_xml_element( + tag: typing.Any, prefix: typing.Optional[str] = None, ns: typing.Optional[str] = None +) -> ET.Element: + if prefix and ns: + _safe_register_namespace(prefix, ns) + if ns: + return ET.Element("{" + ns + "}" + tag) + return ET.Element(tag) + + +def _deserialize_xml( + deserializer: typing.Any, + value: str, +) -> typing.Any: + element = ET.fromstring(value) # nosec + if _is_model(deserializer): + return deserializer._deserialize(element, []) + return _deserialize(deserializer, element) + + +def _convert_element(e: ET.Element): + # dict case + if len(e.attrib) > 0 or len({child.tag for child in e}) > 1: + dict_result: dict[str, typing.Any] = {} + for child in e: + if dict_result.get(child.tag) is not None: + if isinstance(dict_result[child.tag], list): + dict_result[child.tag].append(_convert_element(child)) + else: + dict_result[child.tag] = [dict_result[child.tag], _convert_element(child)] + else: + dict_result[child.tag] = _convert_element(child) + dict_result.update(e.attrib) + return dict_result + # array case + if len(e) > 0: + array_result: list[typing.Any] = [] + for child in e: + array_result.append(_convert_element(child)) + return array_result + # primitive case + return e.text diff --git a/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/_serialization.py b/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/_utils/serialization.py similarity index 73% rename from sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/_serialization.py rename to sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/_utils/serialization.py index 648f84cc4e65..a088671e9c51 100644 --- a/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/_serialization.py +++ b/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/_utils/serialization.py @@ -1,30 +1,13 @@ +# pylint: disable=line-too-long,useless-suppression,too-many-lines +# coding=utf-8 # -------------------------------------------------------------------------- -# # 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. -# +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- -# pylint: skip-file +# pyright: reportUnnecessaryTypeIgnoreComment=false from base64 import b64decode, b64encode import calendar @@ -37,23 +20,37 @@ import re import sys import codecs +from typing import ( + Any, + cast, + Optional, + Union, + AnyStr, + IO, + Mapping, + Callable, + MutableMapping, +) try: from urllib import quote # type: ignore except ImportError: - from urllib.parse import quote # type: ignore + from urllib.parse import quote import xml.etree.ElementTree as ET -import isodate +import isodate # type: ignore -from typing import Dict, Any, cast, TYPE_CHECKING +from azure.core.exceptions import DeserializationError, SerializationError +from azure.core.serialization import NULL as CoreNull -from azure.core.exceptions import DeserializationError, SerializationError, raise_with_traceback +if sys.version_info >= (3, 11): + from typing import Self +else: + from typing_extensions import Self _BOM = codecs.BOM_UTF8.decode(encoding="utf-8") -if TYPE_CHECKING: - from typing import Optional, Union, AnyStr, IO, Mapping +JSON = MutableMapping[str, Any] class RawDeserializer: @@ -65,8 +62,7 @@ class RawDeserializer: CONTEXT_NAME = "deserialized_data" @classmethod - def deserialize_from_text(cls, data, content_type=None): - # type: (Optional[Union[AnyStr, IO]], Optional[str]) -> Any + 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. @@ -76,6 +72,8 @@ def deserialize_from_text(cls, data, content_type=None): :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. + :return: The deserialized data. + :rtype: object """ if hasattr(data, "read"): # Assume a stream @@ -97,7 +95,7 @@ def deserialize_from_text(cls, data, content_type=None): try: return json.loads(data_as_str) except ValueError as err: - raise DeserializationError("JSON is invalid: {}".format(err), err) + raise DeserializationError("JSON is invalid: {}".format(err), err) from err elif "xml" in (content_type or []): try: @@ -109,7 +107,7 @@ def deserialize_from_text(cls, data, content_type=None): pass return ET.fromstring(data_as_str) # nosec - except ET.ParseError: + except ET.ParseError as err: # 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 @@ -128,17 +126,23 @@ def _json_attemp(data): # 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("XML is invalid") from err + elif content_type.startswith("text/"): + return data_as_str raise DeserializationError("Cannot deserialize content-type: {}".format(content_type)) @classmethod - def deserialize_from_http_generics(cls, body_bytes, headers): - # type: (Optional[Union[AnyStr, IO]], Mapping) -> Any + 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" + + :param bytes body_bytes: The body of the response. + :param dict headers: The headers of the response. + :returns: The deserialized data. + :rtype: object """ # Try to use content-type from headers if available content_type = None @@ -156,13 +160,6 @@ def deserialize_from_http_generics(cls, body_bytes, headers): return None -try: - basestring # type: ignore - unicode_str = unicode # type: ignore -except NameError: - basestring = str # type: ignore - unicode_str = str # type: ignore - _LOGGER = logging.getLogger(__name__) try: @@ -170,80 +167,31 @@ def deserialize_from_http_generics(cls, body_bytes, headers): 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 -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 # type: ignore -except ImportError: - TZ_UTC = UTC() # type: ignore +TZ_UTC = datetime.timezone.utc _FLATTEN = re.compile(r"(? None: + self.additional_properties: Optional[dict[str, Any]] = {} + for k in kwargs: # pylint: disable=consider-using-dict-items 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): @@ -290,43 +245,57 @@ def __init__(self, **kwargs): else: setattr(self, k, kwargs[k]) - def __eq__(self, other): - """Compare objects by comparing all attributes.""" + def __eq__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are equal + :rtype: bool + """ if isinstance(other, self.__class__): return self.__dict__ == other.__dict__ return False - def __ne__(self, other): - """Compare objects by comparing all attributes.""" + def __ne__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are not equal + :rtype: bool + """ return not self.__eq__(other) - def __str__(self): + def __str__(self) -> str: return str(self.__dict__) @classmethod - def enable_additional_properties_sending(cls): + def enable_additional_properties_sending(cls) -> None: cls._attribute_map["additional_properties"] = {"key": "", "type": "{object}"} @classmethod - def is_xml_model(cls): + def is_xml_model(cls) -> bool: try: - cls._xml_map + cls._xml_map # type: ignore except AttributeError: return False return True @classmethod def _create_xml_node(cls): - """Create XML node.""" + """Create XML node. + + :returns: The XML node + :rtype: xml.etree.ElementTree.Element + """ try: - xml_map = cls._xml_map + 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=False, **kwargs): - """Return the JSON that would be sent to azure from this model. + def serialize(self, keep_readonly: bool = False, **kwargs: Any) -> JSON: + """Return the JSON that would be sent to server from this model. This is an alias to `as_dict(full_restapi_key_transformer, keep_readonly=False)`. @@ -337,10 +306,17 @@ def serialize(self, keep_readonly=False, **kwargs): :rtype: dict """ serializer = Serializer(self._infer_class_models()) - return serializer._serialize(self, keep_readonly=keep_readonly, **kwargs) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, keep_readonly=keep_readonly, **kwargs + ) - def as_dict(self, keep_readonly=True, key_transformer=attribute_transformer, **kwargs): - """Return a dict that can be JSONify using json.dump. + 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: @@ -366,12 +342,15 @@ def my_key_transformer(key, attr_desc, value): 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 :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) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, key_transformer=key_transformer, keep_readonly=keep_readonly, **kwargs + ) @classmethod def _infer_class_models(cls): @@ -381,25 +360,31 @@ def _infer_class_models(cls): 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: + except Exception: # pylint: disable=broad-exception-caught # Assume it's not Autorest generated (tests?). Add ourselves as dependencies. client_models = {cls.__name__: cls} return client_models @classmethod - def deserialize(cls, data, content_type=None): + def deserialize(cls, data: Any, content_type: Optional[str] = None) -> Self: """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 + :raises DeserializationError: if something went wrong + :rtype: Self """ deserializer = Deserializer(cls._infer_class_models()) - return deserializer(cls.__name__, data, content_type=content_type) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore @classmethod - def from_dict(cls, data, key_extractors=None, content_type=None): + def from_dict( + cls, + data: Any, + key_extractors: Optional[Callable[[str, dict[str, Any], Any], Any]] = None, + content_type: Optional[str] = None, + ) -> Self: """Parse a dict using given key extractor return a model. By default consider key @@ -407,13 +392,15 @@ def from_dict(cls, data, key_extractors=None, content_type=None): and last_rest_key_case_insensitive_extractor) :param dict data: A dict using RestAPI structure + :param function key_extractors: A key extractor function. :param str content_type: JSON by default, set application/xml if XML. :returns: An instance of this model - :raises: DeserializationError if something went wrong + :raises DeserializationError: if something went wrong + :rtype: Self """ deserializer = Deserializer(cls._infer_class_models()) - deserializer.key_extractors = ( - [ + deserializer.key_extractors = ( # type: ignore + [ # type: ignore attribute_key_case_insensitive_extractor, rest_key_case_insensitive_extractor, last_rest_key_case_insensitive_extractor, @@ -421,7 +408,7 @@ def from_dict(cls, data, key_extractors=None, content_type=None): if key_extractors is None else key_extractors ) - return deserializer(cls.__name__, data, content_type=content_type) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore @classmethod def _flatten_subtype(cls, key, objects): @@ -429,21 +416,25 @@ def _flatten_subtype(cls, key, objects): return {} result = dict(cls._subtype_map[key]) for valuetype in cls._subtype_map[key].values(): - result.update(objects[valuetype]._flatten_subtype(key, objects)) + result |= objects[valuetype]._flatten_subtype(key, objects) # pylint: disable=protected-access 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. + + :param dict response: The initial data + :param dict objects: The class objects + :returns: The class to be used + :rtype: class """ 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) + subtype_value = response.get(rest_api_response_key, None) or response.get(subtype_key, None) else: subtype_value = xml_key_extractor(subtype_key, cls._attribute_map[subtype_key], response) if subtype_value: @@ -453,7 +444,7 @@ def _classify(cls, response, objects): return cls flatten_mapping_type = cls._flatten_subtype(subtype_key, objects) try: - return objects[flatten_mapping_type[subtype_value]] + return objects[flatten_mapping_type[subtype_value]] # type: ignore except KeyError: _LOGGER.warning( "Subtype value %s has no mapping, use base class %s.", @@ -482,11 +473,13 @@ def _decode_attribute_map_key(key): inside the received data. :param str key: A key string from the generated code + :returns: The decoded key + :rtype: str """ return key.replace("\\.", ".") -class Serializer(object): +class Serializer: # pylint: disable=too-many-public-methods """Request object model serializer.""" basic_types = {str: "str", int: "int", bool: "bool", float: "float"} @@ -521,7 +514,7 @@ class Serializer(object): "multiple": lambda x, y: x % y != 0, } - def __init__(self, classes=None): + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: self.serialize_type = { "iso-8601": Serializer.serialize_iso, "rfc-1123": Serializer.serialize_rfc, @@ -537,17 +530,20 @@ def __init__(self, classes=None): "[]": self.serialize_iter, "{}": self.serialize_dict, } - self.dependencies = dict(classes) if classes else {} + self.dependencies: dict[str, type] = 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): + def _serialize( # pylint: disable=too-many-nested-blocks, too-many-branches, too-many-statements, too-many-locals + self, target_obj, data_type=None, **kwargs + ): """Serialize data into a string according to type. - :param target_obj: The data to be serialized. + :param object 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. + :raises SerializationError: if serialization fails. + :returns: The serialized data. """ key_transformer = kwargs.get("key_transformer", self.key_transformer) keep_readonly = kwargs.get("keep_readonly", False) @@ -573,17 +569,19 @@ def _serialize(self, target_obj, data_type=None, **kwargs): serialized = {} if is_xml_model_serialization: - serialized = target_obj._create_xml_node() + serialized = target_obj._create_xml_node() # pylint: disable=protected-access try: - attributes = target_obj._attribute_map + attributes = target_obj._attribute_map # pylint: disable=protected-access for attr, attr_desc in attributes.items(): attr_name = attr - if not keep_readonly and target_obj._validation.get(attr_name, {}).get("readonly", False): + if not keep_readonly and target_obj._validation.get( # pylint: disable=protected-access + 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) + serialized |= target_obj.additional_properties continue try: @@ -605,62 +603,63 @@ def _serialize(self, target_obj, data_type=None, **kwargs): 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) + 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 + serialized.text = new_attr # type: ignore continue if isinstance(new_attr, list): - serialized.extend(new_attr) + 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 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) + 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) + local_node.text = str(new_attr) + serialized.append(local_node) # type: ignore else: # JSON - for k in reversed(keys): - unflattened = {k: new_attr} - new_attr = unflattened + for k in reversed(keys): # type: ignore + new_attr = {k: new_attr} _new_attr = new_attr _serialized = serialized - for k in keys: + for k in keys: # type: ignore if k not in _serialized: - _serialized.update(_new_attr) - _new_attr = _new_attr[k] + _serialized.update(_new_attr) # type: ignore + _new_attr = _new_attr[k] # type: ignore _serialized = _serialized[k] - except ValueError: - continue + except ValueError as err: + if isinstance(err, SerializationError): + raise 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 + raise SerializationError(msg) from err + return serialized def body(self, data, data_type, **kwargs): """Serialize data intended for a request body. - :param data: The data to be serialized. + :param object 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 + :raises SerializationError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized request body """ # Just in case this is a dict - internal_data_type = data_type.strip("[]{}") - internal_data_type = self.dependencies.get(internal_data_type, None) + 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: @@ -675,7 +674,7 @@ def body(self, data, data_type, **kwargs): # We're not able to deal with additional properties for now. deserializer.additional_properties_detection = False if is_xml_model_serialization: - deserializer.key_extractors = [ + deserializer.key_extractors = [ # type: ignore attribute_key_case_insensitive_extractor, ] else: @@ -684,20 +683,22 @@ def body(self, data, data_type, **kwargs): attribute_key_case_insensitive_extractor, last_rest_key_case_insensitive_extractor, ] - data = deserializer._deserialize(data_type, data) + data = deserializer._deserialize(data_type, data) # pylint: disable=protected-access except DeserializationError as err: - raise_with_traceback(SerializationError, "Unable to build a model: " + str(err), err) + raise SerializationError("Unable to build a model: " + str(err)) from 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 name: The name of the URL path parameter. + :param object 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 + :returns: The serialized URL path + :raises TypeError: if serialization fails. + :raises ValueError: if data is None """ try: output = self.serialize_data(data, data_type, **kwargs) @@ -706,30 +707,30 @@ def url(self, name, data, data_type, **kwargs): if kwargs.get("skip_quote") is True: output = str(output) + output = output.replace("{", quote("{")).replace("}", quote("}")) else: output = quote(str(output), safe="") - except SerializationError: - raise TypeError("{} must be type {}.".format(name, data_type)) - else: - return output + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + 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 name: The name of the query parameter. + :param object 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 + :rtype: str, list + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized query parameter """ 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)) + do_quote = not kwargs.get("skip_quote", False) + return self.serialize_iter(data, internal_data_type, do_quote=do_quote, **kwargs) # Not a list, regular serialization output = self.serialize_data(data, data_type, **kwargs) @@ -739,19 +740,20 @@ def query(self, name, data, data_type, **kwargs): output = str(output) else: output = quote(str(output), safe="") - except SerializationError: - raise TypeError("{} must be type {}.".format(name, data_type)) - else: - return str(output) + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + 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 name: The name of the header. + :param object 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 + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized header """ try: if data_type in ["[str]"]: @@ -760,35 +762,36 @@ def header(self, name, data, data_type, **kwargs): 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) + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + 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 object 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. + :raises AttributeError: if required data is None. + :raises ValueError: if data is None + :raises SerializationError: if serialization fails. + :returns: The serialized data. + :rtype: str, int, float, bool, dict, list """ if data is None: raise ValueError("No value for given attribute") try: + if data is CoreNull: + 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: + if 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__) + enum_type = self.dependencies.get(data_type, cast(type, data.__class__)) if issubclass(enum_type, Enum): return Serializer.serialize_enum(data, enum_obj=enum_type) @@ -798,12 +801,11 @@ def serialize_data(self, data, data_type, **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) + raise SerializationError(msg.format(data, data_type)) from err + return self._serialize(data, **kwargs) @classmethod - def _get_custom_serializers(cls, data_type, **kwargs): + def _get_custom_serializers(cls, data_type, **kwargs): # pylint: disable=inconsistent-return-statements custom_serializer = kwargs.get("basic_types_serializers", {}).get(data_type) if custom_serializer: return custom_serializer @@ -819,23 +821,33 @@ def serialize_basic(cls, data, data_type, **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 obj data: Object to be serialized. :param str data_type: Type of object in the iterable. + :rtype: str, int, float, bool + :return: serialized object + :raises TypeError: raise if data_type is not one of str, int, float, bool. """ 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 + if data_type == "int": + return int(data) + if data_type == "float": + return float(data) + if data_type == "bool": + return bool(data) + raise TypeError("Unknown basic data type: {}".format(data_type)) @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. + :param str data: Object to be serialized. :rtype: str + :return: serialized object """ try: # If I received an enum, return its value return data.value @@ -843,14 +855,13 @@ def serialize_unicode(cls, data): pass try: - if isinstance(data, unicode): + 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) + return str(data) def serialize_iter(self, data, iter_type, div=None, **kwargs): """Serialize iterable. @@ -860,13 +871,13 @@ def serialize_iter(self, data, iter_type, div=None, **kwargs): 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 list data: 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'. + Defaults to False. :rtype: list, str + :return: serialized iterable """ if isinstance(data, str): raise SerializationError("Refuse str type as a valid iter type.") @@ -878,9 +889,14 @@ def serialize_iter(self, data, iter_type, div=None, **kwargs): for d in data: try: serialized.append(self.serialize_data(d, iter_type, **kwargs)) - except ValueError: + except ValueError as err: + if isinstance(err, SerializationError): + raise serialized.append(None) + if kwargs.get("do_quote", False): + serialized = ["" if s is None else quote(str(s), safe="") for s in serialized] + if div: serialized = ["" if s is None else str(s) for s in serialized] serialized = div.join(serialized) @@ -916,16 +932,17 @@ def serialize_dict(self, attr, dict_type, **kwargs): :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 + :return: serialized dictionary """ 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: + except ValueError as err: + if isinstance(err, SerializationError): + raise serialized[self.serialize_unicode(key)] = None if "xml" in serialization_ctxt: @@ -940,7 +957,7 @@ def serialize_dict(self, attr, dict_type, **kwargs): return serialized - def serialize_object(self, attr, **kwargs): + def serialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements """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 @@ -948,6 +965,7 @@ def serialize_object(self, attr, **kwargs): :param dict attr: Object to be serialized. :rtype: dict or str + :return: serialized object """ if attr is None: return None @@ -958,7 +976,7 @@ def serialize_object(self, attr, **kwargs): 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: + if obj_type is str: return self.serialize_unicode(attr) if obj_type is datetime.datetime: return self.serialize_iso(attr) @@ -972,7 +990,7 @@ def serialize_object(self, attr, **kwargs): 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): + if obj_type in self.dependencies.values() or isinstance(attr, Model): return self._serialize(attr) if obj_type == dict: @@ -1001,58 +1019,63 @@ def serialize_enum(attr, enum_obj=None): except AttributeError: result = attr try: - enum_obj(result) + enum_obj(result) # type: ignore return result - except ValueError: - for enum_value in enum_obj: + except ValueError as exc: + 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)) + raise SerializationError(error.format(attr, enum_obj)) from exc @staticmethod - def serialize_bytearray(attr, **kwargs): + def serialize_bytearray(attr, **kwargs): # pylint: disable=unused-argument """Serialize bytearray into base-64 string. - :param attr: Object to be serialized. + :param str attr: Object to be serialized. :rtype: str + :return: serialized base64 """ return b64encode(attr).decode() @staticmethod - def serialize_base64(attr, **kwargs): + def serialize_base64(attr, **kwargs): # pylint: disable=unused-argument """Serialize str into base-64 string. - :param attr: Object to be serialized. + :param str attr: Object to be serialized. :rtype: str + :return: serialized base64 """ encoded = b64encode(attr).decode("ascii") return encoded.strip("=").replace("+", "-").replace("/", "_") @staticmethod - def serialize_decimal(attr, **kwargs): + def serialize_decimal(attr, **kwargs): # pylint: disable=unused-argument """Serialize Decimal object to float. - :param attr: Object to be serialized. + :param decimal attr: Object to be serialized. :rtype: float + :return: serialized decimal """ return float(attr) @staticmethod - def serialize_long(attr, **kwargs): + def serialize_long(attr, **kwargs): # pylint: disable=unused-argument """Serialize long (Py2) or int (Py3). - :param attr: Object to be serialized. + :param int attr: Object to be serialized. :rtype: int/long + :return: serialized long """ return _long_type(attr) @staticmethod - def serialize_date(attr, **kwargs): + def serialize_date(attr, **kwargs): # pylint: disable=unused-argument """Serialize Date object into ISO-8601 formatted string. :param Date attr: Object to be serialized. :rtype: str + :return: serialized date """ if isinstance(attr, str): attr = isodate.parse_date(attr) @@ -1060,11 +1083,12 @@ def serialize_date(attr, **kwargs): return t @staticmethod - def serialize_time(attr, **kwargs): + def serialize_time(attr, **kwargs): # pylint: disable=unused-argument """Serialize Time object into ISO-8601 formatted string. :param datetime.time attr: Object to be serialized. :rtype: str + :return: serialized time """ if isinstance(attr, str): attr = isodate.parse_time(attr) @@ -1074,30 +1098,32 @@ def serialize_time(attr, **kwargs): return t @staticmethod - def serialize_duration(attr, **kwargs): + def serialize_duration(attr, **kwargs): # pylint: disable=unused-argument """Serialize TimeDelta object into ISO-8601 formatted string. :param TimeDelta attr: Object to be serialized. :rtype: str + :return: serialized duration """ if isinstance(attr, str): attr = isodate.parse_duration(attr) return isodate.duration_isoformat(attr) @staticmethod - def serialize_rfc(attr, **kwargs): + def serialize_rfc(attr, **kwargs): # pylint: disable=unused-argument """Serialize Datetime object into RFC-1123 formatted string. :param Datetime attr: Object to be serialized. :rtype: str - :raises: TypeError if format invalid. + :raises TypeError: if format invalid. + :return: serialized rfc """ 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.") + except AttributeError as exc: + raise TypeError("RFC1123 object must be valid Datetime object.") from exc return "{}, {:02} {} {:04} {:02}:{:02}:{:02} GMT".format( Serializer.days[utc.tm_wday], @@ -1110,12 +1136,13 @@ def serialize_rfc(attr, **kwargs): ) @staticmethod - def serialize_iso(attr, **kwargs): + def serialize_iso(attr, **kwargs): # pylint: disable=unused-argument """Serialize Datetime object into ISO-8601 formatted string. :param Datetime attr: Object to be serialized. :rtype: str - :raises: SerializationError if format invalid. + :raises SerializationError: if format invalid. + :return: serialized iso """ if isinstance(attr, str): attr = isodate.parse_datetime(attr) @@ -1135,19 +1162,20 @@ def serialize_iso(attr, **kwargs): return date + microseconds + "Z" except (ValueError, OverflowError) as err: msg = "Unable to serialize datetime object." - raise_with_traceback(SerializationError, msg, err) + raise SerializationError(msg) from err except AttributeError as err: msg = "ISO-8601 object must be valid Datetime object." - raise_with_traceback(TypeError, msg, err) + raise TypeError(msg) from err @staticmethod - def serialize_unix(attr, **kwargs): + def serialize_unix(attr, **kwargs): # pylint: disable=unused-argument """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 + :raises SerializationError: if format invalid + :return: serialied unix """ if isinstance(attr, int): return attr @@ -1155,16 +1183,17 @@ def serialize_unix(attr, **kwargs): 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.") + except AttributeError as exc: + raise TypeError("Unix time object must be valid Datetime object.") from exc -def rest_key_extractor(attr, attr_desc, data): +def rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument key = attr_desc["key"] working_data = data while "." in key: - dict_keys = _FLATTEN.split(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 @@ -1173,14 +1202,15 @@ def rest_key_extractor(attr, attr_desc, 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): +def rest_key_case_insensitive_extractor( # pylint: disable=unused-argument, inconsistent-return-statements + attr, attr_desc, data +): key = attr_desc["key"] working_data = data @@ -1194,7 +1224,6 @@ def rest_key_case_insensitive_extractor(attr, attr_desc, 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:]) @@ -1202,17 +1231,29 @@ def rest_key_case_insensitive_extractor(attr, attr_desc, 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.""" +def last_rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ 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): +def last_rest_key_case_insensitive_extractor(attr, attr_desc, data): # pylint: disable=unused-argument """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" + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute """ key = attr_desc["key"] dict_keys = _FLATTEN.split(key) @@ -1245,11 +1286,11 @@ def _extract_name_from_internal_type(internal_type): 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) + xml_name = "{{{}}}{}".format(xml_ns, xml_name) return xml_name -def xml_key_extractor(attr, attr_desc, data): +def xml_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument,too-many-return-statements if isinstance(data, dict): return None @@ -1269,7 +1310,7 @@ def xml_key_extractor(attr, attr_desc, data): # 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) + xml_name = "{{{}}}{}".format(xml_ns, xml_name) # If it's an attribute, that's simple if xml_desc.get("attr", False): @@ -1301,22 +1342,21 @@ def xml_key_extractor(attr, attr_desc, data): if is_iter_type: if is_wrapped: return None # is_wrapped no node, we want None - else: - return [] # not wrapped, assume empty list + 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 - ) + # 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. + ) + 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: @@ -1324,7 +1364,7 @@ def xml_key_extractor(attr, attr_desc, data): return children[0] -class Deserializer(object): +class Deserializer: """Response object model deserializer. :param dict classes: Class type dictionary for deserializing complex types. @@ -1333,9 +1373,9 @@ class Deserializer(object): 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}]?") + valid_date = re.compile(r"\d{4}[-]\d{2}[-]\d{2}T\d{2}:\d{2}:\d{2}\.?\d*Z?[-+]?[\d{2}]?:?[\d{2}]?") - def __init__(self, classes=None): + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: self.deserialize_type = { "iso-8601": Deserializer.deserialize_iso, "rfc-1123": Deserializer.deserialize_rfc, @@ -1355,7 +1395,7 @@ def __init__(self, classes=None): "duration": (isodate.Duration, datetime.timedelta), "iso-8601": (datetime.datetime), } - self.dependencies = dict(classes) if classes else {} + self.dependencies: dict[str, type] = 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 @@ -1365,33 +1405,56 @@ def __init__(self, classes=None): # Otherwise, result are unexpected self.additional_properties_detection = True - def __call__(self, target_obj, response_data, content_type=None): + def __call__(self, target_obj, response_data, content_type=None): # pylint: disable=too-many-return-statements """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. + :raises DeserializationError: if deserialization fails. :return: Deserialized object. + :rtype: object """ + # Fast path for header deserialization: response_data is a plain str or None + # and target_obj is a simple scalar type. This avoids the expensive + # _unpack_content → _deserialize → _classify_target → deserialize_data chain. + if response_data is None: + return None + if target_obj == "str" and isinstance(response_data, str): + return response_data + if isinstance(response_data, str): + if target_obj == "int": + return int(response_data) + if target_obj == "bool": + if response_data in ("true", "1", "True"): + return True + if response_data in ("false", "0", "False"): + return False + return bool(response_data) + if target_obj == "rfc-1123": + return Deserializer.deserialize_rfc(response_data) + if target_obj == "bytearray": + return Deserializer.deserialize_bytearray(response_data) + data = self._unpack_content(response_data, content_type) return self._deserialize(target_obj, data) - def _deserialize(self, target_obj, data): + def _deserialize(self, target_obj, data): # pylint: disable=inconsistent-return-statements """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. + :raises DeserializationError: if deserialization fails. :return: Deserialized object. + :rtype: 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(): + for attr, mapconfig in data._attribute_map.items(): # pylint: disable=protected-access if attr in constants: continue value = getattr(data, attr) @@ -1408,15 +1471,15 @@ def _deserialize(self, target_obj, data): response, class_name = self._classify_target(target_obj, data) - if isinstance(response, basestring): + if isinstance(response, str): return self.deserialize_data(data, response) - elif isinstance(response, type) and issubclass(response, Enum): + if isinstance(response, type) and issubclass(response, Enum): return self.deserialize_enum(data, response) - if data is None: + if data is None or data is CoreNull: return data try: - attributes = response._attribute_map + attributes = response._attribute_map # type: ignore # pylint: disable=protected-access d_attrs = {} for attr, attr_desc in attributes.items(): # Check empty string. If it's not empty, someone has a real "additionalProperties"... @@ -1444,11 +1507,10 @@ def _deserialize(self, target_obj, data): 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 - raise_with_traceback(DeserializationError, msg, err) - else: - additional_properties = self._build_additional_properties(attributes, data) - return self._instantiate_model(response, d_attrs, additional_properties) + msg = "Unable to deserialize to object: " + class_name # type: ignore + raise DeserializationError(msg) from err + 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: @@ -1474,22 +1536,24 @@ def _classify_target(self, target, data): 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 deseralize. + :param str/dict data: The response data to deserialize. + :return: The classified target object and its class name. + :rtype: tuple """ if target is None: return None, None - if isinstance(target, basestring): + if isinstance(target, str): try: target = self.dependencies[target] except KeyError: return target, target try: - target = target._classify(data, self.dependencies) + target = target._classify(data, self.dependencies) # type: ignore # pylint: disable=protected-access except AttributeError: pass # Target is not a Model, no classify - return target, target.__class__.__name__ + return target, target.__class__.__name__ # type: ignore def failsafe_deserialize(self, target_obj, data, content_type=None): """Ignores any errors encountered in deserialization, @@ -1499,13 +1563,15 @@ def failsafe_deserialize(self, target_obj, data, content_type=None): a deserialization error. :param str target_obj: The target object type to deserialize to. - :param str/dict data: The response data to deseralize. + :param str/dict data: The response data to deserialize. :param str content_type: Swagger "produces" if available. + :return: Deserialized object. + :rtype: object """ try: return self(target_obj, data, content_type=content_type) - except: - _LOGGER.warning( + except: # pylint: disable=bare-except + _LOGGER.debug( "Ran into a deserialization error. Ignoring since this is failsafe deserialization", exc_info=True ) return None @@ -1522,10 +1588,12 @@ def _unpack_content(raw_data, content_type=None): 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. + :param obj raw_data: Data to be processed. + :param str 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 + :rtype: object + :return: Unpacked content. """ # Assume this is enough to detect a Pipeline Response without importing it context = getattr(raw_data, "context", {}) @@ -1542,31 +1610,42 @@ def _unpack_content(raw_data, content_type=None): 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) + if isinstance(raw_data, (str, 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. + :param Response response: The response model class. + :param dict attrs: The deserialized response attributes. + :param dict additional_properties: Additional properties to be set. + :rtype: Response + :return: The instantiated response model. """ 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")] + readonly = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("readonly") + ] + const = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + 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 + response_obj.additional_properties = additional_properties # type: ignore return response_obj except TypeError as err: - msg = "Unable to deserialize {} into model {}. ".format(kwargs, response) - raise DeserializationError(msg + str(err)) + msg = "Unable to deserialize {} into model {}. ".format(kwargs, response) # type: ignore + raise DeserializationError(msg + str(err)) from err else: try: for attr, value in attrs.items(): @@ -1575,15 +1654,16 @@ def _instantiate_model(self, response, attrs, additional_properties=None): except Exception as exp: msg = "Unable to populate response model. " msg += "Type: {}, Error: {}".format(type(response), exp) - raise DeserializationError(msg) + raise DeserializationError(msg) from exp - def deserialize_data(self, data, data_type): + def deserialize_data(self, data, data_type): # pylint: disable=too-many-return-statements """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. + :raises DeserializationError: if deserialization fails. :return: Deserialized object. + :rtype: object """ if data is None: return data @@ -1597,7 +1677,11 @@ def deserialize_data(self, data, data_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"{}"] + is_a_text_parsing_type = lambda x: x not in [ # pylint: disable=unnecessary-lambda-assignment + "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) @@ -1616,15 +1700,15 @@ def deserialize_data(self, data, data_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) + raise DeserializationError(msg) from err + 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. + :return: Deserialized iterable. :rtype: list """ if attr is None: @@ -1641,6 +1725,7 @@ def deserialize_dict(self, attr, dict_type): :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. + :return: Deserialized dictionary. :rtype: dict """ if isinstance(attr, list): @@ -1651,20 +1736,21 @@ def deserialize_dict(self, attr, dict_type): 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): + def deserialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements """Deserialize a generic object. This will be handled as a dictionary. :param dict attr: Dictionary to be deserialized. + :return: Deserialized object. :rtype: dict - :raises: TypeError if non-builtin datatype encountered. + :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): + if isinstance(attr, str): return self.deserialize_basic(attr, "str") obj_type = type(attr) if obj_type in self.basic_types: @@ -1690,11 +1776,10 @@ def deserialize_object(self, attr, **kwargs): pass return deserialized - else: - error = "Cannot deserialize generic object with type: " - raise TypeError(error + str(obj_type)) + error = "Cannot deserialize generic object with type: " + raise TypeError(error + str(obj_type)) - def deserialize_basic(self, attr, data_type): + def deserialize_basic(self, attr, data_type): # pylint: disable=too-many-return-statements """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 @@ -1702,8 +1787,9 @@ def deserialize_basic(self, attr, data_type): :param str attr: response string to be deserialized. :param str data_type: deserialization data type. + :return: Deserialized basic type. :rtype: str, int, float or bool - :raises: TypeError if string format is not valid. + :raises TypeError: if string format is not valid or data_type is not one of str, int, float, bool. """ # If we're here, data is supposed to be a basic type. # If it's still an XML node, take the text @@ -1713,24 +1799,27 @@ def deserialize_basic(self, attr, data_type): 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 + # 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 isinstance(attr, str): if attr.lower() in ["true", "1"]: return True - elif attr.lower() in ["false", "0"]: + if 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 + if data_type == "int": + return int(attr) + if data_type == "float": + return float(attr) + raise TypeError("Unknown basic data type: {}".format(data_type)) @staticmethod def deserialize_unicode(data): @@ -1738,6 +1827,7 @@ def deserialize_unicode(data): as a string. :param str data: response string to be deserialized. + :return: Deserialized string. :rtype: str or unicode """ # We might be here because we have an enum modeled as string, @@ -1747,12 +1837,11 @@ def deserialize_unicode(data): # Consider this is real string try: - if isinstance(data, unicode): + if isinstance(data, unicode): # type: ignore return data except NameError: return str(data) - else: - return str(data) + return str(data) @staticmethod def deserialize_enum(data, enum_obj): @@ -1764,6 +1853,7 @@ def deserialize_enum(data, enum_obj): :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. + :return: Deserialized enum object. :rtype: Enum """ if isinstance(data, enum_obj) or data is None: @@ -1772,12 +1862,11 @@ def deserialize_enum(data, enum_obj): 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: + except IndexError as exc: error = "{!r} is not a valid index for enum {!r}" - raise DeserializationError(error.format(data, enum_obj)) + raise DeserializationError(error.format(data, enum_obj)) from exc try: return enum_obj(str(data)) except ValueError: @@ -1793,25 +1882,27 @@ def deserialize_bytearray(attr): """Deserialize string into bytearray. :param str attr: response string to be deserialized. + :return: Deserialized bytearray :rtype: bytearray - :raises: TypeError if string format invalid. + :raises TypeError: if string format invalid. """ if isinstance(attr, ET.Element): attr = attr.text - return bytearray(b64decode(attr)) + 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. + :return: Deserialized base64 string :rtype: bytearray - :raises: TypeError if string format invalid. + :raises TypeError: if string format invalid. """ if isinstance(attr, ET.Element): attr = attr.text - padding = "=" * (3 - (len(attr) + 3) % 4) - attr = attr + padding + padding = "=" * (3 - (len(attr) + 3) % 4) # type: ignore + attr = attr + padding # type: ignore encoded = attr.replace("-", "+").replace("_", "/") return b64decode(encoded) @@ -1820,36 +1911,39 @@ 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. + :return: Deserialized decimal + :raises DeserializationError: if string format invalid. + :rtype: decimal """ if isinstance(attr, ET.Element): attr = attr.text try: - return decimal.Decimal(attr) + return decimal.Decimal(str(attr)) # type: ignore except decimal.DecimalException as err: msg = "Invalid decimal {}".format(attr) - raise_with_traceback(DeserializationError, msg, err) + raise DeserializationError(msg) from err @staticmethod def deserialize_long(attr): """Deserialize string into long (Py2) or int (Py3). :param str attr: response string to be deserialized. + :return: Deserialized int :rtype: long or int - :raises: ValueError if string format invalid. + :raises ValueError: if string format invalid. """ if isinstance(attr, ET.Element): attr = attr.text - return _long_type(attr) + 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. + :return: Deserialized duration :rtype: TimeDelta - :raises: DeserializationError if string format invalid. + :raises DeserializationError: if string format invalid. """ if isinstance(attr, ET.Element): attr = attr.text @@ -1857,36 +1951,37 @@ def deserialize_duration(attr): 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 + raise DeserializationError(msg) from err + return duration @staticmethod def deserialize_date(attr): """Deserialize ISO-8601 formatted string into Date object. :param str attr: response string to be deserialized. + :return: Deserialized date :rtype: Date - :raises: DeserializationError if string format invalid. + :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): + 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) + return isodate.parse_date(attr, defaultmonth=0, defaultday=0) @staticmethod def deserialize_time(attr): """Deserialize ISO-8601 formatted string into time object. :param str attr: response string to be deserialized. + :return: Deserialized time :rtype: datetime.time - :raises: DeserializationError if string format invalid. + :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): + 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) @@ -1895,36 +1990,37 @@ def deserialize_rfc(attr): """Deserialize RFC-1123 formatted string into Datetime object. :param str attr: response string to be deserialized. + :return: Deserialized RFC datetime :rtype: Datetime - :raises: DeserializationError if string format invalid. + :raises DeserializationError: if string format invalid. """ if isinstance(attr, ET.Element): attr = attr.text try: - parsed_date = email.utils.parsedate_tz(attr) + 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)) + *parsed_date[:6], tzinfo=datetime.timezone(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 + raise DeserializationError(msg) from err + return date_obj @staticmethod def deserialize_iso(attr): """Deserialize ISO-8601 formatted string into Datetime object. :param str attr: response string to be deserialized. + :return: Deserialized ISO datetime :rtype: Datetime - :raises: DeserializationError if string format invalid. + :raises DeserializationError: if string format invalid. """ if isinstance(attr, ET.Element): attr = attr.text try: - attr = attr.upper() + attr = attr.upper() # type: ignore match = Deserializer.valid_date.match(attr) if not match: raise ValueError("Invalid datetime string: " + attr) @@ -1946,9 +2042,8 @@ def deserialize_iso(attr): 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 + raise DeserializationError(msg) from err + return date_obj @staticmethod def deserialize_unix(attr): @@ -1956,15 +2051,16 @@ def deserialize_unix(attr): This is represented as seconds. :param int attr: Object to be serialized. + :return: Deserialized datetime :rtype: Datetime - :raises: DeserializationError if format invalid + :raises DeserializationError: if format invalid """ if isinstance(attr, ET.Element): - attr = int(attr.text) + attr = int(attr.text) # type: ignore try: + attr = int(attr) 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 + raise DeserializationError(msg) from err + return date_obj diff --git a/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/_utils/utils.py b/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/_utils/utils.py new file mode 100644 index 000000000000..cbaa624660e4 --- /dev/null +++ b/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/_utils/utils.py @@ -0,0 +1,40 @@ +# -------------------------------------------------------------------------- +# 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) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from typing import Optional + +from azure.core import MatchConditions + + +def quote_etag(etag: Optional[str]) -> Optional[str]: + if not etag or etag == "*": + return etag + if etag.startswith("W/"): + return etag + if etag.startswith('"') and etag.endswith('"'): + return etag + if etag.startswith("'") and etag.endswith("'"): + return etag + return '"' + etag + '"' + + +def prep_if_match(etag: Optional[str], match_condition: Optional[MatchConditions]) -> Optional[str]: + if match_condition == MatchConditions.IfNotModified: + if_match = quote_etag(etag) if etag else None + return if_match + if match_condition == MatchConditions.IfPresent: + return "*" + return None + + +def prep_if_none_match(etag: Optional[str], match_condition: Optional[MatchConditions]) -> Optional[str]: + if match_condition == MatchConditions.IfModified: + if_none_match = quote_etag(etag) if etag else None + return if_none_match + if match_condition == MatchConditions.IfMissing: + return "*" + return None diff --git a/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/_vendor.py b/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/_vendor.py deleted file mode 100644 index 54f238858ed8..000000000000 --- a/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/_vendor.py +++ /dev/null @@ -1,17 +0,0 @@ -# -------------------------------------------------------------------------- -# 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. -# -------------------------------------------------------------------------- - - -def _format_url_section(template, **kwargs): - components = template.split("/") - while components: - try: - return template.format(**kwargs) - except KeyError as key: - formatted_components = template.split("/") - components = [c for c in formatted_components if "{}".format(key.args[0]) not in c] - template = "/".join(components) diff --git a/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/_version.py b/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/_version.py index 961c76eb77c1..ed0855dea5e6 100644 --- a/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/_version.py +++ b/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/_version.py @@ -2,8 +2,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. +# Code generated by Microsoft (R) Python Code Generator. # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- -VERSION = "1.0.1" +VERSION = "1.1.0" diff --git a/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/aio/__init__.py b/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/aio/__init__.py index ab8fd8c6084e..546e2154d7d3 100644 --- a/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/aio/__init__.py +++ b/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/aio/__init__.py @@ -2,20 +2,28 @@ # -------------------------------------------------------------------------- # 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. +# Code generated by Microsoft (R) Python Code Generator. # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- +# pylint: disable=wrong-import-position -from ._client import DeviceUpdateClient +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from ._patch import * # pylint: disable=unused-wildcard-import + +from ._client import DeviceUpdateClient # type: ignore try: from ._patch import __all__ as _patch_all - from ._patch import * # type: ignore # pylint: disable=unused-wildcard-import + from ._patch import * except ImportError: _patch_all = [] from ._patch import patch_sdk as _patch_sdk -__all__ = ["DeviceUpdateClient"] -__all__.extend([p for p in _patch_all if p not in __all__]) +__all__ = [ + "DeviceUpdateClient", +] +__all__.extend([p for p in _patch_all if p not in __all__]) # pyright: ignore _patch_sdk() diff --git a/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/aio/_client.py b/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/aio/_client.py index 0f8dc1115dd0..6eef4d350cdf 100644 --- a/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/aio/_client.py +++ b/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/aio/_client.py @@ -2,28 +2,32 @@ # -------------------------------------------------------------------------- # 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. +# Code generated by Microsoft (R) Python Code Generator. # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- from copy import deepcopy +import sys from typing import Any, Awaitable, TYPE_CHECKING from azure.core import AsyncPipelineClient +from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import DeviceUpdateClientConfiguration from .operations import DeviceManagementOperations, DeviceUpdateOperations -if TYPE_CHECKING: - # pylint: disable=unused-import,ungrouped-imports - from typing import Dict +if sys.version_info >= (3, 11): + from typing import Self +else: + from typing_extensions import Self # type: ignore +if TYPE_CHECKING: from azure.core.credentials_async import AsyncTokenCredential -class DeviceUpdateClient: # pylint: disable=client-accepts-api-version-keyword +class DeviceUpdateClient: """Device Update for IoT Hub is an Azure service that enables customers to publish updates for their IoT devices to the cloud, and then deploy that update to their devices (approve updates to groups of devices managed and provisioned in IoT Hub). It leverages the proven security and @@ -38,23 +42,42 @@ class DeviceUpdateClient: # pylint: disable=client-accepts-api-version-keyword :param endpoint: The Device Update for IoT Hub account endpoint (hostname only, no protocol). Required. :type endpoint: str + :param credential: Credential used to authenticate requests to the service. Required. + :type credential: ~azure.core.credentials_async.AsyncTokenCredential :param instance_id: The Device Update for IoT Hub account instance identifier. Required. :type instance_id: str - :param credential: Credential needed for the client to connect to Azure. Required. - :type credential: ~azure.core.credentials_async.AsyncTokenCredential - :keyword api_version: Api Version. Default value is "2022-10-01". Note that overriding this - default value may result in unsupported behavior. + :keyword api_version: The API version to use for this operation. Known values are "2026-06-01" + and None. Default value is None. If not set, the operation's default API version will be used. + Note that overriding this default value may result in unsupported behavior. :paramtype api_version: str :keyword int polling_interval: Default waiting time between two polls for LRO operations if no Retry-After header is present. """ - def __init__(self, endpoint: str, instance_id: str, credential: "AsyncTokenCredential", **kwargs: Any) -> None: + def __init__(self, endpoint: str, credential: "AsyncTokenCredential", instance_id: str, **kwargs: Any) -> None: _endpoint = "https://{endpoint}" self._config = DeviceUpdateClientConfiguration( - endpoint=endpoint, instance_id=instance_id, credential=credential, **kwargs + endpoint=endpoint, credential=credential, instance_id=instance_id, **kwargs ) - self._client = AsyncPipelineClient(base_url=_endpoint, config=self._config, **kwargs) + + _policies = kwargs.pop("policies", None) + if _policies is None: + _policies = [ + policies.RequestIdPolicy(**kwargs), + self._config.headers_policy, + self._config.user_agent_policy, + self._config.proxy_policy, + policies.ContentDecodePolicy(**kwargs), + self._config.redirect_policy, + self._config.retry_policy, + self._config.authentication_policy, + self._config.custom_hook_policy, + self._config.logging_policy, + policies.DistributedTracingPolicy(**kwargs), + policies.SensitiveHeaderCleanupPolicy(**kwargs) if self._config.redirect_policy else None, + self._config.http_logging_policy, + ] + self._client: AsyncPipelineClient = AsyncPipelineClient(base_url=_endpoint, policies=_policies, **kwargs) self._serialize = Serializer() self._deserialize = Deserializer() @@ -64,7 +87,9 @@ def __init__(self, endpoint: str, instance_id: str, credential: "AsyncTokenCrede self._client, self._config, self._serialize, self._deserialize ) - def send_request(self, request: HttpRequest, **kwargs: Any) -> Awaitable[AsyncHttpResponse]: + def send_request( + self, request: HttpRequest, *, stream: bool = False, **kwargs: Any + ) -> Awaitable[AsyncHttpResponse]: """Runs the network request through the client's chained policies. >>> from azure.core.rest import HttpRequest @@ -84,18 +109,18 @@ def send_request(self, request: HttpRequest, **kwargs: Any) -> Awaitable[AsyncHt 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"), } request_copy.url = self._client.format_url(request_copy.url, **path_format_arguments) - return self._client.send_request(request_copy, **kwargs) + return self._client.send_request(request_copy, stream=stream, **kwargs) # type: ignore async def close(self) -> None: await self._client.close() - async def __aenter__(self) -> "DeviceUpdateClient": + async def __aenter__(self) -> Self: 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/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/aio/_configuration.py b/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/aio/_configuration.py index 649663fe5902..39d2645ab5a3 100644 --- a/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/aio/_configuration.py +++ b/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/aio/_configuration.py @@ -2,23 +2,21 @@ # -------------------------------------------------------------------------- # 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. +# Code generated by Microsoft (R) Python Code Generator. # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- from typing import Any, TYPE_CHECKING -from azure.core.configuration import Configuration from azure.core.pipeline import policies from .._version import VERSION if TYPE_CHECKING: - # pylint: disable=unused-import,ungrouped-imports from azure.core.credentials_async import AsyncTokenCredential -class DeviceUpdateClientConfiguration(Configuration): # pylint: disable=too-many-instance-attributes +class DeviceUpdateClientConfiguration: # pylint: disable=too-many-instance-attributes """Configuration for DeviceUpdateClient. Note that all parameters used to create this instance are saved as instance @@ -27,32 +25,33 @@ class DeviceUpdateClientConfiguration(Configuration): # pylint: disable=too-man :param endpoint: The Device Update for IoT Hub account endpoint (hostname only, no protocol). Required. :type endpoint: str + :param credential: Credential used to authenticate requests to the service. Required. + :type credential: ~azure.core.credentials_async.AsyncTokenCredential :param instance_id: The Device Update for IoT Hub account instance identifier. Required. :type instance_id: str - :param credential: Credential needed for the client to connect to Azure. Required. - :type credential: ~azure.core.credentials_async.AsyncTokenCredential - :keyword api_version: Api Version. Default value is "2022-10-01". Note that overriding this - default value may result in unsupported behavior. + :keyword api_version: The API version to use for this operation. Known values are "2026-06-01" + and None. Default value is None. If not set, the operation's default API version will be used. + Note that overriding this default value may result in unsupported behavior. :paramtype api_version: str """ - def __init__(self, endpoint: str, instance_id: str, credential: "AsyncTokenCredential", **kwargs: Any) -> None: - super(DeviceUpdateClientConfiguration, self).__init__(**kwargs) - api_version = kwargs.pop("api_version", "2022-10-01") # type: str + def __init__(self, endpoint: str, credential: "AsyncTokenCredential", instance_id: str, **kwargs: Any) -> None: + api_version: str = kwargs.pop("api_version", "2026-06-01") if endpoint is None: raise ValueError("Parameter 'endpoint' must not be None.") - if instance_id is None: - raise ValueError("Parameter 'instance_id' must not be None.") if credential is None: raise ValueError("Parameter 'credential' must not be None.") + if instance_id is None: + raise ValueError("Parameter 'instance_id' must not be None.") self.endpoint = endpoint - self.instance_id = instance_id self.credential = credential + self.instance_id = instance_id self.api_version = api_version self.credential_scopes = kwargs.pop("credential_scopes", ["https://api.adu.microsoft.com/.default"]) kwargs.setdefault("sdk_moniker", "iot-deviceupdate/{}".format(VERSION)) + self.polling_interval = kwargs.get("polling_interval", 30) self._configure(**kwargs) def _configure(self, **kwargs: Any) -> None: @@ -61,9 +60,9 @@ def _configure(self, **kwargs: Any) -> None: 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.retry_policy = kwargs.get("retry_policy") or policies.AsyncRetryPolicy(**kwargs) self.authentication_policy = kwargs.get("authentication_policy") if self.credential and not self.authentication_policy: self.authentication_policy = policies.AsyncBearerTokenCredentialPolicy( diff --git a/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/aio/_patch.py b/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/aio/_patch.py index f99e77fef986..87676c65a8f0 100644 --- a/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/aio/_patch.py +++ b/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/aio/_patch.py @@ -1,31 +1,21 @@ # coding=utf-8 # -------------------------------------------------------------------------- -# # 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. -# +# Licensed under the MIT License. See License.txt in the project root for license information. # -------------------------------------------------------------------------- +"""Customize generated code here. + +Follow our quickstart for examples: https://aka.ms/azsdk/python/dpcodegen/python/customize +""" + + +__all__: list[str] = [] # Add all objects you want publicly available to users at this package level + -# 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 + """Do not remove from this file. + + `patch_sdk` is a last resort escape hatch that allows you to do customizations + you can't accomplish using the techniques described in + https://aka.ms/azsdk/python/dpcodegen/python/customize + """ diff --git a/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/aio/operations/__init__.py b/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/aio/operations/__init__.py index e15e9b8cde4a..f696baec55ea 100644 --- a/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/aio/operations/__init__.py +++ b/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/aio/operations/__init__.py @@ -2,20 +2,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. +# Code generated by Microsoft (R) Python Code Generator. # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- +# pylint: disable=wrong-import-position -from ._operations import DeviceUpdateOperations -from ._operations import DeviceManagementOperations +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from ._patch import * # pylint: disable=unused-wildcard-import + +from ._operations import DeviceUpdateOperations # type: ignore +from ._operations import DeviceManagementOperations # type: ignore from ._patch import __all__ as _patch_all -from ._patch import * # type: ignore # pylint: disable=unused-wildcard-import +from ._patch import * from ._patch import patch_sdk as _patch_sdk __all__ = [ "DeviceUpdateOperations", "DeviceManagementOperations", ] -__all__.extend([p for p in _patch_all if p not in __all__]) +__all__.extend([p for p in _patch_all if p not in __all__]) # pyright: ignore _patch_sdk() diff --git a/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/aio/operations/_operations.py b/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/aio/operations/_operations.py index b4650a38d604..47aaedcfd5ad 100644 --- a/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/aio/operations/_operations.py +++ b/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/aio/operations/_operations.py @@ -3,30 +3,39 @@ # -------------------------------------------------------------------------- # 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. +# Code generated by Microsoft (R) Python Code Generator. # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- -import sys -from typing import Any, AsyncIterable, Callable, Dict, IO, List, Optional, TypeVar, Union, cast, overload -from urllib.parse import parse_qs, urljoin, urlparse +from collections.abc import MutableMapping +from io import IOBase +import json +from typing import Any, AsyncIterator, Callable, IO, Optional, TypeVar, Union, cast, overload +import urllib.parse +from azure.core import AsyncPipelineClient, MatchConditions from azure.core.async_paging import AsyncItemPaged, AsyncList from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, ResourceExistsError, + ResourceModifiedError, ResourceNotFoundError, + ResourceNotModifiedError, + StreamClosedError, + StreamConsumedError, map_error, ) from azure.core.pipeline import PipelineResponse -from azure.core.pipeline.transport import AsyncHttpResponse from azure.core.polling import AsyncLROPoller, AsyncNoPolling, AsyncPollingMethod from azure.core.polling.async_base_polling import AsyncLROBasePolling -from azure.core.rest import HttpRequest +from azure.core.rest import AsyncHttpResponse, HttpRequest from azure.core.tracing.decorator import distributed_trace from azure.core.tracing.decorator_async import distributed_trace_async from azure.core.utils import case_insensitive_dict +from ... import models as _models +from ..._utils.model_base import SdkJSONEncoder, _deserialize, _failsafe_deserialize +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import ( build_device_management_create_or_update_deployment_request, build_device_management_delete_deployment_for_device_class_subgroup_request, @@ -79,14 +88,11 @@ build_device_update_list_updates_request, build_device_update_list_versions_request, ) +from .._configuration import DeviceUpdateClientConfiguration -if sys.version_info >= (3, 9): - from collections.abc import MutableMapping -else: - from typing import MutableMapping # type: ignore # pylint: disable=ungrouped-imports -JSON = MutableMapping[str, Any] # pylint: disable=unsubscriptable-object +JSON = MutableMapping[str, Any] T = TypeVar("T") -ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] +ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, dict[str, Any]], Any]] class DeviceUpdateOperations: @@ -101,105 +107,42 @@ class DeviceUpdateOperations: 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") + self._client: AsyncPipelineClient = input_args.pop(0) if input_args else kwargs.pop("client") + self._config: DeviceUpdateClientConfiguration = input_args.pop(0) if input_args else kwargs.pop("config") + self._serialize: Serializer = input_args.pop(0) if input_args else kwargs.pop("serializer") + self._deserialize: Deserializer = input_args.pop(0) if input_args else kwargs.pop("deserializer") @distributed_trace def list_updates( self, *, search: Optional[str] = None, filter: Optional[str] = None, **kwargs: Any - ) -> AsyncIterable[JSON]: + ) -> AsyncItemPaged["_models.Update"]: """Get a list of all updates that have been imported to Device Update for IoT Hub. :keyword search: Request updates matching a free-text search expression. Default value is None. :paramtype search: str :keyword filter: Optional to filter updates by isDeployable property. Default value is None. :paramtype filter: str - :return: An iterator like instance of JSON object - :rtype: ~azure.core.async_paging.AsyncItemPaged[JSON] + :return: An iterator like instance of Update + :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.iot.deviceupdate.models.Update] :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "compatibility": [ - { - "str": "str" # List of update compatibility information. - Required. - } - ], - "createdDateTime": "2020-02-20 00:00:00", # Date and time in UTC when the - update was created. Required. - "importedDateTime": "2020-02-20 00:00:00", # Date and time in UTC when the - update was imported. Required. - "manifestVersion": "str", # Schema version of manifest used to import the - update. Required. - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description specified by creator. - "etag": "str", # Optional. Update ETag. - "friendlyName": "str", # Optional. Friendly update name specified by - importer. - "installedCriteria": "str", # Optional. String interpreted by Device Update - client to determine if the update is installed on the device. Deprecated in - latest import manifest schema. - "instructions": { - "steps": [ - { - "description": "str", # Optional. Step description. - "files": [ - "str" # Optional. Collection of file names - to be passed to handler during execution. Required if step type - is inline. - ], - "handler": "str", # Optional. Identity of handler - that will execute this step. Required if step type is inline. - "handlerProperties": {}, # Optional. Parameters to - be passed to handler during execution. - "type": "inline", # Optional. Default value is - "inline". Step type. Known values are: "Inline" and "Reference". - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. - Required. - "version": "str" # Update version. Required. - } - } - ] - }, - "isDeployable": True, # Optional. Default value is True. Whether the update - can be deployed to a device on its own. - "referencedBy": [ - { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - } - ], - "scanResult": "str", # Optional. Update aggregate scan result (calculated - from payload file scan results). - "updateType": "str" # Optional. Update type. Deprecated in latest import - manifest schema. - } """ _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls = kwargs.pop("cls", None) # type: ClsType[JSON] + cls: ClsType[list[_models.Update]] = kwargs.pop("cls", None) - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } error_map.update(kwargs.pop("error_map", {}) or {}) def prepare_request(next_link=None): if not next_link: - request = build_device_update_list_updates_request( + _request = build_device_update_list_updates_request( instance_id=self._config.instance_id, search=search, filter=filter, @@ -208,430 +151,225 @@ def prepare_request(next_link=None): params=_params, ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) else: # make call to next link with the client's api-version - _parsed_next_link = urlparse(next_link) - _next_request_params = case_insensitive_dict(parse_qs(_parsed_next_link.query)) + _parsed_next_link = urllib.parse.urlparse(next_link) + _next_request_params = case_insensitive_dict( + { + key: [urllib.parse.quote(v) for v in value] + for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items() + } + ) _next_request_params["api-version"] = self._config.api_version - request = HttpRequest("GET", urljoin(next_link, _parsed_next_link.path), params=_next_request_params) + _request = HttpRequest( + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + headers=_headers, + params=_next_request_params, + ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - return request + return _request async def extract_data(pipeline_response): deserialized = pipeline_response.http_response.json() - list_of_elem = deserialized["value"] + list_of_elem = _deserialize( + list[_models.Update], + deserialized.get("value", []), + ) if cls: - list_of_elem = cls(list_of_elem) - return deserialized.get("nextLink", None), AsyncList(list_of_elem) + list_of_elem = cls(list_of_elem) # type: ignore + return deserialized.get("nextLink") or None, AsyncList(list_of_elem) async def get_next(next_link=None): - request = prepare_request(next_link) + _request = prepare_request(next_link) - pipeline_response = await self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _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) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) return pipeline_response return AsyncItemPaged(get_next, extract_data) - async def _import_update_initial(self, update_to_import: Union[List[JSON], IO], **kwargs: Any) -> Optional[JSON]: - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + async def _import_update_initial( + self, update_to_import: Union[list[_models.ImportUpdateInputItem], list[JSON], IO[bytes]], **kwargs: Any + ) -> AsyncIterator[bytes]: + error_map: MutableMapping = { + 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 = kwargs.pop("content_type", _headers.pop("Content-Type", None)) # type: Optional[str] - cls = kwargs.pop("cls", None) # type: ClsType[Optional[JSON]] + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[AsyncIterator[bytes]] = kwargs.pop("cls", None) content_type = content_type or "application/json" - _json = None _content = None - if isinstance(update_to_import, (IO, bytes)): + if isinstance(update_to_import, (IOBase, bytes)): _content = update_to_import else: - _json = update_to_import + _content = json.dumps(update_to_import, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - request = build_device_update_import_update_request( + _request = build_device_update_import_update_request( instance_id=self._config.instance_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), + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - pipeline_response = await self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _decompress = kwargs.pop("decompress", True) + _stream = True + 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, 202]: + try: + await response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) - deserialized = None response_headers = {} - if response.status_code == 200: - if response.content: - deserialized = response.json() - else: - deserialized = None - if response.status_code == 202: response_headers["Operation-Location"] = self._deserialize( "str", response.headers.get("Operation-Location") ) + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + if cls: - return cls(pipeline_response, deserialized, response_headers) + return cls(pipeline_response, deserialized, response_headers) # type: ignore - return deserialized + return deserialized # type: ignore @overload async def begin_import_update( - self, update_to_import: List[JSON], *, content_type: str = "application/json", **kwargs: Any - ) -> AsyncLROPoller[JSON]: + self, + update_to_import: list[_models.ImportUpdateInputItem], + *, + content_type: str = "application/json", + **kwargs: Any + ) -> AsyncLROPoller[None]: """Import new update version. This is a long-running-operation; use Operation-Location response header value to check for operation status. :param update_to_import: The update to be imported (see schema - https://json.schemastore.org/azure-deviceupdate-import-manifest-5.0.json for details). - Required. - :type update_to_import: list[JSON] + `https://json.schemastore.org/azure-deviceupdate-import-manifest-5.0.json + `_ for + details). Required. + :type update_to_import: list[~azure.iot.deviceupdate.models.ImportUpdateInputItem] :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str - :keyword str continuation_token: A continuation token to restart a poller from a saved state. - :keyword polling: By default, your polling method will be AsyncLROBasePolling. Pass in False - for this operation to not poll, or pass in your own initialized polling object for a personal - polling strategy. - :paramtype polling: bool or ~azure.core.polling.AsyncPollingMethod - :keyword int polling_interval: Default waiting time between two polls for LRO operations if no - Retry-After header is present. - :return: An instance of AsyncLROPoller that returns JSON object - :rtype: ~azure.core.polling.AsyncLROPoller[JSON] + :return: An instance of AsyncLROPoller that returns None + :rtype: ~azure.core.polling.AsyncLROPoller[None] :raises ~azure.core.exceptions.HttpResponseError: + """ - Example: - .. code-block:: python + @overload + async def begin_import_update( + self, update_to_import: list[JSON], *, content_type: str = "application/json", **kwargs: Any + ) -> AsyncLROPoller[None]: + """Import new update version. This is a long-running-operation; use Operation-Location response + header value to check for operation status. - # JSON input template you can fill out and use as your body input. - update_to_import = [ - { - "importManifest": { - "hashes": { - "str": "str" # A JSON object containing the hash(es) - of the file. At least SHA256 hash is required. This object can be - thought of as a set of key-value pairs where the key is the hash - algorithm, and the value is the hash of the file calculated using - that algorithm. Required. - }, - "sizeInBytes": 0, # File size in number of bytes. Required. - "url": "str" # Azure Blob location from which the import - manifest can be downloaded by Device Update for IoT Hub. This is - typically a read-only SAS-protected blob URL with an expiration set to at - least 4 hours. Required. - }, - "files": [ - { - "filename": "str", # Update file name as specified - inside import manifest. Required. - "url": "str" # Azure Blob location from which the - update file can be downloaded by Device Update for IoT Hub. This is - typically a read-only SAS-protected blob URL with an expiration set - to at least 4 hours. Required. - } - ], - "friendlyName": "str" # Optional. Friendly update name. - } - ] - - # response body for status code(s): 200 - response == { - "compatibility": [ - { - "str": "str" # List of update compatibility information. - Required. - } - ], - "createdDateTime": "2020-02-20 00:00:00", # Date and time in UTC when the - update was created. Required. - "importedDateTime": "2020-02-20 00:00:00", # Date and time in UTC when the - update was imported. Required. - "manifestVersion": "str", # Schema version of manifest used to import the - update. Required. - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description specified by creator. - "etag": "str", # Optional. Update ETag. - "friendlyName": "str", # Optional. Friendly update name specified by - importer. - "installedCriteria": "str", # Optional. String interpreted by Device Update - client to determine if the update is installed on the device. Deprecated in - latest import manifest schema. - "instructions": { - "steps": [ - { - "description": "str", # Optional. Step description. - "files": [ - "str" # Optional. Collection of file names - to be passed to handler during execution. Required if step type - is inline. - ], - "handler": "str", # Optional. Identity of handler - that will execute this step. Required if step type is inline. - "handlerProperties": {}, # Optional. Parameters to - be passed to handler during execution. - "type": "inline", # Optional. Default value is - "inline". Step type. Known values are: "Inline" and "Reference". - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. - Required. - "version": "str" # Update version. Required. - } - } - ] - }, - "isDeployable": True, # Optional. Default value is True. Whether the update - can be deployed to a device on its own. - "referencedBy": [ - { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - } - ], - "scanResult": "str", # Optional. Update aggregate scan result (calculated - from payload file scan results). - "updateType": "str" # Optional. Update type. Deprecated in latest import - manifest schema. - } + :param update_to_import: The update to be imported (see schema + `https://json.schemastore.org/azure-deviceupdate-import-manifest-5.0.json + `_ for + details). Required. + :type update_to_import: list[JSON] + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: An instance of AsyncLROPoller that returns None + :rtype: ~azure.core.polling.AsyncLROPoller[None] + :raises ~azure.core.exceptions.HttpResponseError: """ @overload async def begin_import_update( - self, update_to_import: IO, *, content_type: str = "application/json", **kwargs: Any - ) -> AsyncLROPoller[JSON]: + self, update_to_import: IO[bytes], *, content_type: str = "application/json", **kwargs: Any + ) -> AsyncLROPoller[None]: """Import new update version. This is a long-running-operation; use Operation-Location response header value to check for operation status. :param update_to_import: The update to be imported (see schema - https://json.schemastore.org/azure-deviceupdate-import-manifest-5.0.json for details). - Required. - :type update_to_import: IO + `https://json.schemastore.org/azure-deviceupdate-import-manifest-5.0.json + `_ for + details). Required. + :type update_to_import: IO[bytes] :keyword content_type: Body Parameter content-type. Content type parameter for binary body. Default value is "application/json". :paramtype content_type: str - :keyword str continuation_token: A continuation token to restart a poller from a saved state. - :keyword polling: By default, your polling method will be AsyncLROBasePolling. Pass in False - for this operation to not poll, or pass in your own initialized polling object for a personal - polling strategy. - :paramtype polling: bool or ~azure.core.polling.AsyncPollingMethod - :keyword int polling_interval: Default waiting time between two polls for LRO operations if no - Retry-After header is present. - :return: An instance of AsyncLROPoller that returns JSON object - :rtype: ~azure.core.polling.AsyncLROPoller[JSON] + :return: An instance of AsyncLROPoller that returns None + :rtype: ~azure.core.polling.AsyncLROPoller[None] :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "compatibility": [ - { - "str": "str" # List of update compatibility information. - Required. - } - ], - "createdDateTime": "2020-02-20 00:00:00", # Date and time in UTC when the - update was created. Required. - "importedDateTime": "2020-02-20 00:00:00", # Date and time in UTC when the - update was imported. Required. - "manifestVersion": "str", # Schema version of manifest used to import the - update. Required. - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description specified by creator. - "etag": "str", # Optional. Update ETag. - "friendlyName": "str", # Optional. Friendly update name specified by - importer. - "installedCriteria": "str", # Optional. String interpreted by Device Update - client to determine if the update is installed on the device. Deprecated in - latest import manifest schema. - "instructions": { - "steps": [ - { - "description": "str", # Optional. Step description. - "files": [ - "str" # Optional. Collection of file names - to be passed to handler during execution. Required if step type - is inline. - ], - "handler": "str", # Optional. Identity of handler - that will execute this step. Required if step type is inline. - "handlerProperties": {}, # Optional. Parameters to - be passed to handler during execution. - "type": "inline", # Optional. Default value is - "inline". Step type. Known values are: "Inline" and "Reference". - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. - Required. - "version": "str" # Update version. Required. - } - } - ] - }, - "isDeployable": True, # Optional. Default value is True. Whether the update - can be deployed to a device on its own. - "referencedBy": [ - { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - } - ], - "scanResult": "str", # Optional. Update aggregate scan result (calculated - from payload file scan results). - "updateType": "str" # Optional. Update type. Deprecated in latest import - manifest schema. - } """ @distributed_trace_async - async def begin_import_update(self, update_to_import: Union[List[JSON], IO], **kwargs: Any) -> AsyncLROPoller[JSON]: + async def begin_import_update( + self, update_to_import: Union[list[_models.ImportUpdateInputItem], list[JSON], IO[bytes]], **kwargs: Any + ) -> AsyncLROPoller[None]: """Import new update version. This is a long-running-operation; use Operation-Location response header value to check for operation status. :param update_to_import: The update to be imported (see schema - https://json.schemastore.org/azure-deviceupdate-import-manifest-5.0.json for details). Is - either a list type or a IO type. Required. - :type update_to_import: list[JSON] or IO - :keyword content_type: Body Parameter content-type. Known values are: 'application/json'. - Default value is None. - :paramtype content_type: str - :keyword str continuation_token: A continuation token to restart a poller from a saved state. - :keyword polling: By default, your polling method will be AsyncLROBasePolling. Pass in False - for this operation to not poll, or pass in your own initialized polling object for a personal - polling strategy. - :paramtype polling: bool or ~azure.core.polling.AsyncPollingMethod - :keyword int polling_interval: Default waiting time between two polls for LRO operations if no - Retry-After header is present. - :return: An instance of AsyncLROPoller that returns JSON object - :rtype: ~azure.core.polling.AsyncLROPoller[JSON] + `https://json.schemastore.org/azure-deviceupdate-import-manifest-5.0.json + `_ for + details). Is one of the following types: [ImportUpdateInputItem], [JSON], IO[bytes] Required. + :type update_to_import: list[~azure.iot.deviceupdate.models.ImportUpdateInputItem] or + list[JSON] or IO[bytes] + :return: An instance of AsyncLROPoller that returns None + :rtype: ~azure.core.polling.AsyncLROPoller[None] :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "compatibility": [ - { - "str": "str" # List of update compatibility information. - Required. - } - ], - "createdDateTime": "2020-02-20 00:00:00", # Date and time in UTC when the - update was created. Required. - "importedDateTime": "2020-02-20 00:00:00", # Date and time in UTC when the - update was imported. Required. - "manifestVersion": "str", # Schema version of manifest used to import the - update. Required. - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description specified by creator. - "etag": "str", # Optional. Update ETag. - "friendlyName": "str", # Optional. Friendly update name specified by - importer. - "installedCriteria": "str", # Optional. String interpreted by Device Update - client to determine if the update is installed on the device. Deprecated in - latest import manifest schema. - "instructions": { - "steps": [ - { - "description": "str", # Optional. Step description. - "files": [ - "str" # Optional. Collection of file names - to be passed to handler during execution. Required if step type - is inline. - ], - "handler": "str", # Optional. Identity of handler - that will execute this step. Required if step type is inline. - "handlerProperties": {}, # Optional. Parameters to - be passed to handler during execution. - "type": "inline", # Optional. Default value is - "inline". Step type. Known values are: "Inline" and "Reference". - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. - Required. - "version": "str" # Update version. Required. - } - } - ] - }, - "isDeployable": True, # Optional. Default value is True. Whether the update - can be deployed to a device on its own. - "referencedBy": [ - { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - } - ], - "scanResult": "str", # Optional. Update aggregate scan result (calculated - from payload file scan results). - "updateType": "str" # Optional. Update type. Deprecated in latest import - manifest schema. - } """ _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = kwargs.pop("params", {}) or {} - content_type = kwargs.pop("content_type", _headers.pop("Content-Type", None)) # type: Optional[str] - cls = kwargs.pop("cls", None) # type: ClsType[JSON] - polling = kwargs.pop("polling", True) # type: Union[bool, AsyncPollingMethod] + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[None] = kwargs.pop("cls", None) + polling: Union[bool, AsyncPollingMethod] = kwargs.pop("polling", True) lro_delay = kwargs.pop("polling_interval", self._config.polling_interval) - cont_token = kwargs.pop("continuation_token", None) # type: Optional[str] + cont_token: Optional[str] = kwargs.pop("continuation_token", None) if cont_token is None: - raw_result = await self._import_update_initial( # type: ignore + raw_result = await self._import_update_initial( update_to_import=update_to_import, content_type=content_type, cls=lambda x, y, z: x, @@ -639,44 +377,46 @@ async def begin_import_update(self, update_to_import: Union[List[JSON], IO], **k params=_params, **kwargs ) + await raw_result.http_response.read() # type: ignore kwargs.pop("error_map", None) - def get_long_running_output(pipeline_response): - response = pipeline_response.http_response - if response.content: - deserialized = response.json() - else: - deserialized = None + def get_long_running_output(pipeline_response): # pylint: disable=inconsistent-return-statements if cls: - return cls(pipeline_response, deserialized, {}) - return deserialized + return cls(pipeline_response, None, {}) # type: ignore 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"), } if polling is True: - polling_method = cast( + polling_method: AsyncPollingMethod = cast( AsyncPollingMethod, AsyncLROBasePolling(lro_delay, path_format_arguments=path_format_arguments, **kwargs), - ) # type: AsyncPollingMethod + ) elif polling is False: polling_method = cast(AsyncPollingMethod, AsyncNoPolling()) else: polling_method = polling if cont_token: - return AsyncLROPoller.from_continuation_token( + return AsyncLROPoller[None].from_continuation_token( polling_method=polling_method, continuation_token=cont_token, client=self._client, deserialization_callback=get_long_running_output, ) - return AsyncLROPoller(self._client, raw_result, get_long_running_output, polling_method) + return AsyncLROPoller[None](self._client, raw_result, get_long_running_output, polling_method) # type: ignore @distributed_trace_async async def get_update( - self, provider: str, name: str, version: str, *, if_none_match: Optional[str] = None, **kwargs: Any - ) -> JSON: + self, + provider: str, + name: str, + version: str, + *, + etag: Optional[str] = None, + match_condition: Optional[MatchConditions] = None, + **kwargs: Any + ) -> _models.Update: """Get a specific update version. :param provider: Update provider. Required. @@ -685,136 +425,98 @@ async def get_update( :type name: str :param version: Update version. Required. :type version: str - :keyword if_none_match: Defines the If-None-Match condition. The operation will be performed - only if the ETag on the server does not match this value. Default value is None. - :paramtype if_none_match: str - :return: JSON object - :rtype: JSON + :keyword etag: check if resource is changed. Set None to skip checking etag. Default value is + None. + :paramtype etag: str + :keyword match_condition: The match condition to use upon the etag. Default value is None. + :paramtype match_condition: ~azure.core.MatchConditions + :return: Update. The Update is compatible with MutableMapping + :rtype: ~azure.iot.deviceupdate.models.Update :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "compatibility": [ - { - "str": "str" # List of update compatibility information. - Required. - } - ], - "createdDateTime": "2020-02-20 00:00:00", # Date and time in UTC when the - update was created. Required. - "importedDateTime": "2020-02-20 00:00:00", # Date and time in UTC when the - update was imported. Required. - "manifestVersion": "str", # Schema version of manifest used to import the - update. Required. - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description specified by creator. - "etag": "str", # Optional. Update ETag. - "friendlyName": "str", # Optional. Friendly update name specified by - importer. - "installedCriteria": "str", # Optional. String interpreted by Device Update - client to determine if the update is installed on the device. Deprecated in - latest import manifest schema. - "instructions": { - "steps": [ - { - "description": "str", # Optional. Step description. - "files": [ - "str" # Optional. Collection of file names - to be passed to handler during execution. Required if step type - is inline. - ], - "handler": "str", # Optional. Identity of handler - that will execute this step. Required if step type is inline. - "handlerProperties": {}, # Optional. Parameters to - be passed to handler during execution. - "type": "inline", # Optional. Default value is - "inline". Step type. Known values are: "Inline" and "Reference". - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. - Required. - "version": "str" # Update version. Required. - } - } - ] - }, - "isDeployable": True, # Optional. Default value is True. Whether the update - can be deployed to a device on its own. - "referencedBy": [ - { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - } - ], - "scanResult": "str", # Optional. Update aggregate scan result (calculated - from payload file scan results). - "updateType": "str" # Optional. Update type. Deprecated in latest import - manifest schema. - } """ - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + if match_condition == MatchConditions.IfNotModified: + error_map[412] = ResourceModifiedError + elif match_condition == MatchConditions.IfPresent: + error_map[412] = ResourceNotFoundError + elif match_condition == MatchConditions.IfMissing: + error_map[412] = ResourceExistsError error_map.update(kwargs.pop("error_map", {}) or {}) _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls = kwargs.pop("cls", None) # type: ClsType[JSON] + cls: ClsType[_models.Update] = kwargs.pop("cls", None) - request = build_device_update_get_update_request( + _request = build_device_update_get_update_request( provider=provider, name=name, version=version, instance_id=self._config.instance_id, - if_none_match=if_none_match, + etag=etag, + match_condition=match_condition, 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), + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - pipeline_response = await self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("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]: + if _stream: + try: + await response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) - if response.content: - deserialized = response.json() + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = None + deserialized = _deserialize(_models.Update, response.json()) if cls: - return cls(pipeline_response, cast(JSON, deserialized), {}) + return cls(pipeline_response, deserialized, {}) # type: ignore - return cast(JSON, deserialized) + return deserialized # type: ignore - async def _delete_update_initial( # pylint: disable=inconsistent-return-statements + async def _delete_update_initial( self, provider: str, name: str, version: str, **kwargs: Any - ) -> None: - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + ) -> AsyncIterator[bytes]: + error_map: MutableMapping = { + 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 = kwargs.pop("cls", None) # type: ClsType[None] + cls: ClsType[AsyncIterator[bytes]] = kwargs.pop("cls", None) - request = build_device_update_delete_update_request( + _request = build_device_update_delete_update_request( provider=provider, name=name, version=version, @@ -824,25 +526,39 @@ async def _delete_update_initial( # pylint: disable=inconsistent-return-stateme params=_params, ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - pipeline_response = await self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _decompress = kwargs.pop("decompress", True) + _stream = True + 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 [202]: + try: + await response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) response_headers = {} response_headers["Operation-Location"] = self._deserialize("str", response.headers.get("Operation-Location")) + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + if cls: - return cls(pipeline_response, None, response_headers) + return cls(pipeline_response, deserialized, response_headers) # type: ignore + + return deserialized # type: ignore @distributed_trace_async async def begin_delete_update(self, provider: str, name: str, version: str, **kwargs: Any) -> AsyncLROPoller[None]: @@ -855,13 +571,6 @@ async def begin_delete_update(self, provider: str, name: str, version: str, **kw :type name: str :param version: Update version. Required. :type version: str - :keyword str continuation_token: A continuation token to restart a poller from a saved state. - :keyword polling: By default, your polling method will be AsyncLROBasePolling. Pass in False - for this operation to not poll, or pass in your own initialized polling object for a personal - polling strategy. - :paramtype polling: bool or ~azure.core.polling.AsyncPollingMethod - :keyword int polling_interval: Default waiting time between two polls for LRO operations if no - Retry-After header is present. :return: An instance of AsyncLROPoller that returns None :rtype: ~azure.core.polling.AsyncLROPoller[None] :raises ~azure.core.exceptions.HttpResponseError: @@ -869,12 +578,12 @@ async def begin_delete_update(self, provider: str, name: str, version: str, **kw _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls = kwargs.pop("cls", None) # type: ClsType[None] - polling = kwargs.pop("polling", True) # type: Union[bool, AsyncPollingMethod] + cls: ClsType[None] = kwargs.pop("cls", None) + polling: Union[bool, AsyncPollingMethod] = kwargs.pop("polling", True) lro_delay = kwargs.pop("polling_interval", self._config.polling_interval) - cont_token = kwargs.pop("continuation_token", None) # type: Optional[str] + cont_token: Optional[str] = kwargs.pop("continuation_token", None) if cont_token is None: - raw_result = await self._delete_update_initial( # type: ignore + raw_result = await self._delete_update_initial( provider=provider, name=name, version=version, @@ -883,112 +592,126 @@ async def begin_delete_update(self, provider: str, name: str, version: str, **kw params=_params, **kwargs ) + await raw_result.http_response.read() # type: ignore kwargs.pop("error_map", None) def get_long_running_output(pipeline_response): # pylint: disable=inconsistent-return-statements if cls: - return cls(pipeline_response, None, {}) + return cls(pipeline_response, None, {}) # type: ignore 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"), } if polling is True: - polling_method = cast( + polling_method: AsyncPollingMethod = cast( AsyncPollingMethod, AsyncLROBasePolling(lro_delay, path_format_arguments=path_format_arguments, **kwargs), - ) # type: AsyncPollingMethod + ) elif polling is False: polling_method = cast(AsyncPollingMethod, AsyncNoPolling()) else: polling_method = polling if cont_token: - return AsyncLROPoller.from_continuation_token( + return AsyncLROPoller[None].from_continuation_token( polling_method=polling_method, continuation_token=cont_token, client=self._client, deserialization_callback=get_long_running_output, ) - return AsyncLROPoller(self._client, raw_result, get_long_running_output, polling_method) + return AsyncLROPoller[None](self._client, raw_result, get_long_running_output, polling_method) # type: ignore @distributed_trace - def list_providers(self, **kwargs: Any) -> AsyncIterable[str]: + def list_providers(self, **kwargs: Any) -> AsyncItemPaged[str]: """Get a list of all update providers that have been imported to Device Update for IoT Hub. :return: An iterator like instance of str :rtype: ~azure.core.async_paging.AsyncItemPaged[str] :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == "str" # Optional. """ _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls = kwargs.pop("cls", None) # type: ClsType[JSON] + cls: ClsType[list[str]] = kwargs.pop("cls", None) - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } error_map.update(kwargs.pop("error_map", {}) or {}) def prepare_request(next_link=None): if not next_link: - request = build_device_update_list_providers_request( + _request = build_device_update_list_providers_request( instance_id=self._config.instance_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 - ), + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) else: # make call to next link with the client's api-version - _parsed_next_link = urlparse(next_link) - _next_request_params = case_insensitive_dict(parse_qs(_parsed_next_link.query)) + _parsed_next_link = urllib.parse.urlparse(next_link) + _next_request_params = case_insensitive_dict( + { + key: [urllib.parse.quote(v) for v in value] + for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items() + } + ) _next_request_params["api-version"] = self._config.api_version - request = HttpRequest("GET", urljoin(next_link, _parsed_next_link.path), params=_next_request_params) + _request = HttpRequest( + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + headers=_headers, + params=_next_request_params, + ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - return request + return _request async def extract_data(pipeline_response): deserialized = pipeline_response.http_response.json() - list_of_elem = deserialized["value"] + list_of_elem = _deserialize( + list[str], + deserialized.get("value", []), + ) if cls: - list_of_elem = cls(list_of_elem) - return deserialized.get("nextLink", None), AsyncList(list_of_elem) + list_of_elem = cls(list_of_elem) # type: ignore + return deserialized.get("nextLink") or None, AsyncList(list_of_elem) async def get_next(next_link=None): - request = prepare_request(next_link) + _request = prepare_request(next_link) - pipeline_response = await self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _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) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) return pipeline_response return AsyncItemPaged(get_next, extract_data) @distributed_trace - def list_names(self, provider: str, **kwargs: Any) -> AsyncIterable[str]: + def list_names(self, provider: str, **kwargs: Any) -> AsyncItemPaged[str]: """Get a list of all update names that match the specified provider. :param provider: Update provider. Required. @@ -996,25 +719,24 @@ def list_names(self, provider: str, **kwargs: Any) -> AsyncIterable[str]: :return: An iterator like instance of str :rtype: ~azure.core.async_paging.AsyncItemPaged[str] :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == "str" # Optional. """ _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls = kwargs.pop("cls", None) # type: ClsType[JSON] + cls: ClsType[list[str]] = kwargs.pop("cls", None) - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } error_map.update(kwargs.pop("error_map", {}) or {}) def prepare_request(next_link=None): if not next_link: - request = build_device_update_list_names_request( + _request = build_device_update_list_names_request( provider=provider, instance_id=self._config.instance_id, api_version=self._config.api_version, @@ -1022,45 +744,59 @@ def prepare_request(next_link=None): params=_params, ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) else: # make call to next link with the client's api-version - _parsed_next_link = urlparse(next_link) - _next_request_params = case_insensitive_dict(parse_qs(_parsed_next_link.query)) + _parsed_next_link = urllib.parse.urlparse(next_link) + _next_request_params = case_insensitive_dict( + { + key: [urllib.parse.quote(v) for v in value] + for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items() + } + ) _next_request_params["api-version"] = self._config.api_version - request = HttpRequest("GET", urljoin(next_link, _parsed_next_link.path), params=_next_request_params) + _request = HttpRequest( + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + headers=_headers, + params=_next_request_params, + ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - return request + return _request async def extract_data(pipeline_response): deserialized = pipeline_response.http_response.json() - list_of_elem = deserialized["value"] + list_of_elem = _deserialize( + list[str], + deserialized.get("value", []), + ) if cls: - list_of_elem = cls(list_of_elem) - return deserialized.get("nextLink", None), AsyncList(list_of_elem) + list_of_elem = cls(list_of_elem) # type: ignore + return deserialized.get("nextLink") or None, AsyncList(list_of_elem) async def get_next(next_link=None): - request = prepare_request(next_link) + _request = prepare_request(next_link) - pipeline_response = await self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _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) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) return pipeline_response @@ -1069,7 +805,7 @@ async def get_next(next_link=None): @distributed_trace def list_versions( self, provider: str, name: str, *, filter: Optional[str] = None, **kwargs: Any - ) -> AsyncIterable[str]: + ) -> AsyncItemPaged[str]: """Get a list of all update versions that match the specified provider and name. :param provider: Update provider. Required. @@ -1081,25 +817,24 @@ def list_versions( :return: An iterator like instance of str :rtype: ~azure.core.async_paging.AsyncItemPaged[str] :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == "str" # Optional. """ _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls = kwargs.pop("cls", None) # type: ClsType[JSON] + cls: ClsType[list[str]] = kwargs.pop("cls", None) - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } error_map.update(kwargs.pop("error_map", {}) or {}) def prepare_request(next_link=None): if not next_link: - request = build_device_update_list_versions_request( + _request = build_device_update_list_versions_request( provider=provider, name=name, instance_id=self._config.instance_id, @@ -1109,52 +844,66 @@ def prepare_request(next_link=None): params=_params, ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) else: # make call to next link with the client's api-version - _parsed_next_link = urlparse(next_link) - _next_request_params = case_insensitive_dict(parse_qs(_parsed_next_link.query)) + _parsed_next_link = urllib.parse.urlparse(next_link) + _next_request_params = case_insensitive_dict( + { + key: [urllib.parse.quote(v) for v in value] + for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items() + } + ) _next_request_params["api-version"] = self._config.api_version - request = HttpRequest("GET", urljoin(next_link, _parsed_next_link.path), params=_next_request_params) + _request = HttpRequest( + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + headers=_headers, + params=_next_request_params, + ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - return request + return _request async def extract_data(pipeline_response): deserialized = pipeline_response.http_response.json() - list_of_elem = deserialized["value"] + list_of_elem = _deserialize( + list[str], + deserialized.get("value", []), + ) if cls: - list_of_elem = cls(list_of_elem) - return deserialized.get("nextLink", None), AsyncList(list_of_elem) + list_of_elem = cls(list_of_elem) # type: ignore + return deserialized.get("nextLink") or None, AsyncList(list_of_elem) async def get_next(next_link=None): - request = prepare_request(next_link) + _request = prepare_request(next_link) - pipeline_response = await self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _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) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) return pipeline_response return AsyncItemPaged(get_next, extract_data) @distributed_trace - def list_files(self, provider: str, name: str, version: str, **kwargs: Any) -> AsyncIterable[str]: + def list_files(self, provider: str, name: str, version: str, **kwargs: Any) -> AsyncItemPaged[str]: """Get a list of all update file identifiers for the specified version. :param provider: Update provider. Required. @@ -1166,25 +915,24 @@ def list_files(self, provider: str, name: str, version: str, **kwargs: Any) -> A :return: An iterator like instance of str :rtype: ~azure.core.async_paging.AsyncItemPaged[str] :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == "str" # Optional. """ _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls = kwargs.pop("cls", None) # type: ClsType[JSON] + cls: ClsType[list[str]] = kwargs.pop("cls", None) - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } error_map.update(kwargs.pop("error_map", {}) or {}) def prepare_request(next_link=None): if not next_link: - request = build_device_update_list_files_request( + _request = build_device_update_list_files_request( provider=provider, name=name, version=version, @@ -1194,45 +942,59 @@ def prepare_request(next_link=None): params=_params, ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) else: # make call to next link with the client's api-version - _parsed_next_link = urlparse(next_link) - _next_request_params = case_insensitive_dict(parse_qs(_parsed_next_link.query)) + _parsed_next_link = urllib.parse.urlparse(next_link) + _next_request_params = case_insensitive_dict( + { + key: [urllib.parse.quote(v) for v in value] + for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items() + } + ) _next_request_params["api-version"] = self._config.api_version - request = HttpRequest("GET", urljoin(next_link, _parsed_next_link.path), params=_next_request_params) + _request = HttpRequest( + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + headers=_headers, + params=_next_request_params, + ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - return request + return _request async def extract_data(pipeline_response): deserialized = pipeline_response.http_response.json() - list_of_elem = deserialized["value"] + list_of_elem = _deserialize( + list[str], + deserialized.get("value", []), + ) if cls: - list_of_elem = cls(list_of_elem) - return deserialized.get("nextLink", None), AsyncList(list_of_elem) + list_of_elem = cls(list_of_elem) # type: ignore + return deserialized.get("nextLink") or None, AsyncList(list_of_elem) async def get_next(next_link=None): - request = prepare_request(next_link) + _request = prepare_request(next_link) - pipeline_response = await self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _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) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) return pipeline_response @@ -1246,9 +1008,10 @@ async def get_file( version: str, file_id: str, *, - if_none_match: Optional[str] = None, + etag: Optional[str] = None, + match_condition: Optional[MatchConditions] = None, **kwargs: Any - ) -> JSON: + ) -> _models.UpdateFile: """Get a specific update file from the version. :param provider: Update provider. Required. @@ -1259,178 +1022,117 @@ async def get_file( :type version: str :param file_id: File identifier. Required. :type file_id: str - :keyword if_none_match: Defines the If-None-Match condition. The operation will be performed - only if the ETag on the server does not match this value. Default value is None. - :paramtype if_none_match: str - :return: JSON object - :rtype: JSON + :keyword etag: check if resource is changed. Set None to skip checking etag. Default value is + None. + :paramtype etag: str + :keyword match_condition: The match condition to use upon the etag. Default value is None. + :paramtype match_condition: ~azure.core.MatchConditions + :return: UpdateFile. The UpdateFile is compatible with MutableMapping + :rtype: ~azure.iot.deviceupdate.models.UpdateFile :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "fileId": "str", # File identity, generated by server at import time. - Required. - "fileName": "str", # File name. Required. - "hashes": { - "str": "str" # Mapping of hashing algorithm to base64 encoded hash - values. Required. - }, - "sizeInBytes": 0, # File size in number of bytes. Required. - "downloadHandler": { - "id": "str" # Download handler identifier. Required. - }, - "etag": "str", # Optional. File ETag. - "mimeType": "str", # Optional. File MIME type. - "properties": { - "str": "str" # Optional. Optional file properties (not consumed by - service but pass-through to device). - }, - "relatedFiles": [ - { - "fileName": "str", # File name. Required. - "hashes": { - "str": "str" # Mapping of hashing algorithm to - base64 encoded hash values. Required. - }, - "sizeInBytes": 0, # File size in number of bytes. Required. - "mimeType": "str", # Optional. File MIME type. - "properties": { - "str": "str" # Optional. Optional file properties - (not consumed by service but pass-through to device). - }, - "scanDetails": "str", # Optional. Anti-malware scan details. - "scanResult": "str" # Optional. Anti-malware scan result. - } - ], - "scanDetails": "str", # Optional. Anti-malware scan details. - "scanResult": "str" # Optional. Anti-malware scan result. - } """ - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + if match_condition == MatchConditions.IfNotModified: + error_map[412] = ResourceModifiedError + elif match_condition == MatchConditions.IfPresent: + error_map[412] = ResourceNotFoundError + elif match_condition == MatchConditions.IfMissing: + error_map[412] = ResourceExistsError error_map.update(kwargs.pop("error_map", {}) or {}) _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls = kwargs.pop("cls", None) # type: ClsType[JSON] + cls: ClsType[_models.UpdateFile] = kwargs.pop("cls", None) - request = build_device_update_get_file_request( + _request = build_device_update_get_file_request( provider=provider, name=name, version=version, file_id=file_id, instance_id=self._config.instance_id, - if_none_match=if_none_match, + etag=etag, + match_condition=match_condition, 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), + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - pipeline_response = await self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("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]: + if _stream: + try: + await response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) - if response.content: - deserialized = response.json() + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = None + deserialized = _deserialize(_models.UpdateFile, response.json()) if cls: - return cls(pipeline_response, cast(JSON, deserialized), {}) + return cls(pipeline_response, deserialized, {}) # type: ignore - return cast(JSON, deserialized) + return deserialized # type: ignore @distributed_trace def list_operation_statuses( self, *, filter: Optional[str] = None, top: Optional[int] = None, **kwargs: Any - ) -> AsyncIterable[JSON]: + ) -> AsyncItemPaged["_models.UpdateOperation"]: """Get a list of all import update operations. Completed operations are kept for 7 days before auto-deleted. Delete operations are not returned by this API version. :keyword filter: Optional to filter operations by status property. Only one specific filter is supported: "status eq 'NotStarted' or status eq 'Running'". Default value is None. :paramtype filter: str - :keyword top: Specifies a non-negative integer n that limits the number of items returned from - a collection. The service returns the number of available items up to but not greater than the - specified value n. Default value is None. + :keyword top: Specifies a non-negative integer n that limits the number of items returned + from a collection. The service returns the number of available items up to but + not greater than the specified value n. Default value is None. :paramtype top: int - :return: An iterator like instance of JSON object - :rtype: ~azure.core.async_paging.AsyncItemPaged[JSON] + :return: An iterator like instance of UpdateOperation + :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.iot.deviceupdate.models.UpdateOperation] :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "createdDateTime": "2020-02-20 00:00:00", # Date and time in UTC when the - operation was created. Required. - "lastActionDateTime": "2020-02-20 00:00:00", # Date and time in UTC when the - operation status was last updated. Required. - "operationId": "str", # Operation Id. Required. - "status": "str", # Operation status. Required. Known values are: - "NotStarted", "Running", "Succeeded", and "Failed". - "error": { - "code": "str", # Server defined error code. Required. - "message": "str", # A human-readable representation of the error. - Required. - "details": [ - ... - ], - "innererror": { - "code": "str", # A more specific error code than what was - provided by the containing error. Required. - "errorDetail": "str", # Optional. The internal error or - exception message. - "innerError": ..., - "message": "str" # Optional. A human-readable representation - of the error. - }, - "occurredDateTime": "2020-02-20 00:00:00", # Optional. Date and time - in UTC when the error occurred. - "target": "str" # Optional. The target of the error. - }, - "etag": "str", # Optional. Operation ETag. - "resourceLocation": "str", # Optional. Location of the imported update when - operation is successful. - "traceId": "str", # Optional. Operation correlation identity that can used - by Microsoft Support for troubleshooting. - "update": { - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description. - "friendlyName": "str" # Optional. Friendly update name. - } - } """ _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls = kwargs.pop("cls", None) # type: ClsType[JSON] + cls: ClsType[list[_models.UpdateOperation]] = kwargs.pop("cls", None) - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } error_map.update(kwargs.pop("error_map", {}) or {}) def prepare_request(next_link=None): if not next_link: - request = build_device_update_list_operation_statuses_request( + _request = build_device_update_list_operation_statuses_request( instance_id=self._config.instance_id, filter=filter, top=top, @@ -1439,45 +1141,59 @@ def prepare_request(next_link=None): params=_params, ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) else: # make call to next link with the client's api-version - _parsed_next_link = urlparse(next_link) - _next_request_params = case_insensitive_dict(parse_qs(_parsed_next_link.query)) + _parsed_next_link = urllib.parse.urlparse(next_link) + _next_request_params = case_insensitive_dict( + { + key: [urllib.parse.quote(v) for v in value] + for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items() + } + ) _next_request_params["api-version"] = self._config.api_version - request = HttpRequest("GET", urljoin(next_link, _parsed_next_link.path), params=_next_request_params) + _request = HttpRequest( + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + headers=_headers, + params=_next_request_params, + ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - return request + return _request async def extract_data(pipeline_response): deserialized = pipeline_response.http_response.json() - list_of_elem = deserialized["value"] + list_of_elem = _deserialize( + list[_models.UpdateOperation], + deserialized.get("value", []), + ) if cls: - list_of_elem = cls(list_of_elem) - return deserialized.get("nextLink", None), AsyncList(list_of_elem) + list_of_elem = cls(list_of_elem) # type: ignore + return deserialized.get("nextLink") or None, AsyncList(list_of_elem) async def get_next(next_link=None): - request = prepare_request(next_link) + _request = prepare_request(next_link) - pipeline_response = await self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _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) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) return pipeline_response @@ -1485,110 +1201,92 @@ async def get_next(next_link=None): @distributed_trace_async async def get_operation_status( - self, operation_id: str, *, if_none_match: Optional[str] = None, **kwargs: Any - ) -> JSON: + self, + operation_id: str, + *, + etag: Optional[str] = None, + match_condition: Optional[MatchConditions] = None, + **kwargs: Any + ) -> _models.UpdateOperation: """Retrieve operation status. :param operation_id: Operation identifier. Required. :type operation_id: str - :keyword if_none_match: Defines the If-None-Match condition. The operation will be performed - only if the ETag on the server does not match this value. Default value is None. - :paramtype if_none_match: str - :return: JSON object - :rtype: JSON + :keyword etag: check if resource is changed. Set None to skip checking etag. Default value is + None. + :paramtype etag: str + :keyword match_condition: The match condition to use upon the etag. Default value is None. + :paramtype match_condition: ~azure.core.MatchConditions + :return: UpdateOperation. The UpdateOperation is compatible with MutableMapping + :rtype: ~azure.iot.deviceupdate.models.UpdateOperation :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "createdDateTime": "2020-02-20 00:00:00", # Date and time in UTC when the - operation was created. Required. - "lastActionDateTime": "2020-02-20 00:00:00", # Date and time in UTC when the - operation status was last updated. Required. - "operationId": "str", # Operation Id. Required. - "status": "str", # Operation status. Required. Known values are: - "NotStarted", "Running", "Succeeded", and "Failed". - "error": { - "code": "str", # Server defined error code. Required. - "message": "str", # A human-readable representation of the error. - Required. - "details": [ - ... - ], - "innererror": { - "code": "str", # A more specific error code than what was - provided by the containing error. Required. - "errorDetail": "str", # Optional. The internal error or - exception message. - "innerError": ..., - "message": "str" # Optional. A human-readable representation - of the error. - }, - "occurredDateTime": "2020-02-20 00:00:00", # Optional. Date and time - in UTC when the error occurred. - "target": "str" # Optional. The target of the error. - }, - "etag": "str", # Optional. Operation ETag. - "resourceLocation": "str", # Optional. Location of the imported update when - operation is successful. - "traceId": "str", # Optional. Operation correlation identity that can used - by Microsoft Support for troubleshooting. - "update": { - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description. - "friendlyName": "str" # Optional. Friendly update name. - } - } """ - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + if match_condition == MatchConditions.IfNotModified: + error_map[412] = ResourceModifiedError + elif match_condition == MatchConditions.IfPresent: + error_map[412] = ResourceNotFoundError + elif match_condition == MatchConditions.IfMissing: + error_map[412] = ResourceExistsError error_map.update(kwargs.pop("error_map", {}) or {}) _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls = kwargs.pop("cls", None) # type: ClsType[JSON] + cls: ClsType[_models.UpdateOperation] = kwargs.pop("cls", None) - request = build_device_update_get_operation_status_request( + _request = build_device_update_get_operation_status_request( operation_id=operation_id, instance_id=self._config.instance_id, - if_none_match=if_none_match, + etag=etag, + match_condition=match_condition, 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), + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - pipeline_response = await self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("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]: + if _stream: + try: + await response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) response_headers = {} response_headers["Retry-After"] = self._deserialize("str", response.headers.get("Retry-After")) - if response.content: - deserialized = response.json() + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = None + deserialized = _deserialize(_models.UpdateOperation, response.json()) if cls: - return cls(pipeline_response, cast(JSON, deserialized), response_headers) + return cls(pipeline_response, deserialized, response_headers) # type: ignore - return cast(JSON, deserialized) + return deserialized # type: ignore class DeviceManagementOperations: # pylint: disable=too-many-public-methods @@ -1603,13 +1301,15 @@ class DeviceManagementOperations: # pylint: disable=too-many-public-methods 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") + self._client: AsyncPipelineClient = input_args.pop(0) if input_args else kwargs.pop("client") + self._config: DeviceUpdateClientConfiguration = input_args.pop(0) if input_args else kwargs.pop("config") + self._serialize: Serializer = input_args.pop(0) if input_args else kwargs.pop("serializer") + self._deserialize: Deserializer = input_args.pop(0) if input_args else kwargs.pop("deserializer") @distributed_trace - def list_device_classes(self, *, filter: Optional[str] = None, **kwargs: Any) -> AsyncIterable[JSON]: + def list_device_classes( + self, *, filter: Optional[str] = None, **kwargs: Any + ) -> AsyncItemPaged["_models.DeviceClass"]: """Gets a list of all device classes (sets of devices compatible with the same updates based on the model Id and compat properties reported in the Device Update PnP interface in IoT Hub) for all devices connected to Device Update for IoT Hub. @@ -1617,61 +1317,27 @@ def list_device_classes(self, *, filter: Optional[str] = None, **kwargs: Any) -> :keyword filter: Restricts the set of device classes returned. You can filter on friendly name. Default value is None. :paramtype filter: str - :return: An iterator like instance of JSON object - :rtype: ~azure.core.async_paging.AsyncItemPaged[JSON] + :return: An iterator like instance of DeviceClass + :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.iot.deviceupdate.models.DeviceClass] :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "deviceClassId": "str", # The device class identifier. This is generated - from the model Id and the compat properties reported by the device update agent - in the Device Update PnP interface in IoT Hub. It is a hex-encoded SHA1 hash. - Required. - "deviceClassProperties": { - "compatProperties": { - "str": "str" # The compat properties of the device class. - This object can be thought of as a set of key-value pairs where the key - is the name of the compatibility property and the value is the value of - the compatibility property. There will always be at least 1 compat - property. Required. - }, - "contractModel": { - "id": "str", # The Device Update agent contract model Id of - the device class. This is also used to calculate the device class Id. - Required. - "name": "str" # The Device Update agent contract model name - of the device class. Intended to be a more readable form of the contract - model Id. Required. - } - }, - "bestCompatibleUpdate": { - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description. - "friendlyName": "str" # Optional. Friendly update name. - }, - "friendlyName": "str" # Optional. The device class friendly name. This can - be updated by callers after the device class has been automatically created. - } """ _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls = kwargs.pop("cls", None) # type: ClsType[JSON] + cls: ClsType[list[_models.DeviceClass]] = kwargs.pop("cls", None) - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } error_map.update(kwargs.pop("error_map", {}) or {}) def prepare_request(next_link=None): if not next_link: - request = build_device_management_list_device_classes_request( + _request = build_device_management_list_device_classes_request( instance_id=self._config.instance_id, filter=filter, api_version=self._config.api_version, @@ -1679,108 +1345,88 @@ def prepare_request(next_link=None): params=_params, ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) else: # make call to next link with the client's api-version - _parsed_next_link = urlparse(next_link) - _next_request_params = case_insensitive_dict(parse_qs(_parsed_next_link.query)) + _parsed_next_link = urllib.parse.urlparse(next_link) + _next_request_params = case_insensitive_dict( + { + key: [urllib.parse.quote(v) for v in value] + for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items() + } + ) _next_request_params["api-version"] = self._config.api_version - request = HttpRequest("GET", urljoin(next_link, _parsed_next_link.path), params=_next_request_params) + _request = HttpRequest( + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + headers=_headers, + params=_next_request_params, + ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - return request + return _request async def extract_data(pipeline_response): deserialized = pipeline_response.http_response.json() - list_of_elem = deserialized["value"] + list_of_elem = _deserialize( + list[_models.DeviceClass], + deserialized.get("value", []), + ) if cls: - list_of_elem = cls(list_of_elem) - return deserialized.get("nextLink", None), AsyncList(list_of_elem) + list_of_elem = cls(list_of_elem) # type: ignore + return deserialized.get("nextLink") or None, AsyncList(list_of_elem) async def get_next(next_link=None): - request = prepare_request(next_link) + _request = prepare_request(next_link) - pipeline_response = await self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _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) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) return pipeline_response return AsyncItemPaged(get_next, extract_data) @distributed_trace_async - async def get_device_class(self, device_class_id: str, **kwargs: Any) -> JSON: + async def get_device_class(self, device_class_id: str, **kwargs: Any) -> _models.DeviceClass: """Gets the properties of a device class. :param device_class_id: Device class identifier. Required. :type device_class_id: str - :return: JSON object - :rtype: JSON + :return: DeviceClass. The DeviceClass is compatible with MutableMapping + :rtype: ~azure.iot.deviceupdate.models.DeviceClass :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "deviceClassId": "str", # The device class identifier. This is generated - from the model Id and the compat properties reported by the device update agent - in the Device Update PnP interface in IoT Hub. It is a hex-encoded SHA1 hash. - Required. - "deviceClassProperties": { - "compatProperties": { - "str": "str" # The compat properties of the device class. - This object can be thought of as a set of key-value pairs where the key - is the name of the compatibility property and the value is the value of - the compatibility property. There will always be at least 1 compat - property. Required. - }, - "contractModel": { - "id": "str", # The Device Update agent contract model Id of - the device class. This is also used to calculate the device class Id. - Required. - "name": "str" # The Device Update agent contract model name - of the device class. Intended to be a more readable form of the contract - model Id. Required. - } - }, - "bestCompatibleUpdate": { - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description. - "friendlyName": "str" # Optional. Friendly update name. - }, - "friendlyName": "str" # Optional. The device class friendly name. This can - be updated by callers after the device class has been automatically created. - } """ - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 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 = kwargs.pop("cls", None) # type: ClsType[JSON] + cls: ClsType[_models.DeviceClass] = kwargs.pop("cls", None) - request = build_device_management_get_device_class_request( + _request = build_device_management_get_device_class_request( device_class_id=device_class_id, instance_id=self._config.instance_id, api_version=self._config.api_version, @@ -1788,275 +1434,200 @@ async def get_device_class(self, device_class_id: str, **kwargs: Any) -> JSON: params=_params, ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - pipeline_response = await self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("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]: + if _stream: + try: + await response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) - if response.content: - deserialized = response.json() + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = None + deserialized = _deserialize(_models.DeviceClass, response.json()) if cls: - return cls(pipeline_response, cast(JSON, deserialized), {}) + return cls(pipeline_response, deserialized, {}) # type: ignore - return cast(JSON, deserialized) + return deserialized # type: ignore @overload async def update_device_class( self, device_class_id: str, - device_class_patch: JSON, + device_class_patch: _models.PatchBody, *, content_type: str = "application/merge-patch+json", **kwargs: Any - ) -> JSON: + ) -> _models.DeviceClass: """Update device class details. :param device_class_id: Device class identifier. Required. :type device_class_id: str :param device_class_patch: The device class json merge patch body. Currently only supports - patching friendlyName. Required. - :type device_class_patch: JSON + patching + friendlyName. Required. + :type device_class_patch: ~azure.iot.deviceupdate.models.PatchBody :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: JSON object - :rtype: JSON + :return: DeviceClass. The DeviceClass is compatible with MutableMapping + :rtype: ~azure.iot.deviceupdate.models.DeviceClass :raises ~azure.core.exceptions.HttpResponseError: + """ - Example: - .. code-block:: python - - # JSON input template you can fill out and use as your body input. - device_class_patch = { - "friendlyName": "str" # The device class friendly name. Friendly name can be - 1-100 characters, alphanumeric, dot, and dash. Required. - } + @overload + async def update_device_class( + self, + device_class_id: str, + device_class_patch: JSON, + *, + content_type: str = "application/merge-patch+json", + **kwargs: Any + ) -> _models.DeviceClass: + """Update device class details. - # response body for status code(s): 200 - response == { - "deviceClassId": "str", # The device class identifier. This is generated - from the model Id and the compat properties reported by the device update agent - in the Device Update PnP interface in IoT Hub. It is a hex-encoded SHA1 hash. - Required. - "deviceClassProperties": { - "compatProperties": { - "str": "str" # The compat properties of the device class. - This object can be thought of as a set of key-value pairs where the key - is the name of the compatibility property and the value is the value of - the compatibility property. There will always be at least 1 compat - property. Required. - }, - "contractModel": { - "id": "str", # The Device Update agent contract model Id of - the device class. This is also used to calculate the device class Id. - Required. - "name": "str" # The Device Update agent contract model name - of the device class. Intended to be a more readable form of the contract - model Id. Required. - } - }, - "bestCompatibleUpdate": { - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description. - "friendlyName": "str" # Optional. Friendly update name. - }, - "friendlyName": "str" # Optional. The device class friendly name. This can - be updated by callers after the device class has been automatically created. - } + :param device_class_id: Device class identifier. Required. + :type device_class_id: str + :param device_class_patch: The device class json merge patch body. Currently only supports + patching + friendlyName. Required. + :type device_class_patch: JSON + :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: DeviceClass. The DeviceClass is compatible with MutableMapping + :rtype: ~azure.iot.deviceupdate.models.DeviceClass + :raises ~azure.core.exceptions.HttpResponseError: """ @overload async def update_device_class( self, device_class_id: str, - device_class_patch: IO, + device_class_patch: IO[bytes], *, content_type: str = "application/merge-patch+json", **kwargs: Any - ) -> JSON: + ) -> _models.DeviceClass: """Update device class details. :param device_class_id: Device class identifier. Required. :type device_class_id: str :param device_class_patch: The device class json merge patch body. Currently only supports - patching friendlyName. Required. - :type device_class_patch: IO + patching + friendlyName. Required. + :type device_class_patch: IO[bytes] :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: JSON object - :rtype: JSON + :return: DeviceClass. The DeviceClass is compatible with MutableMapping + :rtype: ~azure.iot.deviceupdate.models.DeviceClass :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "deviceClassId": "str", # The device class identifier. This is generated - from the model Id and the compat properties reported by the device update agent - in the Device Update PnP interface in IoT Hub. It is a hex-encoded SHA1 hash. - Required. - "deviceClassProperties": { - "compatProperties": { - "str": "str" # The compat properties of the device class. - This object can be thought of as a set of key-value pairs where the key - is the name of the compatibility property and the value is the value of - the compatibility property. There will always be at least 1 compat - property. Required. - }, - "contractModel": { - "id": "str", # The Device Update agent contract model Id of - the device class. This is also used to calculate the device class Id. - Required. - "name": "str" # The Device Update agent contract model name - of the device class. Intended to be a more readable form of the contract - model Id. Required. - } - }, - "bestCompatibleUpdate": { - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description. - "friendlyName": "str" # Optional. Friendly update name. - }, - "friendlyName": "str" # Optional. The device class friendly name. This can - be updated by callers after the device class has been automatically created. - } """ @distributed_trace_async async def update_device_class( - self, device_class_id: str, device_class_patch: Union[JSON, IO], **kwargs: Any - ) -> JSON: + self, device_class_id: str, device_class_patch: Union[_models.PatchBody, JSON, IO[bytes]], **kwargs: Any + ) -> _models.DeviceClass: """Update device class details. :param device_class_id: Device class identifier. Required. :type device_class_id: str :param device_class_patch: The device class json merge patch body. Currently only supports - patching friendlyName. Is either a model type or a IO type. Required. - :type device_class_patch: JSON 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: JSON object - :rtype: JSON + patching + friendlyName. Is one of the following types: PatchBody, JSON, IO[bytes] Required. + :type device_class_patch: ~azure.iot.deviceupdate.models.PatchBody or JSON or IO[bytes] + :return: DeviceClass. The DeviceClass is compatible with MutableMapping + :rtype: ~azure.iot.deviceupdate.models.DeviceClass :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "deviceClassId": "str", # The device class identifier. This is generated - from the model Id and the compat properties reported by the device update agent - in the Device Update PnP interface in IoT Hub. It is a hex-encoded SHA1 hash. - Required. - "deviceClassProperties": { - "compatProperties": { - "str": "str" # The compat properties of the device class. - This object can be thought of as a set of key-value pairs where the key - is the name of the compatibility property and the value is the value of - the compatibility property. There will always be at least 1 compat - property. Required. - }, - "contractModel": { - "id": "str", # The Device Update agent contract model Id of - the device class. This is also used to calculate the device class Id. - Required. - "name": "str" # The Device Update agent contract model name - of the device class. Intended to be a more readable form of the contract - model Id. Required. - } - }, - "bestCompatibleUpdate": { - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description. - "friendlyName": "str" # Optional. Friendly update name. - }, - "friendlyName": "str" # Optional. The device class friendly name. This can - be updated by callers after the device class has been automatically created. - } """ - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 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 = kwargs.pop("content_type", _headers.pop("Content-Type", None)) # type: Optional[str] - cls = kwargs.pop("cls", None) # type: ClsType[JSON] + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[_models.DeviceClass] = kwargs.pop("cls", None) content_type = content_type or "application/merge-patch+json" - _json = None _content = None - if isinstance(device_class_patch, (IO, bytes)): + if isinstance(device_class_patch, (IOBase, bytes)): _content = device_class_patch else: - _json = device_class_patch + _content = json.dumps(device_class_patch, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - request = build_device_management_update_device_class_request( + _request = build_device_management_update_device_class_request( device_class_id=device_class_id, instance_id=self._config.instance_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), + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - pipeline_response = await self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("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]: + if _stream: + try: + await response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) - if response.content: - deserialized = response.json() + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = None + deserialized = _deserialize(_models.DeviceClass, response.json()) if cls: - return cls(pipeline_response, cast(JSON, deserialized), {}) + return cls(pipeline_response, deserialized, {}) # type: ignore - return cast(JSON, deserialized) + return deserialized # type: ignore @distributed_trace_async - async def delete_device_class( # pylint: disable=inconsistent-return-statements - self, device_class_id: str, **kwargs: Any - ) -> None: + async def delete_device_class(self, device_class_id: str, **kwargs: Any) -> None: """Deletes a device class. Device classes are created automatically when Device Update-enabled devices are connected to the hub but are not automatically cleaned up since they are referenced by DeviceClassSubgroups. If the user has deleted all DeviceClassSubgroups for a device class @@ -2070,15 +1641,20 @@ async def delete_device_class( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 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 = kwargs.pop("cls", None) # type: ClsType[None] + cls: ClsType[None] = kwargs.pop("cls", None) - request = build_device_management_delete_device_class_request( + _request = build_device_management_delete_device_class_request( device_class_id=device_class_id, instance_id=self._config.instance_id, api_version=self._config.api_version, @@ -2086,59 +1662,57 @@ async def delete_device_class( # pylint: disable=inconsistent-return-statements params=_params, ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - pipeline_response = await self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _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 [204]: map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) if cls: - return cls(pipeline_response, None, {}) + return cls(pipeline_response, None, {}) # type: ignore @distributed_trace - def list_installable_updates_for_device_class(self, device_class_id: str, **kwargs: Any) -> AsyncIterable[JSON]: + def list_installable_updates_for_device_class( # pylint: disable=name-too-long + self, device_class_id: str, **kwargs: Any + ) -> AsyncItemPaged["_models.UpdateInfo"]: """Gets a list of installable updates for a device class. :param device_class_id: Device class identifier. Required. :type device_class_id: str - :return: An iterator like instance of JSON object - :rtype: ~azure.core.async_paging.AsyncItemPaged[JSON] + :return: An iterator like instance of UpdateInfo + :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.iot.deviceupdate.models.UpdateInfo] :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description. - "friendlyName": "str" # Optional. Friendly update name. - } """ _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls = kwargs.pop("cls", None) # type: ClsType[JSON] + cls: ClsType[list[_models.UpdateInfo]] = kwargs.pop("cls", None) - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } error_map.update(kwargs.pop("error_map", {}) or {}) def prepare_request(next_link=None): if not next_link: - request = build_device_management_list_installable_updates_for_device_class_request( + _request = build_device_management_list_installable_updates_for_device_class_request( device_class_id=device_class_id, instance_id=self._config.instance_id, api_version=self._config.api_version, @@ -2146,141 +1720,94 @@ def prepare_request(next_link=None): params=_params, ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) else: # make call to next link with the client's api-version - _parsed_next_link = urlparse(next_link) - _next_request_params = case_insensitive_dict(parse_qs(_parsed_next_link.query)) + _parsed_next_link = urllib.parse.urlparse(next_link) + _next_request_params = case_insensitive_dict( + { + key: [urllib.parse.quote(v) for v in value] + for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items() + } + ) _next_request_params["api-version"] = self._config.api_version - request = HttpRequest("GET", urljoin(next_link, _parsed_next_link.path), params=_next_request_params) + _request = HttpRequest( + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + headers=_headers, + params=_next_request_params, + ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - return request + return _request async def extract_data(pipeline_response): deserialized = pipeline_response.http_response.json() - list_of_elem = deserialized["value"] + list_of_elem = _deserialize( + list[_models.UpdateInfo], + deserialized.get("value", []), + ) if cls: - list_of_elem = cls(list_of_elem) - return deserialized.get("nextLink", None), AsyncList(list_of_elem) + list_of_elem = cls(list_of_elem) # type: ignore + return deserialized.get("nextLink") or None, AsyncList(list_of_elem) async def get_next(next_link=None): - request = prepare_request(next_link) + _request = prepare_request(next_link) - pipeline_response = await self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _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) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) return pipeline_response return AsyncItemPaged(get_next, extract_data) @distributed_trace - def list_devices(self, *, filter: Optional[str] = None, **kwargs: Any) -> AsyncIterable[JSON]: + def list_devices(self, *, filter: Optional[str] = None, **kwargs: Any) -> AsyncItemPaged["_models.Device"]: """Gets a list of devices connected to Device Update for IoT Hub. :keyword filter: Restricts the set of devices returned. You can filter on GroupId, - DeviceClassId, or GroupId and DeploymentStatus. Use DeploymentStatus eq null to query for - devices with no deployment status (that have never been deployed to). Default value is None. + DeviceClassId, or GroupId and DeploymentStatus. Use DeploymentStatus eq null to + query for devices with no deployment status (that have never been deployed to). Default value + is None. :paramtype filter: str - :return: An iterator like instance of JSON object - :rtype: ~azure.core.async_paging.AsyncItemPaged[JSON] + :return: An iterator like instance of Device + :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.iot.deviceupdate.models.Device] :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "deviceClassId": "str", # Device class identity. Required. - "deviceId": "str", # Device identity. Required. - "onLatestUpdate": bool, # Boolean flag indicating whether the latest update - (the best compatible update for the device's device class and group) is installed - on the device. Required. - "deploymentStatus": "str", # Optional. State of the device in its last - deployment. Known values are: "Succeeded", "InProgress", "Canceled", and - "Failed". - "groupId": "str", # Optional. Device group identity. - "installedUpdate": { - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description. - "friendlyName": "str" # Optional. Friendly update name. - }, - "lastAttemptedUpdate": { - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description. - "friendlyName": "str" # Optional. Friendly update name. - }, - "lastDeploymentId": "str", # Optional. The deployment identifier for the - last deployment to the device. - "lastInstallResult": { - "extendedResultCode": 0, # Install extended result code. Required. - "resultCode": 0, # Install result code. Required. - "resultDetails": "str", # Optional. A string containing further - details about the install result. - "stepResults": [ - { - "extendedResultCode": 0, # Install extended result - code. Required. - "resultCode": 0, # Install result code. Required. - "description": "str", # Optional. Step description. - "resultDetails": "str", # Optional. A string - containing further details about the install result. - "update": { - "updateId": { - "name": "str", # Update name. - Required. - "provider": "str", # Update - provider. Required. - "version": "str" # Update version. - Required. - }, - "description": "str", # Optional. Update - description. - "friendlyName": "str" # Optional. Friendly - update name. - } - } - ] - }, - "moduleId": "str" # Optional. Device module identity. - } """ _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls = kwargs.pop("cls", None) # type: ClsType[JSON] + cls: ClsType[list[_models.Device]] = kwargs.pop("cls", None) - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } error_map.update(kwargs.pop("error_map", {}) or {}) def prepare_request(next_link=None): if not next_link: - request = build_device_management_list_devices_request( + _request = build_device_management_list_devices_request( instance_id=self._config.instance_id, filter=filter, api_version=self._config.api_version, @@ -2288,108 +1815,136 @@ def prepare_request(next_link=None): params=_params, ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) else: # make call to next link with the client's api-version - _parsed_next_link = urlparse(next_link) - _next_request_params = case_insensitive_dict(parse_qs(_parsed_next_link.query)) + _parsed_next_link = urllib.parse.urlparse(next_link) + _next_request_params = case_insensitive_dict( + { + key: [urllib.parse.quote(v) for v in value] + for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items() + } + ) _next_request_params["api-version"] = self._config.api_version - request = HttpRequest("GET", urljoin(next_link, _parsed_next_link.path), params=_next_request_params) + _request = HttpRequest( + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + headers=_headers, + params=_next_request_params, + ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - return request + return _request async def extract_data(pipeline_response): deserialized = pipeline_response.http_response.json() - list_of_elem = deserialized["value"] + list_of_elem = _deserialize( + list[_models.Device], + deserialized.get("value", []), + ) if cls: - list_of_elem = cls(list_of_elem) - return deserialized.get("nextLink", None), AsyncList(list_of_elem) + list_of_elem = cls(list_of_elem) # type: ignore + return deserialized.get("nextLink") or None, AsyncList(list_of_elem) async def get_next(next_link=None): - request = prepare_request(next_link) + _request = prepare_request(next_link) - pipeline_response = await self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _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) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) return pipeline_response return AsyncItemPaged(get_next, extract_data) - async def _import_devices_initial( # pylint: disable=inconsistent-return-statements - self, import_type: str, **kwargs: Any - ) -> None: - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + async def _import_devices_initial( + self, import_type: Union[str, _models.ImportType], **kwargs: Any + ) -> AsyncIterator[bytes]: + error_map: MutableMapping = { + 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 = kwargs.pop("content_type", _headers.pop("Content-Type", "application/json")) # type: str - cls = kwargs.pop("cls", None) # type: ClsType[None] + content_type: str = kwargs.pop("content_type", _headers.pop("Content-Type", "application/json")) + cls: ClsType[AsyncIterator[bytes]] = kwargs.pop("cls", None) - _json = import_type + _content = json.dumps(import_type, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - request = build_device_management_import_devices_request( + _request = build_device_management_import_devices_request( instance_id=self._config.instance_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), + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - pipeline_response = await self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _decompress = kwargs.pop("decompress", True) + _stream = True + 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 [202]: + try: + await response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) response_headers = {} response_headers["Operation-Location"] = self._deserialize("str", response.headers.get("Operation-Location")) + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + if cls: - return cls(pipeline_response, None, response_headers) + return cls(pipeline_response, deserialized, response_headers) # type: ignore + + return deserialized # type: ignore @distributed_trace_async - async def begin_import_devices(self, import_type: str, **kwargs: Any) -> AsyncLROPoller[None]: + async def begin_import_devices( + self, import_type: Union[str, _models.ImportType], **kwargs: Any + ) -> AsyncLROPoller[None]: """Import existing devices from IoT Hub. This is a long-running-operation; use Operation-Location response header value to check for operation status. :param import_type: The types of devices to import. Known values are: "Devices", "Modules", and "All". Required. - :type import_type: str - :keyword str continuation_token: A continuation token to restart a poller from a saved state. - :keyword polling: By default, your polling method will be AsyncLROBasePolling. Pass in False - for this operation to not poll, or pass in your own initialized polling object for a personal - polling strategy. - :paramtype polling: bool or ~azure.core.polling.AsyncPollingMethod - :keyword int polling_interval: Default waiting time between two polls for LRO operations if no - Retry-After header is present. + :type import_type: str or ~azure.iot.deviceupdate.models.ImportType :return: An instance of AsyncLROPoller that returns None :rtype: ~azure.core.polling.AsyncLROPoller[None] :raises ~azure.core.exceptions.HttpResponseError: @@ -2397,13 +1952,13 @@ async def begin_import_devices(self, import_type: str, **kwargs: Any) -> AsyncLR _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = kwargs.pop("params", {}) or {} - content_type = kwargs.pop("content_type", _headers.pop("Content-Type", "application/json")) # type: str - cls = kwargs.pop("cls", None) # type: ClsType[None] - polling = kwargs.pop("polling", True) # type: Union[bool, AsyncPollingMethod] + content_type: str = kwargs.pop("content_type", _headers.pop("Content-Type", "application/json")) + cls: ClsType[None] = kwargs.pop("cls", None) + polling: Union[bool, AsyncPollingMethod] = kwargs.pop("polling", True) lro_delay = kwargs.pop("polling_interval", self._config.polling_interval) - cont_token = kwargs.pop("continuation_token", None) # type: Optional[str] + cont_token: Optional[str] = kwargs.pop("continuation_token", None) if cont_token is None: - raw_result = await self._import_devices_initial( # type: ignore + raw_result = await self._import_devices_initial( import_type=import_type, content_type=content_type, cls=lambda x, y, z: x, @@ -2411,121 +1966,60 @@ async def begin_import_devices(self, import_type: str, **kwargs: Any) -> AsyncLR params=_params, **kwargs ) + await raw_result.http_response.read() # type: ignore kwargs.pop("error_map", None) def get_long_running_output(pipeline_response): # pylint: disable=inconsistent-return-statements if cls: - return cls(pipeline_response, None, {}) + return cls(pipeline_response, None, {}) # type: ignore 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"), } if polling is True: - polling_method = cast( + polling_method: AsyncPollingMethod = cast( AsyncPollingMethod, AsyncLROBasePolling(lro_delay, path_format_arguments=path_format_arguments, **kwargs), - ) # type: AsyncPollingMethod + ) elif polling is False: polling_method = cast(AsyncPollingMethod, AsyncNoPolling()) else: polling_method = polling if cont_token: - return AsyncLROPoller.from_continuation_token( + return AsyncLROPoller[None].from_continuation_token( polling_method=polling_method, continuation_token=cont_token, client=self._client, deserialization_callback=get_long_running_output, ) - return AsyncLROPoller(self._client, raw_result, get_long_running_output, polling_method) + return AsyncLROPoller[None](self._client, raw_result, get_long_running_output, polling_method) # type: ignore @distributed_trace_async - async def get_device(self, device_id: str, **kwargs: Any) -> JSON: + async def get_device(self, device_id: str, **kwargs: Any) -> _models.Device: """Gets the device properties and latest deployment status for a device connected to Device Update for IoT Hub. :param device_id: Device identifier in Azure IoT Hub. Required. :type device_id: str - :return: JSON object - :rtype: JSON + :return: Device. The Device is compatible with MutableMapping + :rtype: ~azure.iot.deviceupdate.models.Device :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "deviceClassId": "str", # Device class identity. Required. - "deviceId": "str", # Device identity. Required. - "onLatestUpdate": bool, # Boolean flag indicating whether the latest update - (the best compatible update for the device's device class and group) is installed - on the device. Required. - "deploymentStatus": "str", # Optional. State of the device in its last - deployment. Known values are: "Succeeded", "InProgress", "Canceled", and - "Failed". - "groupId": "str", # Optional. Device group identity. - "installedUpdate": { - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description. - "friendlyName": "str" # Optional. Friendly update name. - }, - "lastAttemptedUpdate": { - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description. - "friendlyName": "str" # Optional. Friendly update name. - }, - "lastDeploymentId": "str", # Optional. The deployment identifier for the - last deployment to the device. - "lastInstallResult": { - "extendedResultCode": 0, # Install extended result code. Required. - "resultCode": 0, # Install result code. Required. - "resultDetails": "str", # Optional. A string containing further - details about the install result. - "stepResults": [ - { - "extendedResultCode": 0, # Install extended result - code. Required. - "resultCode": 0, # Install result code. Required. - "description": "str", # Optional. Step description. - "resultDetails": "str", # Optional. A string - containing further details about the install result. - "update": { - "updateId": { - "name": "str", # Update name. - Required. - "provider": "str", # Update - provider. Required. - "version": "str" # Update version. - Required. - }, - "description": "str", # Optional. Update - description. - "friendlyName": "str" # Optional. Friendly - update name. - } - } - ] - }, - "moduleId": "str" # Optional. Device module identity. - } """ - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 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 = kwargs.pop("cls", None) # type: ClsType[JSON] + cls: ClsType[_models.Device] = kwargs.pop("cls", None) - request = build_device_management_get_device_request( + _request = build_device_management_get_device_request( device_id=device_id, instance_id=self._config.instance_id, api_version=self._config.api_version, @@ -2533,32 +2027,43 @@ async def get_device(self, device_id: str, **kwargs: Any) -> JSON: params=_params, ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - pipeline_response = await self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("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]: + if _stream: + try: + await response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) - if response.content: - deserialized = response.json() + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = None + deserialized = _deserialize(_models.Device, response.json()) if cls: - return cls(pipeline_response, cast(JSON, deserialized), {}) + return cls(pipeline_response, deserialized, {}) # type: ignore - return cast(JSON, deserialized) + return deserialized # type: ignore @distributed_trace_async - async def get_device_module(self, device_id: str, module_id: str, **kwargs: Any) -> JSON: + async def get_device_module(self, device_id: str, module_id: str, **kwargs: Any) -> _models.Device: """Gets the device module properties and latest deployment status for a device module connected to Device Update for IoT Hub. @@ -2566,86 +2071,24 @@ async def get_device_module(self, device_id: str, module_id: str, **kwargs: Any) :type device_id: str :param module_id: Device module identifier in Azure IoT Hub. Required. :type module_id: str - :return: JSON object - :rtype: JSON + :return: Device. The Device is compatible with MutableMapping + :rtype: ~azure.iot.deviceupdate.models.Device :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "deviceClassId": "str", # Device class identity. Required. - "deviceId": "str", # Device identity. Required. - "onLatestUpdate": bool, # Boolean flag indicating whether the latest update - (the best compatible update for the device's device class and group) is installed - on the device. Required. - "deploymentStatus": "str", # Optional. State of the device in its last - deployment. Known values are: "Succeeded", "InProgress", "Canceled", and - "Failed". - "groupId": "str", # Optional. Device group identity. - "installedUpdate": { - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description. - "friendlyName": "str" # Optional. Friendly update name. - }, - "lastAttemptedUpdate": { - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description. - "friendlyName": "str" # Optional. Friendly update name. - }, - "lastDeploymentId": "str", # Optional. The deployment identifier for the - last deployment to the device. - "lastInstallResult": { - "extendedResultCode": 0, # Install extended result code. Required. - "resultCode": 0, # Install result code. Required. - "resultDetails": "str", # Optional. A string containing further - details about the install result. - "stepResults": [ - { - "extendedResultCode": 0, # Install extended result - code. Required. - "resultCode": 0, # Install result code. Required. - "description": "str", # Optional. Step description. - "resultDetails": "str", # Optional. A string - containing further details about the install result. - "update": { - "updateId": { - "name": "str", # Update name. - Required. - "provider": "str", # Update - provider. Required. - "version": "str" # Update version. - Required. - }, - "description": "str", # Optional. Update - description. - "friendlyName": "str" # Optional. Friendly - update name. - } - } - ] - }, - "moduleId": "str" # Optional. Device module identity. - } """ - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 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 = kwargs.pop("cls", None) # type: ClsType[JSON] + cls: ClsType[_models.Device] = kwargs.pop("cls", None) - request = build_device_management_get_device_module_request( + _request = build_device_management_get_device_module_request( device_id=device_id, module_id=module_id, instance_id=self._config.instance_id, @@ -2654,140 +2097,134 @@ async def get_device_module(self, device_id: str, module_id: str, **kwargs: Any) params=_params, ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - pipeline_response = await self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("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]: + if _stream: + try: + await response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) - if response.content: - deserialized = response.json() + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = None + deserialized = _deserialize(_models.Device, response.json()) if cls: - return cls(pipeline_response, cast(JSON, deserialized), {}) + return cls(pipeline_response, deserialized, {}) # type: ignore - return cast(JSON, deserialized) + return deserialized # type: ignore @distributed_trace_async - async def get_update_compliance(self, **kwargs: Any) -> JSON: + async def get_update_compliance(self, **kwargs: Any) -> _models.UpdateCompliance: """Gets the breakdown of how many devices are on their latest update, have new updates available, or are in progress receiving new updates. - :return: JSON object - :rtype: JSON + :return: UpdateCompliance. The UpdateCompliance is compatible with MutableMapping + :rtype: ~azure.iot.deviceupdate.models.UpdateCompliance :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "newUpdatesAvailableDeviceCount": 0, # Number of devices with a newer update - available. Required. - "onLatestUpdateDeviceCount": 0, # Number of devices on the latest update. - Required. - "totalDeviceCount": 0, # Total number of devices. Required. - "updatesInProgressDeviceCount": 0 # Number of devices with update - in-progress. Required. - } """ - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 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 = kwargs.pop("cls", None) # type: ClsType[JSON] + cls: ClsType[_models.UpdateCompliance] = kwargs.pop("cls", None) - request = build_device_management_get_update_compliance_request( + _request = build_device_management_get_update_compliance_request( instance_id=self._config.instance_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), + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - pipeline_response = await self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("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]: + if _stream: + try: + await response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) - if response.content: - deserialized = response.json() + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = None + deserialized = _deserialize(_models.UpdateCompliance, response.json()) if cls: - return cls(pipeline_response, cast(JSON, deserialized), {}) + return cls(pipeline_response, deserialized, {}) # type: ignore - return cast(JSON, deserialized) + return deserialized # type: ignore @distributed_trace - def list_groups(self, *, order_by: Optional[str] = None, **kwargs: Any) -> AsyncIterable[JSON]: + def list_groups(self, *, order_by: Optional[str] = None, **kwargs: Any) -> AsyncItemPaged["_models.Group"]: """Gets a list of all device groups. The $default group will always be returned first. :keyword order_by: Orders the set of groups returned. You can order by groupId, deviceCount, - createdDate, subgroupsWithNewUpdatesAvailableCount, subgroupsWithUpdatesInProgressCount, or - subgroupsOnLatestUpdateCount. Default value is None. + createdDate, subgroupsWithNewUpdatesAvailableCount, + subgroupsWithUpdatesInProgressCount, or subgroupsOnLatestUpdateCount. Default value is None. :paramtype order_by: str - :return: An iterator like instance of JSON object - :rtype: ~azure.core.async_paging.AsyncItemPaged[JSON] + :return: An iterator like instance of Group + :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.iot.deviceupdate.models.Group] :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "createdDateTime": "str", # Date and time when the update was created. - Required. - "groupId": "str", # Group identity. This is created from the value of the - ADUGroup tag in the Iot Hub's device/module twin or $default for devices with no - tag. Required. - "groupType": "str", # Group type. Required. Known values are: "IoTHubTag" - and "DefaultNoTag". - "deployments": [ - "str" # Optional. The active deployment Ids for the group. - ], - "deviceCount": 0, # Optional. The number of devices in the group. - "subgroupsWithNewUpdatesAvailableCount": 0, # Optional. The count of - subgroups with new updates available. - "subgroupsWithOnLatestUpdateCount": 0, # Optional. The count of subgroups - with devices on the latest update. - "subgroupsWithUpdatesInProgressCount": 0 # Optional. The count of subgroups - with updates in progress. - } """ _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls = kwargs.pop("cls", None) # type: ClsType[JSON] + cls: ClsType[list[_models.Group]] = kwargs.pop("cls", None) - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } error_map.update(kwargs.pop("error_map", {}) or {}) def prepare_request(next_link=None): if not next_link: - request = build_device_management_list_groups_request( + _request = build_device_management_list_groups_request( instance_id=self._config.instance_id, order_by=order_by, api_version=self._config.api_version, @@ -2795,93 +2232,88 @@ def prepare_request(next_link=None): params=_params, ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) else: # make call to next link with the client's api-version - _parsed_next_link = urlparse(next_link) - _next_request_params = case_insensitive_dict(parse_qs(_parsed_next_link.query)) + _parsed_next_link = urllib.parse.urlparse(next_link) + _next_request_params = case_insensitive_dict( + { + key: [urllib.parse.quote(v) for v in value] + for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items() + } + ) _next_request_params["api-version"] = self._config.api_version - request = HttpRequest("GET", urljoin(next_link, _parsed_next_link.path), params=_next_request_params) + _request = HttpRequest( + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + headers=_headers, + params=_next_request_params, + ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - return request + return _request async def extract_data(pipeline_response): deserialized = pipeline_response.http_response.json() - list_of_elem = deserialized["value"] + list_of_elem = _deserialize( + list[_models.Group], + deserialized.get("value", []), + ) if cls: - list_of_elem = cls(list_of_elem) - return deserialized.get("nextLink", None), AsyncList(list_of_elem) + list_of_elem = cls(list_of_elem) # type: ignore + return deserialized.get("nextLink") or None, AsyncList(list_of_elem) async def get_next(next_link=None): - request = prepare_request(next_link) + _request = prepare_request(next_link) - pipeline_response = await self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _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) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) return pipeline_response return AsyncItemPaged(get_next, extract_data) @distributed_trace_async - async def get_group(self, group_id: str, **kwargs: Any) -> JSON: + async def get_group(self, group_id: str, **kwargs: Any) -> _models.Group: """Gets the device group properties. :param group_id: Group identifier. Required. :type group_id: str - :return: JSON object - :rtype: JSON + :return: Group. The Group is compatible with MutableMapping + :rtype: ~azure.iot.deviceupdate.models.Group :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "createdDateTime": "str", # Date and time when the update was created. - Required. - "groupId": "str", # Group identity. This is created from the value of the - ADUGroup tag in the Iot Hub's device/module twin or $default for devices with no - tag. Required. - "groupType": "str", # Group type. Required. Known values are: "IoTHubTag" - and "DefaultNoTag". - "deployments": [ - "str" # Optional. The active deployment Ids for the group. - ], - "deviceCount": 0, # Optional. The number of devices in the group. - "subgroupsWithNewUpdatesAvailableCount": 0, # Optional. The count of - subgroups with new updates available. - "subgroupsWithOnLatestUpdateCount": 0, # Optional. The count of subgroups - with devices on the latest update. - "subgroupsWithUpdatesInProgressCount": 0 # Optional. The count of subgroups - with updates in progress. - } """ - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 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 = kwargs.pop("cls", None) # type: ClsType[JSON] + cls: ClsType[_models.Group] = kwargs.pop("cls", None) - request = build_device_management_get_group_request( + _request = build_device_management_get_group_request( group_id=group_id, instance_id=self._config.instance_id, api_version=self._config.api_version, @@ -2889,34 +2321,43 @@ async def get_group(self, group_id: str, **kwargs: Any) -> JSON: params=_params, ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - pipeline_response = await self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("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]: + if _stream: + try: + await response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) - if response.content: - deserialized = response.json() + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = None + deserialized = _deserialize(_models.Group, response.json()) if cls: - return cls(pipeline_response, cast(JSON, deserialized), {}) + return cls(pipeline_response, deserialized, {}) # type: ignore - return cast(JSON, deserialized) + return deserialized # type: ignore @distributed_trace_async - async def delete_group( # pylint: disable=inconsistent-return-statements - self, group_id: str, **kwargs: Any - ) -> None: + async def delete_group(self, group_id: str, **kwargs: Any) -> None: """Deletes a device group. This group is automatically created when a Device Update-enabled device is connected to the hub and reports its properties. Groups, subgroups, and deployments are not automatically cleaned up but are retained for history purposes. Users can call this method to @@ -2930,15 +2371,20 @@ async def delete_group( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 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 = kwargs.pop("cls", None) # type: ClsType[None] + cls: ClsType[None] = kwargs.pop("cls", None) - request = build_device_management_delete_group_request( + _request = build_device_management_delete_group_request( group_id=group_id, instance_id=self._config.instance_id, api_version=self._config.api_version, @@ -2946,57 +2392,53 @@ async def delete_group( # pylint: disable=inconsistent-return-statements params=_params, ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - pipeline_response = await self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _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 [204]: map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) if cls: - return cls(pipeline_response, None, {}) + return cls(pipeline_response, None, {}) # type: ignore @distributed_trace_async - async def get_update_compliance_for_group(self, group_id: str, **kwargs: Any) -> JSON: + async def get_update_compliance_for_group(self, group_id: str, **kwargs: Any) -> _models.UpdateCompliance: """Get device group update compliance information such as how many devices are on their latest update, how many need new updates, and how many are in progress on receiving a new update. :param group_id: Group identifier. Required. :type group_id: str - :return: JSON object - :rtype: JSON + :return: UpdateCompliance. The UpdateCompliance is compatible with MutableMapping + :rtype: ~azure.iot.deviceupdate.models.UpdateCompliance :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "newUpdatesAvailableDeviceCount": 0, # Number of devices with a newer update - available. Required. - "onLatestUpdateDeviceCount": 0, # Number of devices on the latest update. - Required. - "totalDeviceCount": 0, # Total number of devices. Required. - "updatesInProgressDeviceCount": 0 # Number of devices with update - in-progress. Required. - } """ - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 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 = kwargs.pop("cls", None) # type: ClsType[JSON] + cls: ClsType[_models.UpdateCompliance] = kwargs.pop("cls", None) - request = build_device_management_get_update_compliance_for_group_request( + _request = build_device_management_get_update_compliance_for_group_request( group_id=group_id, instance_id=self._config.instance_id, api_version=self._config.api_version, @@ -3004,74 +2446,72 @@ async def get_update_compliance_for_group(self, group_id: str, **kwargs: Any) -> params=_params, ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - pipeline_response = await self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("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]: + if _stream: + try: + await response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) - if response.content: - deserialized = response.json() + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = None + deserialized = _deserialize(_models.UpdateCompliance, response.json()) if cls: - return cls(pipeline_response, cast(JSON, deserialized), {}) + return cls(pipeline_response, deserialized, {}) # type: ignore - return cast(JSON, deserialized) + return deserialized # type: ignore @distributed_trace - def list_best_updates_for_group(self, group_id: str, **kwargs: Any) -> AsyncIterable[JSON]: + def list_best_updates_for_group( + self, group_id: str, **kwargs: Any + ) -> AsyncItemPaged["_models.DeviceClassSubgroupUpdatableDevices"]: """Get the best available updates for a device group and a count of how many devices need each update. :param group_id: Group identifier. Required. :type group_id: str - :return: An iterator like instance of JSON object - :rtype: ~azure.core.async_paging.AsyncItemPaged[JSON] + :return: An iterator like instance of DeviceClassSubgroupUpdatableDevices + :rtype: + ~azure.core.async_paging.AsyncItemPaged[~azure.iot.deviceupdate.models.DeviceClassSubgroupUpdatableDevices] :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "deviceClassId": "str", # The device class subgroup's device class Id. - Required. - "deviceCount": 0, # Total number of devices for which the update is - applicable. Required. - "groupId": "str", # The group Id. Required. - "update": { - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description. - "friendlyName": "str" # Optional. Friendly update name. - } - } """ _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls = kwargs.pop("cls", None) # type: ClsType[JSON] + cls: ClsType[list[_models.DeviceClassSubgroupUpdatableDevices]] = kwargs.pop("cls", None) - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } error_map.update(kwargs.pop("error_map", {}) or {}) def prepare_request(next_link=None): if not next_link: - request = build_device_management_list_best_updates_for_group_request( + _request = build_device_management_list_best_updates_for_group_request( group_id=group_id, instance_id=self._config.instance_id, api_version=self._config.api_version, @@ -3079,45 +2519,59 @@ def prepare_request(next_link=None): params=_params, ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) else: # make call to next link with the client's api-version - _parsed_next_link = urlparse(next_link) - _next_request_params = case_insensitive_dict(parse_qs(_parsed_next_link.query)) + _parsed_next_link = urllib.parse.urlparse(next_link) + _next_request_params = case_insensitive_dict( + { + key: [urllib.parse.quote(v) for v in value] + for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items() + } + ) _next_request_params["api-version"] = self._config.api_version - request = HttpRequest("GET", urljoin(next_link, _parsed_next_link.path), params=_next_request_params) + _request = HttpRequest( + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + headers=_headers, + params=_next_request_params, + ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - return request + return _request async def extract_data(pipeline_response): deserialized = pipeline_response.http_response.json() - list_of_elem = deserialized["value"] + list_of_elem = _deserialize( + list[_models.DeviceClassSubgroupUpdatableDevices], + deserialized.get("value", []), + ) if cls: - list_of_elem = cls(list_of_elem) - return deserialized.get("nextLink", None), AsyncList(list_of_elem) + list_of_elem = cls(list_of_elem) # type: ignore + return deserialized.get("nextLink") or None, AsyncList(list_of_elem) async def get_next(next_link=None): - request = prepare_request(next_link) + _request = prepare_request(next_link) - pipeline_response = await self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _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) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) return pipeline_response @@ -3126,7 +2580,7 @@ async def get_next(next_link=None): @distributed_trace def list_deployments_for_group( self, group_id: str, *, order_by: Optional[str] = None, **kwargs: Any - ) -> AsyncIterable[JSON]: + ) -> AsyncItemPaged["_models.Deployment"]: """Gets a list of deployments for a device group. :param group_id: Group identifier. Required. @@ -3134,76 +2588,27 @@ def list_deployments_for_group( :keyword order_by: Orders the set of deployments returned. You can order by start date. Default value is None. :paramtype order_by: str - :return: An iterator like instance of JSON object - :rtype: ~azure.core.async_paging.AsyncItemPaged[JSON] + :return: An iterator like instance of Deployment + :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.iot.deviceupdate.models.Deployment] :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "deploymentId": "str", # The caller-provided deployment identifier. This - cannot be longer than 73 characters, must be all lower-case, and cannot contain - '&', '^', '[', ']', '{', '}', '|', '<', '>', forward slash, backslash, or double - quote. The Updates view in the Azure Portal IoT Hub resource generates a GUID for - deploymentId when you create a deployment. Required. - "groupId": "str", # The group identity for the devices the deployment is - intended to update. Required. - "startDateTime": "2020-02-20 00:00:00", # The deployment start datetime. - Required. - "update": { - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description. - "friendlyName": "str" # Optional. Friendly update name. - }, - "deviceClassSubgroups": [ - "str" # Optional. The device class subgroups the deployment is - compatible with and subgroup deployments have been created for. This is not - provided by the caller during CreateOrUpdateDeployment but is automatically - determined by Device Update. - ], - "isCanceled": bool, # Optional. Boolean flag indicating whether the - deployment was canceled. - "isCloudInitiatedRollback": bool, # Optional. Boolean flag indicating - whether the deployment is a rollback deployment. - "isRetried": bool, # Optional. Boolean flag indicating whether the - deployment has been retried. - "rollbackPolicy": { - "failure": { - "devicesFailedCount": 0, # Number of devices that failed. - Required. - "devicesFailedPercentage": 0 # Percentage of devices that - failed. Required. - }, - "update": { - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description. - "friendlyName": "str" # Optional. Friendly update name. - } - } - } """ _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls = kwargs.pop("cls", None) # type: ClsType[JSON] + cls: ClsType[list[_models.Deployment]] = kwargs.pop("cls", None) - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } error_map.update(kwargs.pop("error_map", {}) or {}) def prepare_request(next_link=None): if not next_link: - request = build_device_management_list_deployments_for_group_request( + _request = build_device_management_list_deployments_for_group_request( group_id=group_id, instance_id=self._config.instance_id, order_by=order_by, @@ -3212,125 +2617,90 @@ def prepare_request(next_link=None): params=_params, ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) else: # make call to next link with the client's api-version - _parsed_next_link = urlparse(next_link) - _next_request_params = case_insensitive_dict(parse_qs(_parsed_next_link.query)) + _parsed_next_link = urllib.parse.urlparse(next_link) + _next_request_params = case_insensitive_dict( + { + key: [urllib.parse.quote(v) for v in value] + for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items() + } + ) _next_request_params["api-version"] = self._config.api_version - request = HttpRequest("GET", urljoin(next_link, _parsed_next_link.path), params=_next_request_params) + _request = HttpRequest( + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + headers=_headers, + params=_next_request_params, + ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - return request + return _request async def extract_data(pipeline_response): deserialized = pipeline_response.http_response.json() - list_of_elem = deserialized["value"] + list_of_elem = _deserialize( + list[_models.Deployment], + deserialized.get("value", []), + ) if cls: - list_of_elem = cls(list_of_elem) - return deserialized.get("nextLink", None), AsyncList(list_of_elem) + list_of_elem = cls(list_of_elem) # type: ignore + return deserialized.get("nextLink") or None, AsyncList(list_of_elem) async def get_next(next_link=None): - request = prepare_request(next_link) + _request = prepare_request(next_link) - pipeline_response = await self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _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) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) return pipeline_response return AsyncItemPaged(get_next, extract_data) @distributed_trace_async - async def get_deployment(self, group_id: str, deployment_id: str, **kwargs: Any) -> JSON: + async def get_deployment(self, group_id: str, deployment_id: str, **kwargs: Any) -> _models.Deployment: """Gets the deployment properties. :param group_id: Group identifier. Required. :type group_id: str :param deployment_id: Deployment identifier. Required. :type deployment_id: str - :return: JSON object - :rtype: JSON + :return: Deployment. The Deployment is compatible with MutableMapping + :rtype: ~azure.iot.deviceupdate.models.Deployment :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "deploymentId": "str", # The caller-provided deployment identifier. This - cannot be longer than 73 characters, must be all lower-case, and cannot contain - '&', '^', '[', ']', '{', '}', '|', '<', '>', forward slash, backslash, or double - quote. The Updates view in the Azure Portal IoT Hub resource generates a GUID for - deploymentId when you create a deployment. Required. - "groupId": "str", # The group identity for the devices the deployment is - intended to update. Required. - "startDateTime": "2020-02-20 00:00:00", # The deployment start datetime. - Required. - "update": { - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description. - "friendlyName": "str" # Optional. Friendly update name. - }, - "deviceClassSubgroups": [ - "str" # Optional. The device class subgroups the deployment is - compatible with and subgroup deployments have been created for. This is not - provided by the caller during CreateOrUpdateDeployment but is automatically - determined by Device Update. - ], - "isCanceled": bool, # Optional. Boolean flag indicating whether the - deployment was canceled. - "isCloudInitiatedRollback": bool, # Optional. Boolean flag indicating - whether the deployment is a rollback deployment. - "isRetried": bool, # Optional. Boolean flag indicating whether the - deployment has been retried. - "rollbackPolicy": { - "failure": { - "devicesFailedCount": 0, # Number of devices that failed. - Required. - "devicesFailedPercentage": 0 # Percentage of devices that - failed. Required. - }, - "update": { - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description. - "friendlyName": "str" # Optional. Friendly update name. - } - } - } """ - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 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 = kwargs.pop("cls", None) # type: ClsType[JSON] + cls: ClsType[_models.Deployment] = kwargs.pop("cls", None) - request = build_device_management_get_deployment_request( + _request = build_device_management_get_deployment_request( group_id=group_id, deployment_id=deployment_id, instance_id=self._config.instance_id, @@ -3339,40 +2709,51 @@ async def get_deployment(self, group_id: str, deployment_id: str, **kwargs: Any) params=_params, ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - pipeline_response = await self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("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]: + if _stream: + try: + await response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) - if response.content: - deserialized = response.json() + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = None + deserialized = _deserialize(_models.Deployment, response.json()) if cls: - return cls(pipeline_response, cast(JSON, deserialized), {}) + return cls(pipeline_response, deserialized, {}) # type: ignore - return cast(JSON, deserialized) + return deserialized # type: ignore @overload async def create_or_update_deployment( self, group_id: str, deployment_id: str, - deployment: JSON, + deployment: _models.Deployment, *, content_type: str = "application/json", **kwargs: Any - ) -> JSON: + ) -> _models.Deployment: """Creates or updates a deployment. :param group_id: Group identifier. Required. @@ -3380,118 +2761,39 @@ async def create_or_update_deployment( :param deployment_id: Deployment identifier. Required. :type deployment_id: str :param deployment: The deployment properties. Required. - :type deployment: JSON + :type deployment: ~azure.iot.deviceupdate.models.Deployment :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str - :return: JSON object - :rtype: JSON + :return: Deployment. The Deployment is compatible with MutableMapping + :rtype: ~azure.iot.deviceupdate.models.Deployment :raises ~azure.core.exceptions.HttpResponseError: + """ - Example: - .. code-block:: python - - # JSON input template you can fill out and use as your body input. - deployment = { - "deploymentId": "str", # The caller-provided deployment identifier. This - cannot be longer than 73 characters, must be all lower-case, and cannot contain - '&', '^', '[', ']', '{', '}', '|', '<', '>', forward slash, backslash, or double - quote. The Updates view in the Azure Portal IoT Hub resource generates a GUID for - deploymentId when you create a deployment. Required. - "groupId": "str", # The group identity for the devices the deployment is - intended to update. Required. - "startDateTime": "2020-02-20 00:00:00", # The deployment start datetime. - Required. - "update": { - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description. - "friendlyName": "str" # Optional. Friendly update name. - }, - "deviceClassSubgroups": [ - "str" # Optional. The device class subgroups the deployment is - compatible with and subgroup deployments have been created for. This is not - provided by the caller during CreateOrUpdateDeployment but is automatically - determined by Device Update. - ], - "isCanceled": bool, # Optional. Boolean flag indicating whether the - deployment was canceled. - "isCloudInitiatedRollback": bool, # Optional. Boolean flag indicating - whether the deployment is a rollback deployment. - "isRetried": bool, # Optional. Boolean flag indicating whether the - deployment has been retried. - "rollbackPolicy": { - "failure": { - "devicesFailedCount": 0, # Number of devices that failed. - Required. - "devicesFailedPercentage": 0 # Percentage of devices that - failed. Required. - }, - "update": { - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description. - "friendlyName": "str" # Optional. Friendly update name. - } - } - } + @overload + async def create_or_update_deployment( + self, + group_id: str, + deployment_id: str, + deployment: JSON, + *, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.Deployment: + """Creates or updates a deployment. - # response body for status code(s): 200 - response == { - "deploymentId": "str", # The caller-provided deployment identifier. This - cannot be longer than 73 characters, must be all lower-case, and cannot contain - '&', '^', '[', ']', '{', '}', '|', '<', '>', forward slash, backslash, or double - quote. The Updates view in the Azure Portal IoT Hub resource generates a GUID for - deploymentId when you create a deployment. Required. - "groupId": "str", # The group identity for the devices the deployment is - intended to update. Required. - "startDateTime": "2020-02-20 00:00:00", # The deployment start datetime. - Required. - "update": { - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description. - "friendlyName": "str" # Optional. Friendly update name. - }, - "deviceClassSubgroups": [ - "str" # Optional. The device class subgroups the deployment is - compatible with and subgroup deployments have been created for. This is not - provided by the caller during CreateOrUpdateDeployment but is automatically - determined by Device Update. - ], - "isCanceled": bool, # Optional. Boolean flag indicating whether the - deployment was canceled. - "isCloudInitiatedRollback": bool, # Optional. Boolean flag indicating - whether the deployment is a rollback deployment. - "isRetried": bool, # Optional. Boolean flag indicating whether the - deployment has been retried. - "rollbackPolicy": { - "failure": { - "devicesFailedCount": 0, # Number of devices that failed. - Required. - "devicesFailedPercentage": 0 # Percentage of devices that - failed. Required. - }, - "update": { - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description. - "friendlyName": "str" # Optional. Friendly update name. - } - } - } + :param group_id: Group identifier. Required. + :type group_id: str + :param deployment_id: Deployment identifier. Required. + :type deployment_id: str + :param deployment: The deployment properties. Required. + :type deployment: JSON + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: Deployment. The Deployment is compatible with MutableMapping + :rtype: ~azure.iot.deviceupdate.models.Deployment + :raises ~azure.core.exceptions.HttpResponseError: """ @overload @@ -3499,11 +2801,11 @@ async def create_or_update_deployment( self, group_id: str, deployment_id: str, - deployment: IO, + deployment: IO[bytes], *, content_type: str = "application/json", **kwargs: Any - ) -> JSON: + ) -> _models.Deployment: """Creates or updates a deployment. :param group_id: Group identifier. Required. @@ -3511,245 +2813,101 @@ async def create_or_update_deployment( :param deployment_id: Deployment identifier. Required. :type deployment_id: str :param deployment: The deployment properties. Required. - :type deployment: IO + :type deployment: IO[bytes] :keyword content_type: Body Parameter content-type. Content type parameter for binary body. Default value is "application/json". :paramtype content_type: str - :return: JSON object - :rtype: JSON + :return: Deployment. The Deployment is compatible with MutableMapping + :rtype: ~azure.iot.deviceupdate.models.Deployment :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "deploymentId": "str", # The caller-provided deployment identifier. This - cannot be longer than 73 characters, must be all lower-case, and cannot contain - '&', '^', '[', ']', '{', '}', '|', '<', '>', forward slash, backslash, or double - quote. The Updates view in the Azure Portal IoT Hub resource generates a GUID for - deploymentId when you create a deployment. Required. - "groupId": "str", # The group identity for the devices the deployment is - intended to update. Required. - "startDateTime": "2020-02-20 00:00:00", # The deployment start datetime. - Required. - "update": { - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description. - "friendlyName": "str" # Optional. Friendly update name. - }, - "deviceClassSubgroups": [ - "str" # Optional. The device class subgroups the deployment is - compatible with and subgroup deployments have been created for. This is not - provided by the caller during CreateOrUpdateDeployment but is automatically - determined by Device Update. - ], - "isCanceled": bool, # Optional. Boolean flag indicating whether the - deployment was canceled. - "isCloudInitiatedRollback": bool, # Optional. Boolean flag indicating - whether the deployment is a rollback deployment. - "isRetried": bool, # Optional. Boolean flag indicating whether the - deployment has been retried. - "rollbackPolicy": { - "failure": { - "devicesFailedCount": 0, # Number of devices that failed. - Required. - "devicesFailedPercentage": 0 # Percentage of devices that - failed. Required. - }, - "update": { - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description. - "friendlyName": "str" # Optional. Friendly update name. - } - } - } """ @distributed_trace_async async def create_or_update_deployment( - self, group_id: str, deployment_id: str, deployment: Union[JSON, IO], **kwargs: Any - ) -> JSON: + self, group_id: str, deployment_id: str, deployment: Union[_models.Deployment, JSON, IO[bytes]], **kwargs: Any + ) -> _models.Deployment: """Creates or updates a deployment. :param group_id: Group identifier. Required. :type group_id: str :param deployment_id: Deployment identifier. Required. :type deployment_id: str - :param deployment: The deployment properties. Is either a model type or a IO type. Required. - :type deployment: JSON or IO - :keyword content_type: Body Parameter content-type. Known values are: 'application/json'. - Default value is None. - :paramtype content_type: str - :return: JSON object - :rtype: JSON + :param deployment: The deployment properties. Is one of the following types: Deployment, JSON, + IO[bytes] Required. + :type deployment: ~azure.iot.deviceupdate.models.Deployment or JSON or IO[bytes] + :return: Deployment. The Deployment is compatible with MutableMapping + :rtype: ~azure.iot.deviceupdate.models.Deployment :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "deploymentId": "str", # The caller-provided deployment identifier. This - cannot be longer than 73 characters, must be all lower-case, and cannot contain - '&', '^', '[', ']', '{', '}', '|', '<', '>', forward slash, backslash, or double - quote. The Updates view in the Azure Portal IoT Hub resource generates a GUID for - deploymentId when you create a deployment. Required. - "groupId": "str", # The group identity for the devices the deployment is - intended to update. Required. - "startDateTime": "2020-02-20 00:00:00", # The deployment start datetime. - Required. - "update": { - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description. - "friendlyName": "str" # Optional. Friendly update name. - }, - "deviceClassSubgroups": [ - "str" # Optional. The device class subgroups the deployment is - compatible with and subgroup deployments have been created for. This is not - provided by the caller during CreateOrUpdateDeployment but is automatically - determined by Device Update. - ], - "isCanceled": bool, # Optional. Boolean flag indicating whether the - deployment was canceled. - "isCloudInitiatedRollback": bool, # Optional. Boolean flag indicating - whether the deployment is a rollback deployment. - "isRetried": bool, # Optional. Boolean flag indicating whether the - deployment has been retried. - "rollbackPolicy": { - "failure": { - "devicesFailedCount": 0, # Number of devices that failed. - Required. - "devicesFailedPercentage": 0 # Percentage of devices that - failed. Required. - }, - "update": { - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description. - "friendlyName": "str" # Optional. Friendly update name. - } - } - } """ - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 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 = kwargs.pop("content_type", _headers.pop("Content-Type", None)) # type: Optional[str] - cls = kwargs.pop("cls", None) # type: ClsType[JSON] + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[_models.Deployment] = kwargs.pop("cls", None) content_type = content_type or "application/json" - _json = None _content = None - if isinstance(deployment, (IO, bytes)): + if isinstance(deployment, (IOBase, bytes)): _content = deployment else: - _json = deployment + _content = json.dumps(deployment, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - request = build_device_management_create_or_update_deployment_request( + _request = build_device_management_create_or_update_deployment_request( group_id=group_id, deployment_id=deployment_id, instance_id=self._config.instance_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), + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - pipeline_response = await self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("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]: + if _stream: + try: + await response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) - if response.content: - deserialized = response.json() + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = None + deserialized = _deserialize(_models.Deployment, response.json()) if cls: - return cls(pipeline_response, cast(JSON, deserialized), {}) + return cls(pipeline_response, deserialized, {}) # type: ignore - return cast(JSON, deserialized) + return deserialized # type: ignore @distributed_trace_async - async def delete_deployment( # pylint: disable=inconsistent-return-statements - self, group_id: str, deployment_id: str, **kwargs: Any - ) -> None: - """Deletes a deployment. - - :param group_id: Group identifier. Required. - :type group_id: str - :param deployment_id: Deployment identifier. Required. - :type deployment_id: str - :return: None - :rtype: None - :raises ~azure.core.exceptions.HttpResponseError: - """ - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} - error_map.update(kwargs.pop("error_map", {}) or {}) - - _headers = kwargs.pop("headers", {}) or {} - _params = kwargs.pop("params", {}) or {} - - cls = kwargs.pop("cls", None) # type: ClsType[None] - - request = build_device_management_delete_deployment_request( - group_id=group_id, - deployment_id=deployment_id, - instance_id=self._config.instance_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) # type: ignore - - pipeline_response = 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) - raise HttpResponseError(response=response) - - if cls: - return cls(pipeline_response, None, {}) - - @distributed_trace_async - async def get_deployment_status(self, group_id: str, deployment_id: str, **kwargs: Any) -> JSON: + async def get_deployment_status(self, group_id: str, deployment_id: str, **kwargs: Any) -> _models.DeploymentStatus: """Gets the status of a deployment including a breakdown of how many devices in the deployment are in progress, completed, or failed. @@ -3757,91 +2915,24 @@ async def get_deployment_status(self, group_id: str, deployment_id: str, **kwarg :type group_id: str :param deployment_id: Deployment identifier. Required. :type deployment_id: str - :return: JSON object - :rtype: JSON + :return: DeploymentStatus. The DeploymentStatus is compatible with MutableMapping + :rtype: ~azure.iot.deviceupdate.models.DeploymentStatus :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "deploymentState": "str", # The state of the deployment. Required. Known - values are: "Active", "ActiveWithSubgroupFailures", "Failed", "Inactive", and - "Canceled". - "groupId": "str", # The group identity. Required. - "subgroupStatus": [ - { - "deploymentState": "str", # The state of the subgroup - deployment. Required. Known values are: "Active", "Failed", "Inactive", - and "Canceled". - "deviceClassId": "str", # The device class subgroup - identity. Required. - "groupId": "str", # The group identity. Required. - "devicesCanceledCount": 0, # Optional. The number of devices - which have had their deployment canceled. - "devicesCompletedFailedCount": 0, # Optional. The number of - devices that have completed deployment with a failure. - "devicesCompletedSucceededCount": 0, # Optional. The number - of devices which have successfully completed deployment. - "devicesInProgressCount": 0, # Optional. The number of - devices that are currently in deployment. - "error": { - "code": "str", # Server defined error code. - Required. - "message": "str", # A human-readable representation - of the error. Required. - "details": [ - ... - ], - "innererror": { - "code": "str", # A more specific error code - than what was provided by the containing error. Required. - "errorDetail": "str", # Optional. The - internal error or exception message. - "innerError": ..., - "message": "str" # Optional. A - human-readable representation of the error. - }, - "occurredDateTime": "2020-02-20 00:00:00", # - Optional. Date and time in UTC when the error occurred. - "target": "str" # Optional. The target of the error. - }, - "totalDevices": 0 # Optional. The total number of devices in - the deployment. - } - ], - "error": { - "code": "str", # Server defined error code. Required. - "message": "str", # A human-readable representation of the error. - Required. - "details": [ - ... - ], - "innererror": { - "code": "str", # A more specific error code than what was - provided by the containing error. Required. - "errorDetail": "str", # Optional. The internal error or - exception message. - "innerError": ..., - "message": "str" # Optional. A human-readable representation - of the error. - }, - "occurredDateTime": "2020-02-20 00:00:00", # Optional. Date and time - in UTC when the error occurred. - "target": "str" # Optional. The target of the error. - } - } """ - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 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 = kwargs.pop("cls", None) # type: ClsType[JSON] + cls: ClsType[_models.DeploymentStatus] = kwargs.pop("cls", None) - request = build_device_management_get_deployment_status_request( + _request = build_device_management_get_deployment_status_request( group_id=group_id, deployment_id=deployment_id, instance_id=self._config.instance_id, @@ -3850,34 +2941,45 @@ async def get_deployment_status(self, group_id: str, deployment_id: str, **kwarg params=_params, ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - pipeline_response = await self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("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]: + if _stream: + try: + await response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) - if response.content: - deserialized = response.json() + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = None + deserialized = _deserialize(_models.DeploymentStatus, response.json()) if cls: - return cls(pipeline_response, cast(JSON, deserialized), {}) + return cls(pipeline_response, deserialized, {}) # type: ignore - return cast(JSON, deserialized) + return deserialized # type: ignore @distributed_trace def list_device_class_subgroups_for_group( self, group_id: str, *, filter: Optional[str] = None, **kwargs: Any - ) -> AsyncIterable[JSON]: + ) -> AsyncItemPaged["_models.DeviceClassSubgroup"]: """Get the device class subgroups for the group. A device class subgroup is the set of devices within the group that share the same device class. All devices within the same device class are compatible with the same updates. @@ -3885,43 +2987,31 @@ def list_device_class_subgroups_for_group( :param group_id: Group identifier. Required. :type group_id: str :keyword filter: Restricts the set of device class subgroups returned. You can filter on compat - properties by name and value. (i.e. filter=compatProperties/propertyName1 eq 'value1' and - compatProperties/propertyName2 eq 'value2'). Default value is None. + properties by name and value. (i.e. filter=compatProperties/propertyName1 eq + 'value1' and compatProperties/propertyName2 eq 'value2'). Default value is None. :paramtype filter: str - :return: An iterator like instance of JSON object - :rtype: ~azure.core.async_paging.AsyncItemPaged[JSON] + :return: An iterator like instance of DeviceClassSubgroup + :rtype: + ~azure.core.async_paging.AsyncItemPaged[~azure.iot.deviceupdate.models.DeviceClassSubgroup] :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "createdDateTime": "str", # Date and time when the device class subgroup was - created. Required. - "deviceClassId": "str", # Device class subgroup identity. This is generated - from the model Id and the compat properties reported by the device update agent - in the Device Update PnP interface in IoT Hub. It is a hex-encoded SHA1 hash. - Required. - "groupId": "str", # Group identity. Required. - "deploymentId": "str", # Optional. The active deployment Id for the device - class subgroup. - "deviceCount": 0 # Optional. The number of devices in the device class - subgroup. - } """ _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls = kwargs.pop("cls", None) # type: ClsType[JSON] + cls: ClsType[list[_models.DeviceClassSubgroup]] = kwargs.pop("cls", None) - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } error_map.update(kwargs.pop("error_map", {}) or {}) def prepare_request(next_link=None): if not next_link: - request = build_device_management_list_device_class_subgroups_for_group_request( + _request = build_device_management_list_device_class_subgroups_for_group_request( group_id=group_id, instance_id=self._config.instance_id, filter=filter, @@ -3930,52 +3020,68 @@ def prepare_request(next_link=None): params=_params, ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) else: # make call to next link with the client's api-version - _parsed_next_link = urlparse(next_link) - _next_request_params = case_insensitive_dict(parse_qs(_parsed_next_link.query)) + _parsed_next_link = urllib.parse.urlparse(next_link) + _next_request_params = case_insensitive_dict( + { + key: [urllib.parse.quote(v) for v in value] + for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items() + } + ) _next_request_params["api-version"] = self._config.api_version - request = HttpRequest("GET", urljoin(next_link, _parsed_next_link.path), params=_next_request_params) + _request = HttpRequest( + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + headers=_headers, + params=_next_request_params, + ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - return request + return _request async def extract_data(pipeline_response): deserialized = pipeline_response.http_response.json() - list_of_elem = deserialized["value"] + list_of_elem = _deserialize( + list[_models.DeviceClassSubgroup], + deserialized.get("value", []), + ) if cls: - list_of_elem = cls(list_of_elem) - return deserialized.get("nextLink", None), AsyncList(list_of_elem) + list_of_elem = cls(list_of_elem) # type: ignore + return deserialized.get("nextLink") or None, AsyncList(list_of_elem) async def get_next(next_link=None): - request = prepare_request(next_link) + _request = prepare_request(next_link) - pipeline_response = await self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _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) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) return pipeline_response return AsyncItemPaged(get_next, extract_data) @distributed_trace_async - async def get_device_class_subgroup(self, group_id: str, device_class_id: str, **kwargs: Any) -> JSON: + async def get_device_class_subgroup( + self, group_id: str, device_class_id: str, **kwargs: Any + ) -> _models.DeviceClassSubgroup: """Gets device class subgroup details. A device class subgroup is the set of devices within the group that share the same device class. All devices within the same device class are compatible with the same updates. @@ -3984,37 +3090,24 @@ async def get_device_class_subgroup(self, group_id: str, device_class_id: str, * :type group_id: str :param device_class_id: Device class identifier. Required. :type device_class_id: str - :return: JSON object - :rtype: JSON + :return: DeviceClassSubgroup. The DeviceClassSubgroup is compatible with MutableMapping + :rtype: ~azure.iot.deviceupdate.models.DeviceClassSubgroup :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "createdDateTime": "str", # Date and time when the device class subgroup was - created. Required. - "deviceClassId": "str", # Device class subgroup identity. This is generated - from the model Id and the compat properties reported by the device update agent - in the Device Update PnP interface in IoT Hub. It is a hex-encoded SHA1 hash. - Required. - "groupId": "str", # Group identity. Required. - "deploymentId": "str", # Optional. The active deployment Id for the device - class subgroup. - "deviceCount": 0 # Optional. The number of devices in the device class - subgroup. - } """ - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 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 = kwargs.pop("cls", None) # type: ClsType[JSON] + cls: ClsType[_models.DeviceClassSubgroup] = kwargs.pop("cls", None) - request = build_device_management_get_device_class_subgroup_request( + _request = build_device_management_get_device_class_subgroup_request( group_id=group_id, device_class_id=device_class_id, instance_id=self._config.instance_id, @@ -4023,34 +3116,43 @@ class subgroup. params=_params, ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - pipeline_response = await self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("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]: + if _stream: + try: + await response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) - if response.content: - deserialized = response.json() + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = None + deserialized = _deserialize(_models.DeviceClassSubgroup, response.json()) if cls: - return cls(pipeline_response, cast(JSON, deserialized), {}) + return cls(pipeline_response, deserialized, {}) # type: ignore - return cast(JSON, deserialized) + return deserialized # type: ignore @distributed_trace_async - async def delete_device_class_subgroup( # pylint: disable=inconsistent-return-statements - self, group_id: str, device_class_id: str, **kwargs: Any - ) -> None: + async def delete_device_class_subgroup(self, group_id: str, device_class_id: str, **kwargs: Any) -> None: """Deletes a device class subgroup. This subgroup is automatically created when a Device Update-enabled device is connected to the hub and reports its properties. Groups, subgroups, and deployments are not automatically cleaned up but are retained for history purposes. Users @@ -4066,15 +3168,20 @@ async def delete_device_class_subgroup( # pylint: disable=inconsistent-return-s :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 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 = kwargs.pop("cls", None) # type: ClsType[None] + cls: ClsType[None] = kwargs.pop("cls", None) - request = build_device_management_delete_device_class_subgroup_request( + _request = build_device_management_delete_device_class_subgroup_request( group_id=group_id, device_class_id=device_class_id, instance_id=self._config.instance_id, @@ -4083,27 +3190,32 @@ async def delete_device_class_subgroup( # pylint: disable=inconsistent-return-s params=_params, ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - pipeline_response = await self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _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 [204]: map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) if cls: - return cls(pipeline_response, None, {}) + return cls(pipeline_response, None, {}) # type: ignore @distributed_trace_async - async def get_device_class_subgroup_update_compliance( + async def get_device_class_subgroup_update_compliance( # pylint: disable=name-too-long self, group_id: str, device_class_id: str, **kwargs: Any - ) -> JSON: + ) -> _models.UpdateCompliance: """Get device class subgroup update compliance information such as how many devices are on their latest update, how many need new updates, and how many are in progress on receiving a new update. @@ -4112,33 +3224,24 @@ async def get_device_class_subgroup_update_compliance( :type group_id: str :param device_class_id: Device class identifier. Required. :type device_class_id: str - :return: JSON object - :rtype: JSON + :return: UpdateCompliance. The UpdateCompliance is compatible with MutableMapping + :rtype: ~azure.iot.deviceupdate.models.UpdateCompliance :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "newUpdatesAvailableDeviceCount": 0, # Number of devices with a newer update - available. Required. - "onLatestUpdateDeviceCount": 0, # Number of devices on the latest update. - Required. - "totalDeviceCount": 0, # Total number of devices. Required. - "updatesInProgressDeviceCount": 0 # Number of devices with update - in-progress. Required. - } """ - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 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 = kwargs.pop("cls", None) # type: ClsType[JSON] + cls: ClsType[_models.UpdateCompliance] = kwargs.pop("cls", None) - request = build_device_management_get_device_class_subgroup_update_compliance_request( + _request = build_device_management_get_device_class_subgroup_update_compliance_request( group_id=group_id, device_class_id=device_class_id, instance_id=self._config.instance_id, @@ -4147,34 +3250,45 @@ async def get_device_class_subgroup_update_compliance( params=_params, ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - pipeline_response = await self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("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]: + if _stream: + try: + await response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) - if response.content: - deserialized = response.json() + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = None + deserialized = _deserialize(_models.UpdateCompliance, response.json()) if cls: - return cls(pipeline_response, cast(JSON, deserialized), {}) + return cls(pipeline_response, deserialized, {}) # type: ignore - return cast(JSON, deserialized) + return deserialized # type: ignore @distributed_trace_async - async def get_best_updates_for_device_class_subgroup( + async def get_best_updates_for_device_class_subgroup( # pylint: disable=name-too-long self, group_id: str, device_class_id: str, **kwargs: Any - ) -> JSON: + ) -> _models.DeviceClassSubgroupUpdatableDevices: """Get the best available update for a device class subgroup and a count of how many devices need this update. @@ -4182,40 +3296,25 @@ async def get_best_updates_for_device_class_subgroup( :type group_id: str :param device_class_id: Device class identifier. Required. :type device_class_id: str - :return: JSON object - :rtype: JSON + :return: DeviceClassSubgroupUpdatableDevices. The DeviceClassSubgroupUpdatableDevices is + compatible with MutableMapping + :rtype: ~azure.iot.deviceupdate.models.DeviceClassSubgroupUpdatableDevices :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "deviceClassId": "str", # The device class subgroup's device class Id. - Required. - "deviceCount": 0, # Total number of devices for which the update is - applicable. Required. - "groupId": "str", # The group Id. Required. - "update": { - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description. - "friendlyName": "str" # Optional. Friendly update name. - } - } """ - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 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 = kwargs.pop("cls", None) # type: ClsType[JSON] + cls: ClsType[_models.DeviceClassSubgroupUpdatableDevices] = kwargs.pop("cls", None) - request = build_device_management_get_best_updates_for_device_class_subgroup_request( + _request = build_device_management_get_best_updates_for_device_class_subgroup_request( group_id=group_id, device_class_id=device_class_id, instance_id=self._config.instance_id, @@ -4224,34 +3323,45 @@ async def get_best_updates_for_device_class_subgroup( params=_params, ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - pipeline_response = await self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("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]: + if _stream: + try: + await response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) - if response.content: - deserialized = response.json() + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = None + deserialized = _deserialize(_models.DeviceClassSubgroupUpdatableDevices, response.json()) if cls: - return cls(pipeline_response, cast(JSON, deserialized), {}) + return cls(pipeline_response, deserialized, {}) # type: ignore - return cast(JSON, deserialized) + return deserialized # type: ignore @distributed_trace - def list_deployments_for_device_class_subgroup( + def list_deployments_for_device_class_subgroup( # pylint: disable=name-too-long self, group_id: str, device_class_id: str, *, order_by: Optional[str] = None, **kwargs: Any - ) -> AsyncIterable[JSON]: + ) -> AsyncItemPaged["_models.Deployment"]: """Gets a list of deployments for a device class subgroup. :param group_id: Group identifier. Required. @@ -4261,76 +3371,27 @@ def list_deployments_for_device_class_subgroup( :keyword order_by: Orders the set of deployments returned. You can order by start date. Default value is None. :paramtype order_by: str - :return: An iterator like instance of JSON object - :rtype: ~azure.core.async_paging.AsyncItemPaged[JSON] + :return: An iterator like instance of Deployment + :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.iot.deviceupdate.models.Deployment] :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "deploymentId": "str", # The caller-provided deployment identifier. This - cannot be longer than 73 characters, must be all lower-case, and cannot contain - '&', '^', '[', ']', '{', '}', '|', '<', '>', forward slash, backslash, or double - quote. The Updates view in the Azure Portal IoT Hub resource generates a GUID for - deploymentId when you create a deployment. Required. - "groupId": "str", # The group identity for the devices the deployment is - intended to update. Required. - "startDateTime": "2020-02-20 00:00:00", # The deployment start datetime. - Required. - "update": { - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description. - "friendlyName": "str" # Optional. Friendly update name. - }, - "deviceClassSubgroups": [ - "str" # Optional. The device class subgroups the deployment is - compatible with and subgroup deployments have been created for. This is not - provided by the caller during CreateOrUpdateDeployment but is automatically - determined by Device Update. - ], - "isCanceled": bool, # Optional. Boolean flag indicating whether the - deployment was canceled. - "isCloudInitiatedRollback": bool, # Optional. Boolean flag indicating - whether the deployment is a rollback deployment. - "isRetried": bool, # Optional. Boolean flag indicating whether the - deployment has been retried. - "rollbackPolicy": { - "failure": { - "devicesFailedCount": 0, # Number of devices that failed. - Required. - "devicesFailedPercentage": 0 # Percentage of devices that - failed. Required. - }, - "update": { - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description. - "friendlyName": "str" # Optional. Friendly update name. - } - } - } """ _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls = kwargs.pop("cls", None) # type: ClsType[JSON] + cls: ClsType[list[_models.Deployment]] = kwargs.pop("cls", None) - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } error_map.update(kwargs.pop("error_map", {}) or {}) def prepare_request(next_link=None): if not next_link: - request = build_device_management_list_deployments_for_device_class_subgroup_request( + _request = build_device_management_list_deployments_for_device_class_subgroup_request( group_id=group_id, device_class_id=device_class_id, instance_id=self._config.instance_id, @@ -4340,45 +3401,59 @@ def prepare_request(next_link=None): params=_params, ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) else: # make call to next link with the client's api-version - _parsed_next_link = urlparse(next_link) - _next_request_params = case_insensitive_dict(parse_qs(_parsed_next_link.query)) + _parsed_next_link = urllib.parse.urlparse(next_link) + _next_request_params = case_insensitive_dict( + { + key: [urllib.parse.quote(v) for v in value] + for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items() + } + ) _next_request_params["api-version"] = self._config.api_version - request = HttpRequest("GET", urljoin(next_link, _parsed_next_link.path), params=_next_request_params) + _request = HttpRequest( + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + headers=_headers, + params=_next_request_params, + ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - return request + return _request async def extract_data(pipeline_response): deserialized = pipeline_response.http_response.json() - list_of_elem = deserialized["value"] + list_of_elem = _deserialize( + list[_models.Deployment], + deserialized.get("value", []), + ) if cls: - list_of_elem = cls(list_of_elem) - return deserialized.get("nextLink", None), AsyncList(list_of_elem) + list_of_elem = cls(list_of_elem) # type: ignore + return deserialized.get("nextLink") or None, AsyncList(list_of_elem) async def get_next(next_link=None): - request = prepare_request(next_link) + _request = prepare_request(next_link) - pipeline_response = await self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _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) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) return pipeline_response @@ -4387,7 +3462,7 @@ async def get_next(next_link=None): @distributed_trace_async async def get_deployment_for_device_class_subgroup( self, group_id: str, device_class_id: str, deployment_id: str, **kwargs: Any - ) -> JSON: + ) -> _models.Deployment: """Gets the deployment properties. :param group_id: Group identifier. Required. @@ -4396,73 +3471,24 @@ async def get_deployment_for_device_class_subgroup( :type device_class_id: str :param deployment_id: Deployment identifier. Required. :type deployment_id: str - :return: JSON object - :rtype: JSON + :return: Deployment. The Deployment is compatible with MutableMapping + :rtype: ~azure.iot.deviceupdate.models.Deployment :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "deploymentId": "str", # The caller-provided deployment identifier. This - cannot be longer than 73 characters, must be all lower-case, and cannot contain - '&', '^', '[', ']', '{', '}', '|', '<', '>', forward slash, backslash, or double - quote. The Updates view in the Azure Portal IoT Hub resource generates a GUID for - deploymentId when you create a deployment. Required. - "groupId": "str", # The group identity for the devices the deployment is - intended to update. Required. - "startDateTime": "2020-02-20 00:00:00", # The deployment start datetime. - Required. - "update": { - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description. - "friendlyName": "str" # Optional. Friendly update name. - }, - "deviceClassSubgroups": [ - "str" # Optional. The device class subgroups the deployment is - compatible with and subgroup deployments have been created for. This is not - provided by the caller during CreateOrUpdateDeployment but is automatically - determined by Device Update. - ], - "isCanceled": bool, # Optional. Boolean flag indicating whether the - deployment was canceled. - "isCloudInitiatedRollback": bool, # Optional. Boolean flag indicating - whether the deployment is a rollback deployment. - "isRetried": bool, # Optional. Boolean flag indicating whether the - deployment has been retried. - "rollbackPolicy": { - "failure": { - "devicesFailedCount": 0, # Number of devices that failed. - Required. - "devicesFailedPercentage": 0 # Percentage of devices that - failed. Required. - }, - "update": { - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description. - "friendlyName": "str" # Optional. Friendly update name. - } - } - } """ - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 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 = kwargs.pop("cls", None) # type: ClsType[JSON] + cls: ClsType[_models.Deployment] = kwargs.pop("cls", None) - request = build_device_management_get_deployment_for_device_class_subgroup_request( + _request = build_device_management_get_deployment_for_device_class_subgroup_request( group_id=group_id, device_class_id=device_class_id, deployment_id=deployment_id, @@ -4472,83 +3498,45 @@ async def get_deployment_for_device_class_subgroup( params=_params, ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - pipeline_response = await self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("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]: + if _stream: + try: + await response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) - if response.content: - deserialized = response.json() + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = None + deserialized = _deserialize(_models.Deployment, response.json()) if cls: - return cls(pipeline_response, cast(JSON, deserialized), {}) + return cls(pipeline_response, deserialized, {}) # type: ignore - return cast(JSON, deserialized) + return deserialized # type: ignore @distributed_trace_async - async def delete_deployment_for_device_class_subgroup( # pylint: disable=inconsistent-return-statements + async def stop_deployment( self, group_id: str, device_class_id: str, deployment_id: str, **kwargs: Any - ) -> None: - """Deletes a device class subgroup deployment. - - :param group_id: Group identifier. Required. - :type group_id: str - :param device_class_id: Device class identifier. Required. - :type device_class_id: str - :param deployment_id: Deployment identifier. Required. - :type deployment_id: str - :return: None - :rtype: None - :raises ~azure.core.exceptions.HttpResponseError: - """ - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} - error_map.update(kwargs.pop("error_map", {}) or {}) - - _headers = kwargs.pop("headers", {}) or {} - _params = kwargs.pop("params", {}) or {} - - cls = kwargs.pop("cls", None) # type: ClsType[None] - - request = build_device_management_delete_deployment_for_device_class_subgroup_request( - group_id=group_id, - device_class_id=device_class_id, - deployment_id=deployment_id, - instance_id=self._config.instance_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) # type: ignore - - pipeline_response = 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) - raise HttpResponseError(response=response) - - if cls: - return cls(pipeline_response, None, {}) - - @distributed_trace_async - async def stop_deployment(self, group_id: str, device_class_id: str, deployment_id: str, **kwargs: Any) -> JSON: + ) -> _models.Deployment: """Stops a deployment. :param group_id: Group identifier. Required. @@ -4557,73 +3545,24 @@ async def stop_deployment(self, group_id: str, device_class_id: str, deployment_ :type device_class_id: str :param deployment_id: Deployment identifier. Required. :type deployment_id: str - :return: JSON object - :rtype: JSON + :return: Deployment. The Deployment is compatible with MutableMapping + :rtype: ~azure.iot.deviceupdate.models.Deployment :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "deploymentId": "str", # The caller-provided deployment identifier. This - cannot be longer than 73 characters, must be all lower-case, and cannot contain - '&', '^', '[', ']', '{', '}', '|', '<', '>', forward slash, backslash, or double - quote. The Updates view in the Azure Portal IoT Hub resource generates a GUID for - deploymentId when you create a deployment. Required. - "groupId": "str", # The group identity for the devices the deployment is - intended to update. Required. - "startDateTime": "2020-02-20 00:00:00", # The deployment start datetime. - Required. - "update": { - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description. - "friendlyName": "str" # Optional. Friendly update name. - }, - "deviceClassSubgroups": [ - "str" # Optional. The device class subgroups the deployment is - compatible with and subgroup deployments have been created for. This is not - provided by the caller during CreateOrUpdateDeployment but is automatically - determined by Device Update. - ], - "isCanceled": bool, # Optional. Boolean flag indicating whether the - deployment was canceled. - "isCloudInitiatedRollback": bool, # Optional. Boolean flag indicating - whether the deployment is a rollback deployment. - "isRetried": bool, # Optional. Boolean flag indicating whether the - deployment has been retried. - "rollbackPolicy": { - "failure": { - "devicesFailedCount": 0, # Number of devices that failed. - Required. - "devicesFailedPercentage": 0 # Percentage of devices that - failed. Required. - }, - "update": { - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description. - "friendlyName": "str" # Optional. Friendly update name. - } - } - } """ - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 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 = kwargs.pop("cls", None) # type: ClsType[JSON] + cls: ClsType[_models.Deployment] = kwargs.pop("cls", None) - request = build_device_management_stop_deployment_request( + _request = build_device_management_stop_deployment_request( group_id=group_id, device_class_id=device_class_id, deployment_id=deployment_id, @@ -4633,32 +3572,45 @@ async def stop_deployment(self, group_id: str, device_class_id: str, deployment_ params=_params, ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - pipeline_response = await self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("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]: + if _stream: + try: + await response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) - if response.content: - deserialized = response.json() + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = None + deserialized = _deserialize(_models.Deployment, response.json()) if cls: - return cls(pipeline_response, cast(JSON, deserialized), {}) + return cls(pipeline_response, deserialized, {}) # type: ignore - return cast(JSON, deserialized) + return deserialized # type: ignore @distributed_trace_async - async def retry_deployment(self, group_id: str, device_class_id: str, deployment_id: str, **kwargs: Any) -> JSON: + async def retry_deployment( + self, group_id: str, device_class_id: str, deployment_id: str, **kwargs: Any + ) -> _models.Deployment: """Retries a deployment with failed devices. :param group_id: Group identifier. Required. @@ -4667,73 +3619,24 @@ async def retry_deployment(self, group_id: str, device_class_id: str, deployment :type device_class_id: str :param deployment_id: Deployment identifier. Required. :type deployment_id: str - :return: JSON object - :rtype: JSON + :return: Deployment. The Deployment is compatible with MutableMapping + :rtype: ~azure.iot.deviceupdate.models.Deployment :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "deploymentId": "str", # The caller-provided deployment identifier. This - cannot be longer than 73 characters, must be all lower-case, and cannot contain - '&', '^', '[', ']', '{', '}', '|', '<', '>', forward slash, backslash, or double - quote. The Updates view in the Azure Portal IoT Hub resource generates a GUID for - deploymentId when you create a deployment. Required. - "groupId": "str", # The group identity for the devices the deployment is - intended to update. Required. - "startDateTime": "2020-02-20 00:00:00", # The deployment start datetime. - Required. - "update": { - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description. - "friendlyName": "str" # Optional. Friendly update name. - }, - "deviceClassSubgroups": [ - "str" # Optional. The device class subgroups the deployment is - compatible with and subgroup deployments have been created for. This is not - provided by the caller during CreateOrUpdateDeployment but is automatically - determined by Device Update. - ], - "isCanceled": bool, # Optional. Boolean flag indicating whether the - deployment was canceled. - "isCloudInitiatedRollback": bool, # Optional. Boolean flag indicating - whether the deployment is a rollback deployment. - "isRetried": bool, # Optional. Boolean flag indicating whether the - deployment has been retried. - "rollbackPolicy": { - "failure": { - "devicesFailedCount": 0, # Number of devices that failed. - Required. - "devicesFailedPercentage": 0 # Percentage of devices that - failed. Required. - }, - "update": { - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description. - "friendlyName": "str" # Optional. Friendly update name. - } - } - } """ - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 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 = kwargs.pop("cls", None) # type: ClsType[JSON] + cls: ClsType[_models.Deployment] = kwargs.pop("cls", None) - request = build_device_management_retry_deployment_request( + _request = build_device_management_retry_deployment_request( group_id=group_id, device_class_id=device_class_id, deployment_id=deployment_id, @@ -4743,34 +3646,45 @@ async def retry_deployment(self, group_id: str, device_class_id: str, deployment params=_params, ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - pipeline_response = await self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("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]: + if _stream: + try: + await response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) - if response.content: - deserialized = response.json() + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = None + deserialized = _deserialize(_models.Deployment, response.json()) if cls: - return cls(pipeline_response, cast(JSON, deserialized), {}) + return cls(pipeline_response, deserialized, {}) # type: ignore - return cast(JSON, deserialized) + return deserialized # type: ignore @distributed_trace_async - async def get_device_class_subgroup_deployment_status( + async def get_device_class_subgroup_deployment_status( # pylint: disable=name-too-long self, group_id: str, device_class_id: str, deployment_id: str, **kwargs: Any - ) -> JSON: + ) -> _models.DeviceClassSubgroupDeploymentStatus: """Gets the status of a deployment including a breakdown of how many devices in the deployment are in progress, completed, or failed. @@ -4780,59 +3694,25 @@ async def get_device_class_subgroup_deployment_status( :type device_class_id: str :param deployment_id: Deployment identifier. Required. :type deployment_id: str - :return: JSON object - :rtype: JSON + :return: DeviceClassSubgroupDeploymentStatus. The DeviceClassSubgroupDeploymentStatus is + compatible with MutableMapping + :rtype: ~azure.iot.deviceupdate.models.DeviceClassSubgroupDeploymentStatus :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "deploymentState": "str", # The state of the subgroup deployment. Required. - Known values are: "Active", "Failed", "Inactive", and "Canceled". - "deviceClassId": "str", # The device class subgroup identity. Required. - "groupId": "str", # The group identity. Required. - "devicesCanceledCount": 0, # Optional. The number of devices which have had - their deployment canceled. - "devicesCompletedFailedCount": 0, # Optional. The number of devices that - have completed deployment with a failure. - "devicesCompletedSucceededCount": 0, # Optional. The number of devices which - have successfully completed deployment. - "devicesInProgressCount": 0, # Optional. The number of devices that are - currently in deployment. - "error": { - "code": "str", # Server defined error code. Required. - "message": "str", # A human-readable representation of the error. - Required. - "details": [ - ... - ], - "innererror": { - "code": "str", # A more specific error code than what was - provided by the containing error. Required. - "errorDetail": "str", # Optional. The internal error or - exception message. - "innerError": ..., - "message": "str" # Optional. A human-readable representation - of the error. - }, - "occurredDateTime": "2020-02-20 00:00:00", # Optional. Date and time - in UTC when the error occurred. - "target": "str" # Optional. The target of the error. - }, - "totalDevices": 0 # Optional. The total number of devices in the deployment. - } """ - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 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 = kwargs.pop("cls", None) # type: ClsType[JSON] + cls: ClsType[_models.DeviceClassSubgroupDeploymentStatus] = kwargs.pop("cls", None) - request = build_device_management_get_device_class_subgroup_deployment_status_request( + _request = build_device_management_get_device_class_subgroup_deployment_status_request( group_id=group_id, device_class_id=device_class_id, deployment_id=deployment_id, @@ -4842,34 +3722,45 @@ async def get_device_class_subgroup_deployment_status( params=_params, ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - pipeline_response = await self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("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]: + if _stream: + try: + await response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) - if response.content: - deserialized = response.json() + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = None + deserialized = _deserialize(_models.DeviceClassSubgroupDeploymentStatus, response.json()) if cls: - return cls(pipeline_response, cast(JSON, deserialized), {}) + return cls(pipeline_response, deserialized, {}) # type: ignore - return cast(JSON, deserialized) + return deserialized # type: ignore @distributed_trace - def list_device_states_for_device_class_subgroup_deployment( + def list_device_states_for_device_class_subgroup_deployment( # pylint: disable=name-too-long self, group_id: str, device_class_id: str, deployment_id: str, *, filter: Optional[str] = None, **kwargs: Any - ) -> AsyncIterable[JSON]: + ) -> AsyncItemPaged["_models.DeploymentDeviceState"]: """Gets a list of devices in a deployment along with their state. Useful for getting a list of failed devices. @@ -4882,38 +3773,28 @@ def list_device_states_for_device_class_subgroup_deployment( :keyword filter: Restricts the set of deployment device states returned. You can filter on deviceId and moduleId and/or deviceState. Default value is None. :paramtype filter: str - :return: An iterator like instance of JSON object - :rtype: ~azure.core.async_paging.AsyncItemPaged[JSON] + :return: An iterator like instance of DeploymentDeviceState + :rtype: + ~azure.core.async_paging.AsyncItemPaged[~azure.iot.deviceupdate.models.DeploymentDeviceState] :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "deviceId": "str", # Device identity. Required. - "deviceState": "str", # Deployment device state. Required. Known values are: - "Succeeded", "InProgress", "Canceled", and "Failed". - "movedOnToNewDeployment": bool, # Boolean flag indicating whether this - device is in a newer deployment and can no longer retry this deployment. - Required. - "retryCount": 0, # The number of times this deployment has been retried on - this device. Required. - "moduleId": "str" # Optional. Device module identity. - } """ _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls = kwargs.pop("cls", None) # type: ClsType[JSON] + cls: ClsType[list[_models.DeploymentDeviceState]] = kwargs.pop("cls", None) - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } error_map.update(kwargs.pop("error_map", {}) or {}) def prepare_request(next_link=None): if not next_link: - request = build_device_management_list_device_states_for_device_class_subgroup_deployment_request( + _request = build_device_management_list_device_states_for_device_class_subgroup_deployment_request( group_id=group_id, device_class_id=device_class_id, deployment_id=deployment_id, @@ -4924,45 +3805,59 @@ def prepare_request(next_link=None): params=_params, ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) else: # make call to next link with the client's api-version - _parsed_next_link = urlparse(next_link) - _next_request_params = case_insensitive_dict(parse_qs(_parsed_next_link.query)) + _parsed_next_link = urllib.parse.urlparse(next_link) + _next_request_params = case_insensitive_dict( + { + key: [urllib.parse.quote(v) for v in value] + for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items() + } + ) _next_request_params["api-version"] = self._config.api_version - request = HttpRequest("GET", urljoin(next_link, _parsed_next_link.path), params=_next_request_params) + _request = HttpRequest( + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + headers=_headers, + params=_next_request_params, + ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - return request + return _request async def extract_data(pipeline_response): deserialized = pipeline_response.http_response.json() - list_of_elem = deserialized["value"] + list_of_elem = _deserialize( + list[_models.DeploymentDeviceState], + deserialized.get("value", []), + ) if cls: - list_of_elem = cls(list_of_elem) - return deserialized.get("nextLink", None), AsyncList(list_of_elem) + list_of_elem = cls(list_of_elem) # type: ignore + return deserialized.get("nextLink") or None, AsyncList(list_of_elem) async def get_next(next_link=None): - request = prepare_request(next_link) + _request = prepare_request(next_link) - pipeline_response = await self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _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) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) return pipeline_response @@ -4970,167 +3865,128 @@ async def get_next(next_link=None): @distributed_trace_async async def get_operation_status( - self, operation_id: str, *, if_none_match: Optional[str] = None, **kwargs: Any - ) -> JSON: + self, + operation_id: str, + *, + etag: Optional[str] = None, + match_condition: Optional[MatchConditions] = None, + **kwargs: Any + ) -> _models.DeviceOperation: """Retrieve operation status. :param operation_id: Operation identifier. Required. :type operation_id: str - :keyword if_none_match: Defines the If-None-Match condition. The operation will be performed - only if the ETag on the server does not match this value. Default value is None. - :paramtype if_none_match: str - :return: JSON object - :rtype: JSON + :keyword etag: check if resource is changed. Set None to skip checking etag. Default value is + None. + :paramtype etag: str + :keyword match_condition: The match condition to use upon the etag. Default value is None. + :paramtype match_condition: ~azure.core.MatchConditions + :return: DeviceOperation. The DeviceOperation is compatible with MutableMapping + :rtype: ~azure.iot.deviceupdate.models.DeviceOperation :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "createdDateTime": "2020-02-20 00:00:00", # Date and time in UTC when the - operation was created. Required. - "lastActionDateTime": "2020-02-20 00:00:00", # Date and time in UTC when the - operation status was last updated. Required. - "operationId": "str", # Operation Id. Required. - "status": "str", # Operation status. Required. Known values are: - "NotStarted", "Running", "Succeeded", and "Failed". - "error": { - "code": "str", # Server defined error code. Required. - "message": "str", # A human-readable representation of the error. - Required. - "details": [ - ... - ], - "innererror": { - "code": "str", # A more specific error code than what was - provided by the containing error. Required. - "errorDetail": "str", # Optional. The internal error or - exception message. - "innerError": ..., - "message": "str" # Optional. A human-readable representation - of the error. - }, - "occurredDateTime": "2020-02-20 00:00:00", # Optional. Date and time - in UTC when the error occurred. - "target": "str" # Optional. The target of the error. - }, - "etag": "str", # Optional. Operation ETag. - "traceId": "str" # Optional. Operation correlation identity that can used by - Microsoft Support for troubleshooting. - } """ - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + if match_condition == MatchConditions.IfNotModified: + error_map[412] = ResourceModifiedError + elif match_condition == MatchConditions.IfPresent: + error_map[412] = ResourceNotFoundError + elif match_condition == MatchConditions.IfMissing: + error_map[412] = ResourceExistsError error_map.update(kwargs.pop("error_map", {}) or {}) _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls = kwargs.pop("cls", None) # type: ClsType[JSON] + cls: ClsType[_models.DeviceOperation] = kwargs.pop("cls", None) - request = build_device_management_get_operation_status_request( + _request = build_device_management_get_operation_status_request( operation_id=operation_id, instance_id=self._config.instance_id, - if_none_match=if_none_match, + etag=etag, + match_condition=match_condition, 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), + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - pipeline_response = await self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("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]: + if _stream: + try: + await response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) response_headers = {} response_headers["Retry-After"] = self._deserialize("str", response.headers.get("Retry-After")) - if response.content: - deserialized = response.json() + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = None + deserialized = _deserialize(_models.DeviceOperation, response.json()) if cls: - return cls(pipeline_response, cast(JSON, deserialized), response_headers) + return cls(pipeline_response, deserialized, response_headers) # type: ignore - return cast(JSON, deserialized) + return deserialized # type: ignore @distributed_trace def list_operation_statuses( self, *, filter: Optional[str] = None, top: Optional[int] = None, **kwargs: Any - ) -> AsyncIterable[JSON]: + ) -> AsyncItemPaged["_models.DeviceOperation"]: """Get a list of all device import operations. Completed operations are kept for 7 days before auto-deleted. :keyword filter: Restricts the set of operations returned. Only one specific filter is supported: "status eq 'NotStarted' or status eq 'Running'". Default value is None. :paramtype filter: str - :keyword top: Specifies a non-negative integer n that limits the number of items returned from - a collection. The service returns the number of available items up to but not greater than the - specified value n. Default value is None. + :keyword top: Specifies a non-negative integer n that limits the number of items returned + from a collection. The service returns the number of available items up to but + not greater than the specified value n. Default value is None. :paramtype top: int - :return: An iterator like instance of JSON object - :rtype: ~azure.core.async_paging.AsyncItemPaged[JSON] + :return: An iterator like instance of DeviceOperation + :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.iot.deviceupdate.models.DeviceOperation] :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "createdDateTime": "2020-02-20 00:00:00", # Date and time in UTC when the - operation was created. Required. - "lastActionDateTime": "2020-02-20 00:00:00", # Date and time in UTC when the - operation status was last updated. Required. - "operationId": "str", # Operation Id. Required. - "status": "str", # Operation status. Required. Known values are: - "NotStarted", "Running", "Succeeded", and "Failed". - "error": { - "code": "str", # Server defined error code. Required. - "message": "str", # A human-readable representation of the error. - Required. - "details": [ - ... - ], - "innererror": { - "code": "str", # A more specific error code than what was - provided by the containing error. Required. - "errorDetail": "str", # Optional. The internal error or - exception message. - "innerError": ..., - "message": "str" # Optional. A human-readable representation - of the error. - }, - "occurredDateTime": "2020-02-20 00:00:00", # Optional. Date and time - in UTC when the error occurred. - "target": "str" # Optional. The target of the error. - }, - "etag": "str", # Optional. Operation ETag. - "traceId": "str" # Optional. Operation correlation identity that can used by - Microsoft Support for troubleshooting. - } """ _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls = kwargs.pop("cls", None) # type: ClsType[JSON] + cls: ClsType[list[_models.DeviceOperation]] = kwargs.pop("cls", None) - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } error_map.update(kwargs.pop("error_map", {}) or {}) def prepare_request(next_link=None): if not next_link: - request = build_device_management_list_operation_statuses_request( + _request = build_device_management_list_operation_statuses_request( instance_id=self._config.instance_id, filter=filter, top=top, @@ -5139,45 +3995,59 @@ def prepare_request(next_link=None): params=_params, ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) else: # make call to next link with the client's api-version - _parsed_next_link = urlparse(next_link) - _next_request_params = case_insensitive_dict(parse_qs(_parsed_next_link.query)) + _parsed_next_link = urllib.parse.urlparse(next_link) + _next_request_params = case_insensitive_dict( + { + key: [urllib.parse.quote(v) for v in value] + for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items() + } + ) _next_request_params["api-version"] = self._config.api_version - request = HttpRequest("GET", urljoin(next_link, _parsed_next_link.path), params=_next_request_params) + _request = HttpRequest( + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + headers=_headers, + params=_next_request_params, + ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - return request + return _request async def extract_data(pipeline_response): deserialized = pipeline_response.http_response.json() - list_of_elem = deserialized["value"] + list_of_elem = _deserialize( + list[_models.DeviceOperation], + deserialized.get("value", []), + ) if cls: - list_of_elem = cls(list_of_elem) - return deserialized.get("nextLink", None), AsyncList(list_of_elem) + list_of_elem = cls(list_of_elem) # type: ignore + return deserialized.get("nextLink") or None, AsyncList(list_of_elem) async def get_next(next_link=None): - request = prepare_request(next_link) + _request = prepare_request(next_link) - pipeline_response = await self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _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) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) return pipeline_response @@ -5185,231 +4055,173 @@ async def get_next(next_link=None): @overload async def start_log_collection( - self, log_collection_id: str, log_collection: JSON, *, content_type: str = "application/json", **kwargs: Any - ) -> JSON: + self, + log_collection_id: str, + log_collection: _models.LogCollection, + *, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.LogCollection: """Start the device diagnostics log collection on specified devices. :param log_collection_id: Log collection identifier. Required. :type log_collection_id: str :param log_collection: The log collection properties. Required. - :type log_collection: JSON + :type log_collection: ~azure.iot.deviceupdate.models.LogCollection :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str - :return: JSON object - :rtype: JSON + :return: LogCollection. The LogCollection is compatible with MutableMapping + :rtype: ~azure.iot.deviceupdate.models.LogCollection :raises ~azure.core.exceptions.HttpResponseError: + """ - Example: - .. code-block:: python - - # JSON input template you can fill out and use as your body input. - log_collection = { - "deviceList": [ - { - "deviceId": "str", # Device Id. Required. - "moduleId": "str" # Optional. Module Id. - } - ], - "createdDateTime": "str", # Optional. The timestamp when the operation was - created. - "description": "str", # Optional. Description of the diagnostics operation. - "lastActionDateTime": "str", # Optional. A timestamp for when the current - state was entered. - "operationId": "str", # Optional. The log collection id. - "status": "str" # Optional. Operation status. Known values are: - "NotStarted", "Running", "Succeeded", and "Failed". - } + @overload + async def start_log_collection( + self, log_collection_id: str, log_collection: JSON, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.LogCollection: + """Start the device diagnostics log collection on specified devices. - # response body for status code(s): 201 - response == { - "deviceList": [ - { - "deviceId": "str", # Device Id. Required. - "moduleId": "str" # Optional. Module Id. - } - ], - "createdDateTime": "str", # Optional. The timestamp when the operation was - created. - "description": "str", # Optional. Description of the diagnostics operation. - "lastActionDateTime": "str", # Optional. A timestamp for when the current - state was entered. - "operationId": "str", # Optional. The log collection id. - "status": "str" # Optional. Operation status. Known values are: - "NotStarted", "Running", "Succeeded", and "Failed". - } + :param log_collection_id: Log collection identifier. Required. + :type log_collection_id: str + :param log_collection: The log collection properties. Required. + :type log_collection: JSON + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: LogCollection. The LogCollection is compatible with MutableMapping + :rtype: ~azure.iot.deviceupdate.models.LogCollection + :raises ~azure.core.exceptions.HttpResponseError: """ @overload async def start_log_collection( - self, log_collection_id: str, log_collection: IO, *, content_type: str = "application/json", **kwargs: Any - ) -> JSON: + self, + log_collection_id: str, + log_collection: IO[bytes], + *, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.LogCollection: """Start the device diagnostics log collection on specified devices. :param log_collection_id: Log collection identifier. Required. :type log_collection_id: str :param log_collection: The log collection properties. Required. - :type log_collection: IO + :type log_collection: IO[bytes] :keyword content_type: Body Parameter content-type. Content type parameter for binary body. Default value is "application/json". :paramtype content_type: str - :return: JSON object - :rtype: JSON + :return: LogCollection. The LogCollection is compatible with MutableMapping + :rtype: ~azure.iot.deviceupdate.models.LogCollection :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 201 - response == { - "deviceList": [ - { - "deviceId": "str", # Device Id. Required. - "moduleId": "str" # Optional. Module Id. - } - ], - "createdDateTime": "str", # Optional. The timestamp when the operation was - created. - "description": "str", # Optional. Description of the diagnostics operation. - "lastActionDateTime": "str", # Optional. A timestamp for when the current - state was entered. - "operationId": "str", # Optional. The log collection id. - "status": "str" # Optional. Operation status. Known values are: - "NotStarted", "Running", "Succeeded", and "Failed". - } """ @distributed_trace_async async def start_log_collection( - self, log_collection_id: str, log_collection: Union[JSON, IO], **kwargs: Any - ) -> JSON: + self, log_collection_id: str, log_collection: Union[_models.LogCollection, JSON, IO[bytes]], **kwargs: Any + ) -> _models.LogCollection: """Start the device diagnostics log collection on specified devices. :param log_collection_id: Log collection identifier. Required. :type log_collection_id: str - :param log_collection: The log collection properties. Is either a model type or a IO type. - Required. - :type log_collection: JSON or IO - :keyword content_type: Body Parameter content-type. Known values are: 'application/json'. - Default value is None. - :paramtype content_type: str - :return: JSON object - :rtype: JSON + :param log_collection: The log collection properties. Is one of the following types: + LogCollection, JSON, IO[bytes] Required. + :type log_collection: ~azure.iot.deviceupdate.models.LogCollection or JSON or IO[bytes] + :return: LogCollection. The LogCollection is compatible with MutableMapping + :rtype: ~azure.iot.deviceupdate.models.LogCollection :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 201 - response == { - "deviceList": [ - { - "deviceId": "str", # Device Id. Required. - "moduleId": "str" # Optional. Module Id. - } - ], - "createdDateTime": "str", # Optional. The timestamp when the operation was - created. - "description": "str", # Optional. Description of the diagnostics operation. - "lastActionDateTime": "str", # Optional. A timestamp for when the current - state was entered. - "operationId": "str", # Optional. The log collection id. - "status": "str" # Optional. Operation status. Known values are: - "NotStarted", "Running", "Succeeded", and "Failed". - } """ - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 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 = kwargs.pop("content_type", _headers.pop("Content-Type", None)) # type: Optional[str] - cls = kwargs.pop("cls", None) # type: ClsType[JSON] + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[_models.LogCollection] = kwargs.pop("cls", None) content_type = content_type or "application/json" - _json = None _content = None - if isinstance(log_collection, (IO, bytes)): + if isinstance(log_collection, (IOBase, bytes)): _content = log_collection else: - _json = log_collection + _content = json.dumps(log_collection, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - request = build_device_management_start_log_collection_request( + _request = build_device_management_start_log_collection_request( log_collection_id=log_collection_id, instance_id=self._config.instance_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), + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - pipeline_response = await self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("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 [201]: + if _stream: + try: + await response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) - if response.content: - deserialized = response.json() + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = None + deserialized = _deserialize(_models.LogCollection, response.json()) if cls: - return cls(pipeline_response, cast(JSON, deserialized), {}) + return cls(pipeline_response, deserialized, {}) # type: ignore - return cast(JSON, deserialized) + return deserialized # type: ignore @distributed_trace_async - async def get_log_collection(self, log_collection_id: str, **kwargs: Any) -> JSON: + async def get_log_collection(self, log_collection_id: str, **kwargs: Any) -> _models.LogCollection: """Get the device diagnostics log collection. :param log_collection_id: Log collection identifier. Required. :type log_collection_id: str - :return: JSON object - :rtype: JSON + :return: LogCollection. The LogCollection is compatible with MutableMapping + :rtype: ~azure.iot.deviceupdate.models.LogCollection :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "deviceList": [ - { - "deviceId": "str", # Device Id. Required. - "moduleId": "str" # Optional. Module Id. - } - ], - "createdDateTime": "str", # Optional. The timestamp when the operation was - created. - "description": "str", # Optional. Description of the diagnostics operation. - "lastActionDateTime": "str", # Optional. A timestamp for when the current - state was entered. - "operationId": "str", # Optional. The log collection id. - "status": "str" # Optional. Operation status. Known values are: - "NotStarted", "Running", "Succeeded", and "Failed". - } """ - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 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 = kwargs.pop("cls", None) # type: ClsType[JSON] + cls: ClsType[_models.LogCollection] = kwargs.pop("cls", None) - request = build_device_management_get_log_collection_request( + _request = build_device_management_get_log_collection_request( log_collection_id=log_collection_id, instance_id=self._config.instance_id, api_version=self._config.api_version, @@ -5417,167 +4229,157 @@ async def get_log_collection(self, log_collection_id: str, **kwargs: Any) -> JSO params=_params, ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - pipeline_response = await self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("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]: + if _stream: + try: + await response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) - if response.content: - deserialized = response.json() + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = None + deserialized = _deserialize(_models.LogCollection, response.json()) if cls: - return cls(pipeline_response, cast(JSON, deserialized), {}) + return cls(pipeline_response, deserialized, {}) # type: ignore - return cast(JSON, deserialized) + return deserialized # type: ignore @distributed_trace - def list_log_collections(self, **kwargs: Any) -> AsyncIterable[JSON]: + def list_log_collections(self, **kwargs: Any) -> AsyncItemPaged["_models.LogCollection"]: """Get all device diagnostics log collections. - :return: An iterator like instance of JSON object - :rtype: ~azure.core.async_paging.AsyncItemPaged[JSON] + :return: An iterator like instance of LogCollection + :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.iot.deviceupdate.models.LogCollection] :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "deviceList": [ - { - "deviceId": "str", # Device Id. Required. - "moduleId": "str" # Optional. Module Id. - } - ], - "createdDateTime": "str", # Optional. The timestamp when the operation was - created. - "description": "str", # Optional. Description of the diagnostics operation. - "lastActionDateTime": "str", # Optional. A timestamp for when the current - state was entered. - "operationId": "str", # Optional. The log collection id. - "status": "str" # Optional. Operation status. Known values are: - "NotStarted", "Running", "Succeeded", and "Failed". - } """ _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls = kwargs.pop("cls", None) # type: ClsType[JSON] + cls: ClsType[list[_models.LogCollection]] = kwargs.pop("cls", None) - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } error_map.update(kwargs.pop("error_map", {}) or {}) def prepare_request(next_link=None): if not next_link: - request = build_device_management_list_log_collections_request( + _request = build_device_management_list_log_collections_request( instance_id=self._config.instance_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 - ), + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) else: # make call to next link with the client's api-version - _parsed_next_link = urlparse(next_link) - _next_request_params = case_insensitive_dict(parse_qs(_parsed_next_link.query)) + _parsed_next_link = urllib.parse.urlparse(next_link) + _next_request_params = case_insensitive_dict( + { + key: [urllib.parse.quote(v) for v in value] + for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items() + } + ) _next_request_params["api-version"] = self._config.api_version - request = HttpRequest("GET", urljoin(next_link, _parsed_next_link.path), params=_next_request_params) + _request = HttpRequest( + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + headers=_headers, + params=_next_request_params, + ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - return request + return _request async def extract_data(pipeline_response): deserialized = pipeline_response.http_response.json() - list_of_elem = deserialized["value"] + list_of_elem = _deserialize( + list[_models.LogCollection], + deserialized.get("value", []), + ) if cls: - list_of_elem = cls(list_of_elem) - return deserialized.get("nextLink", None), AsyncList(list_of_elem) + list_of_elem = cls(list_of_elem) # type: ignore + return deserialized.get("nextLink") or None, AsyncList(list_of_elem) async def get_next(next_link=None): - request = prepare_request(next_link) + _request = prepare_request(next_link) - pipeline_response = await self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _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) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) return pipeline_response return AsyncItemPaged(get_next, extract_data) @distributed_trace_async - async def get_log_collection_detailed_status(self, log_collection_id: str, **kwargs: Any) -> JSON: + async def get_log_collection_detailed_status( + self, log_collection_id: str, **kwargs: Any + ) -> _models.LogCollectionOperationDetailedStatus: """Get log collection with detailed status. :param log_collection_id: Log collection identifier. Required. :type log_collection_id: str - :return: JSON object - :rtype: JSON + :return: LogCollectionOperationDetailedStatus. The LogCollectionOperationDetailedStatus is + compatible with MutableMapping + :rtype: ~azure.iot.deviceupdate.models.LogCollectionOperationDetailedStatus :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "createdDateTime": "str", # Optional. The timestamp when the operation was - created. - "description": "str", # Optional. Device diagnostics operation description. - "deviceStatus": [ - { - "deviceId": "str", # Device id. Required. - "status": "str", # Log upload status. Required. Known values - are: "NotStarted", "Running", "Succeeded", and "Failed". - "extendedResultCode": "str", # Optional. Log upload extended - result code. - "logLocation": "str", # Optional. Log upload location. - "moduleId": "str", # Optional. Module id. - "resultCode": "str" # Optional. Log upload result code. - } - ], - "lastActionDateTime": "str", # Optional. A timestamp for when the current - state was entered. - "operationId": "str", # Optional. The device diagnostics operation id. - "status": "str" # Optional. Operation status. Known values are: - "NotStarted", "Running", "Succeeded", and "Failed". - } """ - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 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 = kwargs.pop("cls", None) # type: ClsType[JSON] + cls: ClsType[_models.LogCollectionOperationDetailedStatus] = kwargs.pop("cls", None) - request = build_device_management_get_log_collection_detailed_status_request( + _request = build_device_management_get_log_collection_detailed_status_request( log_collection_id=log_collection_id, instance_id=self._config.instance_id, api_version=self._config.api_version, @@ -5585,72 +4387,69 @@ async def get_log_collection_detailed_status(self, log_collection_id: str, **kwa params=_params, ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - pipeline_response = await self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("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]: + if _stream: + try: + await response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) - if response.content: - deserialized = response.json() + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = None + deserialized = _deserialize(_models.LogCollectionOperationDetailedStatus, response.json()) if cls: - return cls(pipeline_response, cast(JSON, deserialized), {}) + return cls(pipeline_response, deserialized, {}) # type: ignore - return cast(JSON, deserialized) + return deserialized # type: ignore @distributed_trace - def list_health_of_devices(self, *, filter: str, **kwargs: Any) -> AsyncIterable[JSON]: + def list_health_of_devices(self, *, filter: str, **kwargs: Any) -> AsyncItemPaged["_models.DeviceHealth"]: """Get list of device health. :keyword filter: Restricts the set of devices for which device health is returned. You can filter on status, device id and module id. Required. :paramtype filter: str - :return: An iterator like instance of JSON object - :rtype: ~azure.core.async_paging.AsyncItemPaged[JSON] + :return: An iterator like instance of DeviceHealth + :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.iot.deviceupdate.models.DeviceHealth] :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "deviceId": "str", # Device id. Required. - "healthChecks": [ - { - "name": "str", # Optional. Health check name. - "result": "str" # Optional. Health check result. Known - values are: "success" and "userError". - } - ], - "state": "str", # Aggregate device health state. Required. Known values are: - "healthy" and "unhealthy". - "digitalTwinModelId": "str", # Optional. Digital twin model Id. - "moduleId": "str" # Optional. Module id. - } """ _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls = kwargs.pop("cls", None) # type: ClsType[JSON] + cls: ClsType[list[_models.DeviceHealth]] = kwargs.pop("cls", None) - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } error_map.update(kwargs.pop("error_map", {}) or {}) def prepare_request(next_link=None): if not next_link: - request = build_device_management_list_health_of_devices_request( + _request = build_device_management_list_health_of_devices_request( instance_id=self._config.instance_id, filter=filter, api_version=self._config.api_version, @@ -5658,46 +4457,177 @@ def prepare_request(next_link=None): params=_params, ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) else: # make call to next link with the client's api-version - _parsed_next_link = urlparse(next_link) - _next_request_params = case_insensitive_dict(parse_qs(_parsed_next_link.query)) + _parsed_next_link = urllib.parse.urlparse(next_link) + _next_request_params = case_insensitive_dict( + { + key: [urllib.parse.quote(v) for v in value] + for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items() + } + ) _next_request_params["api-version"] = self._config.api_version - request = HttpRequest("GET", urljoin(next_link, _parsed_next_link.path), params=_next_request_params) + _request = HttpRequest( + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + headers=_headers, + params=_next_request_params, + ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - return request + return _request async def extract_data(pipeline_response): deserialized = pipeline_response.http_response.json() - list_of_elem = deserialized["value"] + list_of_elem = _deserialize( + list[_models.DeviceHealth], + deserialized.get("value", []), + ) if cls: - list_of_elem = cls(list_of_elem) - return deserialized.get("nextLink", None), AsyncList(list_of_elem) + list_of_elem = cls(list_of_elem) # type: ignore + return deserialized.get("nextLink") or None, AsyncList(list_of_elem) async def get_next(next_link=None): - request = prepare_request(next_link) + _request = prepare_request(next_link) - pipeline_response = await self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _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) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) return pipeline_response return AsyncItemPaged(get_next, extract_data) + + @distributed_trace_async + async def delete_deployment(self, group_id: str, deployment_id: str, **kwargs: Any) -> None: + """Deletes a deployment. + + :param group_id: Group identifier. Required. + :type group_id: str + :param deployment_id: Deployment identifier. Required. + :type deployment_id: str + :return: None + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 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_device_management_delete_deployment_request( + group_id=group_id, + deployment_id=deployment_id, + instance_id=self._config.instance_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"), + } + _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 [204]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) + + if cls: + return cls(pipeline_response, None, {}) # type: ignore + + @distributed_trace_async + async def delete_deployment_for_device_class_subgroup( # pylint: disable=name-too-long + self, group_id: str, device_class_id: str, deployment_id: str, **kwargs: Any + ) -> None: + """Deletes a device class subgroup deployment. + + :param group_id: Group identifier. Required. + :type group_id: str + :param device_class_id: Device class identifier. Required. + :type device_class_id: str + :param deployment_id: Deployment identifier. Required. + :type deployment_id: str + :return: None + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 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_device_management_delete_deployment_for_device_class_subgroup_request( + group_id=group_id, + device_class_id=device_class_id, + deployment_id=deployment_id, + instance_id=self._config.instance_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"), + } + _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 [204]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) + + if cls: + return cls(pipeline_response, None, {}) # type: ignore diff --git a/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/aio/operations/_patch.py b/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/aio/operations/_patch.py index f7dd32510333..87676c65a8f0 100644 --- a/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/aio/operations/_patch.py +++ b/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/aio/operations/_patch.py @@ -1,14 +1,15 @@ -# ------------------------------------ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. -# ------------------------------------ +# 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. +# -------------------------------------------------------------------------- """Customize generated code here. Follow our quickstart for examples: https://aka.ms/azsdk/python/dpcodegen/python/customize """ -from typing import List -__all__: List[str] = [] # Add all objects you want publicly available to users at this package level + +__all__: list[str] = [] # Add all objects you want publicly available to users at this package level def patch_sdk(): diff --git a/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/models/__init__.py b/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/models/__init__.py new file mode 100644 index 000000000000..12fa9c0a854a --- /dev/null +++ b/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/models/__init__.py @@ -0,0 +1,128 @@ +# 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) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +# pylint: disable=wrong-import-position + +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from ._patch import * # pylint: disable=unused-wildcard-import + + +from ._models import ( # type: ignore + CloudInitiatedRollbackPolicy, + CloudInitiatedRollbackPolicyFailure, + Compatibility, + ContractModel, + Deployment, + DeploymentDeviceState, + DeploymentStatus, + Device, + DeviceClass, + DeviceClassProperties, + DeviceClassSubgroup, + DeviceClassSubgroupDeploymentStatus, + DeviceClassSubgroupUpdatableDevices, + DeviceHealth, + DeviceOperation, + DeviceUpdateAgentId, + Error, + ErrorResponse, + FileImportMetadata, + Group, + HealthCheck, + ImportManifestMetadata, + ImportUpdateInputItem, + InnerError, + InstallResult, + Instructions, + LogCollection, + LogCollectionOperationDetailedStatus, + LogCollectionOperationDeviceStatus, + PatchBody, + Step, + StepResult, + Update, + UpdateCompliance, + UpdateFile, + UpdateFileBase, + UpdateFileDownloadHandler, + UpdateId, + UpdateInfo, + UpdateOperation, +) + +from ._enums import ( # type: ignore + DeploymentState, + DeviceClassSubgroupDeploymentState, + DeviceDeploymentState, + DeviceHealthState, + DownloadSecurity, + GroupType, + HealthCheckResult, + ImportType, + OperationStatus, + StepType, +) +from ._patch import __all__ as _patch_all +from ._patch import * +from ._patch import patch_sdk as _patch_sdk + +__all__ = [ + "CloudInitiatedRollbackPolicy", + "CloudInitiatedRollbackPolicyFailure", + "Compatibility", + "ContractModel", + "Deployment", + "DeploymentDeviceState", + "DeploymentStatus", + "Device", + "DeviceClass", + "DeviceClassProperties", + "DeviceClassSubgroup", + "DeviceClassSubgroupDeploymentStatus", + "DeviceClassSubgroupUpdatableDevices", + "DeviceHealth", + "DeviceOperation", + "DeviceUpdateAgentId", + "Error", + "ErrorResponse", + "FileImportMetadata", + "Group", + "HealthCheck", + "ImportManifestMetadata", + "ImportUpdateInputItem", + "InnerError", + "InstallResult", + "Instructions", + "LogCollection", + "LogCollectionOperationDetailedStatus", + "LogCollectionOperationDeviceStatus", + "PatchBody", + "Step", + "StepResult", + "Update", + "UpdateCompliance", + "UpdateFile", + "UpdateFileBase", + "UpdateFileDownloadHandler", + "UpdateId", + "UpdateInfo", + "UpdateOperation", + "DeploymentState", + "DeviceClassSubgroupDeploymentState", + "DeviceDeploymentState", + "DeviceHealthState", + "DownloadSecurity", + "GroupType", + "HealthCheckResult", + "ImportType", + "OperationStatus", + "StepType", +] +__all__.extend([p for p in _patch_all if p not in __all__]) # pyright: ignore +_patch_sdk() diff --git a/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/models/_enums.py b/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/models/_enums.py new file mode 100644 index 000000000000..4d101dbce148 --- /dev/null +++ b/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/models/_enums.py @@ -0,0 +1,124 @@ +# 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) Python 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 DeploymentState(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """Deployment state.""" + + ACTIVE = "Active" + """The deployment can be sent to devices targeted in the deployment.""" + ACTIVE_WITH_SUBGROUP_FAILURES = "ActiveWithSubgroupFailures" + """The deployment can be sent to some devices targeted in the deployment but at least 1 subgroup + is in a failed state.""" + FAILED = "Failed" + """The deployment will not be sent to any devices. Consult error for more details about what + failed.""" + INACTIVE = "Inactive" + """A newer deployment for this group has been created and no devices in the group will receive + this deployment.""" + CANCELED = "Canceled" + """The deployment has been canceled and no devices will receive it.""" + + +class DeviceClassSubgroupDeploymentState(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """Device class subgroup deployment state.""" + + ACTIVE = "Active" + """The subgroup deployment can be sent to devices targeted in the deployment.""" + FAILED = "Failed" + """The subgroup deployment failed and will not be sent to any devices.""" + INACTIVE = "Inactive" + """A newer deployment for this subgroup has been created and no devices in the subgroup will + receive this deployment.""" + CANCELED = "Canceled" + """The subgroup deployment has been canceled and no devices will receive it.""" + + +class DeviceDeploymentState(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """Deployment state.""" + + SUCCEEDED = "Succeeded" + """Deployment has completed with success.""" + IN_PROGRESS = "InProgress" + """Deployment is in progress.""" + CANCELED = "Canceled" + """Deployment was canceled.""" + FAILED = "Failed" + """Deployment has completed with failure.""" + + +class DeviceHealthState(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """Device health states.""" + + HEALTHY = "healthy" + """Agent is healthy.""" + UNHEALTHY = "unhealthy" + """Agent is in an unhealthy state.""" + + +class DownloadSecurity(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """The protocol the device should use when downloading the update payload.""" + + HTTPS = "https" + """Download update payload over HTTPS.""" + HTTP = "http" + """Download update payload over HTTP.""" + + +class GroupType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """Supported group types.""" + + IO_T_HUB_TAG = "IoTHubTag" + """IoT Hub tag based group, all devices in the group share an ADUGroup tag value.""" + DEFAULT_NO_TAG = "DefaultNoTag" + """Default group for untagged devices.""" + + +class HealthCheckResult(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """Health check result.""" + + SUCCESS = "success" + """Health check succeeded.""" + USER_ERROR = "userError" + """Health check failed due to user error.""" + + +class ImportType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """The device import type.""" + + DEVICES = "Devices" + """Import only devices but not modules.""" + MODULES = "Modules" + """Import only modules but not devices.""" + ALL = "All" + """Import both devices and modules.""" + + +class OperationStatus(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """Operation status.""" + + NOT_STARTED = "NotStarted" + """Background operation created but not started yet.""" + RUNNING = "Running" + """Background operation is currently running.""" + SUCCEEDED = "Succeeded" + """Background operation finished with success.""" + FAILED = "Failed" + """Background operation finished with failure.""" + + +class StepType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """Step type.""" + + INLINE = "inline" + """Step type that performs code execution.""" + REFERENCE = "reference" + """Step type that installs another update.""" diff --git a/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/models/_models.py b/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/models/_models.py new file mode 100644 index 000000000000..40e0d650001a --- /dev/null +++ b/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/models/_models.py @@ -0,0 +1,2156 @@ +# 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) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +# pylint: disable=useless-super-delegation + +import datetime +from typing import Any, Mapping, Optional, TYPE_CHECKING, Union, overload + +from .._utils.model_base import Model as _Model, rest_field + +if TYPE_CHECKING: + from .. import models as _models + + +class CloudInitiatedRollbackPolicy(_Model): + """Rollback policy for deployment. + + :ivar update_property: Update to rollback to. Required. + :vartype update_property: ~azure.iot.deviceupdate.models.UpdateInfo + :ivar failure: Failure conditions to initiate rollback policy. Required. + :vartype failure: ~azure.iot.deviceupdate.models.CloudInitiatedRollbackPolicyFailure + """ + + update_property: "_models.UpdateInfo" = rest_field( + name="update", visibility=["read", "create", "update", "delete", "query"], original_tsp_name="update" + ) + """Update to rollback to. Required.""" + failure: "_models.CloudInitiatedRollbackPolicyFailure" = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Failure conditions to initiate rollback policy. Required.""" + + @overload + def __init__( + self, + *, + update_property: "_models.UpdateInfo", + failure: "_models.CloudInitiatedRollbackPolicyFailure", + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + + +class CloudInitiatedRollbackPolicyFailure(_Model): + """Failure conditions to initiate rollback policy. + + :ivar devices_failed_percentage: Percentage of devices that failed. Required. + :vartype devices_failed_percentage: int + :ivar devices_failed_count: Number of devices that failed. Required. + :vartype devices_failed_count: int + """ + + devices_failed_percentage: int = rest_field( + name="devicesFailedPercentage", visibility=["read", "create", "update", "delete", "query"] + ) + """Percentage of devices that failed. Required.""" + devices_failed_count: int = rest_field( + name="devicesFailedCount", visibility=["read", "create", "update", "delete", "query"] + ) + """Number of devices that failed. Required.""" + + @overload + def __init__( + self, + *, + devices_failed_percentage: int, + devices_failed_count: int, + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + + +class Compatibility(_Model): + """Key-value pairs representing update compatibility information.""" + + +class ContractModel(_Model): + """The Device Update agent contract model. + + :ivar id: The Device Update agent contract model Id of the device class. This is also used to + calculate the device class Id. Required. + :vartype id: str + :ivar name: The Device Update agent contract model name of the device class. Intended to be a + more readable form of the contract model Id. Required. + :vartype name: str + """ + + id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The Device Update agent contract model Id of the device class. This is also used to calculate + the device class Id. Required.""" + name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The Device Update agent contract model name of the device class. Intended to be a more readable + form of the contract model Id. Required.""" + + @overload + def __init__( + self, + *, + id: str, # pylint: disable=redefined-builtin + name: str, + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + + +class Deployment(_Model): + """Deployment metadata. + + :ivar deployment_id: The caller-provided deployment identifier. This cannot be longer than 73 + characters, must be all lower-case, and cannot contain '&', '^', '[', ']', '{', '}', '|', '<', + '>', forward slash, backslash, or double quote. The Updates view in the Azure Portal IoT Hub + resource generates a GUID for deploymentId when you create a deployment. Required. + :vartype deployment_id: str + :ivar start_date_time: The deployment start datetime. Required. + :vartype start_date_time: ~datetime.datetime + :ivar update_property: Update information for the update in the deployment. Required. + :vartype update_property: ~azure.iot.deviceupdate.models.UpdateInfo + :ivar group_id: The group identity for the devices the deployment is intended to update. + Required. + :vartype group_id: str + :ivar device_class_subgroups: The device class subgroups the deployment is compatible with and + subgroup deployments have been created for. This is not provided by the caller during + CreateOrUpdateDeployment but is automatically determined by Device Update. + :vartype device_class_subgroups: list[str] + :ivar is_canceled: Boolean flag indicating whether the deployment was canceled. + :vartype is_canceled: bool + :ivar is_retried: Boolean flag indicating whether the deployment has been retried. + :vartype is_retried: bool + :ivar rollback_policy: The rollback policy for the deployment. + :vartype rollback_policy: ~azure.iot.deviceupdate.models.CloudInitiatedRollbackPolicy + :ivar is_cloud_initiated_rollback: Boolean flag indicating whether the deployment is a rollback + deployment. + :vartype is_cloud_initiated_rollback: bool + :ivar download_security: The protocol the device should use when downloading the update + payload. Defaults to "https". Known values are: "https" and "http". + :vartype download_security: str or ~azure.iot.deviceupdate.models.DownloadSecurity + """ + + deployment_id: str = rest_field(name="deploymentId", visibility=["read", "create", "update", "delete", "query"]) + """The caller-provided deployment identifier. This cannot be longer than 73 characters, must be + all lower-case, and cannot contain '&', '^', '[', ']', '{', '}', '|', '<', '>', forward slash, + backslash, or double quote. The Updates view in the Azure Portal IoT Hub resource generates a + GUID for deploymentId when you create a deployment. Required.""" + start_date_time: datetime.datetime = rest_field( + name="startDateTime", visibility=["read", "create", "update", "delete", "query"], format="rfc3339" + ) + """The deployment start datetime. Required.""" + update_property: "_models.UpdateInfo" = rest_field( + name="update", visibility=["read", "create", "update", "delete", "query"], original_tsp_name="update" + ) + """Update information for the update in the deployment. Required.""" + group_id: str = rest_field(name="groupId", visibility=["read", "create", "update", "delete", "query"]) + """The group identity for the devices the deployment is intended to update. Required.""" + device_class_subgroups: Optional[list[str]] = rest_field( + name="deviceClassSubgroups", visibility=["read", "create", "update", "delete", "query"] + ) + """The device class subgroups the deployment is compatible with and subgroup deployments have been + created for. This is not provided by the caller during CreateOrUpdateDeployment but is + automatically determined by Device Update.""" + is_canceled: Optional[bool] = rest_field( + name="isCanceled", visibility=["read", "create", "update", "delete", "query"] + ) + """Boolean flag indicating whether the deployment was canceled.""" + is_retried: Optional[bool] = rest_field( + name="isRetried", visibility=["read", "create", "update", "delete", "query"] + ) + """Boolean flag indicating whether the deployment has been retried.""" + rollback_policy: Optional["_models.CloudInitiatedRollbackPolicy"] = rest_field( + name="rollbackPolicy", visibility=["read", "create", "update", "delete", "query"] + ) + """The rollback policy for the deployment.""" + is_cloud_initiated_rollback: Optional[bool] = rest_field( + name="isCloudInitiatedRollback", visibility=["read", "create", "update", "delete", "query"] + ) + """Boolean flag indicating whether the deployment is a rollback deployment.""" + download_security: Optional[Union[str, "_models.DownloadSecurity"]] = rest_field( + name="downloadSecurity", visibility=["read", "create", "update", "delete", "query"] + ) + """The protocol the device should use when downloading the update payload. Defaults to \"https\". + Known values are: \"https\" and \"http\".""" + + @overload + def __init__( + self, + *, + deployment_id: str, + start_date_time: datetime.datetime, + update_property: "_models.UpdateInfo", + group_id: str, + device_class_subgroups: Optional[list[str]] = None, + is_canceled: Optional[bool] = None, + is_retried: Optional[bool] = None, + rollback_policy: Optional["_models.CloudInitiatedRollbackPolicy"] = None, + is_cloud_initiated_rollback: Optional[bool] = None, + download_security: Optional[Union[str, "_models.DownloadSecurity"]] = None, + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + + +class DeploymentDeviceState(_Model): + """Deployment device status. + + :ivar device_id: Device identity. Required. + :vartype device_id: str + :ivar module_id: Device module identity. + :vartype module_id: str + :ivar retry_count: The number of times this deployment has been retried on this device. + Required. + :vartype retry_count: int + :ivar moved_on_to_new_deployment: Boolean flag indicating whether this device is in a newer + deployment and can no longer retry this deployment. Required. + :vartype moved_on_to_new_deployment: bool + :ivar device_state: Deployment device state. Required. Known values are: "Succeeded", + "InProgress", "Canceled", and "Failed". + :vartype device_state: str or ~azure.iot.deviceupdate.models.DeviceDeploymentState + """ + + device_id: str = rest_field(name="deviceId", visibility=["read", "create", "update", "delete", "query"]) + """Device identity. Required.""" + module_id: Optional[str] = rest_field(name="moduleId", visibility=["read", "create", "update", "delete", "query"]) + """Device module identity.""" + retry_count: int = rest_field(name="retryCount", visibility=["read", "create", "update", "delete", "query"]) + """The number of times this deployment has been retried on this device. Required.""" + moved_on_to_new_deployment: bool = rest_field( + name="movedOnToNewDeployment", visibility=["read", "create", "update", "delete", "query"] + ) + """Boolean flag indicating whether this device is in a newer deployment and can no longer retry + this deployment. Required.""" + device_state: Union[str, "_models.DeviceDeploymentState"] = rest_field( + name="deviceState", visibility=["read", "create", "update", "delete", "query"] + ) + """Deployment device state. Required. Known values are: \"Succeeded\", \"InProgress\", + \"Canceled\", and \"Failed\".""" + + @overload + def __init__( + self, + *, + device_id: str, + retry_count: int, + moved_on_to_new_deployment: bool, + device_state: Union[str, "_models.DeviceDeploymentState"], + module_id: Optional[str] = None, + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + + +class DeploymentStatus(_Model): + """Deployment status metadata. + + :ivar group_id: The group identity. Required. + :vartype group_id: str + :ivar deployment_state: The state of the deployment. Required. Known values are: "Active", + "ActiveWithSubgroupFailures", "Failed", "Inactive", and "Canceled". + :vartype deployment_state: str or ~azure.iot.deviceupdate.models.DeploymentState + :ivar error: The error details of the Failed state. This is not present if the deployment + state is not Failed. + :vartype error: ~azure.iot.deviceupdate.models.Error + :ivar subgroup_status: The collection of device class subgroup status objects. Required. + :vartype subgroup_status: + list[~azure.iot.deviceupdate.models.DeviceClassSubgroupDeploymentStatus] + """ + + group_id: str = rest_field(name="groupId", visibility=["read", "create", "update", "delete", "query"]) + """The group identity. Required.""" + deployment_state: Union[str, "_models.DeploymentState"] = rest_field( + name="deploymentState", visibility=["read", "create", "update", "delete", "query"] + ) + """The state of the deployment. Required. Known values are: \"Active\", + \"ActiveWithSubgroupFailures\", \"Failed\", \"Inactive\", and \"Canceled\".""" + error: Optional["_models.Error"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The error details of the Failed state. This is not present if the deployment state is not + Failed.""" + subgroup_status: list["_models.DeviceClassSubgroupDeploymentStatus"] = rest_field( + name="subgroupStatus", visibility=["read", "create", "update", "delete", "query"] + ) + """The collection of device class subgroup status objects. Required.""" + + @overload + def __init__( + self, + *, + group_id: str, + deployment_state: Union[str, "_models.DeploymentState"], + subgroup_status: list["_models.DeviceClassSubgroupDeploymentStatus"], + error: Optional["_models.Error"] = None, + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + + +class Device(_Model): + """Device metadata. + + :ivar device_id: Device identity. Required. + :vartype device_id: str + :ivar module_id: Device module identity. + :vartype module_id: str + :ivar device_class_id: Device class identity. Required. + :vartype device_class_id: str + :ivar group_id: Device group identity. + :vartype group_id: str + :ivar last_attempted_update: The update that device last attempted to install. + :vartype last_attempted_update: ~azure.iot.deviceupdate.models.UpdateInfo + :ivar deployment_status: State of the device in its last deployment. Known values are: + "Succeeded", "InProgress", "Canceled", and "Failed". + :vartype deployment_status: str or ~azure.iot.deviceupdate.models.DeviceDeploymentState + :ivar installed_update: Currently installed update on device. + :vartype installed_update: ~azure.iot.deviceupdate.models.UpdateInfo + :ivar on_latest_update: Boolean flag indicating whether the latest update (the best compatible + update for the device's device class and group) is installed on the device. Required. + :vartype on_latest_update: bool + :ivar last_deployment_id: The deployment identifier for the last deployment to the device. + :vartype last_deployment_id: str + :ivar last_install_result: Last install result. + :vartype last_install_result: ~azure.iot.deviceupdate.models.InstallResult + """ + + device_id: str = rest_field(name="deviceId", visibility=["read", "create", "update", "delete", "query"]) + """Device identity. Required.""" + module_id: Optional[str] = rest_field(name="moduleId", visibility=["read", "create", "update", "delete", "query"]) + """Device module identity.""" + device_class_id: str = rest_field(name="deviceClassId", visibility=["read", "create", "update", "delete", "query"]) + """Device class identity. Required.""" + group_id: Optional[str] = rest_field(name="groupId", visibility=["read", "create", "update", "delete", "query"]) + """Device group identity.""" + last_attempted_update: Optional["_models.UpdateInfo"] = rest_field( + name="lastAttemptedUpdate", visibility=["read", "create", "update", "delete", "query"] + ) + """The update that device last attempted to install.""" + deployment_status: Optional[Union[str, "_models.DeviceDeploymentState"]] = rest_field( + name="deploymentStatus", visibility=["read", "create", "update", "delete", "query"] + ) + """State of the device in its last deployment. Known values are: \"Succeeded\", \"InProgress\", + \"Canceled\", and \"Failed\".""" + installed_update: Optional["_models.UpdateInfo"] = rest_field( + name="installedUpdate", visibility=["read", "create", "update", "delete", "query"] + ) + """Currently installed update on device.""" + on_latest_update: bool = rest_field( + name="onLatestUpdate", visibility=["read", "create", "update", "delete", "query"] + ) + """Boolean flag indicating whether the latest update (the best compatible update for the device's + device class and group) is installed on the device. Required.""" + last_deployment_id: Optional[str] = rest_field( + name="lastDeploymentId", visibility=["read", "create", "update", "delete", "query"] + ) + """The deployment identifier for the last deployment to the device.""" + last_install_result: Optional["_models.InstallResult"] = rest_field( + name="lastInstallResult", visibility=["read", "create", "update", "delete", "query"] + ) + """Last install result.""" + + @overload + def __init__( + self, + *, + device_id: str, + device_class_id: str, + on_latest_update: bool, + module_id: Optional[str] = None, + group_id: Optional[str] = None, + last_attempted_update: Optional["_models.UpdateInfo"] = None, + deployment_status: Optional[Union[str, "_models.DeviceDeploymentState"]] = None, + installed_update: Optional["_models.UpdateInfo"] = None, + last_deployment_id: Optional[str] = None, + last_install_result: Optional["_models.InstallResult"] = None, + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + + +class DeviceClass(_Model): + """Device class metadata. + + :ivar device_class_id: The device class identifier. This is generated from the model Id and the + compat properties reported by the device update agent in the Device Update PnP interface in IoT + Hub. It is a hex-encoded SHA1 hash. Required. + :vartype device_class_id: str + :ivar friendly_name: The device class friendly name. This can be updated by callers after the + device class has been automatically created. + :vartype friendly_name: str + :ivar device_class_properties: The device class properties that are used to calculate the + device class Id. Required. + :vartype device_class_properties: ~azure.iot.deviceupdate.models.DeviceClassProperties + :ivar best_compatible_update: Update that is the highest version compatible with this device + class. + :vartype best_compatible_update: ~azure.iot.deviceupdate.models.UpdateInfo + """ + + device_class_id: str = rest_field(name="deviceClassId", visibility=["read", "create", "update", "delete", "query"]) + """The device class identifier. This is generated from the model Id and the compat properties + reported by the device update agent in the Device Update PnP interface in IoT Hub. It is a + hex-encoded SHA1 hash. Required.""" + friendly_name: Optional[str] = rest_field( + name="friendlyName", visibility=["read", "create", "update", "delete", "query"] + ) + """The device class friendly name. This can be updated by callers after the device class has been + automatically created.""" + device_class_properties: "_models.DeviceClassProperties" = rest_field( + name="deviceClassProperties", visibility=["read", "create", "update", "delete", "query"] + ) + """The device class properties that are used to calculate the device class Id. Required.""" + best_compatible_update: Optional["_models.UpdateInfo"] = rest_field( + name="bestCompatibleUpdate", visibility=["read", "create", "update", "delete", "query"] + ) + """Update that is the highest version compatible with this device class.""" + + @overload + def __init__( + self, + *, + device_class_id: str, + device_class_properties: "_models.DeviceClassProperties", + friendly_name: Optional[str] = None, + best_compatible_update: Optional["_models.UpdateInfo"] = None, + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + + +class DeviceClassProperties(_Model): + """The device class properties that are used to calculate the device class Id. + + :ivar contract_model: The Device Update agent contract model. + :vartype contract_model: ~azure.iot.deviceupdate.models.ContractModel + :ivar compat_properties: The compat properties of the device class. This object can be thought + of as a set of key-value pairs where the key is the name of the compatibility property and the + value is the value of the compatibility property. There will always be at least 1 compat + property. Required. + :vartype compat_properties: dict[str, str] + """ + + contract_model: Optional["_models.ContractModel"] = rest_field( + name="contractModel", visibility=["read", "create", "update", "delete", "query"] + ) + """The Device Update agent contract model.""" + compat_properties: dict[str, str] = rest_field( + name="compatProperties", visibility=["read", "create", "update", "delete", "query"] + ) + """The compat properties of the device class. This object can be thought of as a set of key-value + pairs where the key is the name of the compatibility property and the value is the value of the + compatibility property. There will always be at least 1 compat property. Required.""" + + @overload + def __init__( + self, + *, + compat_properties: dict[str, str], + contract_model: Optional["_models.ContractModel"] = None, + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + + +class DeviceClassSubgroup(_Model): + """Device class subgroup details. A device class subgroup is a subset of devices in a group that + share the same device class id. + + :ivar device_class_id: Device class subgroup identity. This is generated from the model Id and + the compat properties reported by the device update agent in the Device Update PnP interface in + IoT Hub. It is a hex-encoded SHA1 hash. Required. + :vartype device_class_id: str + :ivar group_id: Group identity. Required. + :vartype group_id: str + :ivar created_date_time: Date and time when the device class subgroup was created. Required. + :vartype created_date_time: str + :ivar device_count: The number of devices in the device class subgroup. + :vartype device_count: int + :ivar deployment_id: The active deployment Id for the device class subgroup. + :vartype deployment_id: str + """ + + device_class_id: str = rest_field(name="deviceClassId", visibility=["read", "create", "update", "delete", "query"]) + """Device class subgroup identity. This is generated from the model Id and the compat properties + reported by the device update agent in the Device Update PnP interface in IoT Hub. It is a + hex-encoded SHA1 hash. Required.""" + group_id: str = rest_field(name="groupId", visibility=["read", "create", "update", "delete", "query"]) + """Group identity. Required.""" + created_date_time: str = rest_field( + name="createdDateTime", visibility=["read", "create", "update", "delete", "query"] + ) + """Date and time when the device class subgroup was created. Required.""" + device_count: Optional[int] = rest_field( + name="deviceCount", visibility=["read", "create", "update", "delete", "query"] + ) + """The number of devices in the device class subgroup.""" + deployment_id: Optional[str] = rest_field( + name="deploymentId", visibility=["read", "create", "update", "delete", "query"] + ) + """The active deployment Id for the device class subgroup.""" + + @overload + def __init__( + self, + *, + device_class_id: str, + group_id: str, + created_date_time: str, + device_count: Optional[int] = None, + deployment_id: Optional[str] = None, + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + + +class DeviceClassSubgroupDeploymentStatus(_Model): + """Device class subgroup deployment status metadata. + + :ivar group_id: The group identity. Required. + :vartype group_id: str + :ivar device_class_id: The device class subgroup identity. Required. + :vartype device_class_id: str + :ivar deployment_state: The state of the subgroup deployment. Required. Known values are: + "Active", "Failed", "Inactive", and "Canceled". + :vartype deployment_state: str or + ~azure.iot.deviceupdate.models.DeviceClassSubgroupDeploymentState + :ivar error: The error details of the Failed state. This is not present if the deployment + state is not Failed. + :vartype error: ~azure.iot.deviceupdate.models.Error + :ivar total_devices: The total number of devices in the deployment. + :vartype total_devices: int + :ivar devices_in_progress_count: The number of devices that are currently in deployment. + :vartype devices_in_progress_count: int + :ivar devices_completed_failed_count: The number of devices that have completed deployment with + a failure. + :vartype devices_completed_failed_count: int + :ivar devices_completed_succeeded_count: The number of devices which have successfully + completed deployment. + :vartype devices_completed_succeeded_count: int + :ivar devices_canceled_count: The number of devices which have had their deployment canceled. + :vartype devices_canceled_count: int + """ + + group_id: str = rest_field(name="groupId", visibility=["read", "create", "update", "delete", "query"]) + """The group identity. Required.""" + device_class_id: str = rest_field(name="deviceClassId", visibility=["read", "create", "update", "delete", "query"]) + """The device class subgroup identity. Required.""" + deployment_state: Union[str, "_models.DeviceClassSubgroupDeploymentState"] = rest_field( + name="deploymentState", visibility=["read", "create", "update", "delete", "query"] + ) + """The state of the subgroup deployment. Required. Known values are: \"Active\", \"Failed\", + \"Inactive\", and \"Canceled\".""" + error: Optional["_models.Error"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The error details of the Failed state. This is not present if the deployment state is not + Failed.""" + total_devices: Optional[int] = rest_field( + name="totalDevices", visibility=["read", "create", "update", "delete", "query"] + ) + """The total number of devices in the deployment.""" + devices_in_progress_count: Optional[int] = rest_field( + name="devicesInProgressCount", visibility=["read", "create", "update", "delete", "query"] + ) + """The number of devices that are currently in deployment.""" + devices_completed_failed_count: Optional[int] = rest_field( + name="devicesCompletedFailedCount", visibility=["read", "create", "update", "delete", "query"] + ) + """The number of devices that have completed deployment with a failure.""" + devices_completed_succeeded_count: Optional[int] = rest_field( + name="devicesCompletedSucceededCount", visibility=["read", "create", "update", "delete", "query"] + ) + """The number of devices which have successfully completed deployment.""" + devices_canceled_count: Optional[int] = rest_field( + name="devicesCanceledCount", visibility=["read", "create", "update", "delete", "query"] + ) + """The number of devices which have had their deployment canceled.""" + + @overload + def __init__( + self, + *, + group_id: str, + device_class_id: str, + deployment_state: Union[str, "_models.DeviceClassSubgroupDeploymentState"], + error: Optional["_models.Error"] = None, + total_devices: Optional[int] = None, + devices_in_progress_count: Optional[int] = None, + devices_completed_failed_count: Optional[int] = None, + devices_completed_succeeded_count: Optional[int] = None, + devices_canceled_count: Optional[int] = None, + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + + +class DeviceClassSubgroupUpdatableDevices(_Model): + """Device class subgroup, update information, and the number of devices for which the update is + applicable. + + :ivar group_id: The group Id. Required. + :vartype group_id: str + :ivar device_class_id: The device class subgroup's device class Id. Required. + :vartype device_class_id: str + :ivar update_property: Update information. Required. + :vartype update_property: ~azure.iot.deviceupdate.models.UpdateInfo + :ivar device_count: Total number of devices for which the update is applicable. Required. + :vartype device_count: int + """ + + group_id: str = rest_field(name="groupId", visibility=["read", "create", "update", "delete", "query"]) + """The group Id. Required.""" + device_class_id: str = rest_field(name="deviceClassId", visibility=["read", "create", "update", "delete", "query"]) + """The device class subgroup's device class Id. Required.""" + update_property: "_models.UpdateInfo" = rest_field( + name="update", visibility=["read", "create", "update", "delete", "query"], original_tsp_name="update" + ) + """Update information. Required.""" + device_count: int = rest_field(name="deviceCount", visibility=["read", "create", "update", "delete", "query"]) + """Total number of devices for which the update is applicable. Required.""" + + @overload + def __init__( + self, + *, + group_id: str, + device_class_id: str, + update_property: "_models.UpdateInfo", + device_count: int, + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + + +class DeviceHealth(_Model): + """Device Health. + + :ivar device_id: Device id. Required. + :vartype device_id: str + :ivar module_id: Module id. + :vartype module_id: str + :ivar state: Aggregate device health state. Required. Known values are: "healthy" and + "unhealthy". + :vartype state: str or ~azure.iot.deviceupdate.models.DeviceHealthState + :ivar digital_twin_model_id: Digital twin model Id. + :vartype digital_twin_model_id: str + :ivar health_checks: Array of health checks and their results. Required. + :vartype health_checks: list[~azure.iot.deviceupdate.models.HealthCheck] + """ + + device_id: str = rest_field(name="deviceId", visibility=["read", "create", "update", "delete", "query"]) + """Device id. Required.""" + module_id: Optional[str] = rest_field(name="moduleId", visibility=["read", "create", "update", "delete", "query"]) + """Module id.""" + state: Union[str, "_models.DeviceHealthState"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Aggregate device health state. Required. Known values are: \"healthy\" and \"unhealthy\".""" + digital_twin_model_id: Optional[str] = rest_field( + name="digitalTwinModelId", visibility=["read", "create", "update", "delete", "query"] + ) + """Digital twin model Id.""" + health_checks: list["_models.HealthCheck"] = rest_field( + name="healthChecks", visibility=["read", "create", "update", "delete", "query"] + ) + """Array of health checks and their results. Required.""" + + @overload + def __init__( + self, + *, + device_id: str, + state: Union[str, "_models.DeviceHealthState"], + health_checks: list["_models.HealthCheck"], + module_id: Optional[str] = None, + digital_twin_model_id: Optional[str] = None, + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + + +class DeviceOperation(_Model): + """Operation metadata. + + :ivar operation_id: Operation Id. Required. + :vartype operation_id: str + :ivar status: Operation status. Required. Known values are: "NotStarted", "Running", + "Succeeded", and "Failed". + :vartype status: str or ~azure.iot.deviceupdate.models.OperationStatus + :ivar error: Operation error encountered, if any. + :vartype error: ~azure.iot.deviceupdate.models.Error + :ivar trace_id: Operation correlation identity that can used by Microsoft Support for + troubleshooting. + :vartype trace_id: str + :ivar last_action_date_time: Date and time in UTC when the operation status was last updated. + Required. + :vartype last_action_date_time: ~datetime.datetime + :ivar created_date_time: Date and time in UTC when the operation was created. Required. + :vartype created_date_time: ~datetime.datetime + :ivar etag: Operation ETag. + :vartype etag: str + """ + + operation_id: str = rest_field(name="operationId", visibility=["read", "create", "update", "delete", "query"]) + """Operation Id. Required.""" + status: Union[str, "_models.OperationStatus"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Operation status. Required. Known values are: \"NotStarted\", \"Running\", \"Succeeded\", and + \"Failed\".""" + error: Optional["_models.Error"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Operation error encountered, if any.""" + trace_id: Optional[str] = rest_field(name="traceId", visibility=["read", "create", "update", "delete", "query"]) + """Operation correlation identity that can used by Microsoft Support for troubleshooting.""" + last_action_date_time: datetime.datetime = rest_field( + name="lastActionDateTime", visibility=["read", "create", "update", "delete", "query"], format="rfc3339" + ) + """Date and time in UTC when the operation status was last updated. Required.""" + created_date_time: datetime.datetime = rest_field( + name="createdDateTime", visibility=["read", "create", "update", "delete", "query"], format="rfc3339" + ) + """Date and time in UTC when the operation was created. Required.""" + etag: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Operation ETag.""" + + @overload + def __init__( + self, + *, + operation_id: str, + status: Union[str, "_models.OperationStatus"], + last_action_date_time: datetime.datetime, + created_date_time: datetime.datetime, + error: Optional["_models.Error"] = None, + trace_id: Optional[str] = None, + etag: Optional[str] = None, + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + + +class DeviceUpdateAgentId(_Model): + """Device Update agent id. + + :ivar device_id: Device Id. Required. + :vartype device_id: str + :ivar module_id: Module Id. + :vartype module_id: str + """ + + device_id: str = rest_field(name="deviceId", visibility=["read", "create", "update", "delete", "query"]) + """Device Id. Required.""" + module_id: Optional[str] = rest_field(name="moduleId", visibility=["read", "create", "update", "delete", "query"]) + """Module Id.""" + + @overload + def __init__( + self, + *, + device_id: str, + module_id: Optional[str] = None, + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + + +class Error(_Model): + """Error details. + + :ivar code: Server defined error code. Required. + :vartype code: str + :ivar message: A human-readable representation of the error. Required. + :vartype message: str + :ivar target: The target of the error. + :vartype target: str + :ivar details: An array of errors that led to the reported error. + :vartype details: list[~azure.iot.deviceupdate.models.Error] + :ivar innererror: An object containing more specific information than the current object about + the error. + :vartype innererror: ~azure.iot.deviceupdate.models.InnerError + :ivar occurred_date_time: Date and time in UTC when the error occurred. + :vartype occurred_date_time: ~datetime.datetime + """ + + code: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Server defined error code. Required.""" + message: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """A human-readable representation of the error. Required.""" + target: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The target of the error.""" + details: Optional[list["_models.Error"]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """An array of errors that led to the reported error.""" + innererror: Optional["_models.InnerError"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """An object containing more specific information than the current object about the error.""" + occurred_date_time: Optional[datetime.datetime] = rest_field( + name="occurredDateTime", visibility=["read", "create", "update", "delete", "query"], format="rfc3339" + ) + """Date and time in UTC when the error occurred.""" + + @overload + def __init__( + self, + *, + code: str, + message: str, + target: Optional[str] = None, + details: Optional[list["_models.Error"]] = None, + innererror: Optional["_models.InnerError"] = None, + occurred_date_time: Optional[datetime.datetime] = None, + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + + +class ErrorResponse(_Model): + """Common error response. + + :ivar error: The error details. Required. + :vartype error: ~azure.iot.deviceupdate.models.Error + """ + + error: "_models.Error" = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The error details. Required.""" + + @overload + def __init__( + self, + *, + error: "_models.Error", + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + + +class FileImportMetadata(_Model): + """Metadata describing an update file. + + :ivar filename: Update file name as specified inside import manifest. Required. + :vartype filename: str + :ivar url: Azure Blob location from which the update file can be downloaded by Device Update + for IoT Hub. This is typically a read-only SAS-protected blob URL with an expiration set to at + least 4 hours. Required. + :vartype url: str + """ + + filename: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Update file name as specified inside import manifest. Required.""" + url: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Azure Blob location from which the update file can be downloaded by Device Update for IoT Hub. + This is typically a read-only SAS-protected blob URL with an expiration set to at least 4 + hours. Required.""" + + @overload + def __init__( + self, + *, + filename: str, + url: str, + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + + +class Group(_Model): + """Group details. + + :ivar group_id: Group identity. This is created from the value of the ADUGroup tag in the Iot + Hub's device/module twin or $default for devices with no tag. Required. + :vartype group_id: str + :ivar group_type: Group type. Required. Known values are: "IoTHubTag" and "DefaultNoTag". + :vartype group_type: str or ~azure.iot.deviceupdate.models.GroupType + :ivar created_date_time: Date and time when the update was created. Required. + :vartype created_date_time: str + :ivar device_count: The number of devices in the group. + :vartype device_count: int + :ivar subgroups_with_new_updates_available_count: The count of subgroups with new updates + available. + :vartype subgroups_with_new_updates_available_count: int + :ivar subgroups_with_updates_in_progress_count: The count of subgroups with updates in + progress. + :vartype subgroups_with_updates_in_progress_count: int + :ivar subgroups_with_on_latest_update_count: The count of subgroups with devices on the latest + update. + :vartype subgroups_with_on_latest_update_count: int + :ivar deployments: The active deployment Ids for the group. + :vartype deployments: list[str] + """ + + group_id: str = rest_field(name="groupId", visibility=["read", "create", "update", "delete", "query"]) + """Group identity. This is created from the value of the ADUGroup tag in the Iot Hub's + device/module twin or $default for devices with no tag. Required.""" + group_type: Union[str, "_models.GroupType"] = rest_field( + name="groupType", visibility=["read", "create", "update", "delete", "query"] + ) + """Group type. Required. Known values are: \"IoTHubTag\" and \"DefaultNoTag\".""" + created_date_time: str = rest_field( + name="createdDateTime", visibility=["read", "create", "update", "delete", "query"] + ) + """Date and time when the update was created. Required.""" + device_count: Optional[int] = rest_field( + name="deviceCount", visibility=["read", "create", "update", "delete", "query"] + ) + """The number of devices in the group.""" + subgroups_with_new_updates_available_count: Optional[int] = rest_field( + name="subgroupsWithNewUpdatesAvailableCount", visibility=["read", "create", "update", "delete", "query"] + ) + """The count of subgroups with new updates available.""" + subgroups_with_updates_in_progress_count: Optional[int] = rest_field( + name="subgroupsWithUpdatesInProgressCount", visibility=["read", "create", "update", "delete", "query"] + ) + """The count of subgroups with updates in progress.""" + subgroups_with_on_latest_update_count: Optional[int] = rest_field( + name="subgroupsWithOnLatestUpdateCount", visibility=["read", "create", "update", "delete", "query"] + ) + """The count of subgroups with devices on the latest update.""" + deployments: Optional[list[str]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The active deployment Ids for the group.""" + + @overload + def __init__( + self, + *, + group_id: str, + group_type: Union[str, "_models.GroupType"], + created_date_time: str, + device_count: Optional[int] = None, + subgroups_with_new_updates_available_count: Optional[int] = None, + subgroups_with_updates_in_progress_count: Optional[int] = None, + subgroups_with_on_latest_update_count: Optional[int] = None, + deployments: Optional[list[str]] = None, + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + + +class HealthCheck(_Model): + """Health check. + + :ivar name: Health check name. + :vartype name: str + :ivar result: Health check result. Known values are: "success" and "userError". + :vartype result: str or ~azure.iot.deviceupdate.models.HealthCheckResult + """ + + name: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Health check name.""" + result: Optional[Union[str, "_models.HealthCheckResult"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Health check result. Known values are: \"success\" and \"userError\".""" + + @overload + def __init__( + self, + *, + name: Optional[str] = None, + result: Optional[Union[str, "_models.HealthCheckResult"]] = None, + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + + +class ImportManifestMetadata(_Model): + """Metadata describing the import manifest, a document which describes the files and other + metadata about an update version. + + :ivar url: Azure Blob location from which the import manifest can be downloaded by Device + Update for IoT Hub. This is typically a read-only SAS-protected blob URL with an expiration set + to at least 4 hours. Required. + :vartype url: str + :ivar size_in_bytes: File size in number of bytes. Required. + :vartype size_in_bytes: int + :ivar hashes: A JSON object containing the hash(es) of the file. At least SHA256 hash is + required. This object can be thought of as a set of key-value pairs where the key is the hash + algorithm, and the value is the hash of the file calculated using that algorithm. Required. + :vartype hashes: dict[str, str] + """ + + url: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Azure Blob location from which the import manifest can be downloaded by Device Update for IoT + Hub. This is typically a read-only SAS-protected blob URL with an expiration set to at least 4 + hours. Required.""" + size_in_bytes: int = rest_field(name="sizeInBytes", visibility=["read", "create", "update", "delete", "query"]) + """File size in number of bytes. Required.""" + hashes: dict[str, str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """A JSON object containing the hash(es) of the file. At least SHA256 hash is required. This + object can be thought of as a set of key-value pairs where the key is the hash algorithm, and + the value is the hash of the file calculated using that algorithm. Required.""" + + @overload + def __init__( + self, + *, + url: str, + size_in_bytes: int, + hashes: dict[str, str], + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + + +class ImportUpdateInputItem(_Model): + """Import update input item metadata. + + :ivar import_manifest: Import manifest metadata like source URL, file size/hashes, etc. + Required. + :vartype import_manifest: ~azure.iot.deviceupdate.models.ImportManifestMetadata + :ivar friendly_name: Friendly update name. + :vartype friendly_name: str + :ivar files: One or more update file properties like filename and source URL. + :vartype files: list[~azure.iot.deviceupdate.models.FileImportMetadata] + """ + + import_manifest: "_models.ImportManifestMetadata" = rest_field( + name="importManifest", visibility=["read", "create", "update", "delete", "query"] + ) + """Import manifest metadata like source URL, file size/hashes, etc. Required.""" + friendly_name: Optional[str] = rest_field( + name="friendlyName", visibility=["read", "create", "update", "delete", "query"] + ) + """Friendly update name.""" + files: Optional[list["_models.FileImportMetadata"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """One or more update file properties like filename and source URL.""" + + @overload + def __init__( + self, + *, + import_manifest: "_models.ImportManifestMetadata", + friendly_name: Optional[str] = None, + files: Optional[list["_models.FileImportMetadata"]] = None, + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + + +class InnerError(_Model): + """An object containing more specific information than the current object about the error. + + :ivar code: A more specific error code than what was provided by the containing error. + Required. + :vartype code: str + :ivar message: A human-readable representation of the error. + :vartype message: str + :ivar error_detail: The internal error or exception message. + :vartype error_detail: str + :ivar inner_error: An object containing more specific information than the current object about + the error. + :vartype inner_error: ~azure.iot.deviceupdate.models.InnerError + """ + + code: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """A more specific error code than what was provided by the containing error. Required.""" + message: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """A human-readable representation of the error.""" + error_detail: Optional[str] = rest_field( + name="errorDetail", visibility=["read", "create", "update", "delete", "query"] + ) + """The internal error or exception message.""" + inner_error: Optional["_models.InnerError"] = rest_field( + name="innerError", visibility=["read", "create", "update", "delete", "query"] + ) + """An object containing more specific information than the current object about the error.""" + + @overload + def __init__( + self, + *, + code: str, + message: Optional[str] = None, + error_detail: Optional[str] = None, + inner_error: Optional["_models.InnerError"] = None, + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + + +class InstallResult(_Model): + """The install result of an update and any step results under it. + + :ivar result_code: Install result code. Required. + :vartype result_code: int + :ivar extended_result_code: Install extended result code. Required. + :vartype extended_result_code: int + :ivar result_details: A string containing further details about the install result. + :vartype result_details: str + :ivar step_results: Array of step results. + :vartype step_results: list[~azure.iot.deviceupdate.models.StepResult] + """ + + result_code: int = rest_field(name="resultCode", visibility=["read", "create", "update", "delete", "query"]) + """Install result code. Required.""" + extended_result_code: int = rest_field( + name="extendedResultCode", visibility=["read", "create", "update", "delete", "query"] + ) + """Install extended result code. Required.""" + result_details: Optional[str] = rest_field( + name="resultDetails", visibility=["read", "create", "update", "delete", "query"] + ) + """A string containing further details about the install result.""" + step_results: Optional[list["_models.StepResult"]] = rest_field( + name="stepResults", visibility=["read", "create", "update", "delete", "query"] + ) + """Array of step results.""" + + @overload + def __init__( + self, + *, + result_code: int, + extended_result_code: int, + result_details: Optional[str] = None, + step_results: Optional[list["_models.StepResult"]] = None, + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + + +class Instructions(_Model): + """Update install instructions container. + + :ivar steps: Collection of installation steps. Required. + :vartype steps: list[~azure.iot.deviceupdate.models.Step] + """ + + steps: list["_models.Step"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Collection of installation steps. Required.""" + + @overload + def __init__( + self, + *, + steps: list["_models.Step"], + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + + +class LogCollection(_Model): + """Diagnostics request body. + + :ivar log_collection_id: The log collection id. + :vartype log_collection_id: str + :ivar device_list: Array of Device Update agent ids. Required. + :vartype device_list: list[~azure.iot.deviceupdate.models.DeviceUpdateAgentId] + :ivar description: Description of the diagnostics operation. + :vartype description: str + :ivar created_date_time: The timestamp when the operation was created. + :vartype created_date_time: str + :ivar last_action_date_time: A timestamp for when the current state was entered. + :vartype last_action_date_time: str + :ivar status: Operation status. Known values are: "NotStarted", "Running", "Succeeded", and + "Failed". + :vartype status: str or ~azure.iot.deviceupdate.models.OperationStatus + """ + + log_collection_id: Optional[str] = rest_field( + name="operationId", visibility=["read", "create", "update", "delete", "query"] + ) + """The log collection id.""" + device_list: list["_models.DeviceUpdateAgentId"] = rest_field( + name="deviceList", visibility=["read", "create", "update", "delete", "query"] + ) + """Array of Device Update agent ids. Required.""" + description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Description of the diagnostics operation.""" + created_date_time: Optional[str] = rest_field(name="createdDateTime", visibility=["read"]) + """The timestamp when the operation was created.""" + last_action_date_time: Optional[str] = rest_field(name="lastActionDateTime", visibility=["read"]) + """A timestamp for when the current state was entered.""" + status: Optional[Union[str, "_models.OperationStatus"]] = rest_field(visibility=["read"]) + """Operation status. Known values are: \"NotStarted\", \"Running\", \"Succeeded\", and \"Failed\".""" + + @overload + def __init__( + self, + *, + device_list: list["_models.DeviceUpdateAgentId"], + log_collection_id: Optional[str] = None, + description: Optional[str] = None, + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + + +class LogCollectionOperationDetailedStatus(_Model): + """Device diagnostics operation detailed status. + + :ivar log_collection_id: The device diagnostics operation id. + :vartype log_collection_id: str + :ivar created_date_time: The timestamp when the operation was created. + :vartype created_date_time: str + :ivar last_action_date_time: A timestamp for when the current state was entered. + :vartype last_action_date_time: str + :ivar status: Operation status. Known values are: "NotStarted", "Running", "Succeeded", and + "Failed". + :vartype status: str or ~azure.iot.deviceupdate.models.OperationStatus + :ivar device_status: Status of the devices in the operation. + :vartype device_status: list[~azure.iot.deviceupdate.models.LogCollectionOperationDeviceStatus] + :ivar description: Device diagnostics operation description. + :vartype description: str + """ + + log_collection_id: Optional[str] = rest_field( + name="operationId", visibility=["read", "create", "update", "delete", "query"] + ) + """The device diagnostics operation id.""" + created_date_time: Optional[str] = rest_field( + name="createdDateTime", visibility=["read", "create", "update", "delete", "query"] + ) + """The timestamp when the operation was created.""" + last_action_date_time: Optional[str] = rest_field( + name="lastActionDateTime", visibility=["read", "create", "update", "delete", "query"] + ) + """A timestamp for when the current state was entered.""" + status: Optional[Union[str, "_models.OperationStatus"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Operation status. Known values are: \"NotStarted\", \"Running\", \"Succeeded\", and \"Failed\".""" + device_status: Optional[list["_models.LogCollectionOperationDeviceStatus"]] = rest_field( + name="deviceStatus", visibility=["read", "create", "update", "delete", "query"] + ) + """Status of the devices in the operation.""" + description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Device diagnostics operation description.""" + + @overload + def __init__( + self, + *, + log_collection_id: Optional[str] = None, + created_date_time: Optional[str] = None, + last_action_date_time: Optional[str] = None, + status: Optional[Union[str, "_models.OperationStatus"]] = None, + device_status: Optional[list["_models.LogCollectionOperationDeviceStatus"]] = None, + description: Optional[str] = None, + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + + +class LogCollectionOperationDeviceStatus(_Model): + """Diagnostics operation device status. + + :ivar device_id: Device id. Required. + :vartype device_id: str + :ivar module_id: Module id. + :vartype module_id: str + :ivar status: Log upload status. Required. Known values are: "NotStarted", "Running", + "Succeeded", and "Failed". + :vartype status: str or ~azure.iot.deviceupdate.models.OperationStatus + :ivar result_code: Log upload result code. + :vartype result_code: str + :ivar extended_result_code: Log upload extended result code. + :vartype extended_result_code: str + :ivar log_location: Log upload location. + :vartype log_location: str + """ + + device_id: str = rest_field(name="deviceId", visibility=["read", "create", "update", "delete", "query"]) + """Device id. Required.""" + module_id: Optional[str] = rest_field(name="moduleId", visibility=["read", "create", "update", "delete", "query"]) + """Module id.""" + status: Union[str, "_models.OperationStatus"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Log upload status. Required. Known values are: \"NotStarted\", \"Running\", \"Succeeded\", and + \"Failed\".""" + result_code: Optional[str] = rest_field( + name="resultCode", visibility=["read", "create", "update", "delete", "query"] + ) + """Log upload result code.""" + extended_result_code: Optional[str] = rest_field( + name="extendedResultCode", visibility=["read", "create", "update", "delete", "query"] + ) + """Log upload extended result code.""" + log_location: Optional[str] = rest_field( + name="logLocation", visibility=["read", "create", "update", "delete", "query"] + ) + """Log upload location.""" + + @overload + def __init__( + self, + *, + device_id: str, + status: Union[str, "_models.OperationStatus"], + module_id: Optional[str] = None, + result_code: Optional[str] = None, + extended_result_code: Optional[str] = None, + log_location: Optional[str] = None, + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + + +class PatchBody(_Model): + """Device Class JSON Merge Patch request body. + + :ivar friendly_name: The device class friendly name. Friendly name can be 1-100 characters, + alphanumeric, dot, and dash. Required. + :vartype friendly_name: str + """ + + friendly_name: str = rest_field(name="friendlyName", visibility=["read", "create", "update", "delete", "query"]) + """The device class friendly name. Friendly name can be 1-100 characters, alphanumeric, dot, and + dash. Required.""" + + @overload + def __init__( + self, + *, + friendly_name: str, + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + + +class Step(_Model): + """Update install instruction step. + + :ivar type: Step type. Known values are: "inline" and "reference". + :vartype type: str or ~azure.iot.deviceupdate.models.StepType + :ivar description: Step description. + :vartype description: str + :ivar handler: Identity of handler that will execute this step. Required if step type is + inline. + :vartype handler: str + :ivar handler_properties: Parameters to be passed to handler during execution. + :vartype handler_properties: dict[str, any] + :ivar files: Collection of file names to be passed to handler during execution. Required if + step type is inline. + :vartype files: list[str] + :ivar update_id: Referenced child update identity. Required if step type is reference. + :vartype update_id: ~azure.iot.deviceupdate.models.UpdateId + """ + + type: Optional[Union[str, "_models.StepType"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Step type. Known values are: \"inline\" and \"reference\".""" + description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Step description.""" + handler: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Identity of handler that will execute this step. Required if step type is inline.""" + handler_properties: Optional[dict[str, Any]] = rest_field( + name="handlerProperties", visibility=["read", "create", "update", "delete", "query"] + ) + """Parameters to be passed to handler during execution.""" + files: Optional[list[str]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Collection of file names to be passed to handler during execution. Required if step type is + inline.""" + update_id: Optional["_models.UpdateId"] = rest_field( + name="updateId", visibility=["read", "create", "update", "delete", "query"] + ) + """Referenced child update identity. Required if step type is reference.""" + + @overload + def __init__( + self, + *, + type: Optional[Union[str, "_models.StepType"]] = None, + description: Optional[str] = None, + handler: Optional[str] = None, + handler_properties: Optional[dict[str, Any]] = None, + files: Optional[list[str]] = None, + update_id: Optional["_models.UpdateId"] = None, + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + + +class StepResult(_Model): + """The step result under an update. + + :ivar update_property: The update that this step installs if it is of reference type. + :vartype update_property: ~azure.iot.deviceupdate.models.UpdateInfo + :ivar description: Step description. + :vartype description: str + :ivar result_code: Install result code. Required. + :vartype result_code: int + :ivar extended_result_code: Install extended result code. Required. + :vartype extended_result_code: int + :ivar result_details: A string containing further details about the install result. + :vartype result_details: str + """ + + update_property: Optional["_models.UpdateInfo"] = rest_field( + name="update", visibility=["read", "create", "update", "delete", "query"], original_tsp_name="update" + ) + """The update that this step installs if it is of reference type.""" + description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Step description.""" + result_code: int = rest_field(name="resultCode", visibility=["read", "create", "update", "delete", "query"]) + """Install result code. Required.""" + extended_result_code: int = rest_field( + name="extendedResultCode", visibility=["read", "create", "update", "delete", "query"] + ) + """Install extended result code. Required.""" + result_details: Optional[str] = rest_field( + name="resultDetails", visibility=["read", "create", "update", "delete", "query"] + ) + """A string containing further details about the install result.""" + + @overload + def __init__( + self, + *, + result_code: int, + extended_result_code: int, + update_property: Optional["_models.UpdateInfo"] = None, + description: Optional[str] = None, + result_details: Optional[str] = None, + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + + +class Update(_Model): + """Update metadata. + + :ivar update_id: Update identity. Required. + :vartype update_id: ~azure.iot.deviceupdate.models.UpdateId + :ivar description: Update description specified by creator. + :vartype description: str + :ivar friendly_name: Friendly update name specified by importer. + :vartype friendly_name: str + :ivar is_deployable: Whether the update can be deployed to a device on its own. + :vartype is_deployable: bool + :ivar update_type: Update type. Deprecated in latest import manifest schema. + :vartype update_type: str + :ivar installed_criteria: String interpreted by Device Update client to determine if the update + is installed on the device. Deprecated in latest import manifest schema. + :vartype installed_criteria: str + :ivar compatibility: List of update compatibility information. Required. + :vartype compatibility: list[~azure.iot.deviceupdate.models.Compatibility] + :ivar instructions: Update install instructions. + :vartype instructions: ~azure.iot.deviceupdate.models.Instructions + :ivar referenced_by: List of update identities that reference this update. + :vartype referenced_by: list[~azure.iot.deviceupdate.models.UpdateId] + :ivar scan_result: Update aggregate scan result (calculated from payload file scan results). + :vartype scan_result: str + :ivar manifest_version: Schema version of manifest used to import the update. Required. + :vartype manifest_version: str + :ivar imported_date_time: Date and time in UTC when the update was imported. Required. + :vartype imported_date_time: ~datetime.datetime + :ivar created_date_time: Date and time in UTC when the update was created. Required. + :vartype created_date_time: ~datetime.datetime + :ivar etag: Update ETag. + :vartype etag: str + """ + + update_id: "_models.UpdateId" = rest_field( + name="updateId", visibility=["read", "create", "update", "delete", "query"] + ) + """Update identity. Required.""" + description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Update description specified by creator.""" + friendly_name: Optional[str] = rest_field( + name="friendlyName", visibility=["read", "create", "update", "delete", "query"] + ) + """Friendly update name specified by importer.""" + is_deployable: Optional[bool] = rest_field( + name="isDeployable", visibility=["read", "create", "update", "delete", "query"] + ) + """Whether the update can be deployed to a device on its own.""" + update_type: Optional[str] = rest_field( + name="updateType", visibility=["read", "create", "update", "delete", "query"] + ) + """Update type. Deprecated in latest import manifest schema.""" + installed_criteria: Optional[str] = rest_field( + name="installedCriteria", visibility=["read", "create", "update", "delete", "query"] + ) + """String interpreted by Device Update client to determine if the update is installed on the + device. Deprecated in latest import manifest schema.""" + compatibility: list["_models.Compatibility"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """List of update compatibility information. Required.""" + instructions: Optional["_models.Instructions"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Update install instructions.""" + referenced_by: Optional[list["_models.UpdateId"]] = rest_field( + name="referencedBy", visibility=["read", "create", "update", "delete", "query"] + ) + """List of update identities that reference this update.""" + scan_result: Optional[str] = rest_field( + name="scanResult", visibility=["read", "create", "update", "delete", "query"] + ) + """Update aggregate scan result (calculated from payload file scan results).""" + manifest_version: str = rest_field( + name="manifestVersion", visibility=["read", "create", "update", "delete", "query"] + ) + """Schema version of manifest used to import the update. Required.""" + imported_date_time: datetime.datetime = rest_field( + name="importedDateTime", visibility=["read", "create", "update", "delete", "query"], format="rfc3339" + ) + """Date and time in UTC when the update was imported. Required.""" + created_date_time: datetime.datetime = rest_field( + name="createdDateTime", visibility=["read", "create", "update", "delete", "query"], format="rfc3339" + ) + """Date and time in UTC when the update was created. Required.""" + etag: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Update ETag.""" + + @overload + def __init__( + self, + *, + update_id: "_models.UpdateId", + compatibility: list["_models.Compatibility"], + manifest_version: str, + imported_date_time: datetime.datetime, + created_date_time: datetime.datetime, + description: Optional[str] = None, + friendly_name: Optional[str] = None, + is_deployable: Optional[bool] = None, + update_type: Optional[str] = None, + installed_criteria: Optional[str] = None, + instructions: Optional["_models.Instructions"] = None, + referenced_by: Optional[list["_models.UpdateId"]] = None, + scan_result: Optional[str] = None, + etag: Optional[str] = None, + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + + +class UpdateCompliance(_Model): + """Update compliance information. + + :ivar total_device_count: Total number of devices. Required. + :vartype total_device_count: int + :ivar on_latest_update_device_count: Number of devices on the latest update. Required. + :vartype on_latest_update_device_count: int + :ivar new_updates_available_device_count: Number of devices with a newer update available. + Required. + :vartype new_updates_available_device_count: int + :ivar updates_in_progress_device_count: Number of devices with update in-progress. Required. + :vartype updates_in_progress_device_count: int + """ + + total_device_count: int = rest_field( + name="totalDeviceCount", visibility=["read", "create", "update", "delete", "query"] + ) + """Total number of devices. Required.""" + on_latest_update_device_count: int = rest_field( + name="onLatestUpdateDeviceCount", visibility=["read", "create", "update", "delete", "query"] + ) + """Number of devices on the latest update. Required.""" + new_updates_available_device_count: int = rest_field( + name="newUpdatesAvailableDeviceCount", visibility=["read", "create", "update", "delete", "query"] + ) + """Number of devices with a newer update available. Required.""" + updates_in_progress_device_count: int = rest_field( + name="updatesInProgressDeviceCount", visibility=["read", "create", "update", "delete", "query"] + ) + """Number of devices with update in-progress. Required.""" + + @overload + def __init__( + self, + *, + total_device_count: int, + on_latest_update_device_count: int, + new_updates_available_device_count: int, + updates_in_progress_device_count: int, + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + + +class UpdateFileBase(_Model): + """Update file basic metadata. + + :ivar file_name: File name. Required. + :vartype file_name: str + :ivar size_in_bytes: File size in number of bytes. Required. + :vartype size_in_bytes: int + :ivar hashes: Mapping of hashing algorithm to base64 encoded hash values. Required. + :vartype hashes: dict[str, str] + :ivar mime_type: File MIME type. + :vartype mime_type: str + :ivar scan_result: Anti-malware scan result. + :vartype scan_result: str + :ivar scan_details: Anti-malware scan details. + :vartype scan_details: str + :ivar properties: Optional file properties (not consumed by service but pass-through to + device). + :vartype properties: dict[str, str] + """ + + file_name: str = rest_field(name="fileName", visibility=["read", "create", "update", "delete", "query"]) + """File name. Required.""" + size_in_bytes: int = rest_field(name="sizeInBytes", visibility=["read", "create", "update", "delete", "query"]) + """File size in number of bytes. Required.""" + hashes: dict[str, str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Mapping of hashing algorithm to base64 encoded hash values. Required.""" + mime_type: Optional[str] = rest_field(name="mimeType", visibility=["read", "create", "update", "delete", "query"]) + """File MIME type.""" + scan_result: Optional[str] = rest_field( + name="scanResult", visibility=["read", "create", "update", "delete", "query"] + ) + """Anti-malware scan result.""" + scan_details: Optional[str] = rest_field( + name="scanDetails", visibility=["read", "create", "update", "delete", "query"] + ) + """Anti-malware scan details.""" + properties: Optional[dict[str, str]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Optional file properties (not consumed by service but pass-through to device).""" + + @overload + def __init__( + self, + *, + file_name: str, + size_in_bytes: int, + hashes: dict[str, str], + mime_type: Optional[str] = None, + scan_result: Optional[str] = None, + scan_details: Optional[str] = None, + properties: Optional[dict[str, str]] = None, + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + + +class UpdateFile(UpdateFileBase): + """Update file metadata. + + :ivar file_name: File name. Required. + :vartype file_name: str + :ivar size_in_bytes: File size in number of bytes. Required. + :vartype size_in_bytes: int + :ivar hashes: Mapping of hashing algorithm to base64 encoded hash values. Required. + :vartype hashes: dict[str, str] + :ivar mime_type: File MIME type. + :vartype mime_type: str + :ivar scan_result: Anti-malware scan result. + :vartype scan_result: str + :ivar scan_details: Anti-malware scan details. + :vartype scan_details: str + :ivar properties: Optional file properties (not consumed by service but pass-through to + device). + :vartype properties: dict[str, str] + :ivar file_id: File identity, generated by server at import time. Required. + :vartype file_id: str + :ivar related_files: Optional related files metadata used together DownloadHandler metadata to + download payload file. + :vartype related_files: list[~azure.iot.deviceupdate.models.UpdateFileBase] + :ivar download_handler: Optional download handler for utilizing related files to download + payload file. + :vartype download_handler: ~azure.iot.deviceupdate.models.UpdateFileDownloadHandler + :ivar etag: File ETag. + :vartype etag: str + """ + + file_id: str = rest_field(name="fileId", visibility=["read", "create", "update", "delete", "query"]) + """File identity, generated by server at import time. Required.""" + related_files: Optional[list["_models.UpdateFileBase"]] = rest_field( + name="relatedFiles", visibility=["read", "create", "update", "delete", "query"] + ) + """Optional related files metadata used together DownloadHandler metadata to download payload + file.""" + download_handler: Optional["_models.UpdateFileDownloadHandler"] = rest_field( + name="downloadHandler", visibility=["read", "create", "update", "delete", "query"] + ) + """Optional download handler for utilizing related files to download payload file.""" + etag: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """File ETag.""" + + @overload + def __init__( + self, + *, + file_name: str, + size_in_bytes: int, + hashes: dict[str, str], + file_id: str, + mime_type: Optional[str] = None, + scan_result: Optional[str] = None, + scan_details: Optional[str] = None, + properties: Optional[dict[str, str]] = None, + related_files: Optional[list["_models.UpdateFileBase"]] = None, + download_handler: Optional["_models.UpdateFileDownloadHandler"] = None, + etag: Optional[str] = None, + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + + +class UpdateFileDownloadHandler(_Model): + """Download handler for utilizing related files to download payload file. + + :ivar id: Download handler identifier. Required. + :vartype id: str + """ + + id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Download handler identifier. Required.""" + + @overload + def __init__( + self, + *, + id: str, # pylint: disable=redefined-builtin + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + + +class UpdateId(_Model): + """Update identifier. + + :ivar provider: Update provider. Required. + :vartype provider: str + :ivar name: Update name. Required. + :vartype name: str + :ivar version: Update version. Required. + :vartype version: str + """ + + provider: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Update provider. Required.""" + name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Update name. Required.""" + version: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Update version. Required.""" + + @overload + def __init__( + self, + *, + provider: str, + name: str, + version: str, + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + + +class UpdateInfo(_Model): + """Update information. + + :ivar update_id: Update identifier. Required. + :vartype update_id: ~azure.iot.deviceupdate.models.UpdateId + :ivar description: Update description. + :vartype description: str + :ivar friendly_name: Friendly update name. + :vartype friendly_name: str + """ + + update_id: "_models.UpdateId" = rest_field( + name="updateId", visibility=["read", "create", "update", "delete", "query"] + ) + """Update identifier. Required.""" + description: Optional[str] = rest_field(visibility=["read"]) + """Update description.""" + friendly_name: Optional[str] = rest_field(name="friendlyName", visibility=["read"]) + """Friendly update name.""" + + @overload + def __init__( + self, + *, + update_id: "_models.UpdateId", + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + + +class UpdateOperation(_Model): + """Operation metadata. + + :ivar operation_id: Operation Id. Required. + :vartype operation_id: str + :ivar status: Operation status. Required. Known values are: "NotStarted", "Running", + "Succeeded", and "Failed". + :vartype status: str or ~azure.iot.deviceupdate.models.OperationStatus + :ivar update_property: The update being imported or deleted. For import, this property will + only be populated after import manifest is processed successfully. + :vartype update_property: ~azure.iot.deviceupdate.models.UpdateInfo + :ivar resource_location: Location of the imported update when operation is successful. + :vartype resource_location: str + :ivar error: Operation error encountered, if any. + :vartype error: ~azure.iot.deviceupdate.models.Error + :ivar trace_id: Operation correlation identity that can used by Microsoft Support for + troubleshooting. + :vartype trace_id: str + :ivar last_action_date_time: Date and time in UTC when the operation status was last updated. + Required. + :vartype last_action_date_time: ~datetime.datetime + :ivar created_date_time: Date and time in UTC when the operation was created. Required. + :vartype created_date_time: ~datetime.datetime + :ivar etag: Operation ETag. + :vartype etag: str + """ + + operation_id: str = rest_field(name="operationId", visibility=["read", "create", "update", "delete", "query"]) + """Operation Id. Required.""" + status: Union[str, "_models.OperationStatus"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Operation status. Required. Known values are: \"NotStarted\", \"Running\", \"Succeeded\", and + \"Failed\".""" + update_property: Optional["_models.UpdateInfo"] = rest_field( + name="update", visibility=["read", "create", "update", "delete", "query"], original_tsp_name="update" + ) + """The update being imported or deleted. For import, this property will only be populated after + import manifest is processed successfully.""" + resource_location: Optional[str] = rest_field( + name="resourceLocation", visibility=["read", "create", "update", "delete", "query"] + ) + """Location of the imported update when operation is successful.""" + error: Optional["_models.Error"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Operation error encountered, if any.""" + trace_id: Optional[str] = rest_field(name="traceId", visibility=["read", "create", "update", "delete", "query"]) + """Operation correlation identity that can used by Microsoft Support for troubleshooting.""" + last_action_date_time: datetime.datetime = rest_field( + name="lastActionDateTime", visibility=["read", "create", "update", "delete", "query"], format="rfc3339" + ) + """Date and time in UTC when the operation status was last updated. Required.""" + created_date_time: datetime.datetime = rest_field( + name="createdDateTime", visibility=["read", "create", "update", "delete", "query"], format="rfc3339" + ) + """Date and time in UTC when the operation was created. Required.""" + etag: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Operation ETag.""" + + @overload + def __init__( + self, + *, + operation_id: str, + status: Union[str, "_models.OperationStatus"], + last_action_date_time: datetime.datetime, + created_date_time: datetime.datetime, + update_property: Optional["_models.UpdateInfo"] = None, + resource_location: Optional[str] = None, + error: Optional["_models.Error"] = None, + trace_id: Optional[str] = None, + etag: Optional[str] = None, + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) diff --git a/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/models/_patch.py b/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/models/_patch.py new file mode 100644 index 000000000000..87676c65a8f0 --- /dev/null +++ b/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/models/_patch.py @@ -0,0 +1,21 @@ +# 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. +# -------------------------------------------------------------------------- +"""Customize generated code here. + +Follow our quickstart for examples: https://aka.ms/azsdk/python/dpcodegen/python/customize +""" + + +__all__: list[str] = [] # Add all objects you want publicly available to users at this package level + + +def patch_sdk(): + """Do not remove from this file. + + `patch_sdk` is a last resort escape hatch that allows you to do customizations + you can't accomplish using the techniques described in + https://aka.ms/azsdk/python/dpcodegen/python/customize + """ diff --git a/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/operations/__init__.py b/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/operations/__init__.py index e15e9b8cde4a..f696baec55ea 100644 --- a/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/operations/__init__.py +++ b/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/operations/__init__.py @@ -2,20 +2,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. +# Code generated by Microsoft (R) Python Code Generator. # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- +# pylint: disable=wrong-import-position -from ._operations import DeviceUpdateOperations -from ._operations import DeviceManagementOperations +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from ._patch import * # pylint: disable=unused-wildcard-import + +from ._operations import DeviceUpdateOperations # type: ignore +from ._operations import DeviceManagementOperations # type: ignore from ._patch import __all__ as _patch_all -from ._patch import * # type: ignore # pylint: disable=unused-wildcard-import +from ._patch import * from ._patch import patch_sdk as _patch_sdk __all__ = [ "DeviceUpdateOperations", "DeviceManagementOperations", ] -__all__.extend([p for p in _patch_all if p not in __all__]) +__all__.extend([p for p in _patch_all if p not in __all__]) # pyright: ignore _patch_sdk() diff --git a/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/operations/_operations.py b/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/operations/_operations.py index 853d4b28ce91..44b7f9e90718 100644 --- a/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/operations/_operations.py +++ b/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/operations/_operations.py @@ -1,41 +1,46 @@ -# pylint: disable=too-many-lines +# pylint: disable=line-too-long,useless-suppression,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. +# Code generated by Microsoft (R) Python 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, Iterable, List, Optional, TypeVar, Union, cast, overload -from urllib.parse import parse_qs, urljoin, urlparse +from collections.abc import MutableMapping +from io import IOBase +import json +from typing import Any, Callable, IO, Iterator, Optional, TypeVar, Union, cast, overload +import urllib.parse +from azure.core import MatchConditions, PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, ResourceExistsError, + ResourceModifiedError, ResourceNotFoundError, + ResourceNotModifiedError, + StreamClosedError, + StreamConsumedError, map_error, ) from azure.core.paging import ItemPaged from azure.core.pipeline import PipelineResponse -from azure.core.pipeline.transport import HttpResponse from azure.core.polling import LROPoller, NoPolling, PollingMethod from azure.core.polling.base_polling import LROBasePolling -from azure.core.rest import HttpRequest +from azure.core.rest import HttpRequest, HttpResponse from azure.core.tracing.decorator import distributed_trace from azure.core.utils import case_insensitive_dict -from .._serialization import Serializer -from .._vendor import _format_url_section +from .. import models as _models +from .._configuration import DeviceUpdateClientConfiguration +from .._utils.model_base import SdkJSONEncoder, _deserialize, _failsafe_deserialize +from .._utils.serialization import Deserializer, Serializer +from .._utils.utils import prep_if_match, prep_if_none_match -if sys.version_info >= (3, 9): - from collections.abc import MutableMapping -else: - from typing import MutableMapping # type: ignore # pylint: disable=ungrouped-imports -JSON = MutableMapping[str, Any] # pylint: disable=unsubscriptable-object +JSON = MutableMapping[str, Any] T = TypeVar("T") -ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] +ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, dict[str, Any]], Any]] _SERIALIZER = Serializer() _SERIALIZER.client_side_validation = False @@ -47,16 +52,16 @@ def build_device_update_list_updates_request( _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) - api_version = kwargs.pop("api_version", _params.pop("api-version", "2022-10-01")) # type: str + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-06-01")) accept = _headers.pop("Accept", "application/json") # Construct URL _url = "/deviceUpdate/{instanceId}/updates" path_format_arguments = { - "instanceId": _SERIALIZER.url("instance_id", instance_id, "str", skip_quote=True), + "instanceId": _SERIALIZER.url("instance_id", instance_id, "str"), } - _url = _format_url_section(_url, **path_format_arguments) + _url: str = _url.format(**path_format_arguments) # type: ignore # Construct parameters _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") @@ -71,21 +76,23 @@ def build_device_update_list_updates_request( return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -def build_device_update_import_update_request(instance_id: str, **kwargs: Any) -> HttpRequest: +def build_device_update_import_update_request( # pylint: disable=name-too-long + instance_id: str, **kwargs: Any +) -> HttpRequest: _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) - content_type = kwargs.pop("content_type", _headers.pop("Content-Type", None)) # type: Optional[str] - api_version = kwargs.pop("api_version", _params.pop("api-version", "2022-10-01")) # type: str + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-06-01")) accept = _headers.pop("Accept", "application/json") # Construct URL _url = "/deviceUpdate/{instanceId}/updates:import" path_format_arguments = { - "instanceId": _SERIALIZER.url("instance_id", instance_id, "str", skip_quote=True), + "instanceId": _SERIALIZER.url("instance_id", instance_id, "str"), } - _url = _format_url_section(_url, **path_format_arguments) + _url: str = _url.format(**path_format_arguments) # type: ignore # Construct parameters _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") @@ -99,79 +106,86 @@ def build_device_update_import_update_request(instance_id: str, **kwargs: Any) - def build_device_update_get_update_request( - provider: str, name: str, version: str, instance_id: str, *, if_none_match: Optional[str] = None, **kwargs: Any + provider: str, + name: str, + version: str, + instance_id: str, + *, + etag: Optional[str] = None, + match_condition: Optional[MatchConditions] = None, + **kwargs: Any ) -> HttpRequest: _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) - api_version = kwargs.pop("api_version", _params.pop("api-version", "2022-10-01")) # type: str + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-06-01")) accept = _headers.pop("Accept", "application/json") # Construct URL _url = "/deviceUpdate/{instanceId}/updates/providers/{provider}/names/{name}/versions/{version}" path_format_arguments = { - "instanceId": _SERIALIZER.url("instance_id", instance_id, "str", skip_quote=True), + "instanceId": _SERIALIZER.url("instance_id", instance_id, "str"), "provider": _SERIALIZER.url("provider", provider, "str"), "name": _SERIALIZER.url("name", name, "str"), "version": _SERIALIZER.url("version", version, "str"), } - _url = _format_url_section(_url, **path_format_arguments) + _url: str = _url.format(**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") + if_match = prep_if_match(etag, match_condition) + if if_match is not None: + _headers["if-match"] = _SERIALIZER.header("if_match", if_match, "str") + if_none_match = prep_if_none_match(etag, match_condition) if if_none_match is not None: _headers["If-None-Match"] = _SERIALIZER.header("if_none_match", if_none_match, "str") - _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -def build_device_update_delete_update_request( +def build_device_update_delete_update_request( # pylint: disable=name-too-long provider: str, name: str, version: str, instance_id: str, **kwargs: Any ) -> HttpRequest: - _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) - api_version = kwargs.pop("api_version", _params.pop("api-version", "2022-10-01")) # type: str - accept = _headers.pop("Accept", "application/json") - + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-06-01")) # Construct URL _url = "/deviceUpdate/{instanceId}/updates/providers/{provider}/names/{name}/versions/{version}" path_format_arguments = { - "instanceId": _SERIALIZER.url("instance_id", instance_id, "str", skip_quote=True), + "instanceId": _SERIALIZER.url("instance_id", instance_id, "str"), "provider": _SERIALIZER.url("provider", provider, "str"), "name": _SERIALIZER.url("name", name, "str"), "version": _SERIALIZER.url("version", version, "str"), } - _url = _format_url_section(_url, **path_format_arguments) + _url: str = _url.format(**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, **kwargs) - return HttpRequest(method="DELETE", url=_url, params=_params, headers=_headers, **kwargs) - -def build_device_update_list_providers_request(instance_id: str, **kwargs: Any) -> HttpRequest: +def build_device_update_list_providers_request( # pylint: disable=name-too-long + instance_id: str, **kwargs: Any +) -> HttpRequest: _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) - api_version = kwargs.pop("api_version", _params.pop("api-version", "2022-10-01")) # type: str + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-06-01")) accept = _headers.pop("Accept", "application/json") # Construct URL _url = "/deviceUpdate/{instanceId}/updates/providers" path_format_arguments = { - "instanceId": _SERIALIZER.url("instance_id", instance_id, "str", skip_quote=True), + "instanceId": _SERIALIZER.url("instance_id", instance_id, "str"), } - _url = _format_url_section(_url, **path_format_arguments) + _url: str = _url.format(**path_format_arguments) # type: ignore # Construct parameters _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") @@ -186,17 +200,17 @@ def build_device_update_list_names_request(provider: str, instance_id: str, **kw _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) - api_version = kwargs.pop("api_version", _params.pop("api-version", "2022-10-01")) # type: str + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-06-01")) accept = _headers.pop("Accept", "application/json") # Construct URL _url = "/deviceUpdate/{instanceId}/updates/providers/{provider}/names" path_format_arguments = { - "instanceId": _SERIALIZER.url("instance_id", instance_id, "str", skip_quote=True), + "instanceId": _SERIALIZER.url("instance_id", instance_id, "str"), "provider": _SERIALIZER.url("provider", provider, "str"), } - _url = _format_url_section(_url, **path_format_arguments) + _url: str = _url.format(**path_format_arguments) # type: ignore # Construct parameters _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") @@ -207,24 +221,24 @@ def build_device_update_list_names_request(provider: str, instance_id: str, **kw return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -def build_device_update_list_versions_request( +def build_device_update_list_versions_request( # pylint: disable=name-too-long provider: str, name: str, instance_id: str, *, filter: Optional[str] = None, **kwargs: Any ) -> HttpRequest: _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) - api_version = kwargs.pop("api_version", _params.pop("api-version", "2022-10-01")) # type: str + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-06-01")) accept = _headers.pop("Accept", "application/json") # Construct URL _url = "/deviceUpdate/{instanceId}/updates/providers/{provider}/names/{name}/versions" path_format_arguments = { - "instanceId": _SERIALIZER.url("instance_id", instance_id, "str", skip_quote=True), + "instanceId": _SERIALIZER.url("instance_id", instance_id, "str"), "provider": _SERIALIZER.url("provider", provider, "str"), "name": _SERIALIZER.url("name", name, "str"), } - _url = _format_url_section(_url, **path_format_arguments) + _url: str = _url.format(**path_format_arguments) # type: ignore # Construct parameters _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") @@ -243,19 +257,19 @@ def build_device_update_list_files_request( _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) - api_version = kwargs.pop("api_version", _params.pop("api-version", "2022-10-01")) # type: str + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-06-01")) accept = _headers.pop("Accept", "application/json") # Construct URL _url = "/deviceUpdate/{instanceId}/updates/providers/{provider}/names/{name}/versions/{version}/files" path_format_arguments = { - "instanceId": _SERIALIZER.url("instance_id", instance_id, "str", skip_quote=True), + "instanceId": _SERIALIZER.url("instance_id", instance_id, "str"), "provider": _SERIALIZER.url("provider", provider, "str"), "name": _SERIALIZER.url("name", name, "str"), "version": _SERIALIZER.url("version", version, "str"), } - _url = _format_url_section(_url, **path_format_arguments) + _url: str = _url.format(**path_format_arguments) # type: ignore # Construct parameters _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") @@ -273,61 +287,66 @@ def build_device_update_get_file_request( file_id: str, instance_id: str, *, - if_none_match: Optional[str] = None, + etag: Optional[str] = None, + match_condition: Optional[MatchConditions] = None, **kwargs: Any ) -> HttpRequest: _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) - api_version = kwargs.pop("api_version", _params.pop("api-version", "2022-10-01")) # type: str + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-06-01")) accept = _headers.pop("Accept", "application/json") # Construct URL _url = "/deviceUpdate/{instanceId}/updates/providers/{provider}/names/{name}/versions/{version}/files/{fileId}" path_format_arguments = { - "instanceId": _SERIALIZER.url("instance_id", instance_id, "str", skip_quote=True), + "instanceId": _SERIALIZER.url("instance_id", instance_id, "str"), "provider": _SERIALIZER.url("provider", provider, "str"), "name": _SERIALIZER.url("name", name, "str"), "version": _SERIALIZER.url("version", version, "str"), "fileId": _SERIALIZER.url("file_id", file_id, "str"), } - _url = _format_url_section(_url, **path_format_arguments) + _url: str = _url.format(**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") + if_match = prep_if_match(etag, match_condition) + if if_match is not None: + _headers["if-match"] = _SERIALIZER.header("if_match", if_match, "str") + if_none_match = prep_if_none_match(etag, match_condition) if if_none_match is not None: _headers["If-None-Match"] = _SERIALIZER.header("if_none_match", if_none_match, "str") - _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -def build_device_update_list_operation_statuses_request( +def build_device_update_list_operation_statuses_request( # pylint: disable=name-too-long instance_id: str, *, filter: Optional[str] = None, top: Optional[int] = None, **kwargs: Any ) -> HttpRequest: _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) - api_version = kwargs.pop("api_version", _params.pop("api-version", "2022-10-01")) # type: str + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-06-01")) accept = _headers.pop("Accept", "application/json") # Construct URL _url = "/deviceUpdate/{instanceId}/updates/operations" path_format_arguments = { - "instanceId": _SERIALIZER.url("instance_id", instance_id, "str", skip_quote=True), + "instanceId": _SERIALIZER.url("instance_id", instance_id, "str"), } - _url = _format_url_section(_url, **path_format_arguments) + _url: str = _url.format(**path_format_arguments) # type: ignore # Construct parameters + _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") if filter is not None: _params["filter"] = _SERIALIZER.query("filter", filter, "str") if top is not None: _params["top"] = _SERIALIZER.query("top", top, "int") - _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") # Construct headers _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") @@ -335,51 +354,60 @@ def build_device_update_list_operation_statuses_request( return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -def build_device_update_get_operation_status_request( - operation_id: str, instance_id: str, *, if_none_match: Optional[str] = None, **kwargs: Any +def build_device_update_get_operation_status_request( # pylint: disable=name-too-long + operation_id: str, + instance_id: str, + *, + etag: Optional[str] = None, + match_condition: Optional[MatchConditions] = None, + **kwargs: Any ) -> HttpRequest: _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) - api_version = kwargs.pop("api_version", _params.pop("api-version", "2022-10-01")) # type: str + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-06-01")) accept = _headers.pop("Accept", "application/json") # Construct URL _url = "/deviceUpdate/{instanceId}/updates/operations/{operationId}" path_format_arguments = { - "instanceId": _SERIALIZER.url("instance_id", instance_id, "str", skip_quote=True), - "operationId": _SERIALIZER.url("operation_id", operation_id, "str", max_length=256, min_length=1), + "instanceId": _SERIALIZER.url("instance_id", instance_id, "str"), + "operationId": _SERIALIZER.url("operation_id", operation_id, "str"), } - _url = _format_url_section(_url, **path_format_arguments) + _url: str = _url.format(**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") + if_match = prep_if_match(etag, match_condition) + if if_match is not None: + _headers["if-match"] = _SERIALIZER.header("if_match", if_match, "str") + if_none_match = prep_if_none_match(etag, match_condition) if if_none_match is not None: _headers["If-None-Match"] = _SERIALIZER.header("if_none_match", if_none_match, "str") - _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -def build_device_management_list_device_classes_request( +def build_device_management_list_device_classes_request( # pylint: disable=name-too-long instance_id: str, *, filter: Optional[str] = None, **kwargs: Any ) -> HttpRequest: _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) - api_version = kwargs.pop("api_version", _params.pop("api-version", "2022-10-01")) # type: str + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-06-01")) accept = _headers.pop("Accept", "application/json") # Construct URL _url = "/deviceUpdate/{instanceId}/management/deviceClasses" path_format_arguments = { - "instanceId": _SERIALIZER.url("instance_id", instance_id, "str", skip_quote=True), + "instanceId": _SERIALIZER.url("instance_id", instance_id, "str"), } - _url = _format_url_section(_url, **path_format_arguments) + _url: str = _url.format(**path_format_arguments) # type: ignore # Construct parameters _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") @@ -392,23 +420,23 @@ def build_device_management_list_device_classes_request( return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -def build_device_management_get_device_class_request( +def build_device_management_get_device_class_request( # pylint: disable=name-too-long device_class_id: str, instance_id: str, **kwargs: Any ) -> HttpRequest: _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) - api_version = kwargs.pop("api_version", _params.pop("api-version", "2022-10-01")) # type: str + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-06-01")) accept = _headers.pop("Accept", "application/json") # Construct URL _url = "/deviceUpdate/{instanceId}/management/deviceClasses/{deviceClassId}" path_format_arguments = { - "instanceId": _SERIALIZER.url("instance_id", instance_id, "str", skip_quote=True), + "instanceId": _SERIALIZER.url("instance_id", instance_id, "str"), "deviceClassId": _SERIALIZER.url("device_class_id", device_class_id, "str"), } - _url = _format_url_section(_url, **path_format_arguments) + _url: str = _url.format(**path_format_arguments) # type: ignore # Construct parameters _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") @@ -419,24 +447,24 @@ def build_device_management_get_device_class_request( return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -def build_device_management_update_device_class_request( +def build_device_management_update_device_class_request( # pylint: disable=name-too-long device_class_id: str, instance_id: str, **kwargs: Any ) -> HttpRequest: _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) - content_type = kwargs.pop("content_type", _headers.pop("Content-Type", None)) # type: Optional[str] - api_version = kwargs.pop("api_version", _params.pop("api-version", "2022-10-01")) # type: str + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-06-01")) accept = _headers.pop("Accept", "application/json") # Construct URL _url = "/deviceUpdate/{instanceId}/management/deviceClasses/{deviceClassId}" path_format_arguments = { - "instanceId": _SERIALIZER.url("instance_id", instance_id, "str", skip_quote=True), + "instanceId": _SERIALIZER.url("instance_id", instance_id, "str"), "deviceClassId": _SERIALIZER.url("device_class_id", device_class_id, "str"), } - _url = _format_url_section(_url, **path_format_arguments) + _url: str = _url.format(**path_format_arguments) # type: ignore # Construct parameters _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") @@ -449,50 +477,44 @@ def build_device_management_update_device_class_request( return HttpRequest(method="PATCH", url=_url, params=_params, headers=_headers, **kwargs) -def build_device_management_delete_device_class_request( +def build_device_management_delete_device_class_request( # pylint: disable=name-too-long device_class_id: str, instance_id: str, **kwargs: Any ) -> HttpRequest: - _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) - api_version = kwargs.pop("api_version", _params.pop("api-version", "2022-10-01")) # type: str - accept = _headers.pop("Accept", "application/json") - + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-06-01")) # Construct URL _url = "/deviceUpdate/{instanceId}/management/deviceClasses/{deviceClassId}" path_format_arguments = { - "instanceId": _SERIALIZER.url("instance_id", instance_id, "str", skip_quote=True), + "instanceId": _SERIALIZER.url("instance_id", instance_id, "str"), "deviceClassId": _SERIALIZER.url("device_class_id", device_class_id, "str"), } - _url = _format_url_section(_url, **path_format_arguments) + _url: str = _url.format(**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, **kwargs) - return HttpRequest(method="DELETE", url=_url, params=_params, headers=_headers, **kwargs) - -def build_device_management_list_installable_updates_for_device_class_request( +def build_device_management_list_installable_updates_for_device_class_request( # pylint: disable=name-too-long device_class_id: str, instance_id: str, **kwargs: Any ) -> HttpRequest: _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) - api_version = kwargs.pop("api_version", _params.pop("api-version", "2022-10-01")) # type: str + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-06-01")) accept = _headers.pop("Accept", "application/json") # Construct URL _url = "/deviceUpdate/{instanceId}/management/deviceClasses/{deviceClassId}/installableUpdates" path_format_arguments = { - "instanceId": _SERIALIZER.url("instance_id", instance_id, "str", skip_quote=True), + "instanceId": _SERIALIZER.url("instance_id", instance_id, "str"), "deviceClassId": _SERIALIZER.url("device_class_id", device_class_id, "str"), } - _url = _format_url_section(_url, **path_format_arguments) + _url: str = _url.format(**path_format_arguments) # type: ignore # Construct parameters _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") @@ -503,27 +525,27 @@ def build_device_management_list_installable_updates_for_device_class_request( return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -def build_device_management_list_devices_request( +def build_device_management_list_devices_request( # pylint: disable=name-too-long instance_id: str, *, filter: Optional[str] = None, **kwargs: Any ) -> HttpRequest: _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) - api_version = kwargs.pop("api_version", _params.pop("api-version", "2022-10-01")) # type: str + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-06-01")) accept = _headers.pop("Accept", "application/json") # Construct URL _url = "/deviceUpdate/{instanceId}/management/devices" path_format_arguments = { - "instanceId": _SERIALIZER.url("instance_id", instance_id, "str", skip_quote=True), + "instanceId": _SERIALIZER.url("instance_id", instance_id, "str"), } - _url = _format_url_section(_url, **path_format_arguments) + _url: str = _url.format(**path_format_arguments) # type: ignore # Construct parameters + _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") if filter is not None: _params["filter"] = _SERIALIZER.query("filter", filter, "str") - _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") # Construct headers _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") @@ -531,48 +553,48 @@ def build_device_management_list_devices_request( return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -def build_device_management_import_devices_request(instance_id: str, *, json: str, **kwargs: Any) -> HttpRequest: +def build_device_management_import_devices_request( # pylint: disable=name-too-long + instance_id: str, **kwargs: Any +) -> HttpRequest: _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) - content_type = kwargs.pop("content_type", _headers.pop("Content-Type", None)) # type: Optional[str] - api_version = kwargs.pop("api_version", _params.pop("api-version", "2022-10-01")) # type: str - accept = _headers.pop("Accept", "application/json") - + content_type: str = kwargs.pop("content_type") + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-06-01")) # Construct URL _url = "/deviceUpdate/{instanceId}/management/devices:import" path_format_arguments = { - "instanceId": _SERIALIZER.url("instance_id", instance_id, "str", skip_quote=True), + "instanceId": _SERIALIZER.url("instance_id", instance_id, "str"), } - _url = _format_url_section(_url, **path_format_arguments) + _url: str = _url.format(**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") + _headers["Content-Type"] = _SERIALIZER.header("content_type", content_type, "str") - return HttpRequest(method="POST", url=_url, params=_params, headers=_headers, json=json, **kwargs) + return HttpRequest(method="POST", url=_url, params=_params, headers=_headers, **kwargs) -def build_device_management_get_device_request(device_id: str, instance_id: str, **kwargs: Any) -> HttpRequest: +def build_device_management_get_device_request( # pylint: disable=name-too-long + device_id: str, instance_id: str, **kwargs: Any +) -> HttpRequest: _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) - api_version = kwargs.pop("api_version", _params.pop("api-version", "2022-10-01")) # type: str + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-06-01")) accept = _headers.pop("Accept", "application/json") # Construct URL _url = "/deviceUpdate/{instanceId}/management/devices/{deviceId}" path_format_arguments = { - "instanceId": _SERIALIZER.url("instance_id", instance_id, "str", skip_quote=True), + "instanceId": _SERIALIZER.url("instance_id", instance_id, "str"), "deviceId": _SERIALIZER.url("device_id", device_id, "str"), } - _url = _format_url_section(_url, **path_format_arguments) + _url: str = _url.format(**path_format_arguments) # type: ignore # Construct parameters _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") @@ -583,24 +605,24 @@ def build_device_management_get_device_request(device_id: str, instance_id: str, return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -def build_device_management_get_device_module_request( +def build_device_management_get_device_module_request( # pylint: disable=name-too-long device_id: str, module_id: str, instance_id: str, **kwargs: Any ) -> HttpRequest: _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) - api_version = kwargs.pop("api_version", _params.pop("api-version", "2022-10-01")) # type: str + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-06-01")) accept = _headers.pop("Accept", "application/json") # Construct URL _url = "/deviceUpdate/{instanceId}/management/devices/{deviceId}/modules/{moduleId}" path_format_arguments = { - "instanceId": _SERIALIZER.url("instance_id", instance_id, "str", skip_quote=True), + "instanceId": _SERIALIZER.url("instance_id", instance_id, "str"), "deviceId": _SERIALIZER.url("device_id", device_id, "str"), "moduleId": _SERIALIZER.url("module_id", module_id, "str"), } - _url = _format_url_section(_url, **path_format_arguments) + _url: str = _url.format(**path_format_arguments) # type: ignore # Construct parameters _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") @@ -611,20 +633,22 @@ def build_device_management_get_device_module_request( return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -def build_device_management_get_update_compliance_request(instance_id: str, **kwargs: Any) -> HttpRequest: +def build_device_management_get_update_compliance_request( # pylint: disable=name-too-long + instance_id: str, **kwargs: Any +) -> HttpRequest: _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) - api_version = kwargs.pop("api_version", _params.pop("api-version", "2022-10-01")) # type: str + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-06-01")) accept = _headers.pop("Accept", "application/json") # Construct URL _url = "/deviceUpdate/{instanceId}/management/updateCompliance" path_format_arguments = { - "instanceId": _SERIALIZER.url("instance_id", instance_id, "str", skip_quote=True), + "instanceId": _SERIALIZER.url("instance_id", instance_id, "str"), } - _url = _format_url_section(_url, **path_format_arguments) + _url: str = _url.format(**path_format_arguments) # type: ignore # Construct parameters _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") @@ -635,27 +659,27 @@ def build_device_management_get_update_compliance_request(instance_id: str, **kw return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -def build_device_management_list_groups_request( +def build_device_management_list_groups_request( # pylint: disable=name-too-long instance_id: str, *, order_by: Optional[str] = None, **kwargs: Any ) -> HttpRequest: _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) - api_version = kwargs.pop("api_version", _params.pop("api-version", "2022-10-01")) # type: str + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-06-01")) accept = _headers.pop("Accept", "application/json") # Construct URL _url = "/deviceUpdate/{instanceId}/management/groups" path_format_arguments = { - "instanceId": _SERIALIZER.url("instance_id", instance_id, "str", skip_quote=True), + "instanceId": _SERIALIZER.url("instance_id", instance_id, "str"), } - _url = _format_url_section(_url, **path_format_arguments) + _url: str = _url.format(**path_format_arguments) # type: ignore # Construct parameters + _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") if order_by is not None: _params["orderby"] = _SERIALIZER.query("order_by", order_by, "str") - _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") # Construct headers _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") @@ -663,21 +687,23 @@ def build_device_management_list_groups_request( return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -def build_device_management_get_group_request(group_id: str, instance_id: str, **kwargs: Any) -> HttpRequest: +def build_device_management_get_group_request( # pylint: disable=name-too-long + group_id: str, instance_id: str, **kwargs: Any +) -> HttpRequest: _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) - api_version = kwargs.pop("api_version", _params.pop("api-version", "2022-10-01")) # type: str + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-06-01")) accept = _headers.pop("Accept", "application/json") # Construct URL _url = "/deviceUpdate/{instanceId}/management/groups/{groupId}" path_format_arguments = { - "instanceId": _SERIALIZER.url("instance_id", instance_id, "str", skip_quote=True), + "instanceId": _SERIALIZER.url("instance_id", instance_id, "str"), "groupId": _SERIALIZER.url("group_id", group_id, "str"), } - _url = _format_url_section(_url, **path_format_arguments) + _url: str = _url.format(**path_format_arguments) # type: ignore # Construct parameters _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") @@ -688,48 +714,44 @@ def build_device_management_get_group_request(group_id: str, instance_id: str, * return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -def build_device_management_delete_group_request(group_id: str, instance_id: str, **kwargs: Any) -> HttpRequest: - _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) +def build_device_management_delete_group_request( # pylint: disable=name-too-long + group_id: str, instance_id: str, **kwargs: Any +) -> HttpRequest: _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) - api_version = kwargs.pop("api_version", _params.pop("api-version", "2022-10-01")) # type: str - accept = _headers.pop("Accept", "application/json") - + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-06-01")) # Construct URL _url = "/deviceUpdate/{instanceId}/management/groups/{groupId}" path_format_arguments = { - "instanceId": _SERIALIZER.url("instance_id", instance_id, "str", skip_quote=True), + "instanceId": _SERIALIZER.url("instance_id", instance_id, "str"), "groupId": _SERIALIZER.url("group_id", group_id, "str"), } - _url = _format_url_section(_url, **path_format_arguments) + _url: str = _url.format(**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) + return HttpRequest(method="DELETE", url=_url, params=_params, **kwargs) -def build_device_management_get_update_compliance_for_group_request( +def build_device_management_get_update_compliance_for_group_request( # pylint: disable=name-too-long group_id: str, instance_id: str, **kwargs: Any ) -> HttpRequest: _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) - api_version = kwargs.pop("api_version", _params.pop("api-version", "2022-10-01")) # type: str + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-06-01")) accept = _headers.pop("Accept", "application/json") # Construct URL _url = "/deviceUpdate/{instanceId}/management/groups/{groupId}/updateCompliance" path_format_arguments = { - "instanceId": _SERIALIZER.url("instance_id", instance_id, "str", skip_quote=True), + "instanceId": _SERIALIZER.url("instance_id", instance_id, "str"), "groupId": _SERIALIZER.url("group_id", group_id, "str"), } - _url = _format_url_section(_url, **path_format_arguments) + _url: str = _url.format(**path_format_arguments) # type: ignore # Construct parameters _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") @@ -740,23 +762,23 @@ def build_device_management_get_update_compliance_for_group_request( return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -def build_device_management_list_best_updates_for_group_request( +def build_device_management_list_best_updates_for_group_request( # pylint: disable=name-too-long group_id: str, instance_id: str, **kwargs: Any ) -> HttpRequest: _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) - api_version = kwargs.pop("api_version", _params.pop("api-version", "2022-10-01")) # type: str + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-06-01")) accept = _headers.pop("Accept", "application/json") # Construct URL _url = "/deviceUpdate/{instanceId}/management/groups/{groupId}/bestUpdates" path_format_arguments = { - "instanceId": _SERIALIZER.url("instance_id", instance_id, "str", skip_quote=True), + "instanceId": _SERIALIZER.url("instance_id", instance_id, "str"), "groupId": _SERIALIZER.url("group_id", group_id, "str"), } - _url = _format_url_section(_url, **path_format_arguments) + _url: str = _url.format(**path_format_arguments) # type: ignore # Construct parameters _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") @@ -767,23 +789,23 @@ def build_device_management_list_best_updates_for_group_request( return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -def build_device_management_list_deployments_for_group_request( +def build_device_management_list_deployments_for_group_request( # pylint: disable=name-too-long group_id: str, instance_id: str, *, order_by: Optional[str] = None, **kwargs: Any ) -> HttpRequest: _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) - api_version = kwargs.pop("api_version", _params.pop("api-version", "2022-10-01")) # type: str + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-06-01")) accept = _headers.pop("Accept", "application/json") # Construct URL _url = "/deviceUpdate/{instanceId}/management/groups/{groupId}/deployments" path_format_arguments = { - "instanceId": _SERIALIZER.url("instance_id", instance_id, "str", skip_quote=True), + "instanceId": _SERIALIZER.url("instance_id", instance_id, "str"), "groupId": _SERIALIZER.url("group_id", group_id, "str"), } - _url = _format_url_section(_url, **path_format_arguments) + _url: str = _url.format(**path_format_arguments) # type: ignore # Construct parameters _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") @@ -796,24 +818,24 @@ def build_device_management_list_deployments_for_group_request( return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -def build_device_management_get_deployment_request( +def build_device_management_get_deployment_request( # pylint: disable=name-too-long group_id: str, deployment_id: str, instance_id: str, **kwargs: Any ) -> HttpRequest: _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) - api_version = kwargs.pop("api_version", _params.pop("api-version", "2022-10-01")) # type: str + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-06-01")) accept = _headers.pop("Accept", "application/json") # Construct URL _url = "/deviceUpdate/{instanceId}/management/groups/{groupId}/deployments/{deploymentId}" path_format_arguments = { - "instanceId": _SERIALIZER.url("instance_id", instance_id, "str", skip_quote=True), + "instanceId": _SERIALIZER.url("instance_id", instance_id, "str"), "groupId": _SERIALIZER.url("group_id", group_id, "str"), "deploymentId": _SERIALIZER.url("deployment_id", deployment_id, "str"), } - _url = _format_url_section(_url, **path_format_arguments) + _url: str = _url.format(**path_format_arguments) # type: ignore # Construct parameters _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") @@ -824,25 +846,25 @@ def build_device_management_get_deployment_request( return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -def build_device_management_create_or_update_deployment_request( +def build_device_management_create_or_update_deployment_request( # pylint: disable=name-too-long group_id: str, deployment_id: str, instance_id: str, **kwargs: Any ) -> HttpRequest: _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) - content_type = kwargs.pop("content_type", _headers.pop("Content-Type", None)) # type: Optional[str] - api_version = kwargs.pop("api_version", _params.pop("api-version", "2022-10-01")) # type: str + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-06-01")) accept = _headers.pop("Accept", "application/json") # Construct URL _url = "/deviceUpdate/{instanceId}/management/groups/{groupId}/deployments/{deploymentId}" path_format_arguments = { - "instanceId": _SERIALIZER.url("instance_id", instance_id, "str", skip_quote=True), + "instanceId": _SERIALIZER.url("instance_id", instance_id, "str"), "groupId": _SERIALIZER.url("group_id", group_id, "str"), "deploymentId": _SERIALIZER.url("deployment_id", deployment_id, "str"), } - _url = _format_url_section(_url, **path_format_arguments) + _url: str = _url.format(**path_format_arguments) # type: ignore # Construct parameters _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") @@ -855,52 +877,24 @@ def build_device_management_create_or_update_deployment_request( return HttpRequest(method="PUT", url=_url, params=_params, headers=_headers, **kwargs) -def build_device_management_delete_deployment_request( - group_id: str, deployment_id: str, instance_id: str, **kwargs: Any -) -> HttpRequest: - _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) - _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) - - api_version = kwargs.pop("api_version", _params.pop("api-version", "2022-10-01")) # type: str - accept = _headers.pop("Accept", "application/json") - - # Construct URL - _url = "/deviceUpdate/{instanceId}/management/groups/{groupId}/deployments/{deploymentId}" - path_format_arguments = { - "instanceId": _SERIALIZER.url("instance_id", instance_id, "str", skip_quote=True), - "groupId": _SERIALIZER.url("group_id", group_id, "str"), - "deploymentId": _SERIALIZER.url("deployment_id", deployment_id, "str"), - } - - _url = _format_url_section(_url, **path_format_arguments) - - # 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_device_management_get_deployment_status_request( +def build_device_management_get_deployment_status_request( # pylint: disable=name-too-long group_id: str, deployment_id: str, instance_id: str, **kwargs: Any ) -> HttpRequest: _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) - api_version = kwargs.pop("api_version", _params.pop("api-version", "2022-10-01")) # type: str + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-06-01")) accept = _headers.pop("Accept", "application/json") # Construct URL _url = "/deviceUpdate/{instanceId}/management/groups/{groupId}/deployments/{deploymentId}/status" path_format_arguments = { - "instanceId": _SERIALIZER.url("instance_id", instance_id, "str", skip_quote=True), + "instanceId": _SERIALIZER.url("instance_id", instance_id, "str"), "groupId": _SERIALIZER.url("group_id", group_id, "str"), "deploymentId": _SERIALIZER.url("deployment_id", deployment_id, "str"), } - _url = _format_url_section(_url, **path_format_arguments) + _url: str = _url.format(**path_format_arguments) # type: ignore # Construct parameters _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") @@ -911,28 +905,28 @@ def build_device_management_get_deployment_status_request( return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -def build_device_management_list_device_class_subgroups_for_group_request( +def build_device_management_list_device_class_subgroups_for_group_request( # pylint: disable=name-too-long group_id: str, instance_id: str, *, filter: Optional[str] = None, **kwargs: Any ) -> HttpRequest: _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) - api_version = kwargs.pop("api_version", _params.pop("api-version", "2022-10-01")) # type: str + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-06-01")) accept = _headers.pop("Accept", "application/json") # Construct URL _url = "/deviceUpdate/{instanceId}/management/groups/{groupId}/deviceClassSubgroups" path_format_arguments = { - "instanceId": _SERIALIZER.url("instance_id", instance_id, "str", skip_quote=True), + "instanceId": _SERIALIZER.url("instance_id", instance_id, "str"), "groupId": _SERIALIZER.url("group_id", group_id, "str"), } - _url = _format_url_section(_url, **path_format_arguments) + _url: str = _url.format(**path_format_arguments) # type: ignore # Construct parameters + _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") if filter is not None: _params["filter"] = _SERIALIZER.query("filter", filter, "str") - _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") # Construct headers _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") @@ -940,24 +934,24 @@ def build_device_management_list_device_class_subgroups_for_group_request( return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -def build_device_management_get_device_class_subgroup_request( +def build_device_management_get_device_class_subgroup_request( # pylint: disable=name-too-long group_id: str, device_class_id: str, instance_id: str, **kwargs: Any ) -> HttpRequest: _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) - api_version = kwargs.pop("api_version", _params.pop("api-version", "2022-10-01")) # type: str + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-06-01")) accept = _headers.pop("Accept", "application/json") # Construct URL _url = "/deviceUpdate/{instanceId}/management/groups/{groupId}/deviceClassSubgroups/{deviceClassId}" path_format_arguments = { - "instanceId": _SERIALIZER.url("instance_id", instance_id, "str", skip_quote=True), + "instanceId": _SERIALIZER.url("instance_id", instance_id, "str"), "groupId": _SERIALIZER.url("group_id", group_id, "str"), "deviceClassId": _SERIALIZER.url("device_class_id", device_class_id, "str"), } - _url = _format_url_section(_url, **path_format_arguments) + _url: str = _url.format(**path_format_arguments) # type: ignore # Construct parameters _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") @@ -968,41 +962,35 @@ def build_device_management_get_device_class_subgroup_request( return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -def build_device_management_delete_device_class_subgroup_request( +def build_device_management_delete_device_class_subgroup_request( # pylint: disable=name-too-long group_id: str, device_class_id: str, instance_id: str, **kwargs: Any ) -> HttpRequest: - _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) - api_version = kwargs.pop("api_version", _params.pop("api-version", "2022-10-01")) # type: str - accept = _headers.pop("Accept", "application/json") - + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-06-01")) # Construct URL _url = "/deviceUpdate/{instanceId}/management/groups/{groupId}/deviceClassSubgroups/{deviceClassId}" path_format_arguments = { - "instanceId": _SERIALIZER.url("instance_id", instance_id, "str", skip_quote=True), + "instanceId": _SERIALIZER.url("instance_id", instance_id, "str"), "groupId": _SERIALIZER.url("group_id", group_id, "str"), "deviceClassId": _SERIALIZER.url("device_class_id", device_class_id, "str"), } - _url = _format_url_section(_url, **path_format_arguments) + _url: str = _url.format(**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) + return HttpRequest(method="DELETE", url=_url, params=_params, **kwargs) -def build_device_management_get_device_class_subgroup_update_compliance_request( +def build_device_management_get_device_class_subgroup_update_compliance_request( # pylint: disable=name-too-long group_id: str, device_class_id: str, instance_id: str, **kwargs: Any ) -> HttpRequest: _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) - api_version = kwargs.pop("api_version", _params.pop("api-version", "2022-10-01")) # type: str + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-06-01")) accept = _headers.pop("Accept", "application/json") # Construct URL @@ -1010,12 +998,12 @@ def build_device_management_get_device_class_subgroup_update_compliance_request( "/deviceUpdate/{instanceId}/management/groups/{groupId}/deviceClassSubgroups/{deviceClassId}/updateCompliance" ) path_format_arguments = { - "instanceId": _SERIALIZER.url("instance_id", instance_id, "str", skip_quote=True), + "instanceId": _SERIALIZER.url("instance_id", instance_id, "str"), "groupId": _SERIALIZER.url("group_id", group_id, "str"), "deviceClassId": _SERIALIZER.url("device_class_id", device_class_id, "str"), } - _url = _format_url_section(_url, **path_format_arguments) + _url: str = _url.format(**path_format_arguments) # type: ignore # Construct parameters _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") @@ -1026,24 +1014,24 @@ def build_device_management_get_device_class_subgroup_update_compliance_request( return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -def build_device_management_get_best_updates_for_device_class_subgroup_request( +def build_device_management_get_best_updates_for_device_class_subgroup_request( # pylint: disable=name-too-long group_id: str, device_class_id: str, instance_id: str, **kwargs: Any ) -> HttpRequest: _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) - api_version = kwargs.pop("api_version", _params.pop("api-version", "2022-10-01")) # type: str + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-06-01")) accept = _headers.pop("Accept", "application/json") # Construct URL _url = "/deviceUpdate/{instanceId}/management/groups/{groupId}/deviceClassSubgroups/{deviceClassId}/bestUpdates" path_format_arguments = { - "instanceId": _SERIALIZER.url("instance_id", instance_id, "str", skip_quote=True), + "instanceId": _SERIALIZER.url("instance_id", instance_id, "str"), "groupId": _SERIALIZER.url("group_id", group_id, "str"), "deviceClassId": _SERIALIZER.url("device_class_id", device_class_id, "str"), } - _url = _format_url_section(_url, **path_format_arguments) + _url: str = _url.format(**path_format_arguments) # type: ignore # Construct parameters _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") @@ -1054,24 +1042,24 @@ def build_device_management_get_best_updates_for_device_class_subgroup_request( return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -def build_device_management_list_deployments_for_device_class_subgroup_request( +def build_device_management_list_deployments_for_device_class_subgroup_request( # pylint: disable=name-too-long group_id: str, device_class_id: str, instance_id: str, *, order_by: Optional[str] = None, **kwargs: Any ) -> HttpRequest: _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) - api_version = kwargs.pop("api_version", _params.pop("api-version", "2022-10-01")) # type: str + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-06-01")) accept = _headers.pop("Accept", "application/json") # Construct URL _url = "/deviceUpdate/{instanceId}/management/groups/{groupId}/deviceClassSubgroups/{deviceClassId}/deployments" path_format_arguments = { - "instanceId": _SERIALIZER.url("instance_id", instance_id, "str", skip_quote=True), + "instanceId": _SERIALIZER.url("instance_id", instance_id, "str"), "groupId": _SERIALIZER.url("group_id", group_id, "str"), "deviceClassId": _SERIALIZER.url("device_class_id", device_class_id, "str"), } - _url = _format_url_section(_url, **path_format_arguments) + _url: str = _url.format(**path_format_arguments) # type: ignore # Construct parameters _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") @@ -1084,25 +1072,25 @@ def build_device_management_list_deployments_for_device_class_subgroup_request( return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -def build_device_management_get_deployment_for_device_class_subgroup_request( +def build_device_management_get_deployment_for_device_class_subgroup_request( # pylint: disable=name-too-long group_id: str, device_class_id: str, deployment_id: str, instance_id: str, **kwargs: Any ) -> HttpRequest: _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) - api_version = kwargs.pop("api_version", _params.pop("api-version", "2022-10-01")) # type: str + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-06-01")) accept = _headers.pop("Accept", "application/json") # Construct URL - _url = "/deviceUpdate/{instanceId}/management/groups/{groupId}/deviceClassSubgroups/{deviceClassId}/deployments/{deploymentId}" # pylint: disable=line-too-long + _url = "/deviceUpdate/{instanceId}/management/groups/{groupId}/deviceClassSubgroups/{deviceClassId}/deployments/{deploymentId}" path_format_arguments = { - "instanceId": _SERIALIZER.url("instance_id", instance_id, "str", skip_quote=True), + "instanceId": _SERIALIZER.url("instance_id", instance_id, "str"), "groupId": _SERIALIZER.url("group_id", group_id, "str"), "deviceClassId": _SERIALIZER.url("device_class_id", device_class_id, "str"), "deploymentId": _SERIALIZER.url("deployment_id", deployment_id, "str"), } - _url = _format_url_section(_url, **path_format_arguments) + _url: str = _url.format(**path_format_arguments) # type: ignore # Construct parameters _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") @@ -1113,54 +1101,25 @@ def build_device_management_get_deployment_for_device_class_subgroup_request( return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -def build_device_management_delete_deployment_for_device_class_subgroup_request( - group_id: str, device_class_id: str, deployment_id: str, instance_id: str, **kwargs: Any -) -> HttpRequest: - _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) - _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) - - api_version = kwargs.pop("api_version", _params.pop("api-version", "2022-10-01")) # type: str - accept = _headers.pop("Accept", "application/json") - - # Construct URL - _url = "/deviceUpdate/{instanceId}/management/groups/{groupId}/deviceClassSubgroups/{deviceClassId}/deployments/{deploymentId}" # pylint: disable=line-too-long - path_format_arguments = { - "instanceId": _SERIALIZER.url("instance_id", instance_id, "str", skip_quote=True), - "groupId": _SERIALIZER.url("group_id", group_id, "str"), - "deviceClassId": _SERIALIZER.url("device_class_id", device_class_id, "str"), - "deploymentId": _SERIALIZER.url("deployment_id", deployment_id, "str"), - } - - _url = _format_url_section(_url, **path_format_arguments) - - # 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_device_management_stop_deployment_request( +def build_device_management_stop_deployment_request( # pylint: disable=name-too-long group_id: str, device_class_id: str, deployment_id: str, instance_id: str, **kwargs: Any ) -> HttpRequest: _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) - api_version = kwargs.pop("api_version", _params.pop("api-version", "2022-10-01")) # type: str + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-06-01")) accept = _headers.pop("Accept", "application/json") # Construct URL - _url = "/deviceUpdate/{instanceId}/management/groups/{groupId}/deviceClassSubgroups/{deviceClassId}/deployments/{deploymentId}:cancel" # pylint: disable=line-too-long + _url = "/deviceUpdate/{instanceId}/management/groups/{groupId}/deviceClassSubgroups/{deviceClassId}/deployments/{deploymentId}:cancel" path_format_arguments = { - "instanceId": _SERIALIZER.url("instance_id", instance_id, "str", skip_quote=True), + "instanceId": _SERIALIZER.url("instance_id", instance_id, "str"), "groupId": _SERIALIZER.url("group_id", group_id, "str"), "deviceClassId": _SERIALIZER.url("device_class_id", device_class_id, "str"), "deploymentId": _SERIALIZER.url("deployment_id", deployment_id, "str"), } - _url = _format_url_section(_url, **path_format_arguments) + _url: str = _url.format(**path_format_arguments) # type: ignore # Construct parameters _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") @@ -1171,25 +1130,25 @@ def build_device_management_stop_deployment_request( return HttpRequest(method="POST", url=_url, params=_params, headers=_headers, **kwargs) -def build_device_management_retry_deployment_request( +def build_device_management_retry_deployment_request( # pylint: disable=name-too-long group_id: str, device_class_id: str, deployment_id: str, instance_id: str, **kwargs: Any ) -> HttpRequest: _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) - api_version = kwargs.pop("api_version", _params.pop("api-version", "2022-10-01")) # type: str + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-06-01")) accept = _headers.pop("Accept", "application/json") # Construct URL - _url = "/deviceUpdate/{instanceId}/management/groups/{groupId}/deviceClassSubgroups/{deviceClassId}/deployments/{deploymentId}:retry" # pylint: disable=line-too-long + _url = "/deviceUpdate/{instanceId}/management/groups/{groupId}/deviceClassSubgroups/{deviceClassId}/deployments/{deploymentId}:retry" path_format_arguments = { - "instanceId": _SERIALIZER.url("instance_id", instance_id, "str", skip_quote=True), + "instanceId": _SERIALIZER.url("instance_id", instance_id, "str"), "groupId": _SERIALIZER.url("group_id", group_id, "str"), "deviceClassId": _SERIALIZER.url("device_class_id", device_class_id, "str"), "deploymentId": _SERIALIZER.url("deployment_id", deployment_id, "str"), } - _url = _format_url_section(_url, **path_format_arguments) + _url: str = _url.format(**path_format_arguments) # type: ignore # Construct parameters _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") @@ -1200,25 +1159,25 @@ def build_device_management_retry_deployment_request( return HttpRequest(method="POST", url=_url, params=_params, headers=_headers, **kwargs) -def build_device_management_get_device_class_subgroup_deployment_status_request( +def build_device_management_get_device_class_subgroup_deployment_status_request( # pylint: disable=name-too-long group_id: str, device_class_id: str, deployment_id: str, instance_id: str, **kwargs: Any ) -> HttpRequest: _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) - api_version = kwargs.pop("api_version", _params.pop("api-version", "2022-10-01")) # type: str + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-06-01")) accept = _headers.pop("Accept", "application/json") # Construct URL - _url = "/deviceUpdate/{instanceId}/management/groups/{groupId}/deviceClassSubgroups/{deviceClassId}/deployments/{deploymentId}/status" # pylint: disable=line-too-long + _url = "/deviceUpdate/{instanceId}/management/groups/{groupId}/deviceClassSubgroups/{deviceClassId}/deployments/{deploymentId}/status" path_format_arguments = { - "instanceId": _SERIALIZER.url("instance_id", instance_id, "str", skip_quote=True), + "instanceId": _SERIALIZER.url("instance_id", instance_id, "str"), "groupId": _SERIALIZER.url("group_id", group_id, "str"), "deviceClassId": _SERIALIZER.url("device_class_id", device_class_id, "str"), "deploymentId": _SERIALIZER.url("deployment_id", deployment_id, "str"), } - _url = _format_url_section(_url, **path_format_arguments) + _url: str = _url.format(**path_format_arguments) # type: ignore # Construct parameters _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") @@ -1229,7 +1188,7 @@ def build_device_management_get_device_class_subgroup_deployment_status_request( return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -def build_device_management_list_device_states_for_device_class_subgroup_deployment_request( +def build_device_management_list_device_states_for_device_class_subgroup_deployment_request( # pylint: disable=name-too-long group_id: str, device_class_id: str, deployment_id: str, @@ -1241,24 +1200,24 @@ def build_device_management_list_device_states_for_device_class_subgroup_deploym _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) - api_version = kwargs.pop("api_version", _params.pop("api-version", "2022-10-01")) # type: str + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-06-01")) accept = _headers.pop("Accept", "application/json") # Construct URL - _url = "/deviceUpdate/{instanceId}/management/groups/{groupId}/deviceClassSubgroups/{deviceClassId}/deployments/{deploymentId}/devicestates" # pylint: disable=line-too-long + _url = "/deviceUpdate/{instanceId}/management/groups/{groupId}/deviceClassSubgroups/{deviceClassId}/deployments/{deploymentId}/devicestates" path_format_arguments = { - "instanceId": _SERIALIZER.url("instance_id", instance_id, "str", skip_quote=True), + "instanceId": _SERIALIZER.url("instance_id", instance_id, "str"), "groupId": _SERIALIZER.url("group_id", group_id, "str"), "deviceClassId": _SERIALIZER.url("device_class_id", device_class_id, "str"), "deploymentId": _SERIALIZER.url("deployment_id", deployment_id, "str"), } - _url = _format_url_section(_url, **path_format_arguments) + _url: str = _url.format(**path_format_arguments) # type: ignore # Construct parameters + _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") if filter is not None: _params["filter"] = _SERIALIZER.query("filter", filter, "str") - _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") # Construct headers _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") @@ -1266,58 +1225,67 @@ def build_device_management_list_device_states_for_device_class_subgroup_deploym return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -def build_device_management_get_operation_status_request( - operation_id: str, instance_id: str, *, if_none_match: Optional[str] = None, **kwargs: Any +def build_device_management_get_operation_status_request( # pylint: disable=name-too-long + operation_id: str, + instance_id: str, + *, + etag: Optional[str] = None, + match_condition: Optional[MatchConditions] = None, + **kwargs: Any ) -> HttpRequest: _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) - api_version = kwargs.pop("api_version", _params.pop("api-version", "2022-10-01")) # type: str + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-06-01")) accept = _headers.pop("Accept", "application/json") # Construct URL _url = "/deviceUpdate/{instanceId}/management/operations/{operationId}" path_format_arguments = { - "instanceId": _SERIALIZER.url("instance_id", instance_id, "str", skip_quote=True), - "operationId": _SERIALIZER.url("operation_id", operation_id, "str", max_length=256, min_length=1), + "instanceId": _SERIALIZER.url("instance_id", instance_id, "str"), + "operationId": _SERIALIZER.url("operation_id", operation_id, "str"), } - _url = _format_url_section(_url, **path_format_arguments) + _url: str = _url.format(**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") + if_match = prep_if_match(etag, match_condition) + if if_match is not None: + _headers["if-match"] = _SERIALIZER.header("if_match", if_match, "str") + if_none_match = prep_if_none_match(etag, match_condition) if if_none_match is not None: _headers["If-None-Match"] = _SERIALIZER.header("if_none_match", if_none_match, "str") - _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -def build_device_management_list_operation_statuses_request( +def build_device_management_list_operation_statuses_request( # pylint: disable=name-too-long instance_id: str, *, filter: Optional[str] = None, top: Optional[int] = None, **kwargs: Any ) -> HttpRequest: _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) - api_version = kwargs.pop("api_version", _params.pop("api-version", "2022-10-01")) # type: str + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-06-01")) accept = _headers.pop("Accept", "application/json") # Construct URL _url = "/deviceUpdate/{instanceId}/management/operations" path_format_arguments = { - "instanceId": _SERIALIZER.url("instance_id", instance_id, "str", skip_quote=True), + "instanceId": _SERIALIZER.url("instance_id", instance_id, "str"), } - _url = _format_url_section(_url, **path_format_arguments) + _url: str = _url.format(**path_format_arguments) # type: ignore # Construct parameters + _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") if filter is not None: _params["filter"] = _SERIALIZER.query("filter", filter, "str") if top is not None: _params["top"] = _SERIALIZER.query("top", top, "int") - _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") # Construct headers _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") @@ -1325,24 +1293,24 @@ def build_device_management_list_operation_statuses_request( return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -def build_device_management_start_log_collection_request( +def build_device_management_start_log_collection_request( # pylint: disable=name-too-long log_collection_id: str, instance_id: str, **kwargs: Any ) -> HttpRequest: _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) - content_type = kwargs.pop("content_type", _headers.pop("Content-Type", None)) # type: Optional[str] - api_version = kwargs.pop("api_version", _params.pop("api-version", "2022-10-01")) # type: str + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-06-01")) accept = _headers.pop("Accept", "application/json") # Construct URL _url = "/deviceUpdate/{instanceId}/management/deviceDiagnostics/logCollections/{operationId}" path_format_arguments = { - "instanceId": _SERIALIZER.url("instance_id", instance_id, "str", skip_quote=True), - "operationId": _SERIALIZER.url("log_collection_id", log_collection_id, "str", max_length=256, min_length=1), + "instanceId": _SERIALIZER.url("instance_id", instance_id, "str"), + "operationId": _SERIALIZER.url("log_collection_id", log_collection_id, "str"), } - _url = _format_url_section(_url, **path_format_arguments) + _url: str = _url.format(**path_format_arguments) # type: ignore # Construct parameters _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") @@ -1355,23 +1323,23 @@ def build_device_management_start_log_collection_request( return HttpRequest(method="PUT", url=_url, params=_params, headers=_headers, **kwargs) -def build_device_management_get_log_collection_request( +def build_device_management_get_log_collection_request( # pylint: disable=name-too-long log_collection_id: str, instance_id: str, **kwargs: Any ) -> HttpRequest: _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) - api_version = kwargs.pop("api_version", _params.pop("api-version", "2022-10-01")) # type: str + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-06-01")) accept = _headers.pop("Accept", "application/json") # Construct URL _url = "/deviceUpdate/{instanceId}/management/deviceDiagnostics/logCollections/{operationId}" path_format_arguments = { - "instanceId": _SERIALIZER.url("instance_id", instance_id, "str", skip_quote=True), - "operationId": _SERIALIZER.url("log_collection_id", log_collection_id, "str", max_length=256, min_length=1), + "instanceId": _SERIALIZER.url("instance_id", instance_id, "str"), + "operationId": _SERIALIZER.url("log_collection_id", log_collection_id, "str"), } - _url = _format_url_section(_url, **path_format_arguments) + _url: str = _url.format(**path_format_arguments) # type: ignore # Construct parameters _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") @@ -1382,20 +1350,22 @@ def build_device_management_get_log_collection_request( return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -def build_device_management_list_log_collections_request(instance_id: str, **kwargs: Any) -> HttpRequest: +def build_device_management_list_log_collections_request( # pylint: disable=name-too-long + instance_id: str, **kwargs: Any +) -> HttpRequest: _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) - api_version = kwargs.pop("api_version", _params.pop("api-version", "2022-10-01")) # type: str + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-06-01")) accept = _headers.pop("Accept", "application/json") # Construct URL _url = "/deviceUpdate/{instanceId}/management/deviceDiagnostics/logCollections" path_format_arguments = { - "instanceId": _SERIALIZER.url("instance_id", instance_id, "str", skip_quote=True), + "instanceId": _SERIALIZER.url("instance_id", instance_id, "str"), } - _url = _format_url_section(_url, **path_format_arguments) + _url: str = _url.format(**path_format_arguments) # type: ignore # Construct parameters _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") @@ -1406,23 +1376,23 @@ def build_device_management_list_log_collections_request(instance_id: str, **kwa return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -def build_device_management_get_log_collection_detailed_status_request( +def build_device_management_get_log_collection_detailed_status_request( # pylint: disable=name-too-long log_collection_id: str, instance_id: str, **kwargs: Any ) -> HttpRequest: _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) - api_version = kwargs.pop("api_version", _params.pop("api-version", "2022-10-01")) # type: str + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-06-01")) accept = _headers.pop("Accept", "application/json") # Construct URL _url = "/deviceUpdate/{instanceId}/management/deviceDiagnostics/logCollections/{operationId}/detailedStatus" path_format_arguments = { - "instanceId": _SERIALIZER.url("instance_id", instance_id, "str", skip_quote=True), - "operationId": _SERIALIZER.url("log_collection_id", log_collection_id, "str", max_length=256, min_length=1), + "instanceId": _SERIALIZER.url("instance_id", instance_id, "str"), + "operationId": _SERIALIZER.url("log_collection_id", log_collection_id, "str"), } - _url = _format_url_section(_url, **path_format_arguments) + _url: str = _url.format(**path_format_arguments) # type: ignore # Construct parameters _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") @@ -1433,22 +1403,22 @@ def build_device_management_get_log_collection_detailed_status_request( return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -def build_device_management_list_health_of_devices_request( +def build_device_management_list_health_of_devices_request( # pylint: disable=name-too-long instance_id: str, *, filter: str, **kwargs: Any ) -> HttpRequest: _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) - api_version = kwargs.pop("api_version", _params.pop("api-version", "2022-10-01")) # type: str + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-06-01")) accept = _headers.pop("Accept", "application/json") # Construct URL _url = "/deviceUpdate/{instanceId}/management/deviceDiagnostics/deviceHealth" path_format_arguments = { - "instanceId": _SERIALIZER.url("instance_id", instance_id, "str", skip_quote=True), + "instanceId": _SERIALIZER.url("instance_id", instance_id, "str"), } - _url = _format_url_section(_url, **path_format_arguments) + _url: str = _url.format(**path_format_arguments) # type: ignore # Construct parameters _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") @@ -1460,6 +1430,51 @@ def build_device_management_list_health_of_devices_request( return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) +def build_device_management_delete_deployment_request( # pylint: disable=name-too-long + group_id: str, deployment_id: str, instance_id: str, **kwargs: Any +) -> HttpRequest: + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-06-01")) + # Construct URL + _url = "/deviceUpdate/{instanceId}/management/groups/{groupId}/deployments/{deploymentId}" + path_format_arguments = { + "instanceId": _SERIALIZER.url("instance_id", instance_id, "str"), + "groupId": _SERIALIZER.url("group_id", group_id, "str"), + "deploymentId": _SERIALIZER.url("deployment_id", deployment_id, "str"), + } + + _url: str = _url.format(**path_format_arguments) # type: ignore + + # Construct parameters + _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") + + return HttpRequest(method="DELETE", url=_url, params=_params, **kwargs) + + +def build_device_management_delete_deployment_for_device_class_subgroup_request( # pylint: disable=name-too-long + group_id: str, device_class_id: str, deployment_id: str, instance_id: str, **kwargs: Any +) -> HttpRequest: + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-06-01")) + # Construct URL + _url = "/deviceUpdate/{instanceId}/management/groups/{groupId}/deviceClassSubgroups/{deviceClassId}/deployments/{deploymentId}" + path_format_arguments = { + "instanceId": _SERIALIZER.url("instance_id", instance_id, "str"), + "groupId": _SERIALIZER.url("group_id", group_id, "str"), + "deviceClassId": _SERIALIZER.url("device_class_id", device_class_id, "str"), + "deploymentId": _SERIALIZER.url("deployment_id", deployment_id, "str"), + } + + _url: str = _url.format(**path_format_arguments) # type: ignore + + # Construct parameters + _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") + + return HttpRequest(method="DELETE", url=_url, params=_params, **kwargs) + + class DeviceUpdateOperations: """ .. warning:: @@ -1470,107 +1485,44 @@ class DeviceUpdateOperations: :attr:`device_update` attribute. """ - def __init__(self, *args, **kwargs): + 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") + self._client: PipelineClient = input_args.pop(0) if input_args else kwargs.pop("client") + self._config: DeviceUpdateClientConfiguration = input_args.pop(0) if input_args else kwargs.pop("config") + self._serialize: Serializer = input_args.pop(0) if input_args else kwargs.pop("serializer") + self._deserialize: Deserializer = input_args.pop(0) if input_args else kwargs.pop("deserializer") @distributed_trace def list_updates( self, *, search: Optional[str] = None, filter: Optional[str] = None, **kwargs: Any - ) -> Iterable[JSON]: + ) -> ItemPaged["_models.Update"]: """Get a list of all updates that have been imported to Device Update for IoT Hub. :keyword search: Request updates matching a free-text search expression. Default value is None. :paramtype search: str :keyword filter: Optional to filter updates by isDeployable property. Default value is None. :paramtype filter: str - :return: An iterator like instance of JSON object - :rtype: ~azure.core.paging.ItemPaged[JSON] + :return: An iterator like instance of Update + :rtype: ~azure.core.paging.ItemPaged[~azure.iot.deviceupdate.models.Update] :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "compatibility": [ - { - "str": "str" # List of update compatibility information. - Required. - } - ], - "createdDateTime": "2020-02-20 00:00:00", # Date and time in UTC when the - update was created. Required. - "importedDateTime": "2020-02-20 00:00:00", # Date and time in UTC when the - update was imported. Required. - "manifestVersion": "str", # Schema version of manifest used to import the - update. Required. - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description specified by creator. - "etag": "str", # Optional. Update ETag. - "friendlyName": "str", # Optional. Friendly update name specified by - importer. - "installedCriteria": "str", # Optional. String interpreted by Device Update - client to determine if the update is installed on the device. Deprecated in - latest import manifest schema. - "instructions": { - "steps": [ - { - "description": "str", # Optional. Step description. - "files": [ - "str" # Optional. Collection of file names - to be passed to handler during execution. Required if step type - is inline. - ], - "handler": "str", # Optional. Identity of handler - that will execute this step. Required if step type is inline. - "handlerProperties": {}, # Optional. Parameters to - be passed to handler during execution. - "type": "inline", # Optional. Default value is - "inline". Step type. Known values are: "Inline" and "Reference". - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. - Required. - "version": "str" # Update version. Required. - } - } - ] - }, - "isDeployable": True, # Optional. Default value is True. Whether the update - can be deployed to a device on its own. - "referencedBy": [ - { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - } - ], - "scanResult": "str", # Optional. Update aggregate scan result (calculated - from payload file scan results). - "updateType": "str" # Optional. Update type. Deprecated in latest import - manifest schema. - } """ _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls = kwargs.pop("cls", None) # type: ClsType[JSON] + cls: ClsType[list[_models.Update]] = kwargs.pop("cls", None) - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } error_map.update(kwargs.pop("error_map", {}) or {}) def prepare_request(next_link=None): if not next_link: - request = build_device_update_list_updates_request( + _request = build_device_update_list_updates_request( instance_id=self._config.instance_id, search=search, filter=filter, @@ -1579,430 +1531,225 @@ def prepare_request(next_link=None): params=_params, ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) else: # make call to next link with the client's api-version - _parsed_next_link = urlparse(next_link) - _next_request_params = case_insensitive_dict(parse_qs(_parsed_next_link.query)) + _parsed_next_link = urllib.parse.urlparse(next_link) + _next_request_params = case_insensitive_dict( + { + key: [urllib.parse.quote(v) for v in value] + for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items() + } + ) _next_request_params["api-version"] = self._config.api_version - request = HttpRequest("GET", urljoin(next_link, _parsed_next_link.path), params=_next_request_params) + _request = HttpRequest( + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + headers=_headers, + params=_next_request_params, + ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - return request + return _request def extract_data(pipeline_response): deserialized = pipeline_response.http_response.json() - list_of_elem = deserialized["value"] + list_of_elem = _deserialize( + list[_models.Update], + deserialized.get("value", []), + ) if cls: - list_of_elem = cls(list_of_elem) - return deserialized.get("nextLink", None), iter(list_of_elem) + list_of_elem = cls(list_of_elem) # type: ignore + return deserialized.get("nextLink") or None, iter(list_of_elem) def get_next(next_link=None): - request = prepare_request(next_link) + _request = prepare_request(next_link) - pipeline_response = self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _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) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) return pipeline_response return ItemPaged(get_next, extract_data) - def _import_update_initial(self, update_to_import: Union[List[JSON], IO], **kwargs: Any) -> Optional[JSON]: - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + def _import_update_initial( + self, update_to_import: Union[list[_models.ImportUpdateInputItem], list[JSON], IO[bytes]], **kwargs: Any + ) -> Iterator[bytes]: + error_map: MutableMapping = { + 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 = kwargs.pop("content_type", _headers.pop("Content-Type", None)) # type: Optional[str] - cls = kwargs.pop("cls", None) # type: ClsType[Optional[JSON]] + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[Iterator[bytes]] = kwargs.pop("cls", None) content_type = content_type or "application/json" - _json = None _content = None - if isinstance(update_to_import, (IO, bytes)): + if isinstance(update_to_import, (IOBase, bytes)): _content = update_to_import else: - _json = update_to_import + _content = json.dumps(update_to_import, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - request = build_device_update_import_update_request( + _request = build_device_update_import_update_request( instance_id=self._config.instance_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), + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - pipeline_response = self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _decompress = kwargs.pop("decompress", True) + _stream = True + 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, 202]: + try: + response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) - deserialized = None response_headers = {} - if response.status_code == 200: - if response.content: - deserialized = response.json() - else: - deserialized = None - if response.status_code == 202: response_headers["Operation-Location"] = self._deserialize( "str", response.headers.get("Operation-Location") ) + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + if cls: - return cls(pipeline_response, deserialized, response_headers) + return cls(pipeline_response, deserialized, response_headers) # type: ignore - return deserialized + return deserialized # type: ignore @overload def begin_import_update( - self, update_to_import: List[JSON], *, content_type: str = "application/json", **kwargs: Any - ) -> LROPoller[JSON]: + self, + update_to_import: list[_models.ImportUpdateInputItem], + *, + content_type: str = "application/json", + **kwargs: Any + ) -> LROPoller[None]: """Import new update version. This is a long-running-operation; use Operation-Location response header value to check for operation status. :param update_to_import: The update to be imported (see schema - https://json.schemastore.org/azure-deviceupdate-import-manifest-5.0.json for details). - Required. - :type update_to_import: list[JSON] + `https://json.schemastore.org/azure-deviceupdate-import-manifest-5.0.json + `_ for + details). Required. + :type update_to_import: list[~azure.iot.deviceupdate.models.ImportUpdateInputItem] :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str - :keyword str continuation_token: A continuation token to restart a poller from a saved state. - :keyword polling: By default, your polling method will be LROBasePolling. Pass in False for - this operation to not poll, or pass in your own initialized polling object for a personal - polling strategy. - :paramtype polling: bool or ~azure.core.polling.PollingMethod - :keyword int polling_interval: Default waiting time between two polls for LRO operations if no - Retry-After header is present. - :return: An instance of LROPoller that returns JSON object - :rtype: ~azure.core.polling.LROPoller[JSON] + :return: An instance of LROPoller that returns None + :rtype: ~azure.core.polling.LROPoller[None] :raises ~azure.core.exceptions.HttpResponseError: + """ - Example: - .. code-block:: python + @overload + def begin_import_update( + self, update_to_import: list[JSON], *, content_type: str = "application/json", **kwargs: Any + ) -> LROPoller[None]: + """Import new update version. This is a long-running-operation; use Operation-Location response + header value to check for operation status. - # JSON input template you can fill out and use as your body input. - update_to_import = [ - { - "importManifest": { - "hashes": { - "str": "str" # A JSON object containing the hash(es) - of the file. At least SHA256 hash is required. This object can be - thought of as a set of key-value pairs where the key is the hash - algorithm, and the value is the hash of the file calculated using - that algorithm. Required. - }, - "sizeInBytes": 0, # File size in number of bytes. Required. - "url": "str" # Azure Blob location from which the import - manifest can be downloaded by Device Update for IoT Hub. This is - typically a read-only SAS-protected blob URL with an expiration set to at - least 4 hours. Required. - }, - "files": [ - { - "filename": "str", # Update file name as specified - inside import manifest. Required. - "url": "str" # Azure Blob location from which the - update file can be downloaded by Device Update for IoT Hub. This is - typically a read-only SAS-protected blob URL with an expiration set - to at least 4 hours. Required. - } - ], - "friendlyName": "str" # Optional. Friendly update name. - } - ] - - # response body for status code(s): 200 - response == { - "compatibility": [ - { - "str": "str" # List of update compatibility information. - Required. - } - ], - "createdDateTime": "2020-02-20 00:00:00", # Date and time in UTC when the - update was created. Required. - "importedDateTime": "2020-02-20 00:00:00", # Date and time in UTC when the - update was imported. Required. - "manifestVersion": "str", # Schema version of manifest used to import the - update. Required. - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description specified by creator. - "etag": "str", # Optional. Update ETag. - "friendlyName": "str", # Optional. Friendly update name specified by - importer. - "installedCriteria": "str", # Optional. String interpreted by Device Update - client to determine if the update is installed on the device. Deprecated in - latest import manifest schema. - "instructions": { - "steps": [ - { - "description": "str", # Optional. Step description. - "files": [ - "str" # Optional. Collection of file names - to be passed to handler during execution. Required if step type - is inline. - ], - "handler": "str", # Optional. Identity of handler - that will execute this step. Required if step type is inline. - "handlerProperties": {}, # Optional. Parameters to - be passed to handler during execution. - "type": "inline", # Optional. Default value is - "inline". Step type. Known values are: "Inline" and "Reference". - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. - Required. - "version": "str" # Update version. Required. - } - } - ] - }, - "isDeployable": True, # Optional. Default value is True. Whether the update - can be deployed to a device on its own. - "referencedBy": [ - { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - } - ], - "scanResult": "str", # Optional. Update aggregate scan result (calculated - from payload file scan results). - "updateType": "str" # Optional. Update type. Deprecated in latest import - manifest schema. - } + :param update_to_import: The update to be imported (see schema + `https://json.schemastore.org/azure-deviceupdate-import-manifest-5.0.json + `_ for + details). Required. + :type update_to_import: list[JSON] + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: An instance of LROPoller that returns None + :rtype: ~azure.core.polling.LROPoller[None] + :raises ~azure.core.exceptions.HttpResponseError: """ @overload def begin_import_update( - self, update_to_import: IO, *, content_type: str = "application/json", **kwargs: Any - ) -> LROPoller[JSON]: + self, update_to_import: IO[bytes], *, content_type: str = "application/json", **kwargs: Any + ) -> LROPoller[None]: """Import new update version. This is a long-running-operation; use Operation-Location response header value to check for operation status. :param update_to_import: The update to be imported (see schema - https://json.schemastore.org/azure-deviceupdate-import-manifest-5.0.json for details). - Required. - :type update_to_import: IO + `https://json.schemastore.org/azure-deviceupdate-import-manifest-5.0.json + `_ for + details). Required. + :type update_to_import: IO[bytes] :keyword content_type: Body Parameter content-type. Content type parameter for binary body. Default value is "application/json". :paramtype content_type: str - :keyword str continuation_token: A continuation token to restart a poller from a saved state. - :keyword polling: By default, your polling method will be LROBasePolling. Pass in False for - this operation to not poll, or pass in your own initialized polling object for a personal - polling strategy. - :paramtype polling: bool or ~azure.core.polling.PollingMethod - :keyword int polling_interval: Default waiting time between two polls for LRO operations if no - Retry-After header is present. - :return: An instance of LROPoller that returns JSON object - :rtype: ~azure.core.polling.LROPoller[JSON] + :return: An instance of LROPoller that returns None + :rtype: ~azure.core.polling.LROPoller[None] :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "compatibility": [ - { - "str": "str" # List of update compatibility information. - Required. - } - ], - "createdDateTime": "2020-02-20 00:00:00", # Date and time in UTC when the - update was created. Required. - "importedDateTime": "2020-02-20 00:00:00", # Date and time in UTC when the - update was imported. Required. - "manifestVersion": "str", # Schema version of manifest used to import the - update. Required. - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description specified by creator. - "etag": "str", # Optional. Update ETag. - "friendlyName": "str", # Optional. Friendly update name specified by - importer. - "installedCriteria": "str", # Optional. String interpreted by Device Update - client to determine if the update is installed on the device. Deprecated in - latest import manifest schema. - "instructions": { - "steps": [ - { - "description": "str", # Optional. Step description. - "files": [ - "str" # Optional. Collection of file names - to be passed to handler during execution. Required if step type - is inline. - ], - "handler": "str", # Optional. Identity of handler - that will execute this step. Required if step type is inline. - "handlerProperties": {}, # Optional. Parameters to - be passed to handler during execution. - "type": "inline", # Optional. Default value is - "inline". Step type. Known values are: "Inline" and "Reference". - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. - Required. - "version": "str" # Update version. Required. - } - } - ] - }, - "isDeployable": True, # Optional. Default value is True. Whether the update - can be deployed to a device on its own. - "referencedBy": [ - { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - } - ], - "scanResult": "str", # Optional. Update aggregate scan result (calculated - from payload file scan results). - "updateType": "str" # Optional. Update type. Deprecated in latest import - manifest schema. - } """ @distributed_trace - def begin_import_update(self, update_to_import: Union[List[JSON], IO], **kwargs: Any) -> LROPoller[JSON]: + def begin_import_update( + self, update_to_import: Union[list[_models.ImportUpdateInputItem], list[JSON], IO[bytes]], **kwargs: Any + ) -> LROPoller[None]: """Import new update version. This is a long-running-operation; use Operation-Location response header value to check for operation status. :param update_to_import: The update to be imported (see schema - https://json.schemastore.org/azure-deviceupdate-import-manifest-5.0.json for details). Is - either a list type or a IO type. Required. - :type update_to_import: list[JSON] or IO - :keyword content_type: Body Parameter content-type. Known values are: 'application/json'. - Default value is None. - :paramtype content_type: str - :keyword str continuation_token: A continuation token to restart a poller from a saved state. - :keyword polling: By default, your polling method will be LROBasePolling. Pass in False for - this operation to not poll, or pass in your own initialized polling object for a personal - polling strategy. - :paramtype polling: bool or ~azure.core.polling.PollingMethod - :keyword int polling_interval: Default waiting time between two polls for LRO operations if no - Retry-After header is present. - :return: An instance of LROPoller that returns JSON object - :rtype: ~azure.core.polling.LROPoller[JSON] + `https://json.schemastore.org/azure-deviceupdate-import-manifest-5.0.json + `_ for + details). Is one of the following types: [ImportUpdateInputItem], [JSON], IO[bytes] Required. + :type update_to_import: list[~azure.iot.deviceupdate.models.ImportUpdateInputItem] or + list[JSON] or IO[bytes] + :return: An instance of LROPoller that returns None + :rtype: ~azure.core.polling.LROPoller[None] :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "compatibility": [ - { - "str": "str" # List of update compatibility information. - Required. - } - ], - "createdDateTime": "2020-02-20 00:00:00", # Date and time in UTC when the - update was created. Required. - "importedDateTime": "2020-02-20 00:00:00", # Date and time in UTC when the - update was imported. Required. - "manifestVersion": "str", # Schema version of manifest used to import the - update. Required. - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description specified by creator. - "etag": "str", # Optional. Update ETag. - "friendlyName": "str", # Optional. Friendly update name specified by - importer. - "installedCriteria": "str", # Optional. String interpreted by Device Update - client to determine if the update is installed on the device. Deprecated in - latest import manifest schema. - "instructions": { - "steps": [ - { - "description": "str", # Optional. Step description. - "files": [ - "str" # Optional. Collection of file names - to be passed to handler during execution. Required if step type - is inline. - ], - "handler": "str", # Optional. Identity of handler - that will execute this step. Required if step type is inline. - "handlerProperties": {}, # Optional. Parameters to - be passed to handler during execution. - "type": "inline", # Optional. Default value is - "inline". Step type. Known values are: "Inline" and "Reference". - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. - Required. - "version": "str" # Update version. Required. - } - } - ] - }, - "isDeployable": True, # Optional. Default value is True. Whether the update - can be deployed to a device on its own. - "referencedBy": [ - { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - } - ], - "scanResult": "str", # Optional. Update aggregate scan result (calculated - from payload file scan results). - "updateType": "str" # Optional. Update type. Deprecated in latest import - manifest schema. - } """ _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = kwargs.pop("params", {}) or {} - content_type = kwargs.pop("content_type", _headers.pop("Content-Type", None)) # type: Optional[str] - cls = kwargs.pop("cls", None) # type: ClsType[JSON] - polling = kwargs.pop("polling", True) # type: Union[bool, PollingMethod] + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[None] = kwargs.pop("cls", None) + polling: Union[bool, PollingMethod] = kwargs.pop("polling", True) lro_delay = kwargs.pop("polling_interval", self._config.polling_interval) - cont_token = kwargs.pop("continuation_token", None) # type: Optional[str] + cont_token: Optional[str] = kwargs.pop("continuation_token", None) if cont_token is None: - raw_result = self._import_update_initial( # type: ignore + raw_result = self._import_update_initial( update_to_import=update_to_import, content_type=content_type, cls=lambda x, y, z: x, @@ -2010,43 +1757,45 @@ def begin_import_update(self, update_to_import: Union[List[JSON], IO], **kwargs: params=_params, **kwargs ) + raw_result.http_response.read() # type: ignore kwargs.pop("error_map", None) - def get_long_running_output(pipeline_response): - response = pipeline_response.http_response - if response.content: - deserialized = response.json() - else: - deserialized = None + def get_long_running_output(pipeline_response): # pylint: disable=inconsistent-return-statements if cls: - return cls(pipeline_response, deserialized, {}) - return deserialized + return cls(pipeline_response, None, {}) # type: ignore 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"), } if polling is True: - polling_method = cast( + polling_method: PollingMethod = cast( PollingMethod, LROBasePolling(lro_delay, path_format_arguments=path_format_arguments, **kwargs) - ) # type: PollingMethod + ) elif polling is False: polling_method = cast(PollingMethod, NoPolling()) else: polling_method = polling if cont_token: - return LROPoller.from_continuation_token( + return LROPoller[None].from_continuation_token( polling_method=polling_method, continuation_token=cont_token, client=self._client, deserialization_callback=get_long_running_output, ) - return LROPoller(self._client, raw_result, get_long_running_output, polling_method) + return LROPoller[None](self._client, raw_result, get_long_running_output, polling_method) # type: ignore @distributed_trace def get_update( - self, provider: str, name: str, version: str, *, if_none_match: Optional[str] = None, **kwargs: Any - ) -> JSON: + self, + provider: str, + name: str, + version: str, + *, + etag: Optional[str] = None, + match_condition: Optional[MatchConditions] = None, + **kwargs: Any + ) -> _models.Update: """Get a specific update version. :param provider: Update provider. Required. @@ -2055,136 +1804,96 @@ def get_update( :type name: str :param version: Update version. Required. :type version: str - :keyword if_none_match: Defines the If-None-Match condition. The operation will be performed - only if the ETag on the server does not match this value. Default value is None. - :paramtype if_none_match: str - :return: JSON object - :rtype: JSON + :keyword etag: check if resource is changed. Set None to skip checking etag. Default value is + None. + :paramtype etag: str + :keyword match_condition: The match condition to use upon the etag. Default value is None. + :paramtype match_condition: ~azure.core.MatchConditions + :return: Update. The Update is compatible with MutableMapping + :rtype: ~azure.iot.deviceupdate.models.Update :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "compatibility": [ - { - "str": "str" # List of update compatibility information. - Required. - } - ], - "createdDateTime": "2020-02-20 00:00:00", # Date and time in UTC when the - update was created. Required. - "importedDateTime": "2020-02-20 00:00:00", # Date and time in UTC when the - update was imported. Required. - "manifestVersion": "str", # Schema version of manifest used to import the - update. Required. - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description specified by creator. - "etag": "str", # Optional. Update ETag. - "friendlyName": "str", # Optional. Friendly update name specified by - importer. - "installedCriteria": "str", # Optional. String interpreted by Device Update - client to determine if the update is installed on the device. Deprecated in - latest import manifest schema. - "instructions": { - "steps": [ - { - "description": "str", # Optional. Step description. - "files": [ - "str" # Optional. Collection of file names - to be passed to handler during execution. Required if step type - is inline. - ], - "handler": "str", # Optional. Identity of handler - that will execute this step. Required if step type is inline. - "handlerProperties": {}, # Optional. Parameters to - be passed to handler during execution. - "type": "inline", # Optional. Default value is - "inline". Step type. Known values are: "Inline" and "Reference". - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. - Required. - "version": "str" # Update version. Required. - } - } - ] - }, - "isDeployable": True, # Optional. Default value is True. Whether the update - can be deployed to a device on its own. - "referencedBy": [ - { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - } - ], - "scanResult": "str", # Optional. Update aggregate scan result (calculated - from payload file scan results). - "updateType": "str" # Optional. Update type. Deprecated in latest import - manifest schema. - } """ - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + if match_condition == MatchConditions.IfNotModified: + error_map[412] = ResourceModifiedError + elif match_condition == MatchConditions.IfPresent: + error_map[412] = ResourceNotFoundError + elif match_condition == MatchConditions.IfMissing: + error_map[412] = ResourceExistsError error_map.update(kwargs.pop("error_map", {}) or {}) _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls = kwargs.pop("cls", None) # type: ClsType[JSON] + cls: ClsType[_models.Update] = kwargs.pop("cls", None) - request = build_device_update_get_update_request( + _request = build_device_update_get_update_request( provider=provider, name=name, version=version, instance_id=self._config.instance_id, - if_none_match=if_none_match, + etag=etag, + match_condition=match_condition, 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), + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - pipeline_response = self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("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]: + if _stream: + try: + response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) - if response.content: - deserialized = response.json() + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = None + deserialized = _deserialize(_models.Update, response.json()) if cls: - return cls(pipeline_response, cast(JSON, deserialized), {}) + return cls(pipeline_response, deserialized, {}) # type: ignore - return cast(JSON, deserialized) + return deserialized # type: ignore - def _delete_update_initial( # pylint: disable=inconsistent-return-statements - self, provider: str, name: str, version: str, **kwargs: Any - ) -> None: - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + def _delete_update_initial(self, provider: str, name: str, version: str, **kwargs: Any) -> Iterator[bytes]: + error_map: MutableMapping = { + 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 = kwargs.pop("cls", None) # type: ClsType[None] + cls: ClsType[Iterator[bytes]] = kwargs.pop("cls", None) - request = build_device_update_delete_update_request( + _request = build_device_update_delete_update_request( provider=provider, name=name, version=version, @@ -2194,25 +1903,39 @@ def _delete_update_initial( # pylint: disable=inconsistent-return-statements params=_params, ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - pipeline_response = self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _decompress = kwargs.pop("decompress", True) + _stream = True + 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 [202]: + try: + response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) response_headers = {} response_headers["Operation-Location"] = self._deserialize("str", response.headers.get("Operation-Location")) + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + if cls: - return cls(pipeline_response, None, response_headers) + return cls(pipeline_response, deserialized, response_headers) # type: ignore + + return deserialized # type: ignore @distributed_trace def begin_delete_update(self, provider: str, name: str, version: str, **kwargs: Any) -> LROPoller[None]: @@ -2225,13 +1948,6 @@ def begin_delete_update(self, provider: str, name: str, version: str, **kwargs: :type name: str :param version: Update version. Required. :type version: str - :keyword str continuation_token: A continuation token to restart a poller from a saved state. - :keyword polling: By default, your polling method will be LROBasePolling. Pass in False for - this operation to not poll, or pass in your own initialized polling object for a personal - polling strategy. - :paramtype polling: bool or ~azure.core.polling.PollingMethod - :keyword int polling_interval: Default waiting time between two polls for LRO operations if no - Retry-After header is present. :return: An instance of LROPoller that returns None :rtype: ~azure.core.polling.LROPoller[None] :raises ~azure.core.exceptions.HttpResponseError: @@ -2239,12 +1955,12 @@ def begin_delete_update(self, provider: str, name: str, version: str, **kwargs: _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls = kwargs.pop("cls", None) # type: ClsType[None] - polling = kwargs.pop("polling", True) # type: Union[bool, PollingMethod] + cls: ClsType[None] = kwargs.pop("cls", None) + polling: Union[bool, PollingMethod] = kwargs.pop("polling", True) lro_delay = kwargs.pop("polling_interval", self._config.polling_interval) - cont_token = kwargs.pop("continuation_token", None) # type: Optional[str] + cont_token: Optional[str] = kwargs.pop("continuation_token", None) if cont_token is None: - raw_result = self._delete_update_initial( # type: ignore + raw_result = self._delete_update_initial( provider=provider, name=name, version=version, @@ -2253,111 +1969,125 @@ def begin_delete_update(self, provider: str, name: str, version: str, **kwargs: params=_params, **kwargs ) + raw_result.http_response.read() # type: ignore kwargs.pop("error_map", None) def get_long_running_output(pipeline_response): # pylint: disable=inconsistent-return-statements if cls: - return cls(pipeline_response, None, {}) + return cls(pipeline_response, None, {}) # type: ignore 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"), } if polling is True: - polling_method = cast( + polling_method: PollingMethod = cast( PollingMethod, LROBasePolling(lro_delay, path_format_arguments=path_format_arguments, **kwargs) - ) # type: PollingMethod + ) elif polling is False: polling_method = cast(PollingMethod, NoPolling()) else: polling_method = polling if cont_token: - return LROPoller.from_continuation_token( + return LROPoller[None].from_continuation_token( polling_method=polling_method, continuation_token=cont_token, client=self._client, deserialization_callback=get_long_running_output, ) - return LROPoller(self._client, raw_result, get_long_running_output, polling_method) + return LROPoller[None](self._client, raw_result, get_long_running_output, polling_method) # type: ignore @distributed_trace - def list_providers(self, **kwargs: Any) -> Iterable[str]: + def list_providers(self, **kwargs: Any) -> ItemPaged[str]: """Get a list of all update providers that have been imported to Device Update for IoT Hub. :return: An iterator like instance of str :rtype: ~azure.core.paging.ItemPaged[str] :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == "str" # Optional. """ _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls = kwargs.pop("cls", None) # type: ClsType[JSON] + cls: ClsType[list[str]] = kwargs.pop("cls", None) - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } error_map.update(kwargs.pop("error_map", {}) or {}) def prepare_request(next_link=None): if not next_link: - request = build_device_update_list_providers_request( + _request = build_device_update_list_providers_request( instance_id=self._config.instance_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 - ), + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) else: # make call to next link with the client's api-version - _parsed_next_link = urlparse(next_link) - _next_request_params = case_insensitive_dict(parse_qs(_parsed_next_link.query)) + _parsed_next_link = urllib.parse.urlparse(next_link) + _next_request_params = case_insensitive_dict( + { + key: [urllib.parse.quote(v) for v in value] + for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items() + } + ) _next_request_params["api-version"] = self._config.api_version - request = HttpRequest("GET", urljoin(next_link, _parsed_next_link.path), params=_next_request_params) + _request = HttpRequest( + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + headers=_headers, + params=_next_request_params, + ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - return request + return _request def extract_data(pipeline_response): deserialized = pipeline_response.http_response.json() - list_of_elem = deserialized["value"] + list_of_elem = _deserialize( + list[str], + deserialized.get("value", []), + ) if cls: - list_of_elem = cls(list_of_elem) - return deserialized.get("nextLink", None), iter(list_of_elem) + list_of_elem = cls(list_of_elem) # type: ignore + return deserialized.get("nextLink") or None, iter(list_of_elem) def get_next(next_link=None): - request = prepare_request(next_link) + _request = prepare_request(next_link) - pipeline_response = self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _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) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) return pipeline_response return ItemPaged(get_next, extract_data) @distributed_trace - def list_names(self, provider: str, **kwargs: Any) -> Iterable[str]: + def list_names(self, provider: str, **kwargs: Any) -> ItemPaged[str]: """Get a list of all update names that match the specified provider. :param provider: Update provider. Required. @@ -2365,25 +2095,24 @@ def list_names(self, provider: str, **kwargs: Any) -> Iterable[str]: :return: An iterator like instance of str :rtype: ~azure.core.paging.ItemPaged[str] :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == "str" # Optional. """ _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls = kwargs.pop("cls", None) # type: ClsType[JSON] + cls: ClsType[list[str]] = kwargs.pop("cls", None) - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } error_map.update(kwargs.pop("error_map", {}) or {}) def prepare_request(next_link=None): if not next_link: - request = build_device_update_list_names_request( + _request = build_device_update_list_names_request( provider=provider, instance_id=self._config.instance_id, api_version=self._config.api_version, @@ -2391,52 +2120,66 @@ def prepare_request(next_link=None): params=_params, ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) else: # make call to next link with the client's api-version - _parsed_next_link = urlparse(next_link) - _next_request_params = case_insensitive_dict(parse_qs(_parsed_next_link.query)) + _parsed_next_link = urllib.parse.urlparse(next_link) + _next_request_params = case_insensitive_dict( + { + key: [urllib.parse.quote(v) for v in value] + for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items() + } + ) _next_request_params["api-version"] = self._config.api_version - request = HttpRequest("GET", urljoin(next_link, _parsed_next_link.path), params=_next_request_params) + _request = HttpRequest( + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + headers=_headers, + params=_next_request_params, + ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - return request + return _request def extract_data(pipeline_response): deserialized = pipeline_response.http_response.json() - list_of_elem = deserialized["value"] + list_of_elem = _deserialize( + list[str], + deserialized.get("value", []), + ) if cls: - list_of_elem = cls(list_of_elem) - return deserialized.get("nextLink", None), iter(list_of_elem) + list_of_elem = cls(list_of_elem) # type: ignore + return deserialized.get("nextLink") or None, iter(list_of_elem) def get_next(next_link=None): - request = prepare_request(next_link) + _request = prepare_request(next_link) - pipeline_response = self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _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) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) return pipeline_response return ItemPaged(get_next, extract_data) @distributed_trace - def list_versions(self, provider: str, name: str, *, filter: Optional[str] = None, **kwargs: Any) -> Iterable[str]: + def list_versions(self, provider: str, name: str, *, filter: Optional[str] = None, **kwargs: Any) -> ItemPaged[str]: """Get a list of all update versions that match the specified provider and name. :param provider: Update provider. Required. @@ -2448,25 +2191,24 @@ def list_versions(self, provider: str, name: str, *, filter: Optional[str] = Non :return: An iterator like instance of str :rtype: ~azure.core.paging.ItemPaged[str] :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == "str" # Optional. """ _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls = kwargs.pop("cls", None) # type: ClsType[JSON] + cls: ClsType[list[str]] = kwargs.pop("cls", None) - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } error_map.update(kwargs.pop("error_map", {}) or {}) def prepare_request(next_link=None): if not next_link: - request = build_device_update_list_versions_request( + _request = build_device_update_list_versions_request( provider=provider, name=name, instance_id=self._config.instance_id, @@ -2476,52 +2218,66 @@ def prepare_request(next_link=None): params=_params, ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) else: # make call to next link with the client's api-version - _parsed_next_link = urlparse(next_link) - _next_request_params = case_insensitive_dict(parse_qs(_parsed_next_link.query)) + _parsed_next_link = urllib.parse.urlparse(next_link) + _next_request_params = case_insensitive_dict( + { + key: [urllib.parse.quote(v) for v in value] + for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items() + } + ) _next_request_params["api-version"] = self._config.api_version - request = HttpRequest("GET", urljoin(next_link, _parsed_next_link.path), params=_next_request_params) + _request = HttpRequest( + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + headers=_headers, + params=_next_request_params, + ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - return request + return _request def extract_data(pipeline_response): deserialized = pipeline_response.http_response.json() - list_of_elem = deserialized["value"] + list_of_elem = _deserialize( + list[str], + deserialized.get("value", []), + ) if cls: - list_of_elem = cls(list_of_elem) - return deserialized.get("nextLink", None), iter(list_of_elem) + list_of_elem = cls(list_of_elem) # type: ignore + return deserialized.get("nextLink") or None, iter(list_of_elem) def get_next(next_link=None): - request = prepare_request(next_link) + _request = prepare_request(next_link) - pipeline_response = self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _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) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) return pipeline_response return ItemPaged(get_next, extract_data) @distributed_trace - def list_files(self, provider: str, name: str, version: str, **kwargs: Any) -> Iterable[str]: + def list_files(self, provider: str, name: str, version: str, **kwargs: Any) -> ItemPaged[str]: """Get a list of all update file identifiers for the specified version. :param provider: Update provider. Required. @@ -2533,25 +2289,24 @@ def list_files(self, provider: str, name: str, version: str, **kwargs: Any) -> I :return: An iterator like instance of str :rtype: ~azure.core.paging.ItemPaged[str] :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == "str" # Optional. """ _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls = kwargs.pop("cls", None) # type: ClsType[JSON] + cls: ClsType[list[str]] = kwargs.pop("cls", None) - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } error_map.update(kwargs.pop("error_map", {}) or {}) def prepare_request(next_link=None): if not next_link: - request = build_device_update_list_files_request( + _request = build_device_update_list_files_request( provider=provider, name=name, version=version, @@ -2561,45 +2316,59 @@ def prepare_request(next_link=None): params=_params, ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) else: # make call to next link with the client's api-version - _parsed_next_link = urlparse(next_link) - _next_request_params = case_insensitive_dict(parse_qs(_parsed_next_link.query)) - _next_request_params["api-version"] = self._config.api_version - request = HttpRequest("GET", urljoin(next_link, _parsed_next_link.path), params=_next_request_params) - path_format_arguments = { - "endpoint": self._serialize.url( - "self._config.endpoint", self._config.endpoint, "str", skip_quote=True - ), + _parsed_next_link = urllib.parse.urlparse(next_link) + _next_request_params = case_insensitive_dict( + { + key: [urllib.parse.quote(v) for v in value] + for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items() + } + ) + _next_request_params["api-version"] = self._config.api_version + _request = HttpRequest( + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + headers=_headers, + params=_next_request_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - return request + return _request def extract_data(pipeline_response): deserialized = pipeline_response.http_response.json() - list_of_elem = deserialized["value"] + list_of_elem = _deserialize( + list[str], + deserialized.get("value", []), + ) if cls: - list_of_elem = cls(list_of_elem) - return deserialized.get("nextLink", None), iter(list_of_elem) + list_of_elem = cls(list_of_elem) # type: ignore + return deserialized.get("nextLink") or None, iter(list_of_elem) def get_next(next_link=None): - request = prepare_request(next_link) + _request = prepare_request(next_link) - pipeline_response = self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _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) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) return pipeline_response @@ -2613,9 +2382,10 @@ def get_file( version: str, file_id: str, *, - if_none_match: Optional[str] = None, + etag: Optional[str] = None, + match_condition: Optional[MatchConditions] = None, **kwargs: Any - ) -> JSON: + ) -> _models.UpdateFile: """Get a specific update file from the version. :param provider: Update provider. Required. @@ -2626,178 +2396,117 @@ def get_file( :type version: str :param file_id: File identifier. Required. :type file_id: str - :keyword if_none_match: Defines the If-None-Match condition. The operation will be performed - only if the ETag on the server does not match this value. Default value is None. - :paramtype if_none_match: str - :return: JSON object - :rtype: JSON + :keyword etag: check if resource is changed. Set None to skip checking etag. Default value is + None. + :paramtype etag: str + :keyword match_condition: The match condition to use upon the etag. Default value is None. + :paramtype match_condition: ~azure.core.MatchConditions + :return: UpdateFile. The UpdateFile is compatible with MutableMapping + :rtype: ~azure.iot.deviceupdate.models.UpdateFile :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "fileId": "str", # File identity, generated by server at import time. - Required. - "fileName": "str", # File name. Required. - "hashes": { - "str": "str" # Mapping of hashing algorithm to base64 encoded hash - values. Required. - }, - "sizeInBytes": 0, # File size in number of bytes. Required. - "downloadHandler": { - "id": "str" # Download handler identifier. Required. - }, - "etag": "str", # Optional. File ETag. - "mimeType": "str", # Optional. File MIME type. - "properties": { - "str": "str" # Optional. Optional file properties (not consumed by - service but pass-through to device). - }, - "relatedFiles": [ - { - "fileName": "str", # File name. Required. - "hashes": { - "str": "str" # Mapping of hashing algorithm to - base64 encoded hash values. Required. - }, - "sizeInBytes": 0, # File size in number of bytes. Required. - "mimeType": "str", # Optional. File MIME type. - "properties": { - "str": "str" # Optional. Optional file properties - (not consumed by service but pass-through to device). - }, - "scanDetails": "str", # Optional. Anti-malware scan details. - "scanResult": "str" # Optional. Anti-malware scan result. - } - ], - "scanDetails": "str", # Optional. Anti-malware scan details. - "scanResult": "str" # Optional. Anti-malware scan result. - } """ - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + if match_condition == MatchConditions.IfNotModified: + error_map[412] = ResourceModifiedError + elif match_condition == MatchConditions.IfPresent: + error_map[412] = ResourceNotFoundError + elif match_condition == MatchConditions.IfMissing: + error_map[412] = ResourceExistsError error_map.update(kwargs.pop("error_map", {}) or {}) _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls = kwargs.pop("cls", None) # type: ClsType[JSON] + cls: ClsType[_models.UpdateFile] = kwargs.pop("cls", None) - request = build_device_update_get_file_request( + _request = build_device_update_get_file_request( provider=provider, name=name, version=version, file_id=file_id, instance_id=self._config.instance_id, - if_none_match=if_none_match, + etag=etag, + match_condition=match_condition, 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), + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - pipeline_response = self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("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]: + if _stream: + try: + response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) - if response.content: - deserialized = response.json() + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = None + deserialized = _deserialize(_models.UpdateFile, response.json()) if cls: - return cls(pipeline_response, cast(JSON, deserialized), {}) + return cls(pipeline_response, deserialized, {}) # type: ignore - return cast(JSON, deserialized) + return deserialized # type: ignore @distributed_trace def list_operation_statuses( self, *, filter: Optional[str] = None, top: Optional[int] = None, **kwargs: Any - ) -> Iterable[JSON]: + ) -> ItemPaged["_models.UpdateOperation"]: """Get a list of all import update operations. Completed operations are kept for 7 days before auto-deleted. Delete operations are not returned by this API version. :keyword filter: Optional to filter operations by status property. Only one specific filter is supported: "status eq 'NotStarted' or status eq 'Running'". Default value is None. :paramtype filter: str - :keyword top: Specifies a non-negative integer n that limits the number of items returned from - a collection. The service returns the number of available items up to but not greater than the - specified value n. Default value is None. + :keyword top: Specifies a non-negative integer n that limits the number of items returned + from a collection. The service returns the number of available items up to but + not greater than the specified value n. Default value is None. :paramtype top: int - :return: An iterator like instance of JSON object - :rtype: ~azure.core.paging.ItemPaged[JSON] + :return: An iterator like instance of UpdateOperation + :rtype: ~azure.core.paging.ItemPaged[~azure.iot.deviceupdate.models.UpdateOperation] :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "createdDateTime": "2020-02-20 00:00:00", # Date and time in UTC when the - operation was created. Required. - "lastActionDateTime": "2020-02-20 00:00:00", # Date and time in UTC when the - operation status was last updated. Required. - "operationId": "str", # Operation Id. Required. - "status": "str", # Operation status. Required. Known values are: - "NotStarted", "Running", "Succeeded", and "Failed". - "error": { - "code": "str", # Server defined error code. Required. - "message": "str", # A human-readable representation of the error. - Required. - "details": [ - ... - ], - "innererror": { - "code": "str", # A more specific error code than what was - provided by the containing error. Required. - "errorDetail": "str", # Optional. The internal error or - exception message. - "innerError": ..., - "message": "str" # Optional. A human-readable representation - of the error. - }, - "occurredDateTime": "2020-02-20 00:00:00", # Optional. Date and time - in UTC when the error occurred. - "target": "str" # Optional. The target of the error. - }, - "etag": "str", # Optional. Operation ETag. - "resourceLocation": "str", # Optional. Location of the imported update when - operation is successful. - "traceId": "str", # Optional. Operation correlation identity that can used - by Microsoft Support for troubleshooting. - "update": { - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description. - "friendlyName": "str" # Optional. Friendly update name. - } - } """ _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls = kwargs.pop("cls", None) # type: ClsType[JSON] + cls: ClsType[list[_models.UpdateOperation]] = kwargs.pop("cls", None) - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } error_map.update(kwargs.pop("error_map", {}) or {}) def prepare_request(next_link=None): if not next_link: - request = build_device_update_list_operation_statuses_request( + _request = build_device_update_list_operation_statuses_request( instance_id=self._config.instance_id, filter=filter, top=top, @@ -2806,154 +2515,152 @@ def prepare_request(next_link=None): params=_params, ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) else: # make call to next link with the client's api-version - _parsed_next_link = urlparse(next_link) - _next_request_params = case_insensitive_dict(parse_qs(_parsed_next_link.query)) + _parsed_next_link = urllib.parse.urlparse(next_link) + _next_request_params = case_insensitive_dict( + { + key: [urllib.parse.quote(v) for v in value] + for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items() + } + ) _next_request_params["api-version"] = self._config.api_version - request = HttpRequest("GET", urljoin(next_link, _parsed_next_link.path), params=_next_request_params) + _request = HttpRequest( + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + headers=_headers, + params=_next_request_params, + ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - return request + return _request def extract_data(pipeline_response): deserialized = pipeline_response.http_response.json() - list_of_elem = deserialized["value"] + list_of_elem = _deserialize( + list[_models.UpdateOperation], + deserialized.get("value", []), + ) if cls: - list_of_elem = cls(list_of_elem) - return deserialized.get("nextLink", None), iter(list_of_elem) + list_of_elem = cls(list_of_elem) # type: ignore + return deserialized.get("nextLink") or None, iter(list_of_elem) def get_next(next_link=None): - request = prepare_request(next_link) + _request = prepare_request(next_link) - pipeline_response = self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _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) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) return pipeline_response return ItemPaged(get_next, extract_data) @distributed_trace - def get_operation_status(self, operation_id: str, *, if_none_match: Optional[str] = None, **kwargs: Any) -> JSON: + def get_operation_status( + self, + operation_id: str, + *, + etag: Optional[str] = None, + match_condition: Optional[MatchConditions] = None, + **kwargs: Any + ) -> _models.UpdateOperation: """Retrieve operation status. :param operation_id: Operation identifier. Required. :type operation_id: str - :keyword if_none_match: Defines the If-None-Match condition. The operation will be performed - only if the ETag on the server does not match this value. Default value is None. - :paramtype if_none_match: str - :return: JSON object - :rtype: JSON + :keyword etag: check if resource is changed. Set None to skip checking etag. Default value is + None. + :paramtype etag: str + :keyword match_condition: The match condition to use upon the etag. Default value is None. + :paramtype match_condition: ~azure.core.MatchConditions + :return: UpdateOperation. The UpdateOperation is compatible with MutableMapping + :rtype: ~azure.iot.deviceupdate.models.UpdateOperation :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "createdDateTime": "2020-02-20 00:00:00", # Date and time in UTC when the - operation was created. Required. - "lastActionDateTime": "2020-02-20 00:00:00", # Date and time in UTC when the - operation status was last updated. Required. - "operationId": "str", # Operation Id. Required. - "status": "str", # Operation status. Required. Known values are: - "NotStarted", "Running", "Succeeded", and "Failed". - "error": { - "code": "str", # Server defined error code. Required. - "message": "str", # A human-readable representation of the error. - Required. - "details": [ - ... - ], - "innererror": { - "code": "str", # A more specific error code than what was - provided by the containing error. Required. - "errorDetail": "str", # Optional. The internal error or - exception message. - "innerError": ..., - "message": "str" # Optional. A human-readable representation - of the error. - }, - "occurredDateTime": "2020-02-20 00:00:00", # Optional. Date and time - in UTC when the error occurred. - "target": "str" # Optional. The target of the error. - }, - "etag": "str", # Optional. Operation ETag. - "resourceLocation": "str", # Optional. Location of the imported update when - operation is successful. - "traceId": "str", # Optional. Operation correlation identity that can used - by Microsoft Support for troubleshooting. - "update": { - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description. - "friendlyName": "str" # Optional. Friendly update name. - } - } """ - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + if match_condition == MatchConditions.IfNotModified: + error_map[412] = ResourceModifiedError + elif match_condition == MatchConditions.IfPresent: + error_map[412] = ResourceNotFoundError + elif match_condition == MatchConditions.IfMissing: + error_map[412] = ResourceExistsError error_map.update(kwargs.pop("error_map", {}) or {}) _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls = kwargs.pop("cls", None) # type: ClsType[JSON] + cls: ClsType[_models.UpdateOperation] = kwargs.pop("cls", None) - request = build_device_update_get_operation_status_request( + _request = build_device_update_get_operation_status_request( operation_id=operation_id, instance_id=self._config.instance_id, - if_none_match=if_none_match, + etag=etag, + match_condition=match_condition, 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), + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - pipeline_response = self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("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]: + if _stream: + try: + response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) response_headers = {} response_headers["Retry-After"] = self._deserialize("str", response.headers.get("Retry-After")) - if response.content: - deserialized = response.json() + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = None + deserialized = _deserialize(_models.UpdateOperation, response.json()) if cls: - return cls(pipeline_response, cast(JSON, deserialized), response_headers) + return cls(pipeline_response, deserialized, response_headers) # type: ignore - return cast(JSON, deserialized) + return deserialized # type: ignore class DeviceManagementOperations: # pylint: disable=too-many-public-methods @@ -2966,15 +2673,15 @@ class DeviceManagementOperations: # pylint: disable=too-many-public-methods :attr:`device_management` attribute. """ - def __init__(self, *args, **kwargs): + 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") + self._client: PipelineClient = input_args.pop(0) if input_args else kwargs.pop("client") + self._config: DeviceUpdateClientConfiguration = input_args.pop(0) if input_args else kwargs.pop("config") + self._serialize: Serializer = input_args.pop(0) if input_args else kwargs.pop("serializer") + self._deserialize: Deserializer = input_args.pop(0) if input_args else kwargs.pop("deserializer") @distributed_trace - def list_device_classes(self, *, filter: Optional[str] = None, **kwargs: Any) -> Iterable[JSON]: + def list_device_classes(self, *, filter: Optional[str] = None, **kwargs: Any) -> ItemPaged["_models.DeviceClass"]: """Gets a list of all device classes (sets of devices compatible with the same updates based on the model Id and compat properties reported in the Device Update PnP interface in IoT Hub) for all devices connected to Device Update for IoT Hub. @@ -2982,61 +2689,27 @@ def list_device_classes(self, *, filter: Optional[str] = None, **kwargs: Any) -> :keyword filter: Restricts the set of device classes returned. You can filter on friendly name. Default value is None. :paramtype filter: str - :return: An iterator like instance of JSON object - :rtype: ~azure.core.paging.ItemPaged[JSON] + :return: An iterator like instance of DeviceClass + :rtype: ~azure.core.paging.ItemPaged[~azure.iot.deviceupdate.models.DeviceClass] :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "deviceClassId": "str", # The device class identifier. This is generated - from the model Id and the compat properties reported by the device update agent - in the Device Update PnP interface in IoT Hub. It is a hex-encoded SHA1 hash. - Required. - "deviceClassProperties": { - "compatProperties": { - "str": "str" # The compat properties of the device class. - This object can be thought of as a set of key-value pairs where the key - is the name of the compatibility property and the value is the value of - the compatibility property. There will always be at least 1 compat - property. Required. - }, - "contractModel": { - "id": "str", # The Device Update agent contract model Id of - the device class. This is also used to calculate the device class Id. - Required. - "name": "str" # The Device Update agent contract model name - of the device class. Intended to be a more readable form of the contract - model Id. Required. - } - }, - "bestCompatibleUpdate": { - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description. - "friendlyName": "str" # Optional. Friendly update name. - }, - "friendlyName": "str" # Optional. The device class friendly name. This can - be updated by callers after the device class has been automatically created. - } """ _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls = kwargs.pop("cls", None) # type: ClsType[JSON] + cls: ClsType[list[_models.DeviceClass]] = kwargs.pop("cls", None) - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } error_map.update(kwargs.pop("error_map", {}) or {}) def prepare_request(next_link=None): if not next_link: - request = build_device_management_list_device_classes_request( + _request = build_device_management_list_device_classes_request( instance_id=self._config.instance_id, filter=filter, api_version=self._config.api_version, @@ -3044,108 +2717,88 @@ def prepare_request(next_link=None): params=_params, ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) else: # make call to next link with the client's api-version - _parsed_next_link = urlparse(next_link) - _next_request_params = case_insensitive_dict(parse_qs(_parsed_next_link.query)) + _parsed_next_link = urllib.parse.urlparse(next_link) + _next_request_params = case_insensitive_dict( + { + key: [urllib.parse.quote(v) for v in value] + for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items() + } + ) _next_request_params["api-version"] = self._config.api_version - request = HttpRequest("GET", urljoin(next_link, _parsed_next_link.path), params=_next_request_params) + _request = HttpRequest( + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + headers=_headers, + params=_next_request_params, + ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - return request + return _request def extract_data(pipeline_response): deserialized = pipeline_response.http_response.json() - list_of_elem = deserialized["value"] + list_of_elem = _deserialize( + list[_models.DeviceClass], + deserialized.get("value", []), + ) if cls: - list_of_elem = cls(list_of_elem) - return deserialized.get("nextLink", None), iter(list_of_elem) + list_of_elem = cls(list_of_elem) # type: ignore + return deserialized.get("nextLink") or None, iter(list_of_elem) def get_next(next_link=None): - request = prepare_request(next_link) + _request = prepare_request(next_link) - pipeline_response = self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _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) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) return pipeline_response return ItemPaged(get_next, extract_data) @distributed_trace - def get_device_class(self, device_class_id: str, **kwargs: Any) -> JSON: + def get_device_class(self, device_class_id: str, **kwargs: Any) -> _models.DeviceClass: """Gets the properties of a device class. :param device_class_id: Device class identifier. Required. :type device_class_id: str - :return: JSON object - :rtype: JSON + :return: DeviceClass. The DeviceClass is compatible with MutableMapping + :rtype: ~azure.iot.deviceupdate.models.DeviceClass :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "deviceClassId": "str", # The device class identifier. This is generated - from the model Id and the compat properties reported by the device update agent - in the Device Update PnP interface in IoT Hub. It is a hex-encoded SHA1 hash. - Required. - "deviceClassProperties": { - "compatProperties": { - "str": "str" # The compat properties of the device class. - This object can be thought of as a set of key-value pairs where the key - is the name of the compatibility property and the value is the value of - the compatibility property. There will always be at least 1 compat - property. Required. - }, - "contractModel": { - "id": "str", # The Device Update agent contract model Id of - the device class. This is also used to calculate the device class Id. - Required. - "name": "str" # The Device Update agent contract model name - of the device class. Intended to be a more readable form of the contract - model Id. Required. - } - }, - "bestCompatibleUpdate": { - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description. - "friendlyName": "str" # Optional. Friendly update name. - }, - "friendlyName": "str" # Optional. The device class friendly name. This can - be updated by callers after the device class has been automatically created. - } """ - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 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 = kwargs.pop("cls", None) # type: ClsType[JSON] + cls: ClsType[_models.DeviceClass] = kwargs.pop("cls", None) - request = build_device_management_get_device_class_request( + _request = build_device_management_get_device_class_request( device_class_id=device_class_id, instance_id=self._config.instance_id, api_version=self._config.api_version, @@ -3153,268 +2806,197 @@ def get_device_class(self, device_class_id: str, **kwargs: Any) -> JSON: params=_params, ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - pipeline_response = self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("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]: + if _stream: + try: + response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) - if response.content: - deserialized = response.json() + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = None + deserialized = _deserialize(_models.DeviceClass, response.json()) if cls: - return cls(pipeline_response, cast(JSON, deserialized), {}) + return cls(pipeline_response, deserialized, {}) # type: ignore - return cast(JSON, deserialized) + return deserialized # type: ignore @overload def update_device_class( self, device_class_id: str, - device_class_patch: JSON, + device_class_patch: _models.PatchBody, *, content_type: str = "application/merge-patch+json", **kwargs: Any - ) -> JSON: + ) -> _models.DeviceClass: """Update device class details. :param device_class_id: Device class identifier. Required. :type device_class_id: str :param device_class_patch: The device class json merge patch body. Currently only supports - patching friendlyName. Required. - :type device_class_patch: JSON + patching + friendlyName. Required. + :type device_class_patch: ~azure.iot.deviceupdate.models.PatchBody :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: JSON object - :rtype: JSON + :return: DeviceClass. The DeviceClass is compatible with MutableMapping + :rtype: ~azure.iot.deviceupdate.models.DeviceClass :raises ~azure.core.exceptions.HttpResponseError: + """ - Example: - .. code-block:: python - - # JSON input template you can fill out and use as your body input. - device_class_patch = { - "friendlyName": "str" # The device class friendly name. Friendly name can be - 1-100 characters, alphanumeric, dot, and dash. Required. - } + @overload + def update_device_class( + self, + device_class_id: str, + device_class_patch: JSON, + *, + content_type: str = "application/merge-patch+json", + **kwargs: Any + ) -> _models.DeviceClass: + """Update device class details. - # response body for status code(s): 200 - response == { - "deviceClassId": "str", # The device class identifier. This is generated - from the model Id and the compat properties reported by the device update agent - in the Device Update PnP interface in IoT Hub. It is a hex-encoded SHA1 hash. - Required. - "deviceClassProperties": { - "compatProperties": { - "str": "str" # The compat properties of the device class. - This object can be thought of as a set of key-value pairs where the key - is the name of the compatibility property and the value is the value of - the compatibility property. There will always be at least 1 compat - property. Required. - }, - "contractModel": { - "id": "str", # The Device Update agent contract model Id of - the device class. This is also used to calculate the device class Id. - Required. - "name": "str" # The Device Update agent contract model name - of the device class. Intended to be a more readable form of the contract - model Id. Required. - } - }, - "bestCompatibleUpdate": { - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description. - "friendlyName": "str" # Optional. Friendly update name. - }, - "friendlyName": "str" # Optional. The device class friendly name. This can - be updated by callers after the device class has been automatically created. - } + :param device_class_id: Device class identifier. Required. + :type device_class_id: str + :param device_class_patch: The device class json merge patch body. Currently only supports + patching + friendlyName. Required. + :type device_class_patch: JSON + :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: DeviceClass. The DeviceClass is compatible with MutableMapping + :rtype: ~azure.iot.deviceupdate.models.DeviceClass + :raises ~azure.core.exceptions.HttpResponseError: """ @overload def update_device_class( self, device_class_id: str, - device_class_patch: IO, + device_class_patch: IO[bytes], *, content_type: str = "application/merge-patch+json", **kwargs: Any - ) -> JSON: + ) -> _models.DeviceClass: """Update device class details. :param device_class_id: Device class identifier. Required. :type device_class_id: str :param device_class_patch: The device class json merge patch body. Currently only supports - patching friendlyName. Required. - :type device_class_patch: IO + patching + friendlyName. Required. + :type device_class_patch: IO[bytes] :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: JSON object - :rtype: JSON + :return: DeviceClass. The DeviceClass is compatible with MutableMapping + :rtype: ~azure.iot.deviceupdate.models.DeviceClass :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "deviceClassId": "str", # The device class identifier. This is generated - from the model Id and the compat properties reported by the device update agent - in the Device Update PnP interface in IoT Hub. It is a hex-encoded SHA1 hash. - Required. - "deviceClassProperties": { - "compatProperties": { - "str": "str" # The compat properties of the device class. - This object can be thought of as a set of key-value pairs where the key - is the name of the compatibility property and the value is the value of - the compatibility property. There will always be at least 1 compat - property. Required. - }, - "contractModel": { - "id": "str", # The Device Update agent contract model Id of - the device class. This is also used to calculate the device class Id. - Required. - "name": "str" # The Device Update agent contract model name - of the device class. Intended to be a more readable form of the contract - model Id. Required. - } - }, - "bestCompatibleUpdate": { - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description. - "friendlyName": "str" # Optional. Friendly update name. - }, - "friendlyName": "str" # Optional. The device class friendly name. This can - be updated by callers after the device class has been automatically created. - } """ @distributed_trace - def update_device_class(self, device_class_id: str, device_class_patch: Union[JSON, IO], **kwargs: Any) -> JSON: + def update_device_class( + self, device_class_id: str, device_class_patch: Union[_models.PatchBody, JSON, IO[bytes]], **kwargs: Any + ) -> _models.DeviceClass: """Update device class details. :param device_class_id: Device class identifier. Required. :type device_class_id: str :param device_class_patch: The device class json merge patch body. Currently only supports - patching friendlyName. Is either a model type or a IO type. Required. - :type device_class_patch: JSON 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: JSON object - :rtype: JSON + patching + friendlyName. Is one of the following types: PatchBody, JSON, IO[bytes] Required. + :type device_class_patch: ~azure.iot.deviceupdate.models.PatchBody or JSON or IO[bytes] + :return: DeviceClass. The DeviceClass is compatible with MutableMapping + :rtype: ~azure.iot.deviceupdate.models.DeviceClass :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "deviceClassId": "str", # The device class identifier. This is generated - from the model Id and the compat properties reported by the device update agent - in the Device Update PnP interface in IoT Hub. It is a hex-encoded SHA1 hash. - Required. - "deviceClassProperties": { - "compatProperties": { - "str": "str" # The compat properties of the device class. - This object can be thought of as a set of key-value pairs where the key - is the name of the compatibility property and the value is the value of - the compatibility property. There will always be at least 1 compat - property. Required. - }, - "contractModel": { - "id": "str", # The Device Update agent contract model Id of - the device class. This is also used to calculate the device class Id. - Required. - "name": "str" # The Device Update agent contract model name - of the device class. Intended to be a more readable form of the contract - model Id. Required. - } - }, - "bestCompatibleUpdate": { - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description. - "friendlyName": "str" # Optional. Friendly update name. - }, - "friendlyName": "str" # Optional. The device class friendly name. This can - be updated by callers after the device class has been automatically created. - } """ - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 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 = kwargs.pop("content_type", _headers.pop("Content-Type", None)) # type: Optional[str] - cls = kwargs.pop("cls", None) # type: ClsType[JSON] + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[_models.DeviceClass] = kwargs.pop("cls", None) content_type = content_type or "application/merge-patch+json" - _json = None _content = None - if isinstance(device_class_patch, (IO, bytes)): + if isinstance(device_class_patch, (IOBase, bytes)): _content = device_class_patch else: - _json = device_class_patch + _content = json.dumps(device_class_patch, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - request = build_device_management_update_device_class_request( + _request = build_device_management_update_device_class_request( device_class_id=device_class_id, instance_id=self._config.instance_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), + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - pipeline_response = self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("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]: + if _stream: + try: + response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) - if response.content: - deserialized = response.json() + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = None + deserialized = _deserialize(_models.DeviceClass, response.json()) if cls: - return cls(pipeline_response, cast(JSON, deserialized), {}) + return cls(pipeline_response, deserialized, {}) # type: ignore - return cast(JSON, deserialized) + return deserialized # type: ignore @distributed_trace def delete_device_class( # pylint: disable=inconsistent-return-statements @@ -3433,15 +3015,20 @@ def delete_device_class( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 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 = kwargs.pop("cls", None) # type: ClsType[None] + cls: ClsType[None] = kwargs.pop("cls", None) - request = build_device_management_delete_device_class_request( + _request = build_device_management_delete_device_class_request( device_class_id=device_class_id, instance_id=self._config.instance_id, api_version=self._config.api_version, @@ -3449,59 +3036,57 @@ def delete_device_class( # pylint: disable=inconsistent-return-statements params=_params, ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - pipeline_response = self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _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 [204]: map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) if cls: - return cls(pipeline_response, None, {}) + return cls(pipeline_response, None, {}) # type: ignore @distributed_trace - def list_installable_updates_for_device_class(self, device_class_id: str, **kwargs: Any) -> Iterable[JSON]: + def list_installable_updates_for_device_class( # pylint: disable=name-too-long + self, device_class_id: str, **kwargs: Any + ) -> ItemPaged["_models.UpdateInfo"]: """Gets a list of installable updates for a device class. :param device_class_id: Device class identifier. Required. :type device_class_id: str - :return: An iterator like instance of JSON object - :rtype: ~azure.core.paging.ItemPaged[JSON] + :return: An iterator like instance of UpdateInfo + :rtype: ~azure.core.paging.ItemPaged[~azure.iot.deviceupdate.models.UpdateInfo] :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description. - "friendlyName": "str" # Optional. Friendly update name. - } """ _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls = kwargs.pop("cls", None) # type: ClsType[JSON] + cls: ClsType[list[_models.UpdateInfo]] = kwargs.pop("cls", None) - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } error_map.update(kwargs.pop("error_map", {}) or {}) def prepare_request(next_link=None): if not next_link: - request = build_device_management_list_installable_updates_for_device_class_request( + _request = build_device_management_list_installable_updates_for_device_class_request( device_class_id=device_class_id, instance_id=self._config.instance_id, api_version=self._config.api_version, @@ -3509,141 +3094,94 @@ def prepare_request(next_link=None): params=_params, ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) else: # make call to next link with the client's api-version - _parsed_next_link = urlparse(next_link) - _next_request_params = case_insensitive_dict(parse_qs(_parsed_next_link.query)) + _parsed_next_link = urllib.parse.urlparse(next_link) + _next_request_params = case_insensitive_dict( + { + key: [urllib.parse.quote(v) for v in value] + for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items() + } + ) _next_request_params["api-version"] = self._config.api_version - request = HttpRequest("GET", urljoin(next_link, _parsed_next_link.path), params=_next_request_params) + _request = HttpRequest( + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + headers=_headers, + params=_next_request_params, + ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - return request + return _request def extract_data(pipeline_response): deserialized = pipeline_response.http_response.json() - list_of_elem = deserialized["value"] + list_of_elem = _deserialize( + list[_models.UpdateInfo], + deserialized.get("value", []), + ) if cls: - list_of_elem = cls(list_of_elem) - return deserialized.get("nextLink", None), iter(list_of_elem) + list_of_elem = cls(list_of_elem) # type: ignore + return deserialized.get("nextLink") or None, iter(list_of_elem) def get_next(next_link=None): - request = prepare_request(next_link) + _request = prepare_request(next_link) - pipeline_response = self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _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) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) return pipeline_response return ItemPaged(get_next, extract_data) @distributed_trace - def list_devices(self, *, filter: Optional[str] = None, **kwargs: Any) -> Iterable[JSON]: + def list_devices(self, *, filter: Optional[str] = None, **kwargs: Any) -> ItemPaged["_models.Device"]: """Gets a list of devices connected to Device Update for IoT Hub. :keyword filter: Restricts the set of devices returned. You can filter on GroupId, - DeviceClassId, or GroupId and DeploymentStatus. Use DeploymentStatus eq null to query for - devices with no deployment status (that have never been deployed to). Default value is None. + DeviceClassId, or GroupId and DeploymentStatus. Use DeploymentStatus eq null to + query for devices with no deployment status (that have never been deployed to). Default value + is None. :paramtype filter: str - :return: An iterator like instance of JSON object - :rtype: ~azure.core.paging.ItemPaged[JSON] + :return: An iterator like instance of Device + :rtype: ~azure.core.paging.ItemPaged[~azure.iot.deviceupdate.models.Device] :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "deviceClassId": "str", # Device class identity. Required. - "deviceId": "str", # Device identity. Required. - "onLatestUpdate": bool, # Boolean flag indicating whether the latest update - (the best compatible update for the device's device class and group) is installed - on the device. Required. - "deploymentStatus": "str", # Optional. State of the device in its last - deployment. Known values are: "Succeeded", "InProgress", "Canceled", and - "Failed". - "groupId": "str", # Optional. Device group identity. - "installedUpdate": { - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description. - "friendlyName": "str" # Optional. Friendly update name. - }, - "lastAttemptedUpdate": { - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description. - "friendlyName": "str" # Optional. Friendly update name. - }, - "lastDeploymentId": "str", # Optional. The deployment identifier for the - last deployment to the device. - "lastInstallResult": { - "extendedResultCode": 0, # Install extended result code. Required. - "resultCode": 0, # Install result code. Required. - "resultDetails": "str", # Optional. A string containing further - details about the install result. - "stepResults": [ - { - "extendedResultCode": 0, # Install extended result - code. Required. - "resultCode": 0, # Install result code. Required. - "description": "str", # Optional. Step description. - "resultDetails": "str", # Optional. A string - containing further details about the install result. - "update": { - "updateId": { - "name": "str", # Update name. - Required. - "provider": "str", # Update - provider. Required. - "version": "str" # Update version. - Required. - }, - "description": "str", # Optional. Update - description. - "friendlyName": "str" # Optional. Friendly - update name. - } - } - ] - }, - "moduleId": "str" # Optional. Device module identity. - } """ _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls = kwargs.pop("cls", None) # type: ClsType[JSON] + cls: ClsType[list[_models.Device]] = kwargs.pop("cls", None) - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } error_map.update(kwargs.pop("error_map", {}) or {}) def prepare_request(next_link=None): if not next_link: - request = build_device_management_list_devices_request( + _request = build_device_management_list_devices_request( instance_id=self._config.instance_id, filter=filter, api_version=self._config.api_version, @@ -3651,108 +3189,132 @@ def prepare_request(next_link=None): params=_params, ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) else: # make call to next link with the client's api-version - _parsed_next_link = urlparse(next_link) - _next_request_params = case_insensitive_dict(parse_qs(_parsed_next_link.query)) + _parsed_next_link = urllib.parse.urlparse(next_link) + _next_request_params = case_insensitive_dict( + { + key: [urllib.parse.quote(v) for v in value] + for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items() + } + ) _next_request_params["api-version"] = self._config.api_version - request = HttpRequest("GET", urljoin(next_link, _parsed_next_link.path), params=_next_request_params) + _request = HttpRequest( + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + headers=_headers, + params=_next_request_params, + ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - return request + return _request def extract_data(pipeline_response): deserialized = pipeline_response.http_response.json() - list_of_elem = deserialized["value"] + list_of_elem = _deserialize( + list[_models.Device], + deserialized.get("value", []), + ) if cls: - list_of_elem = cls(list_of_elem) - return deserialized.get("nextLink", None), iter(list_of_elem) + list_of_elem = cls(list_of_elem) # type: ignore + return deserialized.get("nextLink") or None, iter(list_of_elem) def get_next(next_link=None): - request = prepare_request(next_link) + _request = prepare_request(next_link) - pipeline_response = self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _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) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) return pipeline_response return ItemPaged(get_next, extract_data) - def _import_devices_initial( # pylint: disable=inconsistent-return-statements - self, import_type: str, **kwargs: Any - ) -> None: - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + def _import_devices_initial(self, import_type: Union[str, _models.ImportType], **kwargs: Any) -> Iterator[bytes]: + error_map: MutableMapping = { + 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 = kwargs.pop("content_type", _headers.pop("Content-Type", "application/json")) # type: str - cls = kwargs.pop("cls", None) # type: ClsType[None] + content_type: str = kwargs.pop("content_type", _headers.pop("Content-Type", "application/json")) + cls: ClsType[Iterator[bytes]] = kwargs.pop("cls", None) - _json = import_type + _content = json.dumps(import_type, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - request = build_device_management_import_devices_request( + _request = build_device_management_import_devices_request( instance_id=self._config.instance_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), + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - pipeline_response = self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _decompress = kwargs.pop("decompress", True) + _stream = True + 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 [202]: + try: + response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) response_headers = {} response_headers["Operation-Location"] = self._deserialize("str", response.headers.get("Operation-Location")) + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + if cls: - return cls(pipeline_response, None, response_headers) + return cls(pipeline_response, deserialized, response_headers) # type: ignore + + return deserialized # type: ignore @distributed_trace - def begin_import_devices(self, import_type: str, **kwargs: Any) -> LROPoller[None]: + def begin_import_devices(self, import_type: Union[str, _models.ImportType], **kwargs: Any) -> LROPoller[None]: """Import existing devices from IoT Hub. This is a long-running-operation; use Operation-Location response header value to check for operation status. :param import_type: The types of devices to import. Known values are: "Devices", "Modules", and "All". Required. - :type import_type: str - :keyword str continuation_token: A continuation token to restart a poller from a saved state. - :keyword polling: By default, your polling method will be LROBasePolling. Pass in False for - this operation to not poll, or pass in your own initialized polling object for a personal - polling strategy. - :paramtype polling: bool or ~azure.core.polling.PollingMethod - :keyword int polling_interval: Default waiting time between two polls for LRO operations if no - Retry-After header is present. + :type import_type: str or ~azure.iot.deviceupdate.models.ImportType :return: An instance of LROPoller that returns None :rtype: ~azure.core.polling.LROPoller[None] :raises ~azure.core.exceptions.HttpResponseError: @@ -3760,13 +3322,13 @@ def begin_import_devices(self, import_type: str, **kwargs: Any) -> LROPoller[Non _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = kwargs.pop("params", {}) or {} - content_type = kwargs.pop("content_type", _headers.pop("Content-Type", "application/json")) # type: str - cls = kwargs.pop("cls", None) # type: ClsType[None] - polling = kwargs.pop("polling", True) # type: Union[bool, PollingMethod] + content_type: str = kwargs.pop("content_type", _headers.pop("Content-Type", "application/json")) + cls: ClsType[None] = kwargs.pop("cls", None) + polling: Union[bool, PollingMethod] = kwargs.pop("polling", True) lro_delay = kwargs.pop("polling_interval", self._config.polling_interval) - cont_token = kwargs.pop("continuation_token", None) # type: Optional[str] + cont_token: Optional[str] = kwargs.pop("continuation_token", None) if cont_token is None: - raw_result = self._import_devices_initial( # type: ignore + raw_result = self._import_devices_initial( import_type=import_type, content_type=content_type, cls=lambda x, y, z: x, @@ -3774,120 +3336,59 @@ def begin_import_devices(self, import_type: str, **kwargs: Any) -> LROPoller[Non params=_params, **kwargs ) + raw_result.http_response.read() # type: ignore kwargs.pop("error_map", None) def get_long_running_output(pipeline_response): # pylint: disable=inconsistent-return-statements if cls: - return cls(pipeline_response, None, {}) + return cls(pipeline_response, None, {}) # type: ignore 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"), } if polling is True: - polling_method = cast( + polling_method: PollingMethod = cast( PollingMethod, LROBasePolling(lro_delay, path_format_arguments=path_format_arguments, **kwargs) - ) # type: PollingMethod + ) elif polling is False: polling_method = cast(PollingMethod, NoPolling()) else: polling_method = polling if cont_token: - return LROPoller.from_continuation_token( + return LROPoller[None].from_continuation_token( polling_method=polling_method, continuation_token=cont_token, client=self._client, deserialization_callback=get_long_running_output, ) - return LROPoller(self._client, raw_result, get_long_running_output, polling_method) + return LROPoller[None](self._client, raw_result, get_long_running_output, polling_method) # type: ignore @distributed_trace - def get_device(self, device_id: str, **kwargs: Any) -> JSON: + def get_device(self, device_id: str, **kwargs: Any) -> _models.Device: """Gets the device properties and latest deployment status for a device connected to Device Update for IoT Hub. :param device_id: Device identifier in Azure IoT Hub. Required. :type device_id: str - :return: JSON object - :rtype: JSON + :return: Device. The Device is compatible with MutableMapping + :rtype: ~azure.iot.deviceupdate.models.Device :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "deviceClassId": "str", # Device class identity. Required. - "deviceId": "str", # Device identity. Required. - "onLatestUpdate": bool, # Boolean flag indicating whether the latest update - (the best compatible update for the device's device class and group) is installed - on the device. Required. - "deploymentStatus": "str", # Optional. State of the device in its last - deployment. Known values are: "Succeeded", "InProgress", "Canceled", and - "Failed". - "groupId": "str", # Optional. Device group identity. - "installedUpdate": { - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description. - "friendlyName": "str" # Optional. Friendly update name. - }, - "lastAttemptedUpdate": { - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description. - "friendlyName": "str" # Optional. Friendly update name. - }, - "lastDeploymentId": "str", # Optional. The deployment identifier for the - last deployment to the device. - "lastInstallResult": { - "extendedResultCode": 0, # Install extended result code. Required. - "resultCode": 0, # Install result code. Required. - "resultDetails": "str", # Optional. A string containing further - details about the install result. - "stepResults": [ - { - "extendedResultCode": 0, # Install extended result - code. Required. - "resultCode": 0, # Install result code. Required. - "description": "str", # Optional. Step description. - "resultDetails": "str", # Optional. A string - containing further details about the install result. - "update": { - "updateId": { - "name": "str", # Update name. - Required. - "provider": "str", # Update - provider. Required. - "version": "str" # Update version. - Required. - }, - "description": "str", # Optional. Update - description. - "friendlyName": "str" # Optional. Friendly - update name. - } - } - ] - }, - "moduleId": "str" # Optional. Device module identity. - } """ - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 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 = kwargs.pop("cls", None) # type: ClsType[JSON] + cls: ClsType[_models.Device] = kwargs.pop("cls", None) - request = build_device_management_get_device_request( + _request = build_device_management_get_device_request( device_id=device_id, instance_id=self._config.instance_id, api_version=self._config.api_version, @@ -3895,32 +3396,43 @@ def get_device(self, device_id: str, **kwargs: Any) -> JSON: params=_params, ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - pipeline_response = self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("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]: + if _stream: + try: + response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) - if response.content: - deserialized = response.json() + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = None + deserialized = _deserialize(_models.Device, response.json()) if cls: - return cls(pipeline_response, cast(JSON, deserialized), {}) + return cls(pipeline_response, deserialized, {}) # type: ignore - return cast(JSON, deserialized) + return deserialized # type: ignore @distributed_trace - def get_device_module(self, device_id: str, module_id: str, **kwargs: Any) -> JSON: + def get_device_module(self, device_id: str, module_id: str, **kwargs: Any) -> _models.Device: """Gets the device module properties and latest deployment status for a device module connected to Device Update for IoT Hub. @@ -3928,86 +3440,24 @@ def get_device_module(self, device_id: str, module_id: str, **kwargs: Any) -> JS :type device_id: str :param module_id: Device module identifier in Azure IoT Hub. Required. :type module_id: str - :return: JSON object - :rtype: JSON + :return: Device. The Device is compatible with MutableMapping + :rtype: ~azure.iot.deviceupdate.models.Device :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "deviceClassId": "str", # Device class identity. Required. - "deviceId": "str", # Device identity. Required. - "onLatestUpdate": bool, # Boolean flag indicating whether the latest update - (the best compatible update for the device's device class and group) is installed - on the device. Required. - "deploymentStatus": "str", # Optional. State of the device in its last - deployment. Known values are: "Succeeded", "InProgress", "Canceled", and - "Failed". - "groupId": "str", # Optional. Device group identity. - "installedUpdate": { - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description. - "friendlyName": "str" # Optional. Friendly update name. - }, - "lastAttemptedUpdate": { - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description. - "friendlyName": "str" # Optional. Friendly update name. - }, - "lastDeploymentId": "str", # Optional. The deployment identifier for the - last deployment to the device. - "lastInstallResult": { - "extendedResultCode": 0, # Install extended result code. Required. - "resultCode": 0, # Install result code. Required. - "resultDetails": "str", # Optional. A string containing further - details about the install result. - "stepResults": [ - { - "extendedResultCode": 0, # Install extended result - code. Required. - "resultCode": 0, # Install result code. Required. - "description": "str", # Optional. Step description. - "resultDetails": "str", # Optional. A string - containing further details about the install result. - "update": { - "updateId": { - "name": "str", # Update name. - Required. - "provider": "str", # Update - provider. Required. - "version": "str" # Update version. - Required. - }, - "description": "str", # Optional. Update - description. - "friendlyName": "str" # Optional. Friendly - update name. - } - } - ] - }, - "moduleId": "str" # Optional. Device module identity. - } """ - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 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 = kwargs.pop("cls", None) # type: ClsType[JSON] + cls: ClsType[_models.Device] = kwargs.pop("cls", None) - request = build_device_management_get_device_module_request( + _request = build_device_management_get_device_module_request( device_id=device_id, module_id=module_id, instance_id=self._config.instance_id, @@ -4016,140 +3466,134 @@ def get_device_module(self, device_id: str, module_id: str, **kwargs: Any) -> JS params=_params, ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - pipeline_response = self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("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]: + if _stream: + try: + response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) - if response.content: - deserialized = response.json() + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = None + deserialized = _deserialize(_models.Device, response.json()) if cls: - return cls(pipeline_response, cast(JSON, deserialized), {}) + return cls(pipeline_response, deserialized, {}) # type: ignore - return cast(JSON, deserialized) + return deserialized # type: ignore @distributed_trace - def get_update_compliance(self, **kwargs: Any) -> JSON: + def get_update_compliance(self, **kwargs: Any) -> _models.UpdateCompliance: """Gets the breakdown of how many devices are on their latest update, have new updates available, or are in progress receiving new updates. - :return: JSON object - :rtype: JSON + :return: UpdateCompliance. The UpdateCompliance is compatible with MutableMapping + :rtype: ~azure.iot.deviceupdate.models.UpdateCompliance :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "newUpdatesAvailableDeviceCount": 0, # Number of devices with a newer update - available. Required. - "onLatestUpdateDeviceCount": 0, # Number of devices on the latest update. - Required. - "totalDeviceCount": 0, # Total number of devices. Required. - "updatesInProgressDeviceCount": 0 # Number of devices with update - in-progress. Required. - } """ - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 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 = kwargs.pop("cls", None) # type: ClsType[JSON] + cls: ClsType[_models.UpdateCompliance] = kwargs.pop("cls", None) - request = build_device_management_get_update_compliance_request( + _request = build_device_management_get_update_compliance_request( instance_id=self._config.instance_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), + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - pipeline_response = self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("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]: + if _stream: + try: + response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) - if response.content: - deserialized = response.json() + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = None + deserialized = _deserialize(_models.UpdateCompliance, response.json()) if cls: - return cls(pipeline_response, cast(JSON, deserialized), {}) + return cls(pipeline_response, deserialized, {}) # type: ignore - return cast(JSON, deserialized) + return deserialized # type: ignore @distributed_trace - def list_groups(self, *, order_by: Optional[str] = None, **kwargs: Any) -> Iterable[JSON]: + def list_groups(self, *, order_by: Optional[str] = None, **kwargs: Any) -> ItemPaged["_models.Group"]: """Gets a list of all device groups. The $default group will always be returned first. :keyword order_by: Orders the set of groups returned. You can order by groupId, deviceCount, - createdDate, subgroupsWithNewUpdatesAvailableCount, subgroupsWithUpdatesInProgressCount, or - subgroupsOnLatestUpdateCount. Default value is None. + createdDate, subgroupsWithNewUpdatesAvailableCount, + subgroupsWithUpdatesInProgressCount, or subgroupsOnLatestUpdateCount. Default value is None. :paramtype order_by: str - :return: An iterator like instance of JSON object - :rtype: ~azure.core.paging.ItemPaged[JSON] + :return: An iterator like instance of Group + :rtype: ~azure.core.paging.ItemPaged[~azure.iot.deviceupdate.models.Group] :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "createdDateTime": "str", # Date and time when the update was created. - Required. - "groupId": "str", # Group identity. This is created from the value of the - ADUGroup tag in the Iot Hub's device/module twin or $default for devices with no - tag. Required. - "groupType": "str", # Group type. Required. Known values are: "IoTHubTag" - and "DefaultNoTag". - "deployments": [ - "str" # Optional. The active deployment Ids for the group. - ], - "deviceCount": 0, # Optional. The number of devices in the group. - "subgroupsWithNewUpdatesAvailableCount": 0, # Optional. The count of - subgroups with new updates available. - "subgroupsWithOnLatestUpdateCount": 0, # Optional. The count of subgroups - with devices on the latest update. - "subgroupsWithUpdatesInProgressCount": 0 # Optional. The count of subgroups - with updates in progress. - } """ _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls = kwargs.pop("cls", None) # type: ClsType[JSON] + cls: ClsType[list[_models.Group]] = kwargs.pop("cls", None) - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } error_map.update(kwargs.pop("error_map", {}) or {}) def prepare_request(next_link=None): if not next_link: - request = build_device_management_list_groups_request( + _request = build_device_management_list_groups_request( instance_id=self._config.instance_id, order_by=order_by, api_version=self._config.api_version, @@ -4157,93 +3601,88 @@ def prepare_request(next_link=None): params=_params, ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) else: # make call to next link with the client's api-version - _parsed_next_link = urlparse(next_link) - _next_request_params = case_insensitive_dict(parse_qs(_parsed_next_link.query)) + _parsed_next_link = urllib.parse.urlparse(next_link) + _next_request_params = case_insensitive_dict( + { + key: [urllib.parse.quote(v) for v in value] + for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items() + } + ) _next_request_params["api-version"] = self._config.api_version - request = HttpRequest("GET", urljoin(next_link, _parsed_next_link.path), params=_next_request_params) + _request = HttpRequest( + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + headers=_headers, + params=_next_request_params, + ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - return request + return _request def extract_data(pipeline_response): deserialized = pipeline_response.http_response.json() - list_of_elem = deserialized["value"] + list_of_elem = _deserialize( + list[_models.Group], + deserialized.get("value", []), + ) if cls: - list_of_elem = cls(list_of_elem) - return deserialized.get("nextLink", None), iter(list_of_elem) + list_of_elem = cls(list_of_elem) # type: ignore + return deserialized.get("nextLink") or None, iter(list_of_elem) def get_next(next_link=None): - request = prepare_request(next_link) + _request = prepare_request(next_link) - pipeline_response = self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _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) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) return pipeline_response return ItemPaged(get_next, extract_data) @distributed_trace - def get_group(self, group_id: str, **kwargs: Any) -> JSON: + def get_group(self, group_id: str, **kwargs: Any) -> _models.Group: """Gets the device group properties. :param group_id: Group identifier. Required. :type group_id: str - :return: JSON object - :rtype: JSON + :return: Group. The Group is compatible with MutableMapping + :rtype: ~azure.iot.deviceupdate.models.Group :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "createdDateTime": "str", # Date and time when the update was created. - Required. - "groupId": "str", # Group identity. This is created from the value of the - ADUGroup tag in the Iot Hub's device/module twin or $default for devices with no - tag. Required. - "groupType": "str", # Group type. Required. Known values are: "IoTHubTag" - and "DefaultNoTag". - "deployments": [ - "str" # Optional. The active deployment Ids for the group. - ], - "deviceCount": 0, # Optional. The number of devices in the group. - "subgroupsWithNewUpdatesAvailableCount": 0, # Optional. The count of - subgroups with new updates available. - "subgroupsWithOnLatestUpdateCount": 0, # Optional. The count of subgroups - with devices on the latest update. - "subgroupsWithUpdatesInProgressCount": 0 # Optional. The count of subgroups - with updates in progress. - } """ - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 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 = kwargs.pop("cls", None) # type: ClsType[JSON] + cls: ClsType[_models.Group] = kwargs.pop("cls", None) - request = build_device_management_get_group_request( + _request = build_device_management_get_group_request( group_id=group_id, instance_id=self._config.instance_id, api_version=self._config.api_version, @@ -4251,29 +3690,40 @@ def get_group(self, group_id: str, **kwargs: Any) -> JSON: params=_params, ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - pipeline_response = self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("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]: + if _stream: + try: + response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) - if response.content: - deserialized = response.json() + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = None + deserialized = _deserialize(_models.Group, response.json()) if cls: - return cls(pipeline_response, cast(JSON, deserialized), {}) + return cls(pipeline_response, deserialized, {}) # type: ignore - return cast(JSON, deserialized) + return deserialized # type: ignore @distributed_trace def delete_group(self, group_id: str, **kwargs: Any) -> None: # pylint: disable=inconsistent-return-statements @@ -4290,15 +3740,20 @@ def delete_group(self, group_id: str, **kwargs: Any) -> None: # pylint: disable :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 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 = kwargs.pop("cls", None) # type: ClsType[None] + cls: ClsType[None] = kwargs.pop("cls", None) - request = build_device_management_delete_group_request( + _request = build_device_management_delete_group_request( group_id=group_id, instance_id=self._config.instance_id, api_version=self._config.api_version, @@ -4306,57 +3761,53 @@ def delete_group(self, group_id: str, **kwargs: Any) -> None: # pylint: disable params=_params, ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - pipeline_response = self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _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 [204]: map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) if cls: - return cls(pipeline_response, None, {}) + return cls(pipeline_response, None, {}) # type: ignore @distributed_trace - def get_update_compliance_for_group(self, group_id: str, **kwargs: Any) -> JSON: + def get_update_compliance_for_group(self, group_id: str, **kwargs: Any) -> _models.UpdateCompliance: """Get device group update compliance information such as how many devices are on their latest update, how many need new updates, and how many are in progress on receiving a new update. :param group_id: Group identifier. Required. :type group_id: str - :return: JSON object - :rtype: JSON + :return: UpdateCompliance. The UpdateCompliance is compatible with MutableMapping + :rtype: ~azure.iot.deviceupdate.models.UpdateCompliance :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "newUpdatesAvailableDeviceCount": 0, # Number of devices with a newer update - available. Required. - "onLatestUpdateDeviceCount": 0, # Number of devices on the latest update. - Required. - "totalDeviceCount": 0, # Total number of devices. Required. - "updatesInProgressDeviceCount": 0 # Number of devices with update - in-progress. Required. - } """ - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 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 = kwargs.pop("cls", None) # type: ClsType[JSON] + cls: ClsType[_models.UpdateCompliance] = kwargs.pop("cls", None) - request = build_device_management_get_update_compliance_for_group_request( + _request = build_device_management_get_update_compliance_for_group_request( group_id=group_id, instance_id=self._config.instance_id, api_version=self._config.api_version, @@ -4364,74 +3815,72 @@ def get_update_compliance_for_group(self, group_id: str, **kwargs: Any) -> JSON: params=_params, ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - pipeline_response = self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("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]: + if _stream: + try: + response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) - if response.content: - deserialized = response.json() + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = None + deserialized = _deserialize(_models.UpdateCompliance, response.json()) if cls: - return cls(pipeline_response, cast(JSON, deserialized), {}) + return cls(pipeline_response, deserialized, {}) # type: ignore - return cast(JSON, deserialized) + return deserialized # type: ignore @distributed_trace - def list_best_updates_for_group(self, group_id: str, **kwargs: Any) -> Iterable[JSON]: + def list_best_updates_for_group( + self, group_id: str, **kwargs: Any + ) -> ItemPaged["_models.DeviceClassSubgroupUpdatableDevices"]: """Get the best available updates for a device group and a count of how many devices need each update. :param group_id: Group identifier. Required. :type group_id: str - :return: An iterator like instance of JSON object - :rtype: ~azure.core.paging.ItemPaged[JSON] + :return: An iterator like instance of DeviceClassSubgroupUpdatableDevices + :rtype: + ~azure.core.paging.ItemPaged[~azure.iot.deviceupdate.models.DeviceClassSubgroupUpdatableDevices] :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "deviceClassId": "str", # The device class subgroup's device class Id. - Required. - "deviceCount": 0, # Total number of devices for which the update is - applicable. Required. - "groupId": "str", # The group Id. Required. - "update": { - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description. - "friendlyName": "str" # Optional. Friendly update name. - } - } """ _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls = kwargs.pop("cls", None) # type: ClsType[JSON] + cls: ClsType[list[_models.DeviceClassSubgroupUpdatableDevices]] = kwargs.pop("cls", None) - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } error_map.update(kwargs.pop("error_map", {}) or {}) def prepare_request(next_link=None): if not next_link: - request = build_device_management_list_best_updates_for_group_request( + _request = build_device_management_list_best_updates_for_group_request( group_id=group_id, instance_id=self._config.instance_id, api_version=self._config.api_version, @@ -4439,45 +3888,59 @@ def prepare_request(next_link=None): params=_params, ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) else: # make call to next link with the client's api-version - _parsed_next_link = urlparse(next_link) - _next_request_params = case_insensitive_dict(parse_qs(_parsed_next_link.query)) + _parsed_next_link = urllib.parse.urlparse(next_link) + _next_request_params = case_insensitive_dict( + { + key: [urllib.parse.quote(v) for v in value] + for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items() + } + ) _next_request_params["api-version"] = self._config.api_version - request = HttpRequest("GET", urljoin(next_link, _parsed_next_link.path), params=_next_request_params) + _request = HttpRequest( + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + headers=_headers, + params=_next_request_params, + ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - return request + return _request def extract_data(pipeline_response): deserialized = pipeline_response.http_response.json() - list_of_elem = deserialized["value"] + list_of_elem = _deserialize( + list[_models.DeviceClassSubgroupUpdatableDevices], + deserialized.get("value", []), + ) if cls: - list_of_elem = cls(list_of_elem) - return deserialized.get("nextLink", None), iter(list_of_elem) + list_of_elem = cls(list_of_elem) # type: ignore + return deserialized.get("nextLink") or None, iter(list_of_elem) def get_next(next_link=None): - request = prepare_request(next_link) + _request = prepare_request(next_link) - pipeline_response = self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _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) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) return pipeline_response @@ -4486,7 +3949,7 @@ def get_next(next_link=None): @distributed_trace def list_deployments_for_group( self, group_id: str, *, order_by: Optional[str] = None, **kwargs: Any - ) -> Iterable[JSON]: + ) -> ItemPaged["_models.Deployment"]: """Gets a list of deployments for a device group. :param group_id: Group identifier. Required. @@ -4494,76 +3957,27 @@ def list_deployments_for_group( :keyword order_by: Orders the set of deployments returned. You can order by start date. Default value is None. :paramtype order_by: str - :return: An iterator like instance of JSON object - :rtype: ~azure.core.paging.ItemPaged[JSON] + :return: An iterator like instance of Deployment + :rtype: ~azure.core.paging.ItemPaged[~azure.iot.deviceupdate.models.Deployment] :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "deploymentId": "str", # The caller-provided deployment identifier. This - cannot be longer than 73 characters, must be all lower-case, and cannot contain - '&', '^', '[', ']', '{', '}', '|', '<', '>', forward slash, backslash, or double - quote. The Updates view in the Azure Portal IoT Hub resource generates a GUID for - deploymentId when you create a deployment. Required. - "groupId": "str", # The group identity for the devices the deployment is - intended to update. Required. - "startDateTime": "2020-02-20 00:00:00", # The deployment start datetime. - Required. - "update": { - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description. - "friendlyName": "str" # Optional. Friendly update name. - }, - "deviceClassSubgroups": [ - "str" # Optional. The device class subgroups the deployment is - compatible with and subgroup deployments have been created for. This is not - provided by the caller during CreateOrUpdateDeployment but is automatically - determined by Device Update. - ], - "isCanceled": bool, # Optional. Boolean flag indicating whether the - deployment was canceled. - "isCloudInitiatedRollback": bool, # Optional. Boolean flag indicating - whether the deployment is a rollback deployment. - "isRetried": bool, # Optional. Boolean flag indicating whether the - deployment has been retried. - "rollbackPolicy": { - "failure": { - "devicesFailedCount": 0, # Number of devices that failed. - Required. - "devicesFailedPercentage": 0 # Percentage of devices that - failed. Required. - }, - "update": { - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description. - "friendlyName": "str" # Optional. Friendly update name. - } - } - } """ _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls = kwargs.pop("cls", None) # type: ClsType[JSON] + cls: ClsType[list[_models.Deployment]] = kwargs.pop("cls", None) - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } error_map.update(kwargs.pop("error_map", {}) or {}) def prepare_request(next_link=None): if not next_link: - request = build_device_management_list_deployments_for_group_request( + _request = build_device_management_list_deployments_for_group_request( group_id=group_id, instance_id=self._config.instance_id, order_by=order_by, @@ -4572,125 +3986,90 @@ def prepare_request(next_link=None): params=_params, ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) else: # make call to next link with the client's api-version - _parsed_next_link = urlparse(next_link) - _next_request_params = case_insensitive_dict(parse_qs(_parsed_next_link.query)) + _parsed_next_link = urllib.parse.urlparse(next_link) + _next_request_params = case_insensitive_dict( + { + key: [urllib.parse.quote(v) for v in value] + for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items() + } + ) _next_request_params["api-version"] = self._config.api_version - request = HttpRequest("GET", urljoin(next_link, _parsed_next_link.path), params=_next_request_params) + _request = HttpRequest( + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + headers=_headers, + params=_next_request_params, + ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - return request + return _request def extract_data(pipeline_response): deserialized = pipeline_response.http_response.json() - list_of_elem = deserialized["value"] + list_of_elem = _deserialize( + list[_models.Deployment], + deserialized.get("value", []), + ) if cls: - list_of_elem = cls(list_of_elem) - return deserialized.get("nextLink", None), iter(list_of_elem) + list_of_elem = cls(list_of_elem) # type: ignore + return deserialized.get("nextLink") or None, iter(list_of_elem) def get_next(next_link=None): - request = prepare_request(next_link) + _request = prepare_request(next_link) - pipeline_response = self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _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) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) return pipeline_response return ItemPaged(get_next, extract_data) @distributed_trace - def get_deployment(self, group_id: str, deployment_id: str, **kwargs: Any) -> JSON: + def get_deployment(self, group_id: str, deployment_id: str, **kwargs: Any) -> _models.Deployment: """Gets the deployment properties. :param group_id: Group identifier. Required. :type group_id: str :param deployment_id: Deployment identifier. Required. :type deployment_id: str - :return: JSON object - :rtype: JSON + :return: Deployment. The Deployment is compatible with MutableMapping + :rtype: ~azure.iot.deviceupdate.models.Deployment :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "deploymentId": "str", # The caller-provided deployment identifier. This - cannot be longer than 73 characters, must be all lower-case, and cannot contain - '&', '^', '[', ']', '{', '}', '|', '<', '>', forward slash, backslash, or double - quote. The Updates view in the Azure Portal IoT Hub resource generates a GUID for - deploymentId when you create a deployment. Required. - "groupId": "str", # The group identity for the devices the deployment is - intended to update. Required. - "startDateTime": "2020-02-20 00:00:00", # The deployment start datetime. - Required. - "update": { - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description. - "friendlyName": "str" # Optional. Friendly update name. - }, - "deviceClassSubgroups": [ - "str" # Optional. The device class subgroups the deployment is - compatible with and subgroup deployments have been created for. This is not - provided by the caller during CreateOrUpdateDeployment but is automatically - determined by Device Update. - ], - "isCanceled": bool, # Optional. Boolean flag indicating whether the - deployment was canceled. - "isCloudInitiatedRollback": bool, # Optional. Boolean flag indicating - whether the deployment is a rollback deployment. - "isRetried": bool, # Optional. Boolean flag indicating whether the - deployment has been retried. - "rollbackPolicy": { - "failure": { - "devicesFailedCount": 0, # Number of devices that failed. - Required. - "devicesFailedPercentage": 0 # Percentage of devices that - failed. Required. - }, - "update": { - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description. - "friendlyName": "str" # Optional. Friendly update name. - } - } - } """ - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 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 = kwargs.pop("cls", None) # type: ClsType[JSON] + cls: ClsType[_models.Deployment] = kwargs.pop("cls", None) - request = build_device_management_get_deployment_request( + _request = build_device_management_get_deployment_request( group_id=group_id, deployment_id=deployment_id, instance_id=self._config.instance_id, @@ -4699,40 +4078,51 @@ def get_deployment(self, group_id: str, deployment_id: str, **kwargs: Any) -> JS params=_params, ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - pipeline_response = self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("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]: + if _stream: + try: + response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) - if response.content: - deserialized = response.json() + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = None + deserialized = _deserialize(_models.Deployment, response.json()) if cls: - return cls(pipeline_response, cast(JSON, deserialized), {}) + return cls(pipeline_response, deserialized, {}) # type: ignore - return cast(JSON, deserialized) + return deserialized # type: ignore @overload def create_or_update_deployment( self, group_id: str, deployment_id: str, - deployment: JSON, + deployment: _models.Deployment, *, content_type: str = "application/json", **kwargs: Any - ) -> JSON: + ) -> _models.Deployment: """Creates or updates a deployment. :param group_id: Group identifier. Required. @@ -4740,118 +4130,39 @@ def create_or_update_deployment( :param deployment_id: Deployment identifier. Required. :type deployment_id: str :param deployment: The deployment properties. Required. - :type deployment: JSON + :type deployment: ~azure.iot.deviceupdate.models.Deployment :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str - :return: JSON object - :rtype: JSON + :return: Deployment. The Deployment is compatible with MutableMapping + :rtype: ~azure.iot.deviceupdate.models.Deployment :raises ~azure.core.exceptions.HttpResponseError: + """ - Example: - .. code-block:: python - - # JSON input template you can fill out and use as your body input. - deployment = { - "deploymentId": "str", # The caller-provided deployment identifier. This - cannot be longer than 73 characters, must be all lower-case, and cannot contain - '&', '^', '[', ']', '{', '}', '|', '<', '>', forward slash, backslash, or double - quote. The Updates view in the Azure Portal IoT Hub resource generates a GUID for - deploymentId when you create a deployment. Required. - "groupId": "str", # The group identity for the devices the deployment is - intended to update. Required. - "startDateTime": "2020-02-20 00:00:00", # The deployment start datetime. - Required. - "update": { - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description. - "friendlyName": "str" # Optional. Friendly update name. - }, - "deviceClassSubgroups": [ - "str" # Optional. The device class subgroups the deployment is - compatible with and subgroup deployments have been created for. This is not - provided by the caller during CreateOrUpdateDeployment but is automatically - determined by Device Update. - ], - "isCanceled": bool, # Optional. Boolean flag indicating whether the - deployment was canceled. - "isCloudInitiatedRollback": bool, # Optional. Boolean flag indicating - whether the deployment is a rollback deployment. - "isRetried": bool, # Optional. Boolean flag indicating whether the - deployment has been retried. - "rollbackPolicy": { - "failure": { - "devicesFailedCount": 0, # Number of devices that failed. - Required. - "devicesFailedPercentage": 0 # Percentage of devices that - failed. Required. - }, - "update": { - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description. - "friendlyName": "str" # Optional. Friendly update name. - } - } - } + @overload + def create_or_update_deployment( + self, + group_id: str, + deployment_id: str, + deployment: JSON, + *, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.Deployment: + """Creates or updates a deployment. - # response body for status code(s): 200 - response == { - "deploymentId": "str", # The caller-provided deployment identifier. This - cannot be longer than 73 characters, must be all lower-case, and cannot contain - '&', '^', '[', ']', '{', '}', '|', '<', '>', forward slash, backslash, or double - quote. The Updates view in the Azure Portal IoT Hub resource generates a GUID for - deploymentId when you create a deployment. Required. - "groupId": "str", # The group identity for the devices the deployment is - intended to update. Required. - "startDateTime": "2020-02-20 00:00:00", # The deployment start datetime. - Required. - "update": { - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description. - "friendlyName": "str" # Optional. Friendly update name. - }, - "deviceClassSubgroups": [ - "str" # Optional. The device class subgroups the deployment is - compatible with and subgroup deployments have been created for. This is not - provided by the caller during CreateOrUpdateDeployment but is automatically - determined by Device Update. - ], - "isCanceled": bool, # Optional. Boolean flag indicating whether the - deployment was canceled. - "isCloudInitiatedRollback": bool, # Optional. Boolean flag indicating - whether the deployment is a rollback deployment. - "isRetried": bool, # Optional. Boolean flag indicating whether the - deployment has been retried. - "rollbackPolicy": { - "failure": { - "devicesFailedCount": 0, # Number of devices that failed. - Required. - "devicesFailedPercentage": 0 # Percentage of devices that - failed. Required. - }, - "update": { - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description. - "friendlyName": "str" # Optional. Friendly update name. - } - } - } + :param group_id: Group identifier. Required. + :type group_id: str + :param deployment_id: Deployment identifier. Required. + :type deployment_id: str + :param deployment: The deployment properties. Required. + :type deployment: JSON + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: Deployment. The Deployment is compatible with MutableMapping + :rtype: ~azure.iot.deviceupdate.models.Deployment + :raises ~azure.core.exceptions.HttpResponseError: """ @overload @@ -4859,11 +4170,11 @@ def create_or_update_deployment( self, group_id: str, deployment_id: str, - deployment: IO, + deployment: IO[bytes], *, content_type: str = "application/json", **kwargs: Any - ) -> JSON: + ) -> _models.Deployment: """Creates or updates a deployment. :param group_id: Group identifier. Required. @@ -4871,245 +4182,101 @@ def create_or_update_deployment( :param deployment_id: Deployment identifier. Required. :type deployment_id: str :param deployment: The deployment properties. Required. - :type deployment: IO + :type deployment: IO[bytes] :keyword content_type: Body Parameter content-type. Content type parameter for binary body. Default value is "application/json". :paramtype content_type: str - :return: JSON object - :rtype: JSON + :return: Deployment. The Deployment is compatible with MutableMapping + :rtype: ~azure.iot.deviceupdate.models.Deployment :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "deploymentId": "str", # The caller-provided deployment identifier. This - cannot be longer than 73 characters, must be all lower-case, and cannot contain - '&', '^', '[', ']', '{', '}', '|', '<', '>', forward slash, backslash, or double - quote. The Updates view in the Azure Portal IoT Hub resource generates a GUID for - deploymentId when you create a deployment. Required. - "groupId": "str", # The group identity for the devices the deployment is - intended to update. Required. - "startDateTime": "2020-02-20 00:00:00", # The deployment start datetime. - Required. - "update": { - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description. - "friendlyName": "str" # Optional. Friendly update name. - }, - "deviceClassSubgroups": [ - "str" # Optional. The device class subgroups the deployment is - compatible with and subgroup deployments have been created for. This is not - provided by the caller during CreateOrUpdateDeployment but is automatically - determined by Device Update. - ], - "isCanceled": bool, # Optional. Boolean flag indicating whether the - deployment was canceled. - "isCloudInitiatedRollback": bool, # Optional. Boolean flag indicating - whether the deployment is a rollback deployment. - "isRetried": bool, # Optional. Boolean flag indicating whether the - deployment has been retried. - "rollbackPolicy": { - "failure": { - "devicesFailedCount": 0, # Number of devices that failed. - Required. - "devicesFailedPercentage": 0 # Percentage of devices that - failed. Required. - }, - "update": { - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description. - "friendlyName": "str" # Optional. Friendly update name. - } - } - } """ @distributed_trace def create_or_update_deployment( - self, group_id: str, deployment_id: str, deployment: Union[JSON, IO], **kwargs: Any - ) -> JSON: + self, group_id: str, deployment_id: str, deployment: Union[_models.Deployment, JSON, IO[bytes]], **kwargs: Any + ) -> _models.Deployment: """Creates or updates a deployment. :param group_id: Group identifier. Required. :type group_id: str :param deployment_id: Deployment identifier. Required. :type deployment_id: str - :param deployment: The deployment properties. Is either a model type or a IO type. Required. - :type deployment: JSON or IO - :keyword content_type: Body Parameter content-type. Known values are: 'application/json'. - Default value is None. - :paramtype content_type: str - :return: JSON object - :rtype: JSON + :param deployment: The deployment properties. Is one of the following types: Deployment, JSON, + IO[bytes] Required. + :type deployment: ~azure.iot.deviceupdate.models.Deployment or JSON or IO[bytes] + :return: Deployment. The Deployment is compatible with MutableMapping + :rtype: ~azure.iot.deviceupdate.models.Deployment :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "deploymentId": "str", # The caller-provided deployment identifier. This - cannot be longer than 73 characters, must be all lower-case, and cannot contain - '&', '^', '[', ']', '{', '}', '|', '<', '>', forward slash, backslash, or double - quote. The Updates view in the Azure Portal IoT Hub resource generates a GUID for - deploymentId when you create a deployment. Required. - "groupId": "str", # The group identity for the devices the deployment is - intended to update. Required. - "startDateTime": "2020-02-20 00:00:00", # The deployment start datetime. - Required. - "update": { - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description. - "friendlyName": "str" # Optional. Friendly update name. - }, - "deviceClassSubgroups": [ - "str" # Optional. The device class subgroups the deployment is - compatible with and subgroup deployments have been created for. This is not - provided by the caller during CreateOrUpdateDeployment but is automatically - determined by Device Update. - ], - "isCanceled": bool, # Optional. Boolean flag indicating whether the - deployment was canceled. - "isCloudInitiatedRollback": bool, # Optional. Boolean flag indicating - whether the deployment is a rollback deployment. - "isRetried": bool, # Optional. Boolean flag indicating whether the - deployment has been retried. - "rollbackPolicy": { - "failure": { - "devicesFailedCount": 0, # Number of devices that failed. - Required. - "devicesFailedPercentage": 0 # Percentage of devices that - failed. Required. - }, - "update": { - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description. - "friendlyName": "str" # Optional. Friendly update name. - } - } - } """ - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 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 = kwargs.pop("content_type", _headers.pop("Content-Type", None)) # type: Optional[str] - cls = kwargs.pop("cls", None) # type: ClsType[JSON] + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[_models.Deployment] = kwargs.pop("cls", None) content_type = content_type or "application/json" - _json = None _content = None - if isinstance(deployment, (IO, bytes)): + if isinstance(deployment, (IOBase, bytes)): _content = deployment else: - _json = deployment + _content = json.dumps(deployment, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - request = build_device_management_create_or_update_deployment_request( + _request = build_device_management_create_or_update_deployment_request( group_id=group_id, deployment_id=deployment_id, instance_id=self._config.instance_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), + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - pipeline_response = self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("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]: + if _stream: + try: + response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) - if response.content: - deserialized = response.json() + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = None + deserialized = _deserialize(_models.Deployment, response.json()) if cls: - return cls(pipeline_response, cast(JSON, deserialized), {}) - - return cast(JSON, deserialized) - - @distributed_trace - def delete_deployment( # pylint: disable=inconsistent-return-statements - self, group_id: str, deployment_id: str, **kwargs: Any - ) -> None: - """Deletes a deployment. - - :param group_id: Group identifier. Required. - :type group_id: str - :param deployment_id: Deployment identifier. Required. - :type deployment_id: str - :return: None - :rtype: None - :raises ~azure.core.exceptions.HttpResponseError: - """ - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} - error_map.update(kwargs.pop("error_map", {}) or {}) - - _headers = kwargs.pop("headers", {}) or {} - _params = kwargs.pop("params", {}) or {} - - cls = kwargs.pop("cls", None) # type: ClsType[None] + return cls(pipeline_response, deserialized, {}) # type: ignore - request = build_device_management_delete_deployment_request( - group_id=group_id, - deployment_id=deployment_id, - instance_id=self._config.instance_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) # type: ignore - - pipeline_response = 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) - raise HttpResponseError(response=response) - - if cls: - return cls(pipeline_response, None, {}) + return deserialized # type: ignore @distributed_trace - def get_deployment_status(self, group_id: str, deployment_id: str, **kwargs: Any) -> JSON: + def get_deployment_status(self, group_id: str, deployment_id: str, **kwargs: Any) -> _models.DeploymentStatus: """Gets the status of a deployment including a breakdown of how many devices in the deployment are in progress, completed, or failed. @@ -5117,91 +4284,24 @@ def get_deployment_status(self, group_id: str, deployment_id: str, **kwargs: Any :type group_id: str :param deployment_id: Deployment identifier. Required. :type deployment_id: str - :return: JSON object - :rtype: JSON + :return: DeploymentStatus. The DeploymentStatus is compatible with MutableMapping + :rtype: ~azure.iot.deviceupdate.models.DeploymentStatus :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "deploymentState": "str", # The state of the deployment. Required. Known - values are: "Active", "ActiveWithSubgroupFailures", "Failed", "Inactive", and - "Canceled". - "groupId": "str", # The group identity. Required. - "subgroupStatus": [ - { - "deploymentState": "str", # The state of the subgroup - deployment. Required. Known values are: "Active", "Failed", "Inactive", - and "Canceled". - "deviceClassId": "str", # The device class subgroup - identity. Required. - "groupId": "str", # The group identity. Required. - "devicesCanceledCount": 0, # Optional. The number of devices - which have had their deployment canceled. - "devicesCompletedFailedCount": 0, # Optional. The number of - devices that have completed deployment with a failure. - "devicesCompletedSucceededCount": 0, # Optional. The number - of devices which have successfully completed deployment. - "devicesInProgressCount": 0, # Optional. The number of - devices that are currently in deployment. - "error": { - "code": "str", # Server defined error code. - Required. - "message": "str", # A human-readable representation - of the error. Required. - "details": [ - ... - ], - "innererror": { - "code": "str", # A more specific error code - than what was provided by the containing error. Required. - "errorDetail": "str", # Optional. The - internal error or exception message. - "innerError": ..., - "message": "str" # Optional. A - human-readable representation of the error. - }, - "occurredDateTime": "2020-02-20 00:00:00", # - Optional. Date and time in UTC when the error occurred. - "target": "str" # Optional. The target of the error. - }, - "totalDevices": 0 # Optional. The total number of devices in - the deployment. - } - ], - "error": { - "code": "str", # Server defined error code. Required. - "message": "str", # A human-readable representation of the error. - Required. - "details": [ - ... - ], - "innererror": { - "code": "str", # A more specific error code than what was - provided by the containing error. Required. - "errorDetail": "str", # Optional. The internal error or - exception message. - "innerError": ..., - "message": "str" # Optional. A human-readable representation - of the error. - }, - "occurredDateTime": "2020-02-20 00:00:00", # Optional. Date and time - in UTC when the error occurred. - "target": "str" # Optional. The target of the error. - } - } """ - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 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 = kwargs.pop("cls", None) # type: ClsType[JSON] + cls: ClsType[_models.DeploymentStatus] = kwargs.pop("cls", None) - request = build_device_management_get_deployment_status_request( + _request = build_device_management_get_deployment_status_request( group_id=group_id, deployment_id=deployment_id, instance_id=self._config.instance_id, @@ -5210,34 +4310,45 @@ def get_deployment_status(self, group_id: str, deployment_id: str, **kwargs: Any params=_params, ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - pipeline_response = self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("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]: + if _stream: + try: + response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) - if response.content: - deserialized = response.json() + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = None + deserialized = _deserialize(_models.DeploymentStatus, response.json()) if cls: - return cls(pipeline_response, cast(JSON, deserialized), {}) + return cls(pipeline_response, deserialized, {}) # type: ignore - return cast(JSON, deserialized) + return deserialized # type: ignore @distributed_trace def list_device_class_subgroups_for_group( self, group_id: str, *, filter: Optional[str] = None, **kwargs: Any - ) -> Iterable[JSON]: + ) -> ItemPaged["_models.DeviceClassSubgroup"]: """Get the device class subgroups for the group. A device class subgroup is the set of devices within the group that share the same device class. All devices within the same device class are compatible with the same updates. @@ -5245,43 +4356,30 @@ def list_device_class_subgroups_for_group( :param group_id: Group identifier. Required. :type group_id: str :keyword filter: Restricts the set of device class subgroups returned. You can filter on compat - properties by name and value. (i.e. filter=compatProperties/propertyName1 eq 'value1' and - compatProperties/propertyName2 eq 'value2'). Default value is None. + properties by name and value. (i.e. filter=compatProperties/propertyName1 eq + 'value1' and compatProperties/propertyName2 eq 'value2'). Default value is None. :paramtype filter: str - :return: An iterator like instance of JSON object - :rtype: ~azure.core.paging.ItemPaged[JSON] + :return: An iterator like instance of DeviceClassSubgroup + :rtype: ~azure.core.paging.ItemPaged[~azure.iot.deviceupdate.models.DeviceClassSubgroup] :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "createdDateTime": "str", # Date and time when the device class subgroup was - created. Required. - "deviceClassId": "str", # Device class subgroup identity. This is generated - from the model Id and the compat properties reported by the device update agent - in the Device Update PnP interface in IoT Hub. It is a hex-encoded SHA1 hash. - Required. - "groupId": "str", # Group identity. Required. - "deploymentId": "str", # Optional. The active deployment Id for the device - class subgroup. - "deviceCount": 0 # Optional. The number of devices in the device class - subgroup. - } """ _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls = kwargs.pop("cls", None) # type: ClsType[JSON] + cls: ClsType[list[_models.DeviceClassSubgroup]] = kwargs.pop("cls", None) - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } error_map.update(kwargs.pop("error_map", {}) or {}) def prepare_request(next_link=None): if not next_link: - request = build_device_management_list_device_class_subgroups_for_group_request( + _request = build_device_management_list_device_class_subgroups_for_group_request( group_id=group_id, instance_id=self._config.instance_id, filter=filter, @@ -5290,52 +4388,68 @@ def prepare_request(next_link=None): params=_params, ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) else: # make call to next link with the client's api-version - _parsed_next_link = urlparse(next_link) - _next_request_params = case_insensitive_dict(parse_qs(_parsed_next_link.query)) + _parsed_next_link = urllib.parse.urlparse(next_link) + _next_request_params = case_insensitive_dict( + { + key: [urllib.parse.quote(v) for v in value] + for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items() + } + ) _next_request_params["api-version"] = self._config.api_version - request = HttpRequest("GET", urljoin(next_link, _parsed_next_link.path), params=_next_request_params) + _request = HttpRequest( + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + headers=_headers, + params=_next_request_params, + ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - return request + return _request def extract_data(pipeline_response): deserialized = pipeline_response.http_response.json() - list_of_elem = deserialized["value"] + list_of_elem = _deserialize( + list[_models.DeviceClassSubgroup], + deserialized.get("value", []), + ) if cls: - list_of_elem = cls(list_of_elem) - return deserialized.get("nextLink", None), iter(list_of_elem) + list_of_elem = cls(list_of_elem) # type: ignore + return deserialized.get("nextLink") or None, iter(list_of_elem) def get_next(next_link=None): - request = prepare_request(next_link) + _request = prepare_request(next_link) - pipeline_response = self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _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) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) return pipeline_response return ItemPaged(get_next, extract_data) @distributed_trace - def get_device_class_subgroup(self, group_id: str, device_class_id: str, **kwargs: Any) -> JSON: + def get_device_class_subgroup( + self, group_id: str, device_class_id: str, **kwargs: Any + ) -> _models.DeviceClassSubgroup: """Gets device class subgroup details. A device class subgroup is the set of devices within the group that share the same device class. All devices within the same device class are compatible with the same updates. @@ -5344,37 +4458,24 @@ def get_device_class_subgroup(self, group_id: str, device_class_id: str, **kwarg :type group_id: str :param device_class_id: Device class identifier. Required. :type device_class_id: str - :return: JSON object - :rtype: JSON + :return: DeviceClassSubgroup. The DeviceClassSubgroup is compatible with MutableMapping + :rtype: ~azure.iot.deviceupdate.models.DeviceClassSubgroup :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "createdDateTime": "str", # Date and time when the device class subgroup was - created. Required. - "deviceClassId": "str", # Device class subgroup identity. This is generated - from the model Id and the compat properties reported by the device update agent - in the Device Update PnP interface in IoT Hub. It is a hex-encoded SHA1 hash. - Required. - "groupId": "str", # Group identity. Required. - "deploymentId": "str", # Optional. The active deployment Id for the device - class subgroup. - "deviceCount": 0 # Optional. The number of devices in the device class - subgroup. - } """ - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 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 = kwargs.pop("cls", None) # type: ClsType[JSON] + cls: ClsType[_models.DeviceClassSubgroup] = kwargs.pop("cls", None) - request = build_device_management_get_device_class_subgroup_request( + _request = build_device_management_get_device_class_subgroup_request( group_id=group_id, device_class_id=device_class_id, instance_id=self._config.instance_id, @@ -5383,29 +4484,40 @@ class subgroup. params=_params, ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - pipeline_response = self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("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]: + if _stream: + try: + response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) - if response.content: - deserialized = response.json() + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = None + deserialized = _deserialize(_models.DeviceClassSubgroup, response.json()) if cls: - return cls(pipeline_response, cast(JSON, deserialized), {}) + return cls(pipeline_response, deserialized, {}) # type: ignore - return cast(JSON, deserialized) + return deserialized # type: ignore @distributed_trace def delete_device_class_subgroup( # pylint: disable=inconsistent-return-statements @@ -5426,15 +4538,20 @@ def delete_device_class_subgroup( # pylint: disable=inconsistent-return-stateme :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 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 = kwargs.pop("cls", None) # type: ClsType[None] + cls: ClsType[None] = kwargs.pop("cls", None) - request = build_device_management_delete_device_class_subgroup_request( + _request = build_device_management_delete_device_class_subgroup_request( group_id=group_id, device_class_id=device_class_id, instance_id=self._config.instance_id, @@ -5443,25 +4560,32 @@ def delete_device_class_subgroup( # pylint: disable=inconsistent-return-stateme params=_params, ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - pipeline_response = self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _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 [204]: map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) if cls: - return cls(pipeline_response, None, {}) + return cls(pipeline_response, None, {}) # type: ignore @distributed_trace - def get_device_class_subgroup_update_compliance(self, group_id: str, device_class_id: str, **kwargs: Any) -> JSON: + def get_device_class_subgroup_update_compliance( # pylint: disable=name-too-long + self, group_id: str, device_class_id: str, **kwargs: Any + ) -> _models.UpdateCompliance: """Get device class subgroup update compliance information such as how many devices are on their latest update, how many need new updates, and how many are in progress on receiving a new update. @@ -5470,33 +4594,24 @@ def get_device_class_subgroup_update_compliance(self, group_id: str, device_clas :type group_id: str :param device_class_id: Device class identifier. Required. :type device_class_id: str - :return: JSON object - :rtype: JSON + :return: UpdateCompliance. The UpdateCompliance is compatible with MutableMapping + :rtype: ~azure.iot.deviceupdate.models.UpdateCompliance :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "newUpdatesAvailableDeviceCount": 0, # Number of devices with a newer update - available. Required. - "onLatestUpdateDeviceCount": 0, # Number of devices on the latest update. - Required. - "totalDeviceCount": 0, # Total number of devices. Required. - "updatesInProgressDeviceCount": 0 # Number of devices with update - in-progress. Required. - } """ - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 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 = kwargs.pop("cls", None) # type: ClsType[JSON] + cls: ClsType[_models.UpdateCompliance] = kwargs.pop("cls", None) - request = build_device_management_get_device_class_subgroup_update_compliance_request( + _request = build_device_management_get_device_class_subgroup_update_compliance_request( group_id=group_id, device_class_id=device_class_id, instance_id=self._config.instance_id, @@ -5505,32 +4620,45 @@ def get_device_class_subgroup_update_compliance(self, group_id: str, device_clas params=_params, ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - pipeline_response = self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("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]: + if _stream: + try: + response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) - if response.content: - deserialized = response.json() + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = None + deserialized = _deserialize(_models.UpdateCompliance, response.json()) if cls: - return cls(pipeline_response, cast(JSON, deserialized), {}) + return cls(pipeline_response, deserialized, {}) # type: ignore - return cast(JSON, deserialized) + return deserialized # type: ignore @distributed_trace - def get_best_updates_for_device_class_subgroup(self, group_id: str, device_class_id: str, **kwargs: Any) -> JSON: + def get_best_updates_for_device_class_subgroup( # pylint: disable=name-too-long + self, group_id: str, device_class_id: str, **kwargs: Any + ) -> _models.DeviceClassSubgroupUpdatableDevices: """Get the best available update for a device class subgroup and a count of how many devices need this update. @@ -5538,40 +4666,25 @@ def get_best_updates_for_device_class_subgroup(self, group_id: str, device_class :type group_id: str :param device_class_id: Device class identifier. Required. :type device_class_id: str - :return: JSON object - :rtype: JSON + :return: DeviceClassSubgroupUpdatableDevices. The DeviceClassSubgroupUpdatableDevices is + compatible with MutableMapping + :rtype: ~azure.iot.deviceupdate.models.DeviceClassSubgroupUpdatableDevices :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "deviceClassId": "str", # The device class subgroup's device class Id. - Required. - "deviceCount": 0, # Total number of devices for which the update is - applicable. Required. - "groupId": "str", # The group Id. Required. - "update": { - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description. - "friendlyName": "str" # Optional. Friendly update name. - } - } """ - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 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 = kwargs.pop("cls", None) # type: ClsType[JSON] + cls: ClsType[_models.DeviceClassSubgroupUpdatableDevices] = kwargs.pop("cls", None) - request = build_device_management_get_best_updates_for_device_class_subgroup_request( + _request = build_device_management_get_best_updates_for_device_class_subgroup_request( group_id=group_id, device_class_id=device_class_id, instance_id=self._config.instance_id, @@ -5580,34 +4693,45 @@ def get_best_updates_for_device_class_subgroup(self, group_id: str, device_class params=_params, ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - pipeline_response = self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("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]: + if _stream: + try: + response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) - if response.content: - deserialized = response.json() + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = None + deserialized = _deserialize(_models.DeviceClassSubgroupUpdatableDevices, response.json()) if cls: - return cls(pipeline_response, cast(JSON, deserialized), {}) + return cls(pipeline_response, deserialized, {}) # type: ignore - return cast(JSON, deserialized) + return deserialized # type: ignore @distributed_trace - def list_deployments_for_device_class_subgroup( + def list_deployments_for_device_class_subgroup( # pylint: disable=name-too-long self, group_id: str, device_class_id: str, *, order_by: Optional[str] = None, **kwargs: Any - ) -> Iterable[JSON]: + ) -> ItemPaged["_models.Deployment"]: """Gets a list of deployments for a device class subgroup. :param group_id: Group identifier. Required. @@ -5617,76 +4741,27 @@ def list_deployments_for_device_class_subgroup( :keyword order_by: Orders the set of deployments returned. You can order by start date. Default value is None. :paramtype order_by: str - :return: An iterator like instance of JSON object - :rtype: ~azure.core.paging.ItemPaged[JSON] + :return: An iterator like instance of Deployment + :rtype: ~azure.core.paging.ItemPaged[~azure.iot.deviceupdate.models.Deployment] :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "deploymentId": "str", # The caller-provided deployment identifier. This - cannot be longer than 73 characters, must be all lower-case, and cannot contain - '&', '^', '[', ']', '{', '}', '|', '<', '>', forward slash, backslash, or double - quote. The Updates view in the Azure Portal IoT Hub resource generates a GUID for - deploymentId when you create a deployment. Required. - "groupId": "str", # The group identity for the devices the deployment is - intended to update. Required. - "startDateTime": "2020-02-20 00:00:00", # The deployment start datetime. - Required. - "update": { - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description. - "friendlyName": "str" # Optional. Friendly update name. - }, - "deviceClassSubgroups": [ - "str" # Optional. The device class subgroups the deployment is - compatible with and subgroup deployments have been created for. This is not - provided by the caller during CreateOrUpdateDeployment but is automatically - determined by Device Update. - ], - "isCanceled": bool, # Optional. Boolean flag indicating whether the - deployment was canceled. - "isCloudInitiatedRollback": bool, # Optional. Boolean flag indicating - whether the deployment is a rollback deployment. - "isRetried": bool, # Optional. Boolean flag indicating whether the - deployment has been retried. - "rollbackPolicy": { - "failure": { - "devicesFailedCount": 0, # Number of devices that failed. - Required. - "devicesFailedPercentage": 0 # Percentage of devices that - failed. Required. - }, - "update": { - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description. - "friendlyName": "str" # Optional. Friendly update name. - } - } - } """ _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls = kwargs.pop("cls", None) # type: ClsType[JSON] + cls: ClsType[list[_models.Deployment]] = kwargs.pop("cls", None) - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } error_map.update(kwargs.pop("error_map", {}) or {}) def prepare_request(next_link=None): if not next_link: - request = build_device_management_list_deployments_for_device_class_subgroup_request( + _request = build_device_management_list_deployments_for_device_class_subgroup_request( group_id=group_id, device_class_id=device_class_id, instance_id=self._config.instance_id, @@ -5696,45 +4771,59 @@ def prepare_request(next_link=None): params=_params, ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) else: # make call to next link with the client's api-version - _parsed_next_link = urlparse(next_link) - _next_request_params = case_insensitive_dict(parse_qs(_parsed_next_link.query)) + _parsed_next_link = urllib.parse.urlparse(next_link) + _next_request_params = case_insensitive_dict( + { + key: [urllib.parse.quote(v) for v in value] + for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items() + } + ) _next_request_params["api-version"] = self._config.api_version - request = HttpRequest("GET", urljoin(next_link, _parsed_next_link.path), params=_next_request_params) + _request = HttpRequest( + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + headers=_headers, + params=_next_request_params, + ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - return request + return _request def extract_data(pipeline_response): deserialized = pipeline_response.http_response.json() - list_of_elem = deserialized["value"] + list_of_elem = _deserialize( + list[_models.Deployment], + deserialized.get("value", []), + ) if cls: - list_of_elem = cls(list_of_elem) - return deserialized.get("nextLink", None), iter(list_of_elem) + list_of_elem = cls(list_of_elem) # type: ignore + return deserialized.get("nextLink") or None, iter(list_of_elem) def get_next(next_link=None): - request = prepare_request(next_link) + _request = prepare_request(next_link) - pipeline_response = self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _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) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) return pipeline_response @@ -5743,7 +4832,7 @@ def get_next(next_link=None): @distributed_trace def get_deployment_for_device_class_subgroup( self, group_id: str, device_class_id: str, deployment_id: str, **kwargs: Any - ) -> JSON: + ) -> _models.Deployment: """Gets the deployment properties. :param group_id: Group identifier. Required. @@ -5752,73 +4841,24 @@ def get_deployment_for_device_class_subgroup( :type device_class_id: str :param deployment_id: Deployment identifier. Required. :type deployment_id: str - :return: JSON object - :rtype: JSON + :return: Deployment. The Deployment is compatible with MutableMapping + :rtype: ~azure.iot.deviceupdate.models.Deployment :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "deploymentId": "str", # The caller-provided deployment identifier. This - cannot be longer than 73 characters, must be all lower-case, and cannot contain - '&', '^', '[', ']', '{', '}', '|', '<', '>', forward slash, backslash, or double - quote. The Updates view in the Azure Portal IoT Hub resource generates a GUID for - deploymentId when you create a deployment. Required. - "groupId": "str", # The group identity for the devices the deployment is - intended to update. Required. - "startDateTime": "2020-02-20 00:00:00", # The deployment start datetime. - Required. - "update": { - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description. - "friendlyName": "str" # Optional. Friendly update name. - }, - "deviceClassSubgroups": [ - "str" # Optional. The device class subgroups the deployment is - compatible with and subgroup deployments have been created for. This is not - provided by the caller during CreateOrUpdateDeployment but is automatically - determined by Device Update. - ], - "isCanceled": bool, # Optional. Boolean flag indicating whether the - deployment was canceled. - "isCloudInitiatedRollback": bool, # Optional. Boolean flag indicating - whether the deployment is a rollback deployment. - "isRetried": bool, # Optional. Boolean flag indicating whether the - deployment has been retried. - "rollbackPolicy": { - "failure": { - "devicesFailedCount": 0, # Number of devices that failed. - Required. - "devicesFailedPercentage": 0 # Percentage of devices that - failed. Required. - }, - "update": { - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description. - "friendlyName": "str" # Optional. Friendly update name. - } - } - } """ - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 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 = kwargs.pop("cls", None) # type: ClsType[JSON] + cls: ClsType[_models.Deployment] = kwargs.pop("cls", None) - request = build_device_management_get_deployment_for_device_class_subgroup_request( + _request = build_device_management_get_deployment_for_device_class_subgroup_request( group_id=group_id, device_class_id=device_class_id, deployment_id=deployment_id, @@ -5828,83 +4868,45 @@ def get_deployment_for_device_class_subgroup( params=_params, ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - pipeline_response = self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("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]: + if _stream: + try: + response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) - if response.content: - deserialized = response.json() + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = None + deserialized = _deserialize(_models.Deployment, response.json()) if cls: - return cls(pipeline_response, cast(JSON, deserialized), {}) + return cls(pipeline_response, deserialized, {}) # type: ignore - return cast(JSON, deserialized) + return deserialized # type: ignore @distributed_trace - def delete_deployment_for_device_class_subgroup( # pylint: disable=inconsistent-return-statements + def stop_deployment( self, group_id: str, device_class_id: str, deployment_id: str, **kwargs: Any - ) -> None: - """Deletes a device class subgroup deployment. - - :param group_id: Group identifier. Required. - :type group_id: str - :param device_class_id: Device class identifier. Required. - :type device_class_id: str - :param deployment_id: Deployment identifier. Required. - :type deployment_id: str - :return: None - :rtype: None - :raises ~azure.core.exceptions.HttpResponseError: - """ - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} - error_map.update(kwargs.pop("error_map", {}) or {}) - - _headers = kwargs.pop("headers", {}) or {} - _params = kwargs.pop("params", {}) or {} - - cls = kwargs.pop("cls", None) # type: ClsType[None] - - request = build_device_management_delete_deployment_for_device_class_subgroup_request( - group_id=group_id, - device_class_id=device_class_id, - deployment_id=deployment_id, - instance_id=self._config.instance_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) # type: ignore - - pipeline_response = 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) - raise HttpResponseError(response=response) - - if cls: - return cls(pipeline_response, None, {}) - - @distributed_trace - def stop_deployment(self, group_id: str, device_class_id: str, deployment_id: str, **kwargs: Any) -> JSON: + ) -> _models.Deployment: """Stops a deployment. :param group_id: Group identifier. Required. @@ -5913,73 +4915,24 @@ def stop_deployment(self, group_id: str, device_class_id: str, deployment_id: st :type device_class_id: str :param deployment_id: Deployment identifier. Required. :type deployment_id: str - :return: JSON object - :rtype: JSON + :return: Deployment. The Deployment is compatible with MutableMapping + :rtype: ~azure.iot.deviceupdate.models.Deployment :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "deploymentId": "str", # The caller-provided deployment identifier. This - cannot be longer than 73 characters, must be all lower-case, and cannot contain - '&', '^', '[', ']', '{', '}', '|', '<', '>', forward slash, backslash, or double - quote. The Updates view in the Azure Portal IoT Hub resource generates a GUID for - deploymentId when you create a deployment. Required. - "groupId": "str", # The group identity for the devices the deployment is - intended to update. Required. - "startDateTime": "2020-02-20 00:00:00", # The deployment start datetime. - Required. - "update": { - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description. - "friendlyName": "str" # Optional. Friendly update name. - }, - "deviceClassSubgroups": [ - "str" # Optional. The device class subgroups the deployment is - compatible with and subgroup deployments have been created for. This is not - provided by the caller during CreateOrUpdateDeployment but is automatically - determined by Device Update. - ], - "isCanceled": bool, # Optional. Boolean flag indicating whether the - deployment was canceled. - "isCloudInitiatedRollback": bool, # Optional. Boolean flag indicating - whether the deployment is a rollback deployment. - "isRetried": bool, # Optional. Boolean flag indicating whether the - deployment has been retried. - "rollbackPolicy": { - "failure": { - "devicesFailedCount": 0, # Number of devices that failed. - Required. - "devicesFailedPercentage": 0 # Percentage of devices that - failed. Required. - }, - "update": { - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description. - "friendlyName": "str" # Optional. Friendly update name. - } - } - } """ - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 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 = kwargs.pop("cls", None) # type: ClsType[JSON] + cls: ClsType[_models.Deployment] = kwargs.pop("cls", None) - request = build_device_management_stop_deployment_request( + _request = build_device_management_stop_deployment_request( group_id=group_id, device_class_id=device_class_id, deployment_id=deployment_id, @@ -5989,32 +4942,45 @@ def stop_deployment(self, group_id: str, device_class_id: str, deployment_id: st params=_params, ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - pipeline_response = self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("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]: + if _stream: + try: + response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) - if response.content: - deserialized = response.json() + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = None + deserialized = _deserialize(_models.Deployment, response.json()) if cls: - return cls(pipeline_response, cast(JSON, deserialized), {}) + return cls(pipeline_response, deserialized, {}) # type: ignore - return cast(JSON, deserialized) + return deserialized # type: ignore @distributed_trace - def retry_deployment(self, group_id: str, device_class_id: str, deployment_id: str, **kwargs: Any) -> JSON: + def retry_deployment( + self, group_id: str, device_class_id: str, deployment_id: str, **kwargs: Any + ) -> _models.Deployment: """Retries a deployment with failed devices. :param group_id: Group identifier. Required. @@ -6023,73 +4989,24 @@ def retry_deployment(self, group_id: str, device_class_id: str, deployment_id: s :type device_class_id: str :param deployment_id: Deployment identifier. Required. :type deployment_id: str - :return: JSON object - :rtype: JSON + :return: Deployment. The Deployment is compatible with MutableMapping + :rtype: ~azure.iot.deviceupdate.models.Deployment :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "deploymentId": "str", # The caller-provided deployment identifier. This - cannot be longer than 73 characters, must be all lower-case, and cannot contain - '&', '^', '[', ']', '{', '}', '|', '<', '>', forward slash, backslash, or double - quote. The Updates view in the Azure Portal IoT Hub resource generates a GUID for - deploymentId when you create a deployment. Required. - "groupId": "str", # The group identity for the devices the deployment is - intended to update. Required. - "startDateTime": "2020-02-20 00:00:00", # The deployment start datetime. - Required. - "update": { - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description. - "friendlyName": "str" # Optional. Friendly update name. - }, - "deviceClassSubgroups": [ - "str" # Optional. The device class subgroups the deployment is - compatible with and subgroup deployments have been created for. This is not - provided by the caller during CreateOrUpdateDeployment but is automatically - determined by Device Update. - ], - "isCanceled": bool, # Optional. Boolean flag indicating whether the - deployment was canceled. - "isCloudInitiatedRollback": bool, # Optional. Boolean flag indicating - whether the deployment is a rollback deployment. - "isRetried": bool, # Optional. Boolean flag indicating whether the - deployment has been retried. - "rollbackPolicy": { - "failure": { - "devicesFailedCount": 0, # Number of devices that failed. - Required. - "devicesFailedPercentage": 0 # Percentage of devices that - failed. Required. - }, - "update": { - "updateId": { - "name": "str", # Update name. Required. - "provider": "str", # Update provider. Required. - "version": "str" # Update version. Required. - }, - "description": "str", # Optional. Update description. - "friendlyName": "str" # Optional. Friendly update name. - } - } - } """ - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 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 = kwargs.pop("cls", None) # type: ClsType[JSON] + cls: ClsType[_models.Deployment] = kwargs.pop("cls", None) - request = build_device_management_retry_deployment_request( + _request = build_device_management_retry_deployment_request( group_id=group_id, device_class_id=device_class_id, deployment_id=deployment_id, @@ -6099,34 +5016,45 @@ def retry_deployment(self, group_id: str, device_class_id: str, deployment_id: s params=_params, ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - pipeline_response = self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("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]: + if _stream: + try: + response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) - if response.content: - deserialized = response.json() + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = None + deserialized = _deserialize(_models.Deployment, response.json()) if cls: - return cls(pipeline_response, cast(JSON, deserialized), {}) + return cls(pipeline_response, deserialized, {}) # type: ignore - return cast(JSON, deserialized) + return deserialized # type: ignore @distributed_trace - def get_device_class_subgroup_deployment_status( + def get_device_class_subgroup_deployment_status( # pylint: disable=name-too-long self, group_id: str, device_class_id: str, deployment_id: str, **kwargs: Any - ) -> JSON: + ) -> _models.DeviceClassSubgroupDeploymentStatus: """Gets the status of a deployment including a breakdown of how many devices in the deployment are in progress, completed, or failed. @@ -6136,59 +5064,25 @@ def get_device_class_subgroup_deployment_status( :type device_class_id: str :param deployment_id: Deployment identifier. Required. :type deployment_id: str - :return: JSON object - :rtype: JSON + :return: DeviceClassSubgroupDeploymentStatus. The DeviceClassSubgroupDeploymentStatus is + compatible with MutableMapping + :rtype: ~azure.iot.deviceupdate.models.DeviceClassSubgroupDeploymentStatus :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "deploymentState": "str", # The state of the subgroup deployment. Required. - Known values are: "Active", "Failed", "Inactive", and "Canceled". - "deviceClassId": "str", # The device class subgroup identity. Required. - "groupId": "str", # The group identity. Required. - "devicesCanceledCount": 0, # Optional. The number of devices which have had - their deployment canceled. - "devicesCompletedFailedCount": 0, # Optional. The number of devices that - have completed deployment with a failure. - "devicesCompletedSucceededCount": 0, # Optional. The number of devices which - have successfully completed deployment. - "devicesInProgressCount": 0, # Optional. The number of devices that are - currently in deployment. - "error": { - "code": "str", # Server defined error code. Required. - "message": "str", # A human-readable representation of the error. - Required. - "details": [ - ... - ], - "innererror": { - "code": "str", # A more specific error code than what was - provided by the containing error. Required. - "errorDetail": "str", # Optional. The internal error or - exception message. - "innerError": ..., - "message": "str" # Optional. A human-readable representation - of the error. - }, - "occurredDateTime": "2020-02-20 00:00:00", # Optional. Date and time - in UTC when the error occurred. - "target": "str" # Optional. The target of the error. - }, - "totalDevices": 0 # Optional. The total number of devices in the deployment. - } """ - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 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 = kwargs.pop("cls", None) # type: ClsType[JSON] + cls: ClsType[_models.DeviceClassSubgroupDeploymentStatus] = kwargs.pop("cls", None) - request = build_device_management_get_device_class_subgroup_deployment_status_request( + _request = build_device_management_get_device_class_subgroup_deployment_status_request( group_id=group_id, device_class_id=device_class_id, deployment_id=deployment_id, @@ -6198,34 +5092,45 @@ def get_device_class_subgroup_deployment_status( params=_params, ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - pipeline_response = self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("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]: + if _stream: + try: + response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) - if response.content: - deserialized = response.json() + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = None + deserialized = _deserialize(_models.DeviceClassSubgroupDeploymentStatus, response.json()) if cls: - return cls(pipeline_response, cast(JSON, deserialized), {}) + return cls(pipeline_response, deserialized, {}) # type: ignore - return cast(JSON, deserialized) + return deserialized # type: ignore @distributed_trace - def list_device_states_for_device_class_subgroup_deployment( + def list_device_states_for_device_class_subgroup_deployment( # pylint: disable=name-too-long self, group_id: str, device_class_id: str, deployment_id: str, *, filter: Optional[str] = None, **kwargs: Any - ) -> Iterable[JSON]: + ) -> ItemPaged["_models.DeploymentDeviceState"]: """Gets a list of devices in a deployment along with their state. Useful for getting a list of failed devices. @@ -6238,38 +5143,27 @@ def list_device_states_for_device_class_subgroup_deployment( :keyword filter: Restricts the set of deployment device states returned. You can filter on deviceId and moduleId and/or deviceState. Default value is None. :paramtype filter: str - :return: An iterator like instance of JSON object - :rtype: ~azure.core.paging.ItemPaged[JSON] + :return: An iterator like instance of DeploymentDeviceState + :rtype: ~azure.core.paging.ItemPaged[~azure.iot.deviceupdate.models.DeploymentDeviceState] :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "deviceId": "str", # Device identity. Required. - "deviceState": "str", # Deployment device state. Required. Known values are: - "Succeeded", "InProgress", "Canceled", and "Failed". - "movedOnToNewDeployment": bool, # Boolean flag indicating whether this - device is in a newer deployment and can no longer retry this deployment. - Required. - "retryCount": 0, # The number of times this deployment has been retried on - this device. Required. - "moduleId": "str" # Optional. Device module identity. - } """ _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls = kwargs.pop("cls", None) # type: ClsType[JSON] + cls: ClsType[list[_models.DeploymentDeviceState]] = kwargs.pop("cls", None) - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } error_map.update(kwargs.pop("error_map", {}) or {}) def prepare_request(next_link=None): if not next_link: - request = build_device_management_list_device_states_for_device_class_subgroup_deployment_request( + _request = build_device_management_list_device_states_for_device_class_subgroup_deployment_request( group_id=group_id, device_class_id=device_class_id, deployment_id=deployment_id, @@ -6280,211 +5174,188 @@ def prepare_request(next_link=None): params=_params, ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) else: # make call to next link with the client's api-version - _parsed_next_link = urlparse(next_link) - _next_request_params = case_insensitive_dict(parse_qs(_parsed_next_link.query)) + _parsed_next_link = urllib.parse.urlparse(next_link) + _next_request_params = case_insensitive_dict( + { + key: [urllib.parse.quote(v) for v in value] + for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items() + } + ) _next_request_params["api-version"] = self._config.api_version - request = HttpRequest("GET", urljoin(next_link, _parsed_next_link.path), params=_next_request_params) + _request = HttpRequest( + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + headers=_headers, + params=_next_request_params, + ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - return request + return _request def extract_data(pipeline_response): deserialized = pipeline_response.http_response.json() - list_of_elem = deserialized["value"] + list_of_elem = _deserialize( + list[_models.DeploymentDeviceState], + deserialized.get("value", []), + ) if cls: - list_of_elem = cls(list_of_elem) - return deserialized.get("nextLink", None), iter(list_of_elem) + list_of_elem = cls(list_of_elem) # type: ignore + return deserialized.get("nextLink") or None, iter(list_of_elem) def get_next(next_link=None): - request = prepare_request(next_link) + _request = prepare_request(next_link) - pipeline_response = self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _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) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) return pipeline_response return ItemPaged(get_next, extract_data) @distributed_trace - def get_operation_status(self, operation_id: str, *, if_none_match: Optional[str] = None, **kwargs: Any) -> JSON: + def get_operation_status( + self, + operation_id: str, + *, + etag: Optional[str] = None, + match_condition: Optional[MatchConditions] = None, + **kwargs: Any + ) -> _models.DeviceOperation: """Retrieve operation status. :param operation_id: Operation identifier. Required. :type operation_id: str - :keyword if_none_match: Defines the If-None-Match condition. The operation will be performed - only if the ETag on the server does not match this value. Default value is None. - :paramtype if_none_match: str - :return: JSON object - :rtype: JSON + :keyword etag: check if resource is changed. Set None to skip checking etag. Default value is + None. + :paramtype etag: str + :keyword match_condition: The match condition to use upon the etag. Default value is None. + :paramtype match_condition: ~azure.core.MatchConditions + :return: DeviceOperation. The DeviceOperation is compatible with MutableMapping + :rtype: ~azure.iot.deviceupdate.models.DeviceOperation :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "createdDateTime": "2020-02-20 00:00:00", # Date and time in UTC when the - operation was created. Required. - "lastActionDateTime": "2020-02-20 00:00:00", # Date and time in UTC when the - operation status was last updated. Required. - "operationId": "str", # Operation Id. Required. - "status": "str", # Operation status. Required. Known values are: - "NotStarted", "Running", "Succeeded", and "Failed". - "error": { - "code": "str", # Server defined error code. Required. - "message": "str", # A human-readable representation of the error. - Required. - "details": [ - ... - ], - "innererror": { - "code": "str", # A more specific error code than what was - provided by the containing error. Required. - "errorDetail": "str", # Optional. The internal error or - exception message. - "innerError": ..., - "message": "str" # Optional. A human-readable representation - of the error. - }, - "occurredDateTime": "2020-02-20 00:00:00", # Optional. Date and time - in UTC when the error occurred. - "target": "str" # Optional. The target of the error. - }, - "etag": "str", # Optional. Operation ETag. - "traceId": "str" # Optional. Operation correlation identity that can used by - Microsoft Support for troubleshooting. - } """ - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + if match_condition == MatchConditions.IfNotModified: + error_map[412] = ResourceModifiedError + elif match_condition == MatchConditions.IfPresent: + error_map[412] = ResourceNotFoundError + elif match_condition == MatchConditions.IfMissing: + error_map[412] = ResourceExistsError error_map.update(kwargs.pop("error_map", {}) or {}) _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls = kwargs.pop("cls", None) # type: ClsType[JSON] + cls: ClsType[_models.DeviceOperation] = kwargs.pop("cls", None) - request = build_device_management_get_operation_status_request( + _request = build_device_management_get_operation_status_request( operation_id=operation_id, instance_id=self._config.instance_id, - if_none_match=if_none_match, + etag=etag, + match_condition=match_condition, 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), + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - pipeline_response = self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("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]: + if _stream: + try: + response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) response_headers = {} response_headers["Retry-After"] = self._deserialize("str", response.headers.get("Retry-After")) - if response.content: - deserialized = response.json() + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = None + deserialized = _deserialize(_models.DeviceOperation, response.json()) if cls: - return cls(pipeline_response, cast(JSON, deserialized), response_headers) + return cls(pipeline_response, deserialized, response_headers) # type: ignore - return cast(JSON, deserialized) + return deserialized # type: ignore @distributed_trace def list_operation_statuses( self, *, filter: Optional[str] = None, top: Optional[int] = None, **kwargs: Any - ) -> Iterable[JSON]: + ) -> ItemPaged["_models.DeviceOperation"]: """Get a list of all device import operations. Completed operations are kept for 7 days before auto-deleted. :keyword filter: Restricts the set of operations returned. Only one specific filter is supported: "status eq 'NotStarted' or status eq 'Running'". Default value is None. :paramtype filter: str - :keyword top: Specifies a non-negative integer n that limits the number of items returned from - a collection. The service returns the number of available items up to but not greater than the - specified value n. Default value is None. + :keyword top: Specifies a non-negative integer n that limits the number of items returned + from a collection. The service returns the number of available items up to but + not greater than the specified value n. Default value is None. :paramtype top: int - :return: An iterator like instance of JSON object - :rtype: ~azure.core.paging.ItemPaged[JSON] + :return: An iterator like instance of DeviceOperation + :rtype: ~azure.core.paging.ItemPaged[~azure.iot.deviceupdate.models.DeviceOperation] :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "createdDateTime": "2020-02-20 00:00:00", # Date and time in UTC when the - operation was created. Required. - "lastActionDateTime": "2020-02-20 00:00:00", # Date and time in UTC when the - operation status was last updated. Required. - "operationId": "str", # Operation Id. Required. - "status": "str", # Operation status. Required. Known values are: - "NotStarted", "Running", "Succeeded", and "Failed". - "error": { - "code": "str", # Server defined error code. Required. - "message": "str", # A human-readable representation of the error. - Required. - "details": [ - ... - ], - "innererror": { - "code": "str", # A more specific error code than what was - provided by the containing error. Required. - "errorDetail": "str", # Optional. The internal error or - exception message. - "innerError": ..., - "message": "str" # Optional. A human-readable representation - of the error. - }, - "occurredDateTime": "2020-02-20 00:00:00", # Optional. Date and time - in UTC when the error occurred. - "target": "str" # Optional. The target of the error. - }, - "etag": "str", # Optional. Operation ETag. - "traceId": "str" # Optional. Operation correlation identity that can used by - Microsoft Support for troubleshooting. - } """ _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls = kwargs.pop("cls", None) # type: ClsType[JSON] + cls: ClsType[list[_models.DeviceOperation]] = kwargs.pop("cls", None) - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } error_map.update(kwargs.pop("error_map", {}) or {}) def prepare_request(next_link=None): if not next_link: - request = build_device_management_list_operation_statuses_request( + _request = build_device_management_list_operation_statuses_request( instance_id=self._config.instance_id, filter=filter, top=top, @@ -6493,45 +5364,59 @@ def prepare_request(next_link=None): params=_params, ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) else: # make call to next link with the client's api-version - _parsed_next_link = urlparse(next_link) - _next_request_params = case_insensitive_dict(parse_qs(_parsed_next_link.query)) + _parsed_next_link = urllib.parse.urlparse(next_link) + _next_request_params = case_insensitive_dict( + { + key: [urllib.parse.quote(v) for v in value] + for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items() + } + ) _next_request_params["api-version"] = self._config.api_version - request = HttpRequest("GET", urljoin(next_link, _parsed_next_link.path), params=_next_request_params) + _request = HttpRequest( + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + headers=_headers, + params=_next_request_params, + ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - return request + return _request def extract_data(pipeline_response): deserialized = pipeline_response.http_response.json() - list_of_elem = deserialized["value"] + list_of_elem = _deserialize( + list[_models.DeviceOperation], + deserialized.get("value", []), + ) if cls: - list_of_elem = cls(list_of_elem) - return deserialized.get("nextLink", None), iter(list_of_elem) + list_of_elem = cls(list_of_elem) # type: ignore + return deserialized.get("nextLink") or None, iter(list_of_elem) def get_next(next_link=None): - request = prepare_request(next_link) + _request = prepare_request(next_link) - pipeline_response = self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _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) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) return pipeline_response @@ -6539,229 +5424,173 @@ def get_next(next_link=None): @overload def start_log_collection( - self, log_collection_id: str, log_collection: JSON, *, content_type: str = "application/json", **kwargs: Any - ) -> JSON: + self, + log_collection_id: str, + log_collection: _models.LogCollection, + *, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.LogCollection: """Start the device diagnostics log collection on specified devices. :param log_collection_id: Log collection identifier. Required. :type log_collection_id: str :param log_collection: The log collection properties. Required. - :type log_collection: JSON + :type log_collection: ~azure.iot.deviceupdate.models.LogCollection :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str - :return: JSON object - :rtype: JSON + :return: LogCollection. The LogCollection is compatible with MutableMapping + :rtype: ~azure.iot.deviceupdate.models.LogCollection :raises ~azure.core.exceptions.HttpResponseError: + """ - Example: - .. code-block:: python - - # JSON input template you can fill out and use as your body input. - log_collection = { - "deviceList": [ - { - "deviceId": "str", # Device Id. Required. - "moduleId": "str" # Optional. Module Id. - } - ], - "createdDateTime": "str", # Optional. The timestamp when the operation was - created. - "description": "str", # Optional. Description of the diagnostics operation. - "lastActionDateTime": "str", # Optional. A timestamp for when the current - state was entered. - "operationId": "str", # Optional. The log collection id. - "status": "str" # Optional. Operation status. Known values are: - "NotStarted", "Running", "Succeeded", and "Failed". - } + @overload + def start_log_collection( + self, log_collection_id: str, log_collection: JSON, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.LogCollection: + """Start the device diagnostics log collection on specified devices. - # response body for status code(s): 201 - response == { - "deviceList": [ - { - "deviceId": "str", # Device Id. Required. - "moduleId": "str" # Optional. Module Id. - } - ], - "createdDateTime": "str", # Optional. The timestamp when the operation was - created. - "description": "str", # Optional. Description of the diagnostics operation. - "lastActionDateTime": "str", # Optional. A timestamp for when the current - state was entered. - "operationId": "str", # Optional. The log collection id. - "status": "str" # Optional. Operation status. Known values are: - "NotStarted", "Running", "Succeeded", and "Failed". - } + :param log_collection_id: Log collection identifier. Required. + :type log_collection_id: str + :param log_collection: The log collection properties. Required. + :type log_collection: JSON + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: LogCollection. The LogCollection is compatible with MutableMapping + :rtype: ~azure.iot.deviceupdate.models.LogCollection + :raises ~azure.core.exceptions.HttpResponseError: """ @overload def start_log_collection( - self, log_collection_id: str, log_collection: IO, *, content_type: str = "application/json", **kwargs: Any - ) -> JSON: + self, + log_collection_id: str, + log_collection: IO[bytes], + *, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.LogCollection: """Start the device diagnostics log collection on specified devices. :param log_collection_id: Log collection identifier. Required. :type log_collection_id: str :param log_collection: The log collection properties. Required. - :type log_collection: IO + :type log_collection: IO[bytes] :keyword content_type: Body Parameter content-type. Content type parameter for binary body. Default value is "application/json". :paramtype content_type: str - :return: JSON object - :rtype: JSON + :return: LogCollection. The LogCollection is compatible with MutableMapping + :rtype: ~azure.iot.deviceupdate.models.LogCollection :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 201 - response == { - "deviceList": [ - { - "deviceId": "str", # Device Id. Required. - "moduleId": "str" # Optional. Module Id. - } - ], - "createdDateTime": "str", # Optional. The timestamp when the operation was - created. - "description": "str", # Optional. Description of the diagnostics operation. - "lastActionDateTime": "str", # Optional. A timestamp for when the current - state was entered. - "operationId": "str", # Optional. The log collection id. - "status": "str" # Optional. Operation status. Known values are: - "NotStarted", "Running", "Succeeded", and "Failed". - } """ @distributed_trace - def start_log_collection(self, log_collection_id: str, log_collection: Union[JSON, IO], **kwargs: Any) -> JSON: + def start_log_collection( + self, log_collection_id: str, log_collection: Union[_models.LogCollection, JSON, IO[bytes]], **kwargs: Any + ) -> _models.LogCollection: """Start the device diagnostics log collection on specified devices. :param log_collection_id: Log collection identifier. Required. :type log_collection_id: str - :param log_collection: The log collection properties. Is either a model type or a IO type. - Required. - :type log_collection: JSON or IO - :keyword content_type: Body Parameter content-type. Known values are: 'application/json'. - Default value is None. - :paramtype content_type: str - :return: JSON object - :rtype: JSON + :param log_collection: The log collection properties. Is one of the following types: + LogCollection, JSON, IO[bytes] Required. + :type log_collection: ~azure.iot.deviceupdate.models.LogCollection or JSON or IO[bytes] + :return: LogCollection. The LogCollection is compatible with MutableMapping + :rtype: ~azure.iot.deviceupdate.models.LogCollection :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 201 - response == { - "deviceList": [ - { - "deviceId": "str", # Device Id. Required. - "moduleId": "str" # Optional. Module Id. - } - ], - "createdDateTime": "str", # Optional. The timestamp when the operation was - created. - "description": "str", # Optional. Description of the diagnostics operation. - "lastActionDateTime": "str", # Optional. A timestamp for when the current - state was entered. - "operationId": "str", # Optional. The log collection id. - "status": "str" # Optional. Operation status. Known values are: - "NotStarted", "Running", "Succeeded", and "Failed". - } """ - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 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 = kwargs.pop("content_type", _headers.pop("Content-Type", None)) # type: Optional[str] - cls = kwargs.pop("cls", None) # type: ClsType[JSON] + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[_models.LogCollection] = kwargs.pop("cls", None) content_type = content_type or "application/json" - _json = None _content = None - if isinstance(log_collection, (IO, bytes)): + if isinstance(log_collection, (IOBase, bytes)): _content = log_collection else: - _json = log_collection + _content = json.dumps(log_collection, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - request = build_device_management_start_log_collection_request( + _request = build_device_management_start_log_collection_request( log_collection_id=log_collection_id, instance_id=self._config.instance_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), + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - pipeline_response = self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("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 [201]: + if _stream: + try: + response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) - if response.content: - deserialized = response.json() + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = None + deserialized = _deserialize(_models.LogCollection, response.json()) if cls: - return cls(pipeline_response, cast(JSON, deserialized), {}) + return cls(pipeline_response, deserialized, {}) # type: ignore - return cast(JSON, deserialized) + return deserialized # type: ignore @distributed_trace - def get_log_collection(self, log_collection_id: str, **kwargs: Any) -> JSON: + def get_log_collection(self, log_collection_id: str, **kwargs: Any) -> _models.LogCollection: """Get the device diagnostics log collection. :param log_collection_id: Log collection identifier. Required. :type log_collection_id: str - :return: JSON object - :rtype: JSON + :return: LogCollection. The LogCollection is compatible with MutableMapping + :rtype: ~azure.iot.deviceupdate.models.LogCollection :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "deviceList": [ - { - "deviceId": "str", # Device Id. Required. - "moduleId": "str" # Optional. Module Id. - } - ], - "createdDateTime": "str", # Optional. The timestamp when the operation was - created. - "description": "str", # Optional. Description of the diagnostics operation. - "lastActionDateTime": "str", # Optional. A timestamp for when the current - state was entered. - "operationId": "str", # Optional. The log collection id. - "status": "str" # Optional. Operation status. Known values are: - "NotStarted", "Running", "Succeeded", and "Failed". - } """ - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 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 = kwargs.pop("cls", None) # type: ClsType[JSON] + cls: ClsType[_models.LogCollection] = kwargs.pop("cls", None) - request = build_device_management_get_log_collection_request( + _request = build_device_management_get_log_collection_request( log_collection_id=log_collection_id, instance_id=self._config.instance_id, api_version=self._config.api_version, @@ -6769,167 +5598,157 @@ def get_log_collection(self, log_collection_id: str, **kwargs: Any) -> JSON: params=_params, ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - pipeline_response = self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("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]: + if _stream: + try: + response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) - if response.content: - deserialized = response.json() + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = None + deserialized = _deserialize(_models.LogCollection, response.json()) if cls: - return cls(pipeline_response, cast(JSON, deserialized), {}) + return cls(pipeline_response, deserialized, {}) # type: ignore - return cast(JSON, deserialized) + return deserialized # type: ignore @distributed_trace - def list_log_collections(self, **kwargs: Any) -> Iterable[JSON]: + def list_log_collections(self, **kwargs: Any) -> ItemPaged["_models.LogCollection"]: """Get all device diagnostics log collections. - :return: An iterator like instance of JSON object - :rtype: ~azure.core.paging.ItemPaged[JSON] + :return: An iterator like instance of LogCollection + :rtype: ~azure.core.paging.ItemPaged[~azure.iot.deviceupdate.models.LogCollection] :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "deviceList": [ - { - "deviceId": "str", # Device Id. Required. - "moduleId": "str" # Optional. Module Id. - } - ], - "createdDateTime": "str", # Optional. The timestamp when the operation was - created. - "description": "str", # Optional. Description of the diagnostics operation. - "lastActionDateTime": "str", # Optional. A timestamp for when the current - state was entered. - "operationId": "str", # Optional. The log collection id. - "status": "str" # Optional. Operation status. Known values are: - "NotStarted", "Running", "Succeeded", and "Failed". - } """ _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls = kwargs.pop("cls", None) # type: ClsType[JSON] + cls: ClsType[list[_models.LogCollection]] = kwargs.pop("cls", None) - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } error_map.update(kwargs.pop("error_map", {}) or {}) def prepare_request(next_link=None): if not next_link: - request = build_device_management_list_log_collections_request( + _request = build_device_management_list_log_collections_request( instance_id=self._config.instance_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 - ), + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) else: # make call to next link with the client's api-version - _parsed_next_link = urlparse(next_link) - _next_request_params = case_insensitive_dict(parse_qs(_parsed_next_link.query)) + _parsed_next_link = urllib.parse.urlparse(next_link) + _next_request_params = case_insensitive_dict( + { + key: [urllib.parse.quote(v) for v in value] + for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items() + } + ) _next_request_params["api-version"] = self._config.api_version - request = HttpRequest("GET", urljoin(next_link, _parsed_next_link.path), params=_next_request_params) + _request = HttpRequest( + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + headers=_headers, + params=_next_request_params, + ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - return request + return _request def extract_data(pipeline_response): deserialized = pipeline_response.http_response.json() - list_of_elem = deserialized["value"] + list_of_elem = _deserialize( + list[_models.LogCollection], + deserialized.get("value", []), + ) if cls: - list_of_elem = cls(list_of_elem) - return deserialized.get("nextLink", None), iter(list_of_elem) + list_of_elem = cls(list_of_elem) # type: ignore + return deserialized.get("nextLink") or None, iter(list_of_elem) def get_next(next_link=None): - request = prepare_request(next_link) + _request = prepare_request(next_link) - pipeline_response = self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _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) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) return pipeline_response return ItemPaged(get_next, extract_data) @distributed_trace - def get_log_collection_detailed_status(self, log_collection_id: str, **kwargs: Any) -> JSON: + def get_log_collection_detailed_status( + self, log_collection_id: str, **kwargs: Any + ) -> _models.LogCollectionOperationDetailedStatus: """Get log collection with detailed status. :param log_collection_id: Log collection identifier. Required. :type log_collection_id: str - :return: JSON object - :rtype: JSON + :return: LogCollectionOperationDetailedStatus. The LogCollectionOperationDetailedStatus is + compatible with MutableMapping + :rtype: ~azure.iot.deviceupdate.models.LogCollectionOperationDetailedStatus :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "createdDateTime": "str", # Optional. The timestamp when the operation was - created. - "description": "str", # Optional. Device diagnostics operation description. - "deviceStatus": [ - { - "deviceId": "str", # Device id. Required. - "status": "str", # Log upload status. Required. Known values - are: "NotStarted", "Running", "Succeeded", and "Failed". - "extendedResultCode": "str", # Optional. Log upload extended - result code. - "logLocation": "str", # Optional. Log upload location. - "moduleId": "str", # Optional. Module id. - "resultCode": "str" # Optional. Log upload result code. - } - ], - "lastActionDateTime": "str", # Optional. A timestamp for when the current - state was entered. - "operationId": "str", # Optional. The device diagnostics operation id. - "status": "str" # Optional. Operation status. Known values are: - "NotStarted", "Running", "Succeeded", and "Failed". - } """ - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 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 = kwargs.pop("cls", None) # type: ClsType[JSON] + cls: ClsType[_models.LogCollectionOperationDetailedStatus] = kwargs.pop("cls", None) - request = build_device_management_get_log_collection_detailed_status_request( + _request = build_device_management_get_log_collection_detailed_status_request( log_collection_id=log_collection_id, instance_id=self._config.instance_id, api_version=self._config.api_version, @@ -6937,72 +5756,69 @@ def get_log_collection_detailed_status(self, log_collection_id: str, **kwargs: A params=_params, ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - pipeline_response = self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("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]: + if _stream: + try: + response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) - if response.content: - deserialized = response.json() + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = None + deserialized = _deserialize(_models.LogCollectionOperationDetailedStatus, response.json()) if cls: - return cls(pipeline_response, cast(JSON, deserialized), {}) + return cls(pipeline_response, deserialized, {}) # type: ignore - return cast(JSON, deserialized) + return deserialized # type: ignore @distributed_trace - def list_health_of_devices(self, *, filter: str, **kwargs: Any) -> Iterable[JSON]: + def list_health_of_devices(self, *, filter: str, **kwargs: Any) -> ItemPaged["_models.DeviceHealth"]: """Get list of device health. :keyword filter: Restricts the set of devices for which device health is returned. You can filter on status, device id and module id. Required. :paramtype filter: str - :return: An iterator like instance of JSON object - :rtype: ~azure.core.paging.ItemPaged[JSON] + :return: An iterator like instance of DeviceHealth + :rtype: ~azure.core.paging.ItemPaged[~azure.iot.deviceupdate.models.DeviceHealth] :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "deviceId": "str", # Device id. Required. - "healthChecks": [ - { - "name": "str", # Optional. Health check name. - "result": "str" # Optional. Health check result. Known - values are: "success" and "userError". - } - ], - "state": "str", # Aggregate device health state. Required. Known values are: - "healthy" and "unhealthy". - "digitalTwinModelId": "str", # Optional. Digital twin model Id. - "moduleId": "str" # Optional. Module id. - } """ _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls = kwargs.pop("cls", None) # type: ClsType[JSON] + cls: ClsType[list[_models.DeviceHealth]] = kwargs.pop("cls", None) - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError} + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } error_map.update(kwargs.pop("error_map", {}) or {}) def prepare_request(next_link=None): if not next_link: - request = build_device_management_list_health_of_devices_request( + _request = build_device_management_list_health_of_devices_request( instance_id=self._config.instance_id, filter=filter, api_version=self._config.api_version, @@ -7010,46 +5826,179 @@ def prepare_request(next_link=None): params=_params, ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) else: # make call to next link with the client's api-version - _parsed_next_link = urlparse(next_link) - _next_request_params = case_insensitive_dict(parse_qs(_parsed_next_link.query)) + _parsed_next_link = urllib.parse.urlparse(next_link) + _next_request_params = case_insensitive_dict( + { + key: [urllib.parse.quote(v) for v in value] + for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items() + } + ) _next_request_params["api-version"] = self._config.api_version - request = HttpRequest("GET", urljoin(next_link, _parsed_next_link.path), params=_next_request_params) + _request = HttpRequest( + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + headers=_headers, + params=_next_request_params, + ) 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"), } - request.url = self._client.format_url(request.url, **path_format_arguments) # type: ignore + _request.url = self._client.format_url(_request.url, **path_format_arguments) - return request + return _request def extract_data(pipeline_response): deserialized = pipeline_response.http_response.json() - list_of_elem = deserialized["value"] + list_of_elem = _deserialize( + list[_models.DeviceHealth], + deserialized.get("value", []), + ) if cls: - list_of_elem = cls(list_of_elem) - return deserialized.get("nextLink", None), iter(list_of_elem) + list_of_elem = cls(list_of_elem) # type: ignore + return deserialized.get("nextLink") or None, iter(list_of_elem) def get_next(next_link=None): - request = prepare_request(next_link) + _request = prepare_request(next_link) - pipeline_response = self._client._pipeline.run( # type: ignore # pylint: disable=protected-access - request, stream=False, **kwargs + _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) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) return pipeline_response return ItemPaged(get_next, extract_data) + + @distributed_trace + def delete_deployment( # pylint: disable=inconsistent-return-statements + self, group_id: str, deployment_id: str, **kwargs: Any + ) -> None: + """Deletes a deployment. + + :param group_id: Group identifier. Required. + :type group_id: str + :param deployment_id: Deployment identifier. Required. + :type deployment_id: str + :return: None + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 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_device_management_delete_deployment_request( + group_id=group_id, + deployment_id=deployment_id, + instance_id=self._config.instance_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"), + } + _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 [204]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) + + if cls: + return cls(pipeline_response, None, {}) # type: ignore + + @distributed_trace + def delete_deployment_for_device_class_subgroup( # pylint: disable=inconsistent-return-statements,name-too-long + self, group_id: str, device_class_id: str, deployment_id: str, **kwargs: Any + ) -> None: + """Deletes a device class subgroup deployment. + + :param group_id: Group identifier. Required. + :type group_id: str + :param device_class_id: Device class identifier. Required. + :type device_class_id: str + :param deployment_id: Deployment identifier. Required. + :type deployment_id: str + :return: None + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 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_device_management_delete_deployment_for_device_class_subgroup_request( + group_id=group_id, + device_class_id=device_class_id, + deployment_id=deployment_id, + instance_id=self._config.instance_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"), + } + _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 [204]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) + + if cls: + return cls(pipeline_response, None, {}) # type: ignore diff --git a/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/operations/_patch.py b/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/operations/_patch.py index f7dd32510333..87676c65a8f0 100644 --- a/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/operations/_patch.py +++ b/sdk/deviceupdate/azure-iot-deviceupdate/azure/iot/deviceupdate/operations/_patch.py @@ -1,14 +1,15 @@ -# ------------------------------------ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. -# ------------------------------------ +# 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. +# -------------------------------------------------------------------------- """Customize generated code here. Follow our quickstart for examples: https://aka.ms/azsdk/python/dpcodegen/python/customize """ -from typing import List -__all__: List[str] = [] # Add all objects you want publicly available to users at this package level + +__all__: list[str] = [] # Add all objects you want publicly available to users at this package level def patch_sdk(): diff --git a/sdk/deviceupdate/azure-iot-deviceupdate/pyproject.toml b/sdk/deviceupdate/azure-iot-deviceupdate/pyproject.toml index 8d96766d96bb..e229dbc2160b 100644 --- a/sdk/deviceupdate/azure-iot-deviceupdate/pyproject.toml +++ b/sdk/deviceupdate/azure-iot-deviceupdate/pyproject.toml @@ -1,6 +1,82 @@ +[build-system] +requires = [ + "setuptools>=77.0.3", + "wheel", +] +build-backend = "setuptools.build_meta" + +[project] +name = "azure-iot-deviceupdate" +authors = [ + { name = "Microsoft Corporation", email = "azpysdkhelp@microsoft.com" }, +] +description = "Microsoft Corporation Azure Iot Deviceupdate Client Library for Python" +license = "MIT" +classifiers = [ + "Development Status :: 4 - Beta", + "Programming Language :: Python", + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", +] +requires-python = ">=3.10" +keywords = [ + "azure", + "azure sdk", +] +dependencies = [ + "isodate>=0.6.1", + "azure-core>=1.37.0", + "typing-extensions>=4.6.0", +] +dynamic = [ + "version", + "readme", +] + +[project.urls] +repository = "https://github.com/Azure/azure-sdk-for-python" + +[tool.setuptools.dynamic.version] +attr = "azure.iot.deviceupdate._version.VERSION" + +[tool.setuptools.dynamic.readme] +file = [ + "README.md", + "CHANGELOG.md", +] +content-type = "text/markdown" + +[tool.setuptools.packages.find] +exclude = [ + "tests*", + "generated_tests*", + "samples*", + "generated_samples*", + "doc*", + "azure", + "azure.iot", +] + +[tool.setuptools.package-data] +pytyped = [ + "py.typed", +] + [tool.azure-sdk-build] pyright = false ci_enabled = false [tool.azure-sdk-conda] in_bundle = false + +[packaging] +auto_update = false +package_name = "azure-iot-deviceupdate" +package_pprint_name = "Azure Device Update" +is_stable = false +is_arm = false diff --git a/sdk/deviceupdate/azure-iot-deviceupdate/samples/DeleteUpdate/sample_delete_update.py b/sdk/deviceupdate/azure-iot-deviceupdate/samples/DeleteUpdate/sample_delete_update.py index 9d03ed5d7f9c..7ae665b51cea 100644 --- a/sdk/deviceupdate/azure-iot-deviceupdate/samples/DeleteUpdate/sample_delete_update.py +++ b/sdk/deviceupdate/azure-iot-deviceupdate/samples/DeleteUpdate/sample_delete_update.py @@ -23,8 +23,10 @@ update_name = os.environ["DEVICEUPDATE_UPDATE_NAME"] update_version = "2022.812.234.42" # os.environ["DEVICEUPDATE_UPDATE_VERSION"] except KeyError: - print("Missing one of environment variables: DEVICEUPDATE_ENDPOINT, DEVICEUPDATE_INSTANCE_ID, " - "DEVICEUPDATE_UPDATE_PROVIDER, DEVICEUPDATE_UPDATE_NAME, DEVICEUPDATE_UPDATE_VERSION") + print( + "Missing one of environment variables: DEVICEUPDATE_ENDPOINT, DEVICEUPDATE_INSTANCE_ID, " + "DEVICEUPDATE_UPDATE_PROVIDER, DEVICEUPDATE_UPDATE_NAME, DEVICEUPDATE_UPDATE_VERSION" + ) exit() # Build a client through AAD @@ -35,4 +37,4 @@ response.wait except HttpResponseError as e: - print('Failed to delete update: {}'.format(e)) + print("Failed to delete update: {}".format(e)) diff --git a/sdk/deviceupdate/azure-iot-deviceupdate/samples/DeployUpdate/sample_deploy_update.py b/sdk/deviceupdate/azure-iot-deviceupdate/samples/DeployUpdate/sample_deploy_update.py index e56bdd7836de..cc5f98f72e45 100644 --- a/sdk/deviceupdate/azure-iot-deviceupdate/samples/DeployUpdate/sample_deploy_update.py +++ b/sdk/deviceupdate/azure-iot-deviceupdate/samples/DeployUpdate/sample_deploy_update.py @@ -27,7 +27,9 @@ group = os.environ["DEVICEUPDATE_DEVICE_GROUP"] except KeyError: print("Missing one of environment variables: DEVICEUPDATE_ENDPOINT, DEVICEUPDATE_INSTANCE_ID, ") - print("DEVICEUPDATE_DEVICE_GROUP, DEVICEUPDATE_UPDATE_PROVIDER, DEVICEUPDATE_UPDATE_NAME, DEVICEUPDATE_UPDATE_VERSION") + print( + "DEVICEUPDATE_DEVICE_GROUP, DEVICEUPDATE_UPDATE_PROVIDER, DEVICEUPDATE_UPDATE_NAME, DEVICEUPDATE_UPDATE_VERSION" + ) exit() # Build a client through AAD @@ -38,16 +40,12 @@ deployment = { "deploymentId": deployment_id, "startDateTime": str(datetime.now(timezone.utc)), - "updateId": { - "provider": update_provider, - "name": update_name, - "version": update_version - }, - "groupId": group + "updateId": {"provider": update_provider, "name": update_name, "version": update_version}, + "groupId": group, } response = client.device_management.create_or_update_deployment(group, deployment_id, deployment) response = client.device_management.get_deployment_status(group, deployment_id) print(response) except HttpResponseError as e: - print('Failed to deploy update: {}'.format(e)) + print("Failed to deploy update: {}".format(e)) diff --git a/sdk/deviceupdate/azure-iot-deviceupdate/samples/GetDevice/sample_get_device.py b/sdk/deviceupdate/azure-iot-deviceupdate/samples/GetDevice/sample_get_device.py index f062c56ebb03..7b9a00b4b8b0 100644 --- a/sdk/deviceupdate/azure-iot-deviceupdate/samples/GetDevice/sample_get_device.py +++ b/sdk/deviceupdate/azure-iot-deviceupdate/samples/GetDevice/sample_get_device.py @@ -1,3 +1,4 @@ +# pylint: disable=line-too-long,useless-suppression # ------------------------------------------------------------------------- # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. See License.txt in the project root for @@ -20,7 +21,9 @@ instance = os.environ["DEVICEUPDATE_INSTANCE_ID"] group = os.environ["DEVICEUPDATE_DEVICE_GROUP"] except KeyError: - print("Missing one of environment variables: DEVICEUPDATE_ENDPOINT, DEVICEUPDATE_INSTANCE_ID, DEVICEUPDATE_DEVICE_GROUP") + print( + "Missing one of environment variables: DEVICEUPDATE_ENDPOINT, DEVICEUPDATE_INSTANCE_ID, DEVICEUPDATE_DEVICE_GROUP" + ) exit() # Build a client through AAD @@ -52,4 +55,4 @@ print(f" {item['update']['updateId']['name']}") print(f" {item['update']['updateId']['version']}") except HttpResponseError as e: - print('Failed to get device message: {}'.format(e)) + print("Failed to get device message: {}".format(e)) diff --git a/sdk/deviceupdate/azure-iot-deviceupdate/samples/GetUpdate/sample_get_update.py b/sdk/deviceupdate/azure-iot-deviceupdate/samples/GetUpdate/sample_get_update.py index ed8ad0cd6f9f..9e65df1a9bd2 100644 --- a/sdk/deviceupdate/azure-iot-deviceupdate/samples/GetUpdate/sample_get_update.py +++ b/sdk/deviceupdate/azure-iot-deviceupdate/samples/GetUpdate/sample_get_update.py @@ -23,8 +23,10 @@ update_name = os.environ["DEVICEUPDATE_UPDATE_NAME"] update_version = os.environ["DEVICEUPDATE_UPDATE_VERSION"] except KeyError: - print("Missing one of environment variables: DEVICEUPDATE_ENDPOINT, DEVICEUPDATE_INSTANCE_ID, " - "DEVICEUPDATE_UPDATE_PROVIDER, DEVICEUPDATE_UPDATE_NAME, DEVICEUPDATE_UPDATE_VERSION") + print( + "Missing one of environment variables: DEVICEUPDATE_ENDPOINT, DEVICEUPDATE_INSTANCE_ID, " + "DEVICEUPDATE_UPDATE_PROVIDER, DEVICEUPDATE_UPDATE_NAME, DEVICEUPDATE_UPDATE_VERSION" + ) exit() # Build a client through AAD @@ -56,4 +58,4 @@ print(response) except HttpResponseError as e: - print('Failed to get update: {}'.format(e)) + print("Failed to get update: {}".format(e)) diff --git a/sdk/deviceupdate/azure-iot-deviceupdate/samples/ImportUpdate/sample_import_update.py b/sdk/deviceupdate/azure-iot-deviceupdate/samples/ImportUpdate/sample_import_update.py index d1a2f377ef8b..ea85becdf7eb 100644 --- a/sdk/deviceupdate/azure-iot-deviceupdate/samples/ImportUpdate/sample_import_update.py +++ b/sdk/deviceupdate/azure-iot-deviceupdate/samples/ImportUpdate/sample_import_update.py @@ -27,8 +27,10 @@ manifest_file = os.environ["DEVICEUPDATE_MANIFEST_FILE"] manifest_url = os.environ["DEVICEUPDATE_MANIFEST_URL"] except KeyError: - print("Missing one of environment variables: DEVICEUPDATE_ENDPOINT, DEVICEUPDATE_INSTANCE_ID, " - "DEVICEUPDATE_PAYLOAD_FILE, DEVICEUPDATE_PAYLOAD_URL, DEVICEUPDATE_MANIFEST_FILE, DEVICEUPDATE_MANIFEST_URL") + print( + "Missing one of environment variables: DEVICEUPDATE_ENDPOINT, DEVICEUPDATE_INSTANCE_ID, " + "DEVICEUPDATE_PAYLOAD_FILE, DEVICEUPDATE_PAYLOAD_URL, DEVICEUPDATE_MANIFEST_FILE, DEVICEUPDATE_MANIFEST_URL" + ) exit() @@ -46,25 +48,20 @@ def get_file_hash(file_path): client = DeviceUpdateClient(credential=DefaultAzureCredential(), endpoint=endpoint, instance_id=instance) try: - content = [{ - "importManifest": { - "url": manifest_url, - "sizeInBytes": get_file_size(manifest_file), - "hashes": { - "sha256": get_file_hash(manifest_file) - } - }, - "files": [{ - "fileName": os.path.basename(payload_file), - "url": payload_url - }] - }] + content = [ + { + "importManifest": { + "url": manifest_url, + "sizeInBytes": get_file_size(manifest_file), + "hashes": {"sha256": get_file_hash(manifest_file)}, + }, + "files": [{"fileName": os.path.basename(payload_file), "url": payload_url}], + } + ] response = client.device_update.begin_import_update(content) response.wait print(response.result()) except HttpResponseError as e: - print('Failed to import update: {}'.format(e)) - - + print("Failed to import update: {}".format(e)) diff --git a/sdk/deviceupdate/azure-iot-deviceupdate/samples/ListUpdates/sample_list_updates.py b/sdk/deviceupdate/azure-iot-deviceupdate/samples/ListUpdates/sample_list_updates.py index 95e178f02a63..7c1ee632caca 100644 --- a/sdk/deviceupdate/azure-iot-deviceupdate/samples/ListUpdates/sample_list_updates.py +++ b/sdk/deviceupdate/azure-iot-deviceupdate/samples/ListUpdates/sample_list_updates.py @@ -23,8 +23,10 @@ update_name = os.environ["DEVICEUPDATE_UPDATE_NAME"] update_version = os.environ["DEVICEUPDATE_UPDATE_VERSION"] except KeyError: - print("Missing one of environment variables: DEVICEUPDATE_ENDPOINT, DEVICEUPDATE_INSTANCE_ID, " - "DEVICEUPDATE_UPDATE_PROVIDER, DEVICEUPDATE_UPDATE_NAME, DEVICEUPDATE_UPDATE_VERSION") + print( + "Missing one of environment variables: DEVICEUPDATE_ENDPOINT, DEVICEUPDATE_INSTANCE_ID, " + "DEVICEUPDATE_UPDATE_PROVIDER, DEVICEUPDATE_UPDATE_NAME, DEVICEUPDATE_UPDATE_VERSION" + ) exit() # Build a client through AAD @@ -48,4 +50,4 @@ for item in response: print(f" {item}") except HttpResponseError as e: - print('Failed to get data: {}'.format(e)) + print("Failed to get data: {}".format(e)) diff --git a/sdk/deviceupdate/azure-iot-deviceupdate/sdk_packaging.toml b/sdk/deviceupdate/azure-iot-deviceupdate/sdk_packaging.toml deleted file mode 100644 index bf5e3af204e6..000000000000 --- a/sdk/deviceupdate/azure-iot-deviceupdate/sdk_packaging.toml +++ /dev/null @@ -1,6 +0,0 @@ -[packaging] -auto_update = false -package_name = "azure-iot-deviceupdate" -package_pprint_name = "Azure Device Update" -is_stable = false -is_arm = false diff --git a/sdk/deviceupdate/azure-iot-deviceupdate/setup.py b/sdk/deviceupdate/azure-iot-deviceupdate/setup.py deleted file mode 100644 index 4ba12b083a3d..000000000000 --- a/sdk/deviceupdate/azure-iot-deviceupdate/setup.py +++ /dev/null @@ -1,75 +0,0 @@ -#!/usr/bin/env python - -#------------------------------------------------------------------------- -# 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 os.path -from io import open -from setuptools import find_packages, setup - -# Change the PACKAGE_NAME only to change folder and different name -PACKAGE_NAME = "azure-iot-deviceupdate" -PACKAGE_PPRINT_NAME = "Azure Device Update" - -# 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: - readme = f.read() -with open('CHANGELOG.md', encoding='utf-8') as f: - changelog = f.read() - -setup( - name=PACKAGE_NAME, - version=version, - description='Microsoft {} Client Library for Python'.format(PACKAGE_PPRINT_NAME), - long_description=readme + "\n\n" + changelog, - long_description_content_type='text/markdown', - license='MIT License', - author='Microsoft Corporation', - author_email='adupmdevteam@microsoft.com', - url='https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/deviceupdate/azure-iot-deviceupdate', - keywords="azure, azure sdk", - classifiers=[ - "Development Status :: 5 - Production/Stable", - "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", - "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.iot', - ]), - include_package_data=True, - package_data={ - 'pytyped': ['py.typed'], - }, - install_requires=[ - "isodate<1.0.0,>=0.6.1", - "azure-core<2.0.0,>=1.24.0", - ], - python_requires=">=3.6", -) diff --git a/sdk/deviceupdate/azure-iot-deviceupdate/tests/test_management_service.py b/sdk/deviceupdate/azure-iot-deviceupdate/tests/test_management_service.py index 2d45cd5408cc..b30f5c590855 100644 --- a/sdk/deviceupdate/azure-iot-deviceupdate/tests/test_management_service.py +++ b/sdk/deviceupdate/azure-iot-deviceupdate/tests/test_management_service.py @@ -9,14 +9,11 @@ from azure.core.exceptions import ResourceNotFoundError import pytest + class TestDeviceManagementClient(DeviceUpdateTest): @recorded_by_proxy @DeviceUpdatePowerShellPreparer() - def test_get_devices( - self, - deviceupdate_endpoint, - deviceupdate_instance_id - ): + def test_get_devices(self, deviceupdate_endpoint, deviceupdate_instance_id): client = self.create_client(endpoint=deviceupdate_endpoint, instance_id=deviceupdate_instance_id) try: response = client.device_management.list_devices() @@ -27,11 +24,7 @@ def test_get_devices( @recorded_by_proxy @DeviceUpdatePowerShellPreparer() - def test_get_device_not_found( - self, - deviceupdate_endpoint, - deviceupdate_instance_id - ): + def test_get_device_not_found(self, deviceupdate_endpoint, deviceupdate_instance_id): client = self.create_client(endpoint=deviceupdate_endpoint, instance_id=deviceupdate_instance_id) try: client.device_management.get_device("foo") @@ -41,11 +34,7 @@ def test_get_device_not_found( @recorded_by_proxy @DeviceUpdatePowerShellPreparer() - def test_get_groups( - self, - deviceupdate_endpoint, - deviceupdate_instance_id - ): + def test_get_groups(self, deviceupdate_endpoint, deviceupdate_instance_id): client = self.create_client(endpoint=deviceupdate_endpoint, instance_id=deviceupdate_instance_id) try: response = client.device_management.list_groups() @@ -56,23 +45,14 @@ def test_get_groups( @recorded_by_proxy @DeviceUpdatePowerShellPreparer() - def test_get_group( - self, - deviceupdate_endpoint, - deviceupdate_instance_id, - deviceupdate_device_group - ): + def test_get_group(self, deviceupdate_endpoint, deviceupdate_instance_id, deviceupdate_device_group): client = self.create_client(endpoint=deviceupdate_endpoint, instance_id=deviceupdate_instance_id) response = client.device_management.get_group(deviceupdate_device_group) assert response is not None @recorded_by_proxy @DeviceUpdatePowerShellPreparer() - def test_get_group_not_found( - self, - deviceupdate_endpoint, - deviceupdate_instance_id - ): + def test_get_group_not_found(self, deviceupdate_endpoint, deviceupdate_instance_id): client = self.create_client(endpoint=deviceupdate_endpoint, instance_id=deviceupdate_instance_id) try: client.device_management.get_group("foo") @@ -82,11 +62,7 @@ def test_get_group_not_found( @recorded_by_proxy @DeviceUpdatePowerShellPreparer() - def _test_get_device_classes( - self, - deviceupdate_endpoint, - deviceupdate_instance_id - ): + def _test_get_device_classes(self, deviceupdate_endpoint, deviceupdate_instance_id): client = self.create_client(endpoint=deviceupdate_endpoint, instance_id=deviceupdate_instance_id) try: response = client.device_management.list_device_classes() @@ -97,11 +73,7 @@ def _test_get_device_classes( @recorded_by_proxy @DeviceUpdatePowerShellPreparer() - def test_get_device_class_not_found( - self, - deviceupdate_endpoint, - deviceupdate_instance_id - ): + def test_get_device_class_not_found(self, deviceupdate_endpoint, deviceupdate_instance_id): client = self.create_client(endpoint=deviceupdate_endpoint, instance_id=deviceupdate_instance_id) try: client.device_management.get_device_class("foo") @@ -112,10 +84,7 @@ def test_get_device_class_not_found( @recorded_by_proxy @DeviceUpdatePowerShellPreparer() def _test_get_best_updates_for_group( - self, - deviceupdate_endpoint, - deviceupdate_instance_id, - deviceupdate_device_group + self, deviceupdate_endpoint, deviceupdate_instance_id, deviceupdate_device_group ): client = self.create_client(endpoint=deviceupdate_endpoint, instance_id=deviceupdate_instance_id) response = client.device_management.list_best_updates_for_group(deviceupdate_device_group) @@ -124,11 +93,7 @@ def _test_get_best_updates_for_group( @recorded_by_proxy @DeviceUpdatePowerShellPreparer() - def test_get_best_updates_for_group_not_found( - self, - deviceupdate_endpoint, - deviceupdate_instance_id - ): + def test_get_best_updates_for_group_not_found(self, deviceupdate_endpoint, deviceupdate_instance_id): client = self.create_client(endpoint=deviceupdate_endpoint, instance_id=deviceupdate_instance_id) try: response = client.device_management.list_best_updates_for_group("foo") @@ -140,10 +105,7 @@ def test_get_best_updates_for_group_not_found( @recorded_by_proxy @DeviceUpdatePowerShellPreparer() def _test_get_deployments_for_group( - self, - deviceupdate_endpoint, - deviceupdate_instance_id, - deviceupdate_device_group + self, deviceupdate_endpoint, deviceupdate_instance_id, deviceupdate_device_group ): client = self.create_client(endpoint=deviceupdate_endpoint, instance_id=deviceupdate_instance_id) response = client.device_management.list_best_updates_for_group(deviceupdate_device_group) @@ -152,11 +114,7 @@ def _test_get_deployments_for_group( @recorded_by_proxy @DeviceUpdatePowerShellPreparer() - def test_get_deployments_for_group_not_found( - self, - deviceupdate_endpoint, - deviceupdate_instance_id - ): + def test_get_deployments_for_group_not_found(self, deviceupdate_endpoint, deviceupdate_instance_id): client = self.create_client(endpoint=deviceupdate_endpoint, instance_id=deviceupdate_instance_id) try: response = client.device_management.list_best_updates_for_group("foo") @@ -164,4 +122,3 @@ def test_get_deployments_for_group_not_found( assert len(result) > 0 except ResourceNotFoundError as e: assert 404 == e.status_code - diff --git a/sdk/deviceupdate/azure-iot-deviceupdate/tests/test_updates_service.py b/sdk/deviceupdate/azure-iot-deviceupdate/tests/test_updates_service.py index 22cbda39cec1..055c7866622e 100644 --- a/sdk/deviceupdate/azure-iot-deviceupdate/tests/test_updates_service.py +++ b/sdk/deviceupdate/azure-iot-deviceupdate/tests/test_updates_service.py @@ -15,9 +15,9 @@ class TestDeviceUpdateClient(DeviceUpdateTest): @recorded_by_proxy @DeviceUpdatePowerShellPreparer() def test_get_update_providers( - self, - deviceupdate_endpoint, - deviceupdate_instance_id, + self, + deviceupdate_endpoint, + deviceupdate_instance_id, ): client = self.create_client(endpoint=deviceupdate_endpoint, instance_id=deviceupdate_instance_id) try: @@ -30,10 +30,10 @@ def test_get_update_providers( @recorded_by_proxy @DeviceUpdatePowerShellPreparer() def test_get_update_names( - self, - deviceupdate_endpoint, - deviceupdate_instance_id, - deviceupdate_update_provider, + self, + deviceupdate_endpoint, + deviceupdate_instance_id, + deviceupdate_update_provider, ): client = self.create_client(endpoint=deviceupdate_endpoint, instance_id=deviceupdate_instance_id) try: @@ -46,9 +46,9 @@ def test_get_update_names( @recorded_by_proxy @DeviceUpdatePowerShellPreparer() def test_get_update_names_not_found( - self, - deviceupdate_endpoint, - deviceupdate_instance_id, + self, + deviceupdate_endpoint, + deviceupdate_instance_id, ): client = self.create_client(endpoint=deviceupdate_endpoint, instance_id=deviceupdate_instance_id) try: @@ -61,11 +61,11 @@ def test_get_update_names_not_found( @recorded_by_proxy @DeviceUpdatePowerShellPreparer() def test_get_update_versions( - self, - deviceupdate_endpoint, - deviceupdate_instance_id, - deviceupdate_update_provider, - deviceupdate_update_name, + self, + deviceupdate_endpoint, + deviceupdate_instance_id, + deviceupdate_update_provider, + deviceupdate_update_name, ): client = self.create_client(endpoint=deviceupdate_endpoint, instance_id=deviceupdate_instance_id) try: @@ -78,9 +78,9 @@ def test_get_update_versions( @recorded_by_proxy @DeviceUpdatePowerShellPreparer() def test_get_update_versions_not_found( - self, - deviceupdate_endpoint, - deviceupdate_instance_id, + self, + deviceupdate_endpoint, + deviceupdate_instance_id, ): client = self.create_client(endpoint=deviceupdate_endpoint, instance_id=deviceupdate_instance_id) try: @@ -93,23 +93,25 @@ def test_get_update_versions_not_found( @recorded_by_proxy @DeviceUpdatePowerShellPreparer() def test_get_update( - self, - deviceupdate_endpoint, - deviceupdate_instance_id, - deviceupdate_update_provider, - deviceupdate_update_name, - deviceupdate_update_version, + self, + deviceupdate_endpoint, + deviceupdate_instance_id, + deviceupdate_update_provider, + deviceupdate_update_name, + deviceupdate_update_version, ): client = self.create_client(endpoint=deviceupdate_endpoint, instance_id=deviceupdate_instance_id) - response = client.device_update.get_update(deviceupdate_update_provider, deviceupdate_update_name, deviceupdate_update_version) + response = client.device_update.get_update( + deviceupdate_update_provider, deviceupdate_update_name, deviceupdate_update_version + ) assert response is not None @recorded_by_proxy @DeviceUpdatePowerShellPreparer() def test_get_update_not_found( - self, - deviceupdate_endpoint, - deviceupdate_instance_id, + self, + deviceupdate_endpoint, + deviceupdate_instance_id, ): client = self.create_client(endpoint=deviceupdate_endpoint, instance_id=deviceupdate_instance_id) try: @@ -121,16 +123,18 @@ def test_get_update_not_found( @recorded_by_proxy @DeviceUpdatePowerShellPreparer() def test_get_update_files( - self, - deviceupdate_endpoint, - deviceupdate_instance_id, - deviceupdate_update_provider, - deviceupdate_update_name, - deviceupdate_update_version, + self, + deviceupdate_endpoint, + deviceupdate_instance_id, + deviceupdate_update_provider, + deviceupdate_update_name, + deviceupdate_update_version, ): client = self.create_client(endpoint=deviceupdate_endpoint, instance_id=deviceupdate_instance_id) try: - response = client.device_update.list_files(deviceupdate_update_provider, deviceupdate_update_name, deviceupdate_update_version) + response = client.device_update.list_files( + deviceupdate_update_provider, deviceupdate_update_name, deviceupdate_update_version + ) result = [item for item in response] assert len(result) > 0 except ResourceNotFoundError as e: @@ -139,9 +143,9 @@ def test_get_update_files( @recorded_by_proxy @DeviceUpdatePowerShellPreparer() def test_get_update_files_not_found( - self, - deviceupdate_endpoint, - deviceupdate_instance_id, + self, + deviceupdate_endpoint, + deviceupdate_instance_id, ): client = self.create_client(endpoint=deviceupdate_endpoint, instance_id=deviceupdate_instance_id) try: diff --git a/sdk/deviceupdate/azure-iot-deviceupdate/tests/testcase.py b/sdk/deviceupdate/azure-iot-deviceupdate/tests/testcase.py index b25f44dd4e2c..e48cbadc4f6c 100644 --- a/sdk/deviceupdate/azure-iot-deviceupdate/tests/testcase.py +++ b/sdk/deviceupdate/azure-iot-deviceupdate/tests/testcase.py @@ -13,10 +13,7 @@ class DeviceUpdateTest(AzureRecordedTestCase): def create_client(self, endpoint, instance_id): credential = self.get_credential(DeviceUpdateClient) return self.create_client_from_credential( - DeviceUpdateClient, - endpoint=endpoint, - instance_id=instance_id, - credential=credential + DeviceUpdateClient, endpoint=endpoint, instance_id=instance_id, credential=credential ) @@ -28,5 +25,5 @@ def create_client(self, endpoint, instance_id): deviceupdate_update_provider="foo", deviceupdate_update_name="bar", deviceupdate_update_version="1.2", - deviceupdate_device_group="foo" + deviceupdate_device_group="foo", ) diff --git a/sdk/deviceupdate/azure-iot-deviceupdate/tsp-location.yaml b/sdk/deviceupdate/azure-iot-deviceupdate/tsp-location.yaml new file mode 100644 index 000000000000..dfe6b1560ec3 --- /dev/null +++ b/sdk/deviceupdate/azure-iot-deviceupdate/tsp-location.yaml @@ -0,0 +1,4 @@ +directory: specification/deviceupdate/data-plane/duiothub +commit: 292231b1131ff9fd070377372a0647c6ac7a6ce2 +repo: Azure/azure-rest-api-specs +additionalDirectories: