From f73471a711e1c012c6aaec82a177302a3d83ce26 Mon Sep 17 00:00:00 2001 From: Krista Pratico Date: Mon, 4 May 2020 17:50:15 -0700 Subject: [PATCH 01/22] add copy feature gen code --- .../ai/formrecognizer/_generated/__init__.py | 2 +- .../_generated/_configuration.py | 3 +- .../_generated/_form_recognizer_client.py | 2 +- .../ai/formrecognizer/_generated/_version.py | 4 +- .../formrecognizer/_generated/aio/__init__.py | 2 +- .../_generated/aio/_configuration_async.py | 3 +- .../aio/_form_recognizer_client_async.py | 2 +- .../aio/operations_async/__init__.py | 2 +- ...form_recognizer_client_operations_async.py | 250 +++++++++++++++-- .../_generated/models/__init__.py | 14 +- .../models/_form_recognizer_client_enums.py | 2 +- .../_generated/models/_models.py | 144 +++++++++- .../_generated/models/_models_py3.py | 160 ++++++++++- .../_generated/operations/__init__.py | 2 +- .../_form_recognizer_client_operations.py | 254 ++++++++++++++++-- 15 files changed, 798 insertions(+), 48 deletions(-) diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/__init__.py b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/__init__.py index cddb554367aa..bbb35174dae1 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/__init__.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/__init__.py @@ -1,6 +1,6 @@ # coding=utf-8 # -------------------------------------------------------------------------- -# Code generated by Microsoft (R) AutoRest Code Generator (autorest: 3.0.6246, generator: {generator}) +# Code generated by Microsoft (R) AutoRest Code Generator (autorest: 3.0.6282, generator: {generator}) # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/_configuration.py b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/_configuration.py index 2a292d8c068a..db0a5e6f5c48 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/_configuration.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/_configuration.py @@ -1,6 +1,6 @@ # coding=utf-8 # -------------------------------------------------------------------------- -# Code generated by Microsoft (R) AutoRest Code Generator (autorest: 3.0.6246, generator: {generator}) +# Code generated by Microsoft (R) AutoRest Code Generator (autorest: 3.0.6282, generator: {generator}) # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- @@ -46,6 +46,7 @@ def __init__( self.credential = credential self.endpoint = endpoint self.credential_scopes = ['https://cognitiveservices.azure.com/.default'] + self.credential_scopes.extend(kwargs.pop('credential_scopes', [])) kwargs.setdefault('sdk_moniker', 'ai-formrecognizer/{}'.format(VERSION)) self._configure(**kwargs) diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/_form_recognizer_client.py b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/_form_recognizer_client.py index be5f79b99ff9..ad4fc9939ad0 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/_form_recognizer_client.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/_form_recognizer_client.py @@ -1,6 +1,6 @@ # coding=utf-8 # -------------------------------------------------------------------------- -# Code generated by Microsoft (R) AutoRest Code Generator (autorest: 3.0.6246, generator: {generator}) +# Code generated by Microsoft (R) AutoRest Code Generator (autorest: 3.0.6282, generator: {generator}) # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/_version.py b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/_version.py index 257ed871fc93..4b19902c2480 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/_version.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/_version.py @@ -1,7 +1,7 @@ # coding=utf-8 # -------------------------------------------------------------------------- -# Code generated by Microsoft (R) AutoRest Code Generator (autorest: 3.0.6246, generator: {generator}) +# Code generated by Microsoft (R) AutoRest Code Generator (autorest: 3.0.6282, generator: {generator}) # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- -VERSION = "1.0.0b1" +VERSION = "1.0.0b2" diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/aio/__init__.py b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/aio/__init__.py index f37952aa7a51..8e5a144b5cf0 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/aio/__init__.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/aio/__init__.py @@ -1,6 +1,6 @@ # coding=utf-8 # -------------------------------------------------------------------------- -# Code generated by Microsoft (R) AutoRest Code Generator (autorest: 3.0.6246, generator: {generator}) +# Code generated by Microsoft (R) AutoRest Code Generator (autorest: 3.0.6282, generator: {generator}) # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/aio/_configuration_async.py b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/aio/_configuration_async.py index 44cffe657f45..5a4c7f8cb2eb 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/aio/_configuration_async.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/aio/_configuration_async.py @@ -1,6 +1,6 @@ # coding=utf-8 # -------------------------------------------------------------------------- -# Code generated by Microsoft (R) AutoRest Code Generator (autorest: 3.0.6246, generator: {generator}) +# Code generated by Microsoft (R) AutoRest Code Generator (autorest: 3.0.6282, generator: {generator}) # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- @@ -43,6 +43,7 @@ def __init__( self.credential = credential self.endpoint = endpoint self.credential_scopes = ['https://cognitiveservices.azure.com/.default'] + self.credential_scopes.extend(kwargs.pop('credential_scopes', [])) kwargs.setdefault('sdk_moniker', 'ai-formrecognizer/{}'.format(VERSION)) self._configure(**kwargs) diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/aio/_form_recognizer_client_async.py b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/aio/_form_recognizer_client_async.py index 5ede3dadd72c..c084748c0821 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/aio/_form_recognizer_client_async.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/aio/_form_recognizer_client_async.py @@ -1,6 +1,6 @@ # coding=utf-8 # -------------------------------------------------------------------------- -# Code generated by Microsoft (R) AutoRest Code Generator (autorest: 3.0.6246, generator: {generator}) +# Code generated by Microsoft (R) AutoRest Code Generator (autorest: 3.0.6282, generator: {generator}) # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/aio/operations_async/__init__.py b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/aio/operations_async/__init__.py index 8d1731ea865d..6711b796ba93 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/aio/operations_async/__init__.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/aio/operations_async/__init__.py @@ -1,6 +1,6 @@ # coding=utf-8 # -------------------------------------------------------------------------- -# Code generated by Microsoft (R) AutoRest Code Generator (autorest: 3.0.6246, generator: {generator}) +# Code generated by Microsoft (R) AutoRest Code Generator (autorest: 3.0.6282, generator: {generator}) # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/aio/operations_async/_form_recognizer_client_operations_async.py b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/aio/operations_async/_form_recognizer_client_operations_async.py index cf80151ed32b..64ce71c09954 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/aio/operations_async/_form_recognizer_client_operations_async.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/aio/operations_async/_form_recognizer_client_operations_async.py @@ -1,6 +1,6 @@ # coding=utf-8 # -------------------------------------------------------------------------- -# Code generated by Microsoft (R) AutoRest Code Generator (autorest: 3.0.6246, generator: {generator}) +# Code generated by Microsoft (R) AutoRest Code Generator (autorest: 3.0.6282, generator: {generator}) # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- from typing import Any, AsyncIterable, Callable, Dict, Generic, Optional, TypeVar, Union @@ -40,7 +40,8 @@ async def train_custom_model_async( :raises: ~azure.core.exceptions.HttpResponseError """ cls = kwargs.pop('cls', None) # type: ClsType[None] - error_map = kwargs.pop('error_map', {404: ResourceNotFoundError, 409: ResourceExistsError}) + error_map = {404: ResourceNotFoundError, 409: ResourceExistsError} + error_map.update(kwargs.pop('error_map', {})) content_type = kwargs.pop("content_type", "application/json") # Construct URL @@ -100,7 +101,8 @@ async def get_custom_model( :raises: ~azure.core.exceptions.HttpResponseError """ cls = kwargs.pop('cls', None) # type: ClsType["models.Model"] - error_map = kwargs.pop('error_map', {404: ResourceNotFoundError, 409: ResourceExistsError}) + error_map = {404: ResourceNotFoundError, 409: ResourceExistsError} + error_map.update(kwargs.pop('error_map', {})) # Construct URL url = self.get_custom_model.metadata['url'] # type: ignore @@ -155,7 +157,8 @@ async def delete_custom_model( :raises: ~azure.core.exceptions.HttpResponseError """ cls = kwargs.pop('cls', None) # type: ClsType[None] - error_map = kwargs.pop('error_map', {404: ResourceNotFoundError, 409: ResourceExistsError}) + error_map = {404: ResourceNotFoundError, 409: ResourceExistsError} + error_map.update(kwargs.pop('error_map', {})) # Construct URL url = self.delete_custom_model.metadata['url'] # type: ignore @@ -194,7 +197,8 @@ async def _analyze_with_custom_model_initial( **kwargs ) -> None: cls = kwargs.pop('cls', None) # type: ClsType[None] - error_map = kwargs.pop('error_map', {404: ResourceNotFoundError, 409: ResourceExistsError}) + error_map = {404: ResourceNotFoundError, 409: ResourceExistsError} + error_map.update(kwargs.pop('error_map', {})) content_type = kwargs.pop("content_type", "application/json") # Construct URL @@ -318,7 +322,8 @@ async def get_analyze_form_result( :raises: ~azure.core.exceptions.HttpResponseError """ cls = kwargs.pop('cls', None) # type: ClsType["models.AnalyzeOperationResult"] - error_map = kwargs.pop('error_map', {404: ResourceNotFoundError, 409: ResourceExistsError}) + error_map = {404: ResourceNotFoundError, 409: ResourceExistsError} + error_map.update(kwargs.pop('error_map', {})) # Construct URL url = self.get_analyze_form_result.metadata['url'] # type: ignore @@ -354,6 +359,211 @@ async def get_analyze_form_result( return deserialized get_analyze_form_result.metadata = {'url': '/custom/models/{modelId}/analyzeResults/{resultId}'} # type: ignore + async def _copy_custom_model_initial( + self, + model_id: str, + copy_request: "models.CopyRequest", + **kwargs + ) -> None: + cls = kwargs.pop('cls', None) # type: ClsType[None] + error_map = {404: ResourceNotFoundError, 409: ResourceExistsError} + error_map.update(kwargs.pop('error_map', {})) + content_type = kwargs.pop("content_type", "application/json") + + # Construct URL + url = self._copy_custom_model_initial.metadata['url'] # type: ignore + path_format_arguments = { + 'endpoint': self._serialize.url("self._config.endpoint", self._config.endpoint, 'str', skip_quote=True), + 'modelId': self._serialize.url("model_id", model_id, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Content-Type'] = self._serialize.header("content_type", content_type, 'str') + + # Construct and send request + body_content_kwargs = {} # type: Dict[str, Any] + body_content = self._serialize.body(copy_request, 'CopyRequest') + body_content_kwargs['content'] = body_content + request = self._client.post(url, query_parameters, header_parameters, **body_content_kwargs) + + pipeline_response = await self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [202]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize(models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers['Operation-Location']=self._deserialize('str', response.headers.get('Operation-Location')) + + if cls: + return cls(pipeline_response, None, response_headers) + + _copy_custom_model_initial.metadata = {'url': '/custom/models/{modelId}/copy'} # type: ignore + + @distributed_trace_async + async def copy_custom_model( + self, + model_id: str, + copy_request: "models.CopyRequest", + **kwargs + ) -> None: + """Copy custom model stored in this resource (the source) to user specified target Form Recognizer resource. + + Copy Custom Model. + + :param model_id: Model identifier. + :type model_id: str + :param copy_request: Copy request parameters. + :type copy_request: ~azure.ai.formrecognizer.models.CopyRequest + :keyword callable cls: A custom type or function that will be passed the direct response + :keyword polling: True for ARMPolling, False for no polling, or a + polling object for 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: None + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + polling = kwargs.pop('polling', False) # type: Union[bool, AsyncPollingMethod] + cls = kwargs.pop('cls', None) # type: ClsType[None] + lro_delay = kwargs.pop( + 'polling_interval', + self._config.polling_interval + ) + raw_result = await self._copy_custom_model_initial( + model_id=model_id, + copy_request=copy_request, + cls=lambda x,y,z: x, + **kwargs + ) + + def get_long_running_output(pipeline_response): + if cls: + return cls(pipeline_response, None, {}) + + if polling is True: polling_method = AsyncLROBasePolling(lro_delay, **kwargs) + elif polling is False: polling_method = AsyncNoPolling() + else: polling_method = polling + return await async_poller(self._client, raw_result, get_long_running_output, polling_method) + copy_custom_model.metadata = {'url': '/custom/models/{modelId}/copy'} # type: ignore + + @distributed_trace_async + async def get_custom_model_copy_result( + self, + model_id: str, + result_id: str, + **kwargs + ) -> "models.CopyOperationResult": + """Obtain current status and the result of a custom model copy operation. + + Get Custom Model Copy Result. + + :param model_id: Model identifier. + :type model_id: str + :param result_id: Copy operation result identifier. + :type result_id: str + :keyword callable cls: A custom type or function that will be passed the direct response + :return: CopyOperationResult or the result of cls(response) + :rtype: ~azure.ai.formrecognizer.models.CopyOperationResult + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["models.CopyOperationResult"] + error_map = {404: ResourceNotFoundError, 409: ResourceExistsError} + error_map.update(kwargs.pop('error_map', {})) + + # Construct URL + url = self.get_custom_model_copy_result.metadata['url'] # type: ignore + path_format_arguments = { + 'endpoint': self._serialize.url("self._config.endpoint", self._config.endpoint, 'str', skip_quote=True), + 'modelId': self._serialize.url("model_id", model_id, 'str'), + 'resultId': self._serialize.url("result_id", result_id, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = 'application/json' + + # Construct and send request + request = self._client.get(url, query_parameters, header_parameters) + pipeline_response = await self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize(models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error) + + deserialized = self._deserialize('CopyOperationResult', pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + get_custom_model_copy_result.metadata = {'url': '/custom/models/{modelId}/copyResults/{resultId}'} # type: ignore + + @distributed_trace_async + async def generate_model_copy_authorization( + self, + **kwargs + ) -> "models.CopyAuthorizationResult": + """Generate authorization to copy a model into the target Form Recognizer resource. + + Generate Copy Authorization. + + :keyword callable cls: A custom type or function that will be passed the direct response + :return: CopyAuthorizationResult or the result of cls(response) + :rtype: ~azure.ai.formrecognizer.models.CopyAuthorizationResult + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["models.CopyAuthorizationResult"] + error_map = {404: ResourceNotFoundError, 409: ResourceExistsError} + error_map.update(kwargs.pop('error_map', {})) + + # Construct URL + url = self.generate_model_copy_authorization.metadata['url'] # type: ignore + path_format_arguments = { + 'endpoint': self._serialize.url("self._config.endpoint", self._config.endpoint, 'str', skip_quote=True), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = 'application/json' + + # Construct and send request + request = self._client.post(url, query_parameters, header_parameters) + pipeline_response = await self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [201]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize(models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers['Location']=self._deserialize('str', response.headers.get('Location')) + deserialized = self._deserialize('CopyAuthorizationResult', pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, response_headers) + + return deserialized + generate_model_copy_authorization.metadata = {'url': '/custom/models/copyAuthorization'} # type: ignore + async def _analyze_receipt_async_initial( self, include_text_details: Optional[bool] = False, @@ -361,7 +571,8 @@ async def _analyze_receipt_async_initial( **kwargs ) -> None: cls = kwargs.pop('cls', None) # type: ClsType[None] - error_map = kwargs.pop('error_map', {404: ResourceNotFoundError, 409: ResourceExistsError}) + error_map = {404: ResourceNotFoundError, 409: ResourceExistsError} + error_map.update(kwargs.pop('error_map', {})) content_type = kwargs.pop("content_type", "application/json") # Construct URL @@ -477,7 +688,8 @@ async def get_analyze_receipt_result( :raises: ~azure.core.exceptions.HttpResponseError """ cls = kwargs.pop('cls', None) # type: ClsType["models.AnalyzeOperationResult"] - error_map = kwargs.pop('error_map', {404: ResourceNotFoundError, 409: ResourceExistsError}) + error_map = {404: ResourceNotFoundError, 409: ResourceExistsError} + error_map.update(kwargs.pop('error_map', {})) # Construct URL url = self.get_analyze_receipt_result.metadata['url'] # type: ignore @@ -518,7 +730,8 @@ async def _analyze_layout_async_initial( **kwargs ) -> None: cls = kwargs.pop('cls', None) # type: ClsType[None] - error_map = kwargs.pop('error_map', {404: ResourceNotFoundError, 409: ResourceExistsError}) + error_map = {404: ResourceNotFoundError, 409: ResourceExistsError} + error_map.update(kwargs.pop('error_map', {})) content_type = kwargs.pop("content_type", "application/json") # Construct URL @@ -628,7 +841,8 @@ async def get_analyze_layout_result( :raises: ~azure.core.exceptions.HttpResponseError """ cls = kwargs.pop('cls', None) # type: ClsType["models.AnalyzeOperationResult"] - error_map = kwargs.pop('error_map', {404: ResourceNotFoundError, 409: ResourceExistsError}) + error_map = {404: ResourceNotFoundError, 409: ResourceExistsError} + error_map.update(kwargs.pop('error_map', {})) # Construct URL url = self.get_analyze_layout_result.metadata['url'] # type: ignore @@ -678,7 +892,8 @@ def list_custom_models( :raises: ~azure.core.exceptions.HttpResponseError """ cls = kwargs.pop('cls', None) # type: ClsType["models.Models"] - error_map = kwargs.pop('error_map', {404: ResourceNotFoundError, 409: ResourceExistsError}) + error_map = {404: ResourceNotFoundError, 409: ResourceExistsError} + error_map.update(kwargs.pop('error_map', {})) op = "full" def prepare_request(next_link=None): @@ -689,17 +904,17 @@ def prepare_request(next_link=None): 'endpoint': self._serialize.url("self._config.endpoint", self._config.endpoint, 'str', skip_quote=True), } url = self._client.format_url(url, **path_format_arguments) + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['op'] = self._serialize.query("op", op, 'str') + else: url = next_link + query_parameters = {} # type: Dict[str, Any] path_format_arguments = { 'endpoint': self._serialize.url("self._config.endpoint", self._config.endpoint, 'str', skip_quote=True), } url = self._client.format_url(url, **path_format_arguments) - - # Construct parameters - query_parameters = {} # type: Dict[str, Any] - query_parameters['op'] = self._serialize.query("op", op, 'str') - # Construct headers header_parameters = {} # type: Dict[str, Any] header_parameters['Accept'] = 'application/json' @@ -748,7 +963,8 @@ async def get_custom_models( :raises: ~azure.core.exceptions.HttpResponseError """ cls = kwargs.pop('cls', None) # type: ClsType["models.Models"] - error_map = kwargs.pop('error_map', {404: ResourceNotFoundError, 409: ResourceExistsError}) + error_map = {404: ResourceNotFoundError, 409: ResourceExistsError} + error_map.update(kwargs.pop('error_map', {})) op = "summary" # Construct URL diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/models/__init__.py b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/models/__init__.py index 5b6db4e8f600..9a57f152e316 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/models/__init__.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/models/__init__.py @@ -1,12 +1,16 @@ # coding=utf-8 # -------------------------------------------------------------------------- -# Code generated by Microsoft (R) AutoRest Code Generator (autorest: 3.0.6246, generator: {generator}) +# Code generated by Microsoft (R) AutoRest Code Generator (autorest: 3.0.6282, generator: {generator}) # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- try: from ._models_py3 import AnalyzeOperationResult from ._models_py3 import AnalyzeResult + from ._models_py3 import CopyAuthorizationResult + from ._models_py3 import CopyOperationResult + from ._models_py3 import CopyRequest + from ._models_py3 import CopyResult from ._models_py3 import DataTable from ._models_py3 import DataTableCell from ._models_py3 import DocumentResult @@ -33,6 +37,10 @@ except (SyntaxError, ImportError): from ._models import AnalyzeOperationResult # type: ignore from ._models import AnalyzeResult # type: ignore + from ._models import CopyAuthorizationResult # type: ignore + from ._models import CopyOperationResult # type: ignore + from ._models import CopyRequest # type: ignore + from ._models import CopyResult # type: ignore from ._models import DataTable # type: ignore from ._models import DataTableCell # type: ignore from ._models import DocumentResult # type: ignore @@ -70,6 +78,10 @@ __all__ = [ 'AnalyzeOperationResult', 'AnalyzeResult', + 'CopyAuthorizationResult', + 'CopyOperationResult', + 'CopyRequest', + 'CopyResult', 'DataTable', 'DataTableCell', 'DocumentResult', diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/models/_form_recognizer_client_enums.py b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/models/_form_recognizer_client_enums.py index 2bc1b585740d..cded7e466b2a 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/models/_form_recognizer_client_enums.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/models/_form_recognizer_client_enums.py @@ -1,6 +1,6 @@ # coding=utf-8 # -------------------------------------------------------------------------- -# Code generated by Microsoft (R) AutoRest Code Generator (autorest: 3.0.6246, generator: {generator}) +# Code generated by Microsoft (R) AutoRest Code Generator (autorest: 3.0.6282, generator: {generator}) # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/models/_models.py b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/models/_models.py index 44ae84dc803a..1f3be66bb217 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/models/_models.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/models/_models.py @@ -1,6 +1,6 @@ # coding=utf-8 # -------------------------------------------------------------------------- -# Code generated by Microsoft (R) AutoRest Code Generator (autorest: 3.0.6246, generator: {generator}) +# Code generated by Microsoft (R) AutoRest Code Generator (autorest: 3.0.6282, generator: {generator}) # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- @@ -91,6 +91,148 @@ def __init__( self.errors = kwargs.get('errors', None) +class CopyAuthorizationResult(msrest.serialization.Model): + """Request parameter that contains authorization claims for copy operation. + + All required parameters must be populated in order to send to Azure. + + :param model_id: Required. Model identifier. + :type model_id: str + :param access_token: Required. Token claim used to authorize the request. + :type access_token: str + :param expiration_date_time_ticks: Required. The time when the access token expires. The date + is represented as the number of seconds from 1970-01-01T0:0:0Z UTC until the expiration time. + :type expiration_date_time_ticks: long + """ + + _validation = { + 'model_id': {'required': True}, + 'access_token': {'required': True}, + 'expiration_date_time_ticks': {'required': True}, + } + + _attribute_map = { + 'model_id': {'key': 'modelId', 'type': 'str'}, + 'access_token': {'key': 'accessToken', 'type': 'str'}, + 'expiration_date_time_ticks': {'key': 'expirationDateTimeTicks', 'type': 'long'}, + } + + def __init__( + self, + **kwargs + ): + super(CopyAuthorizationResult, self).__init__(**kwargs) + self.model_id = kwargs['model_id'] + self.access_token = kwargs['access_token'] + self.expiration_date_time_ticks = kwargs['expiration_date_time_ticks'] + + +class CopyOperationResult(msrest.serialization.Model): + """Status and result of the queued copy operation. + + All required parameters must be populated in order to send to Azure. + + :param status: Required. Operation status. Possible values include: "notStarted", "running", + "succeeded", "failed". + :type status: str or ~azure.ai.formrecognizer.models.OperationStatus + :param created_date_time: Required. Date and time (UTC) when the copy operation was submitted. + :type created_date_time: ~datetime.datetime + :param last_updated_date_time: Required. Date and time (UTC) when the status was last updated. + :type last_updated_date_time: ~datetime.datetime + :param copy_result: Results of the copy operation. + :type copy_result: ~azure.ai.formrecognizer.models.CopyResult + """ + + _validation = { + 'status': {'required': True}, + 'created_date_time': {'required': True}, + 'last_updated_date_time': {'required': True}, + } + + _attribute_map = { + 'status': {'key': 'status', 'type': 'str'}, + 'created_date_time': {'key': 'createdDateTime', 'type': 'iso-8601'}, + 'last_updated_date_time': {'key': 'lastUpdatedDateTime', 'type': 'iso-8601'}, + 'copy_result': {'key': 'copyResult', 'type': 'CopyResult'}, + } + + def __init__( + self, + **kwargs + ): + super(CopyOperationResult, self).__init__(**kwargs) + self.status = kwargs['status'] + self.created_date_time = kwargs['created_date_time'] + self.last_updated_date_time = kwargs['last_updated_date_time'] + self.copy_result = kwargs.get('copy_result', None) + + +class CopyRequest(msrest.serialization.Model): + """Request parameter to copy an existing custom model from the source resource to a target resource referenced by the resource ID. + + All required parameters must be populated in order to send to Azure. + + :param target_resource_id: Required. Azure Resource Id of the target Form Recognizer resource + where the model is copied to. + :type target_resource_id: str + :param target_resource_region: Required. Location of the target Azure resource. A valid Azure + region name supported by Cognitive Services. + :type target_resource_region: str + :param copy_authorization: Required. Entity that encodes claims to authorize the copy request. + :type copy_authorization: ~azure.ai.formrecognizer.models.CopyAuthorizationResult + """ + + _validation = { + 'target_resource_id': {'required': True, 'max_length': 1024, 'min_length': 0, 'pattern': r'^/subscriptions/[^/]*/resourceGroups/[^/]*/providers/Microsoft.CognitiveServices/accounts/[^/]*$'}, + 'target_resource_region': {'required': True, 'max_length': 24, 'min_length': 1, 'pattern': r'^[a-z0-9]+$'}, + 'copy_authorization': {'required': True}, + } + + _attribute_map = { + 'target_resource_id': {'key': 'targetResourceId', 'type': 'str'}, + 'target_resource_region': {'key': 'targetResourceRegion', 'type': 'str'}, + 'copy_authorization': {'key': 'copyAuthorization', 'type': 'CopyAuthorizationResult'}, + } + + def __init__( + self, + **kwargs + ): + super(CopyRequest, self).__init__(**kwargs) + self.target_resource_id = kwargs['target_resource_id'] + self.target_resource_region = kwargs['target_resource_region'] + self.copy_authorization = kwargs['copy_authorization'] + + +class CopyResult(msrest.serialization.Model): + """Custom model copy result. + + All required parameters must be populated in order to send to Azure. + + :param model_id: Required. Identifier of the target model. + :type model_id: str + :param errors: Errors returned during the copy operation. + :type errors: list[~azure.ai.formrecognizer.models.ErrorInformation] + """ + + _validation = { + 'model_id': {'required': True}, + } + + _attribute_map = { + 'model_id': {'key': 'modelId', 'type': 'str'}, + 'errors': {'key': 'errors', 'type': '[ErrorInformation]'}, + } + + def __init__( + self, + **kwargs + ): + super(CopyResult, self).__init__(**kwargs) + self.model_id = kwargs['model_id'] + self.errors = kwargs.get('errors', None) + + class DataTable(msrest.serialization.Model): """Information about the extracted table contained in a page. diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/models/_models_py3.py b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/models/_models_py3.py index ca0f1f97dce0..6f7110ece583 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/models/_models_py3.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/models/_models_py3.py @@ -1,6 +1,6 @@ # coding=utf-8 # -------------------------------------------------------------------------- -# Code generated by Microsoft (R) AutoRest Code Generator (autorest: 3.0.6246, generator: {generator}) +# Code generated by Microsoft (R) AutoRest Code Generator (autorest: 3.0.6282, generator: {generator}) # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- @@ -107,6 +107,164 @@ def __init__( self.errors = errors +class CopyAuthorizationResult(msrest.serialization.Model): + """Request parameter that contains authorization claims for copy operation. + + All required parameters must be populated in order to send to Azure. + + :param model_id: Required. Model identifier. + :type model_id: str + :param access_token: Required. Token claim used to authorize the request. + :type access_token: str + :param expiration_date_time_ticks: Required. The time when the access token expires. The date + is represented as the number of seconds from 1970-01-01T0:0:0Z UTC until the expiration time. + :type expiration_date_time_ticks: long + """ + + _validation = { + 'model_id': {'required': True}, + 'access_token': {'required': True}, + 'expiration_date_time_ticks': {'required': True}, + } + + _attribute_map = { + 'model_id': {'key': 'modelId', 'type': 'str'}, + 'access_token': {'key': 'accessToken', 'type': 'str'}, + 'expiration_date_time_ticks': {'key': 'expirationDateTimeTicks', 'type': 'long'}, + } + + def __init__( + self, + *, + model_id: str, + access_token: str, + expiration_date_time_ticks: int, + **kwargs + ): + super(CopyAuthorizationResult, self).__init__(**kwargs) + self.model_id = model_id + self.access_token = access_token + self.expiration_date_time_ticks = expiration_date_time_ticks + + +class CopyOperationResult(msrest.serialization.Model): + """Status and result of the queued copy operation. + + All required parameters must be populated in order to send to Azure. + + :param status: Required. Operation status. Possible values include: "notStarted", "running", + "succeeded", "failed". + :type status: str or ~azure.ai.formrecognizer.models.OperationStatus + :param created_date_time: Required. Date and time (UTC) when the copy operation was submitted. + :type created_date_time: ~datetime.datetime + :param last_updated_date_time: Required. Date and time (UTC) when the status was last updated. + :type last_updated_date_time: ~datetime.datetime + :param copy_result: Results of the copy operation. + :type copy_result: ~azure.ai.formrecognizer.models.CopyResult + """ + + _validation = { + 'status': {'required': True}, + 'created_date_time': {'required': True}, + 'last_updated_date_time': {'required': True}, + } + + _attribute_map = { + 'status': {'key': 'status', 'type': 'str'}, + 'created_date_time': {'key': 'createdDateTime', 'type': 'iso-8601'}, + 'last_updated_date_time': {'key': 'lastUpdatedDateTime', 'type': 'iso-8601'}, + 'copy_result': {'key': 'copyResult', 'type': 'CopyResult'}, + } + + def __init__( + self, + *, + status: Union[str, "OperationStatus"], + created_date_time: datetime.datetime, + last_updated_date_time: datetime.datetime, + copy_result: Optional["CopyResult"] = None, + **kwargs + ): + super(CopyOperationResult, self).__init__(**kwargs) + self.status = status + self.created_date_time = created_date_time + self.last_updated_date_time = last_updated_date_time + self.copy_result = copy_result + + +class CopyRequest(msrest.serialization.Model): + """Request parameter to copy an existing custom model from the source resource to a target resource referenced by the resource ID. + + All required parameters must be populated in order to send to Azure. + + :param target_resource_id: Required. Azure Resource Id of the target Form Recognizer resource + where the model is copied to. + :type target_resource_id: str + :param target_resource_region: Required. Location of the target Azure resource. A valid Azure + region name supported by Cognitive Services. + :type target_resource_region: str + :param copy_authorization: Required. Entity that encodes claims to authorize the copy request. + :type copy_authorization: ~azure.ai.formrecognizer.models.CopyAuthorizationResult + """ + + _validation = { + 'target_resource_id': {'required': True, 'max_length': 1024, 'min_length': 0, 'pattern': r'^/subscriptions/[^/]*/resourceGroups/[^/]*/providers/Microsoft.CognitiveServices/accounts/[^/]*$'}, + 'target_resource_region': {'required': True, 'max_length': 24, 'min_length': 1, 'pattern': r'^[a-z0-9]+$'}, + 'copy_authorization': {'required': True}, + } + + _attribute_map = { + 'target_resource_id': {'key': 'targetResourceId', 'type': 'str'}, + 'target_resource_region': {'key': 'targetResourceRegion', 'type': 'str'}, + 'copy_authorization': {'key': 'copyAuthorization', 'type': 'CopyAuthorizationResult'}, + } + + def __init__( + self, + *, + target_resource_id: str, + target_resource_region: str, + copy_authorization: "CopyAuthorizationResult", + **kwargs + ): + super(CopyRequest, self).__init__(**kwargs) + self.target_resource_id = target_resource_id + self.target_resource_region = target_resource_region + self.copy_authorization = copy_authorization + + +class CopyResult(msrest.serialization.Model): + """Custom model copy result. + + All required parameters must be populated in order to send to Azure. + + :param model_id: Required. Identifier of the target model. + :type model_id: str + :param errors: Errors returned during the copy operation. + :type errors: list[~azure.ai.formrecognizer.models.ErrorInformation] + """ + + _validation = { + 'model_id': {'required': True}, + } + + _attribute_map = { + 'model_id': {'key': 'modelId', 'type': 'str'}, + 'errors': {'key': 'errors', 'type': '[ErrorInformation]'}, + } + + def __init__( + self, + *, + model_id: str, + errors: Optional[List["ErrorInformation"]] = None, + **kwargs + ): + super(CopyResult, self).__init__(**kwargs) + self.model_id = model_id + self.errors = errors + + class DataTable(msrest.serialization.Model): """Information about the extracted table contained in a page. diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/operations/__init__.py b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/operations/__init__.py index fb98aab6d184..b0169450f22b 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/operations/__init__.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/operations/__init__.py @@ -1,6 +1,6 @@ # coding=utf-8 # -------------------------------------------------------------------------- -# Code generated by Microsoft (R) AutoRest Code Generator (autorest: 3.0.6246, generator: {generator}) +# Code generated by Microsoft (R) AutoRest Code Generator (autorest: 3.0.6282, generator: {generator}) # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/operations/_form_recognizer_client_operations.py b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/operations/_form_recognizer_client_operations.py index 57731e914413..6a93c83008f9 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/operations/_form_recognizer_client_operations.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/operations/_form_recognizer_client_operations.py @@ -1,6 +1,6 @@ # coding=utf-8 # -------------------------------------------------------------------------- -# Code generated by Microsoft (R) AutoRest Code Generator (autorest: 3.0.6246, generator: {generator}) +# Code generated by Microsoft (R) AutoRest Code Generator (autorest: 3.0.6282, generator: {generator}) # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- from typing import TYPE_CHECKING @@ -44,7 +44,8 @@ def train_custom_model_async( :raises: ~azure.core.exceptions.HttpResponseError """ cls = kwargs.pop('cls', None) # type: ClsType[None] - error_map = kwargs.pop('error_map', {404: ResourceNotFoundError, 409: ResourceExistsError}) + error_map = {404: ResourceNotFoundError, 409: ResourceExistsError} + error_map.update(kwargs.pop('error_map', {})) content_type = kwargs.pop("content_type", "application/json") # Construct URL @@ -105,7 +106,8 @@ def get_custom_model( :raises: ~azure.core.exceptions.HttpResponseError """ cls = kwargs.pop('cls', None) # type: ClsType["models.Model"] - error_map = kwargs.pop('error_map', {404: ResourceNotFoundError, 409: ResourceExistsError}) + error_map = {404: ResourceNotFoundError, 409: ResourceExistsError} + error_map.update(kwargs.pop('error_map', {})) # Construct URL url = self.get_custom_model.metadata['url'] # type: ignore @@ -161,7 +163,8 @@ def delete_custom_model( :raises: ~azure.core.exceptions.HttpResponseError """ cls = kwargs.pop('cls', None) # type: ClsType[None] - error_map = kwargs.pop('error_map', {404: ResourceNotFoundError, 409: ResourceExistsError}) + error_map = {404: ResourceNotFoundError, 409: ResourceExistsError} + error_map.update(kwargs.pop('error_map', {})) # Construct URL url = self.delete_custom_model.metadata['url'] # type: ignore @@ -201,7 +204,8 @@ def _analyze_with_custom_model_initial( ): # type: (...) -> None cls = kwargs.pop('cls', None) # type: ClsType[None] - error_map = kwargs.pop('error_map', {404: ResourceNotFoundError, 409: ResourceExistsError}) + error_map = {404: ResourceNotFoundError, 409: ResourceExistsError} + error_map.update(kwargs.pop('error_map', {})) content_type = kwargs.pop("content_type", "application/json") # Construct URL @@ -327,7 +331,8 @@ def get_analyze_form_result( :raises: ~azure.core.exceptions.HttpResponseError """ cls = kwargs.pop('cls', None) # type: ClsType["models.AnalyzeOperationResult"] - error_map = kwargs.pop('error_map', {404: ResourceNotFoundError, 409: ResourceExistsError}) + error_map = {404: ResourceNotFoundError, 409: ResourceExistsError} + error_map.update(kwargs.pop('error_map', {})) # Construct URL url = self.get_analyze_form_result.metadata['url'] # type: ignore @@ -363,6 +368,215 @@ def get_analyze_form_result( return deserialized get_analyze_form_result.metadata = {'url': '/custom/models/{modelId}/analyzeResults/{resultId}'} # type: ignore + def _copy_custom_model_initial( + self, + model_id, # type: str + copy_request, # type: "models.CopyRequest" + **kwargs # type: Any + ): + # type: (...) -> None + cls = kwargs.pop('cls', None) # type: ClsType[None] + error_map = {404: ResourceNotFoundError, 409: ResourceExistsError} + error_map.update(kwargs.pop('error_map', {})) + content_type = kwargs.pop("content_type", "application/json") + + # Construct URL + url = self._copy_custom_model_initial.metadata['url'] # type: ignore + path_format_arguments = { + 'endpoint': self._serialize.url("self._config.endpoint", self._config.endpoint, 'str', skip_quote=True), + 'modelId': self._serialize.url("model_id", model_id, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Content-Type'] = self._serialize.header("content_type", content_type, 'str') + + # Construct and send request + body_content_kwargs = {} # type: Dict[str, Any] + body_content = self._serialize.body(copy_request, 'CopyRequest') + body_content_kwargs['content'] = body_content + request = self._client.post(url, query_parameters, header_parameters, **body_content_kwargs) + + pipeline_response = self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [202]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize(models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers['Operation-Location']=self._deserialize('str', response.headers.get('Operation-Location')) + + if cls: + return cls(pipeline_response, None, response_headers) + + _copy_custom_model_initial.metadata = {'url': '/custom/models/{modelId}/copy'} # type: ignore + + @distributed_trace + def begin_copy_custom_model( + self, + model_id, # type: str + copy_request, # type: "models.CopyRequest" + **kwargs # type: Any + ): + # type: (...) -> LROPoller + """Copy custom model stored in this resource (the source) to user specified target Form Recognizer resource. + + Copy Custom Model. + + :param model_id: Model identifier. + :type model_id: str + :param copy_request: Copy request parameters. + :type copy_request: ~azure.ai.formrecognizer.models.CopyRequest + :keyword callable cls: A custom type or function that will be passed the direct response + :keyword polling: True for ARMPolling, False for no polling, or a + polling object for 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: + """ + polling = kwargs.pop('polling', False) # type: Union[bool, PollingMethod] + cls = kwargs.pop('cls', None) # type: ClsType[None] + lro_delay = kwargs.pop( + 'polling_interval', + self._config.polling_interval + ) + raw_result = self._copy_custom_model_initial( + model_id=model_id, + copy_request=copy_request, + cls=lambda x,y,z: x, + **kwargs + ) + + def get_long_running_output(pipeline_response): + if cls: + return cls(pipeline_response, None, {}) + + if polling is True: polling_method = LROBasePolling(lro_delay, **kwargs) + elif polling is False: polling_method = NoPolling() + else: polling_method = polling + return LROPoller(self._client, raw_result, get_long_running_output, polling_method) + begin_copy_custom_model.metadata = {'url': '/custom/models/{modelId}/copy'} # type: ignore + + @distributed_trace + def get_custom_model_copy_result( + self, + model_id, # type: str + result_id, # type: str + **kwargs # type: Any + ): + # type: (...) -> "models.CopyOperationResult" + """Obtain current status and the result of a custom model copy operation. + + Get Custom Model Copy Result. + + :param model_id: Model identifier. + :type model_id: str + :param result_id: Copy operation result identifier. + :type result_id: str + :keyword callable cls: A custom type or function that will be passed the direct response + :return: CopyOperationResult or the result of cls(response) + :rtype: ~azure.ai.formrecognizer.models.CopyOperationResult + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["models.CopyOperationResult"] + error_map = {404: ResourceNotFoundError, 409: ResourceExistsError} + error_map.update(kwargs.pop('error_map', {})) + + # Construct URL + url = self.get_custom_model_copy_result.metadata['url'] # type: ignore + path_format_arguments = { + 'endpoint': self._serialize.url("self._config.endpoint", self._config.endpoint, 'str', skip_quote=True), + 'modelId': self._serialize.url("model_id", model_id, 'str'), + 'resultId': self._serialize.url("result_id", result_id, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = 'application/json' + + # Construct and send request + request = self._client.get(url, query_parameters, header_parameters) + pipeline_response = self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize(models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error) + + deserialized = self._deserialize('CopyOperationResult', pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + get_custom_model_copy_result.metadata = {'url': '/custom/models/{modelId}/copyResults/{resultId}'} # type: ignore + + @distributed_trace + def generate_model_copy_authorization( + self, + **kwargs # type: Any + ): + # type: (...) -> "models.CopyAuthorizationResult" + """Generate authorization to copy a model into the target Form Recognizer resource. + + Generate Copy Authorization. + + :keyword callable cls: A custom type or function that will be passed the direct response + :return: CopyAuthorizationResult or the result of cls(response) + :rtype: ~azure.ai.formrecognizer.models.CopyAuthorizationResult + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["models.CopyAuthorizationResult"] + error_map = {404: ResourceNotFoundError, 409: ResourceExistsError} + error_map.update(kwargs.pop('error_map', {})) + + # Construct URL + url = self.generate_model_copy_authorization.metadata['url'] # type: ignore + path_format_arguments = { + 'endpoint': self._serialize.url("self._config.endpoint", self._config.endpoint, 'str', skip_quote=True), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = 'application/json' + + # Construct and send request + request = self._client.post(url, query_parameters, header_parameters) + pipeline_response = self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [201]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize(models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers['Location']=self._deserialize('str', response.headers.get('Location')) + deserialized = self._deserialize('CopyAuthorizationResult', pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, response_headers) + + return deserialized + generate_model_copy_authorization.metadata = {'url': '/custom/models/copyAuthorization'} # type: ignore + def _analyze_receipt_async_initial( self, include_text_details=False, # type: Optional[bool] @@ -371,7 +585,8 @@ def _analyze_receipt_async_initial( ): # type: (...) -> None cls = kwargs.pop('cls', None) # type: ClsType[None] - error_map = kwargs.pop('error_map', {404: ResourceNotFoundError, 409: ResourceExistsError}) + error_map = {404: ResourceNotFoundError, 409: ResourceExistsError} + error_map.update(kwargs.pop('error_map', {})) content_type = kwargs.pop("content_type", "application/json") # Construct URL @@ -489,7 +704,8 @@ def get_analyze_receipt_result( :raises: ~azure.core.exceptions.HttpResponseError """ cls = kwargs.pop('cls', None) # type: ClsType["models.AnalyzeOperationResult"] - error_map = kwargs.pop('error_map', {404: ResourceNotFoundError, 409: ResourceExistsError}) + error_map = {404: ResourceNotFoundError, 409: ResourceExistsError} + error_map.update(kwargs.pop('error_map', {})) # Construct URL url = self.get_analyze_receipt_result.metadata['url'] # type: ignore @@ -531,7 +747,8 @@ def _analyze_layout_async_initial( ): # type: (...) -> None cls = kwargs.pop('cls', None) # type: ClsType[None] - error_map = kwargs.pop('error_map', {404: ResourceNotFoundError, 409: ResourceExistsError}) + error_map = {404: ResourceNotFoundError, 409: ResourceExistsError} + error_map.update(kwargs.pop('error_map', {})) content_type = kwargs.pop("content_type", "application/json") # Construct URL @@ -643,7 +860,8 @@ def get_analyze_layout_result( :raises: ~azure.core.exceptions.HttpResponseError """ cls = kwargs.pop('cls', None) # type: ClsType["models.AnalyzeOperationResult"] - error_map = kwargs.pop('error_map', {404: ResourceNotFoundError, 409: ResourceExistsError}) + error_map = {404: ResourceNotFoundError, 409: ResourceExistsError} + error_map.update(kwargs.pop('error_map', {})) # Construct URL url = self.get_analyze_layout_result.metadata['url'] # type: ignore @@ -694,7 +912,8 @@ def list_custom_models( :raises: ~azure.core.exceptions.HttpResponseError """ cls = kwargs.pop('cls', None) # type: ClsType["models.Models"] - error_map = kwargs.pop('error_map', {404: ResourceNotFoundError, 409: ResourceExistsError}) + error_map = {404: ResourceNotFoundError, 409: ResourceExistsError} + error_map.update(kwargs.pop('error_map', {})) op = "full" def prepare_request(next_link=None): @@ -705,17 +924,17 @@ def prepare_request(next_link=None): 'endpoint': self._serialize.url("self._config.endpoint", self._config.endpoint, 'str', skip_quote=True), } url = self._client.format_url(url, **path_format_arguments) + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['op'] = self._serialize.query("op", op, 'str') + else: url = next_link + query_parameters = {} # type: Dict[str, Any] path_format_arguments = { 'endpoint': self._serialize.url("self._config.endpoint", self._config.endpoint, 'str', skip_quote=True), } url = self._client.format_url(url, **path_format_arguments) - - # Construct parameters - query_parameters = {} # type: Dict[str, Any] - query_parameters['op'] = self._serialize.query("op", op, 'str') - # Construct headers header_parameters = {} # type: Dict[str, Any] header_parameters['Accept'] = 'application/json' @@ -765,7 +984,8 @@ def get_custom_models( :raises: ~azure.core.exceptions.HttpResponseError """ cls = kwargs.pop('cls', None) # type: ClsType["models.Models"] - error_map = kwargs.pop('error_map', {404: ResourceNotFoundError, 409: ResourceExistsError}) + error_map = {404: ResourceNotFoundError, 409: ResourceExistsError} + error_map.update(kwargs.pop('error_map', {})) op = "summary" # Construct URL From 39033198ca83fb131cdd50f28c94d537b9d960ea Mon Sep 17 00:00:00 2001 From: Krista Pratico Date: Tue, 5 May 2020 14:45:29 -0700 Subject: [PATCH 02/22] add copy implementation (wip) --- .../azure/ai/formrecognizer/__init__.py | 8 +- .../formrecognizer/_form_training_client.py | 74 ++++++++++++++++++- .../azure/ai/formrecognizer/_models.py | 59 +++++++++++++++ .../aio/_form_training_client_async.py | 72 +++++++++++++++++- 4 files changed, 205 insertions(+), 8 deletions(-) diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/__init__.py b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/__init__.py index b8225d383dbe..19de3f6814be 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/__init__.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/__init__.py @@ -33,7 +33,9 @@ FormWord, CustomFormModel, CustomFormSubModel, - CustomFormModelField + CustomFormModelField, + CopyAuthorizationResult, + CopyModelResult ) @@ -64,7 +66,9 @@ 'FormWord', 'CustomFormModel', 'CustomFormSubModel', - 'CustomFormModelField' + 'CustomFormModelField', + 'CopyAuthorizationResult', + 'CopyModelResult' ] __VERSION__ = VERSION diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_form_training_client.py b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_form_training_client.py index e699dbac99ab..098ed466a38b 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_form_training_client.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_form_training_client.py @@ -16,14 +16,15 @@ from azure.core.polling import LROPoller from azure.core.polling.base_polling import LROBasePolling from azure.core.pipeline.policies import AzureKeyCredentialPolicy -from ._generated.models import Model from ._generated._form_recognizer_client import FormRecognizerClient as FormRecognizer -from ._generated.models import TrainRequest, TrainSourceFilter +from ._generated.models import TrainRequest, TrainSourceFilter, CopyRequest, Model, CopyOperationResult from ._helpers import error_map, POLLING_INTERVAL, COGNITIVE_KEY_HEADER from ._models import ( CustomFormModelInfo, AccountProperties, - CustomFormModel + CustomFormModel, + CopyAuthorizationResult, + CopyModelResult ) from ._polling import TrainingPolling from ._user_agent import USER_AGENT @@ -224,6 +225,73 @@ def get_custom_model(self, model_id, **kwargs): response = self._client.get_custom_model(model_id=model_id, include_keys=True, error_map=error_map, **kwargs) return CustomFormModel._from_generated(response) + @distributed_trace + def generate_model_copy_authorization(self, **kwargs): + # type: (Any) -> CopyAuthorizationResult + """Generate authorization to copy a model into the target Form Recognizer resource. + + Generate Copy Authorization. + + :return: CopyAuthorizationResult + :rtype: ~azure.ai.formrecognizer.CopyAuthorizationResult + :raises: ~azure.core.exceptions.HttpResponseError + """ + + response = self._client.generate_model_copy_authorization( # type: ignore + cls=lambda pipeline_response, deserialized, response_headers: deserialized, + error_map=error_map, + **kwargs + ) + + return CopyAuthorizationResult._from_generated(response) + + @distributed_trace + def begin_copy_model( + self, + source_model_id, # type: str + target_resource_id, # type: str + target_resource_region, # type: str + copy_authorization, # type: CopyAuthorizationResult + **kwargs # type: Any + ): + # type: (...) -> LROPoller + """Copy custom model stored in this resource (the source) to user specified target Form Recognizer resource. + + Copy Custom Model. + + :param source_model_id: Model identifier. + :type source_model_id: str + :param str target_resource_id: Azure Resource Id of the target Form Recognizer resource + where the model is copied to. + :param str target_resource_region: Location of the target Azure resource. A valid Azure + region name supported by Cognitive Services. + :param copy_authorization: Entity that encodes claims to authorize the copy request. + :type copy_authorization: ~azure.ai.formrecognizer.CopyAuthorizationResult + :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 + :rtype: ~azure.core.polling.LROPoller[CopyModelResult] + :raises ~azure.core.exceptions.HttpResponseError: + """ + polling_interval = kwargs.pop("polling_interval", POLLING_INTERVAL) + + def _copy_callback(raw_response, _, headers): # pylint: disable=unused-argument + copy_result = self._client._deserialize(CopyOperationResult, raw_response) + return CopyModelResult._from_generated(copy_result.copy_result) + + return self._client.begin_copy_custom_model( # type: ignore + model_id=source_model_id, + copy_request=CopyRequest( + target_resource_id=target_resource_id, + target_resource_region=target_resource_region, + copy_authorization=copy_authorization + ), + cls=kwargs.pop("cls", _copy_callback), + polling=LROBasePolling(timeout=polling_interval, **kwargs), + error_map=error_map, + **kwargs + ) + def close(self): # type: () -> None """Close the :class:`~azure.ai.formrecognizer.FormTrainingClient` session. diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_models.py b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_models.py index ae13e57a4967..8e04d2de1fa7 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_models.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_models.py @@ -10,6 +10,7 @@ from collections import namedtuple import re import six +from ._generated.models import CopyAuthorizationResult as GeneratedCopyAuthorizationResult def adjust_confidence(score): @@ -884,3 +885,61 @@ def __repr__(self): return "AccountProperties(custom_model_count={}, custom_model_limit={})".format( self.custom_model_count, self.custom_model_limit )[:1024] + + +class CopyAuthorizationResult(GeneratedCopyAuthorizationResult): + """Request parameter that contains authorization claims for copy operation. + + :ivar str model_id: Model identifier. + :ivar str access_token: Required. Token claim used to authorize the request. + :ivar int expiration_date_time_ticks: The time when the access token expires. The date + is represented as the number of seconds from 1970-01-01T0:0:0Z UTC until the expiration time. + """ + + def __init__( + self, + **kwargs + ): + super(CopyAuthorizationResult, self).__init__(**kwargs) + self.model_id = kwargs.get('model_id', None) + self.access_token = kwargs.get('access_token', None) + self.expiration_date_time_ticks = kwargs.get('expiration_date_time_ticks', None) + + @classmethod + def _from_generated(cls, copy): + return cls( + model_id=copy.model_id, + access_token=copy.access_token, + expiration_date_time_ticks=copy.expiration_date_time_ticks + ) + + def __repr__(self): + return "CopyAuthorizationResult(model_id={}, access_token={}, expiration_date_time_ticks={})".format( + self.model_id, self.access_token, self.expiration_date_time_ticks + )[:1024] + + +class CopyModelResult(object): + """Custom model copy result. + + :ivar str model_id: Identifier of the target model. + :ivar list[~azure.ai.formrecognizer.FormRecognizerError] errors: + Errors returned during the copy operation. + """ + + def __init__( + self, + **kwargs + ): + self.model_id = kwargs.get('model_id', None) + self.errors = kwargs.get('errors', None) + + @classmethod + def _from_generated(cls, copy): + return cls( + model_id=copy.model_id if copy else None, + errors=FormRecognizerError._from_generated(copy.errors) if copy else None + ) + + def __repr__(self): + return "CopyModelResult(model_id={}, errors={})".format(self.model_id, self.errors)[:1024] diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/aio/_form_training_client_async.py b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/aio/_form_training_client_async.py index 51798412b6bb..737919b81ae3 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/aio/_form_training_client_async.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/aio/_form_training_client_async.py @@ -18,13 +18,14 @@ from azure.core.tracing.decorator_async import distributed_trace_async from azure.core.pipeline.policies import AzureKeyCredentialPolicy from .._generated.aio._form_recognizer_client_async import FormRecognizerClient as FormRecognizer -from .._generated.models import TrainRequest, TrainSourceFilter -from .._generated.models import Model +from .._generated.models import TrainRequest, TrainSourceFilter, Model, CopyRequest, CopyOperationResult from .._helpers import error_map, POLLING_INTERVAL, COGNITIVE_KEY_HEADER from .._models import ( CustomFormModelInfo, AccountProperties, - CustomFormModel + CustomFormModel, + CopyAuthorizationResult, + CopyModelResult ) from .._user_agent import USER_AGENT from .._polling import TrainingPolling @@ -230,6 +231,71 @@ async def get_custom_model(self, model_id: str, **kwargs: Any) -> CustomFormMode ) return CustomFormModel._from_generated(response) + @distributed_trace_async + async def generate_model_copy_authorization(self, **kwargs: Any) -> CopyAuthorizationResult: + """Generate authorization to copy a model into the target Form Recognizer resource. + + Generate Copy Authorization. + + :return: CopyAuthorizationResult + :rtype: ~azure.ai.formrecognizer.CopyAuthorizationResult + :raises: ~azure.core.exceptions.HttpResponseError + """ + + response = await self._client.generate_model_copy_authorization( # type: ignore + cls=lambda pipeline_response, deserialized, response_headers: deserialized, + error_map=error_map, + **kwargs + ) + + return CopyAuthorizationResult._from_generated(response) + + @distributed_trace_async + async def copy_model( + self, + source_model_id: str, + target_resource_id: str, + target_resource_region: str, + copy_authorization: CopyAuthorizationResult, + **kwargs: Any + ) -> CopyModelResult: + """Copy custom model stored in this resource (the source) to user specified target Form Recognizer resource. + + Copy Custom Model. + + :param source_model_id: Model identifier. + :type source_model_id: str + :param str target_resource_id: Azure Resource Id of the target Form Recognizer resource + where the model is copied to. + :param str target_resource_region: Location of the target Azure resource. A valid Azure + region name supported by Cognitive Services. + :param copy_authorization: Entity that encodes claims to authorize the copy request. + :type copy_authorization: ~azure.ai.formrecognizer.CopyAuthorizationResult + :keyword int polling_interval: Default waiting time between two polls for LRO operations if + no Retry-After header is present. + :return: An instance of CopyModelResult + :rtype: ~azure.ai.formrecognizer.CopyModelResult + :raises ~azure.core.exceptions.HttpResponseError: + """ + polling_interval = kwargs.pop("polling_interval", POLLING_INTERVAL) + + def _copy_callback(raw_response, _, headers): # pylint: disable=unused-argument + copy_result = self._client._deserialize(CopyOperationResult, raw_response) + return CopyModelResult._from_generated(copy_result.copy_result) + + return await self._client.copy_custom_model( # type: ignore + model_id=source_model_id, + copy_request=CopyRequest( + target_resource_id=target_resource_id, + target_resource_region=target_resource_region, + copy_authorization=copy_authorization + ), + cls=kwargs.pop("cls", _copy_callback), + polling=AsyncLROBasePolling(timeout=polling_interval, **kwargs), + error_map=error_map, + **kwargs + ) + async def __aenter__(self) -> "FormTrainingClient": await self._client.__aenter__() return self From d7160bbfa917a1630b09b634d5cde094805aa885 Mon Sep 17 00:00:00 2001 From: Krista Pratico Date: Tue, 5 May 2020 16:23:45 -0700 Subject: [PATCH 03/22] update copy implementation --- .../azure/ai/formrecognizer/__init__.py | 8 +-- .../formrecognizer/_form_training_client.py | 30 +++++---- .../azure/ai/formrecognizer/_models.py | 67 +++---------------- .../aio/_form_training_client_async.py | 44 +++++++----- 4 files changed, 55 insertions(+), 94 deletions(-) diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/__init__.py b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/__init__.py index 19de3f6814be..b8225d383dbe 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/__init__.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/__init__.py @@ -33,9 +33,7 @@ FormWord, CustomFormModel, CustomFormSubModel, - CustomFormModelField, - CopyAuthorizationResult, - CopyModelResult + CustomFormModelField ) @@ -66,9 +64,7 @@ 'FormWord', 'CustomFormModel', 'CustomFormSubModel', - 'CustomFormModelField', - 'CopyAuthorizationResult', - 'CopyModelResult' + 'CustomFormModelField' ] __VERSION__ = VERSION diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_form_training_client.py b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_form_training_client.py index 098ed466a38b..725fae6ab52b 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_form_training_client.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_form_training_client.py @@ -23,14 +23,13 @@ CustomFormModelInfo, AccountProperties, CustomFormModel, - CopyAuthorizationResult, - CopyModelResult ) from ._polling import TrainingPolling from ._user_agent import USER_AGENT if TYPE_CHECKING: from azure.core.credentials import AzureKeyCredential from azure.core.pipeline.transport import HttpResponse + from ._generated.models import CopyAuthorizationResult PipelineResponseType = HttpResponse @@ -226,32 +225,29 @@ def get_custom_model(self, model_id, **kwargs): return CustomFormModel._from_generated(response) @distributed_trace - def generate_model_copy_authorization(self, **kwargs): + def _generate_model_copy_authorization(self, **kwargs): # type: (Any) -> CopyAuthorizationResult """Generate authorization to copy a model into the target Form Recognizer resource. - Generate Copy Authorization. - :return: CopyAuthorizationResult :rtype: ~azure.ai.formrecognizer.CopyAuthorizationResult :raises: ~azure.core.exceptions.HttpResponseError """ - response = self._client.generate_model_copy_authorization( # type: ignore + return self._client.generate_model_copy_authorization( # type: ignore cls=lambda pipeline_response, deserialized, response_headers: deserialized, error_map=error_map, **kwargs ) - return CopyAuthorizationResult._from_generated(response) - @distributed_trace def begin_copy_model( self, source_model_id, # type: str target_resource_id, # type: str target_resource_region, # type: str - copy_authorization, # type: CopyAuthorizationResult + target_endpoint, # type: str + target_credential, # type: AzureKeyCredential **kwargs # type: Any ): # type: (...) -> LROPoller @@ -265,19 +261,23 @@ def begin_copy_model( where the model is copied to. :param str target_resource_region: Location of the target Azure resource. A valid Azure region name supported by Cognitive Services. - :param copy_authorization: Entity that encodes claims to authorize the copy request. - :type copy_authorization: ~azure.ai.formrecognizer.CopyAuthorizationResult + :param str target_endpoint: The target endpoint to transfer the copied model. + :param ~azure.core.credentials.AzureKeyCredential target_credential: + The credential for the target resource. :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 - :rtype: ~azure.core.polling.LROPoller[CopyModelResult] + :rtype: ~azure.core.polling.LROPoller[CustomFormModelInfo] :raises ~azure.core.exceptions.HttpResponseError: """ polling_interval = kwargs.pop("polling_interval", POLLING_INTERVAL) + target_client = self._get_form_training_client(target_endpoint, target_credential) + copy_authorization = target_client._generate_model_copy_authorization() + def _copy_callback(raw_response, _, headers): # pylint: disable=unused-argument copy_result = self._client._deserialize(CopyOperationResult, raw_response) - return CopyModelResult._from_generated(copy_result.copy_result) + return CustomFormModelInfo._from_generated_copy(copy_result, copy_authorization.model_id) return self._client.begin_copy_custom_model( # type: ignore model_id=source_model_id, @@ -292,6 +292,10 @@ def _copy_callback(raw_response, _, headers): # pylint: disable=unused-argument **kwargs ) + @classmethod + def _get_form_training_client(cls, endpoint, credential): + return cls(endpoint, credential) + def close(self): # type: () -> None """Close the :class:`~azure.ai.formrecognizer.FormTrainingClient` session. diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_models.py b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_models.py index 8e04d2de1fa7..5daef7ac11ae 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_models.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_models.py @@ -857,6 +857,15 @@ def _from_generated(cls, model): last_modified=model.last_updated_date_time ) + @classmethod + def _from_generated_copy(cls, copy, model_id): + return cls( + model_id=model_id, + status=copy.status, + created_on=copy.created_date_time, + last_modified=copy.last_updated_date_time + ) + def __repr__(self): return "CustomFormModelInfo(model_id={}, status={}, created_on={}, last_modified={})".format( self.model_id, self.status, self.created_on, self.last_modified @@ -885,61 +894,3 @@ def __repr__(self): return "AccountProperties(custom_model_count={}, custom_model_limit={})".format( self.custom_model_count, self.custom_model_limit )[:1024] - - -class CopyAuthorizationResult(GeneratedCopyAuthorizationResult): - """Request parameter that contains authorization claims for copy operation. - - :ivar str model_id: Model identifier. - :ivar str access_token: Required. Token claim used to authorize the request. - :ivar int expiration_date_time_ticks: The time when the access token expires. The date - is represented as the number of seconds from 1970-01-01T0:0:0Z UTC until the expiration time. - """ - - def __init__( - self, - **kwargs - ): - super(CopyAuthorizationResult, self).__init__(**kwargs) - self.model_id = kwargs.get('model_id', None) - self.access_token = kwargs.get('access_token', None) - self.expiration_date_time_ticks = kwargs.get('expiration_date_time_ticks', None) - - @classmethod - def _from_generated(cls, copy): - return cls( - model_id=copy.model_id, - access_token=copy.access_token, - expiration_date_time_ticks=copy.expiration_date_time_ticks - ) - - def __repr__(self): - return "CopyAuthorizationResult(model_id={}, access_token={}, expiration_date_time_ticks={})".format( - self.model_id, self.access_token, self.expiration_date_time_ticks - )[:1024] - - -class CopyModelResult(object): - """Custom model copy result. - - :ivar str model_id: Identifier of the target model. - :ivar list[~azure.ai.formrecognizer.FormRecognizerError] errors: - Errors returned during the copy operation. - """ - - def __init__( - self, - **kwargs - ): - self.model_id = kwargs.get('model_id', None) - self.errors = kwargs.get('errors', None) - - @classmethod - def _from_generated(cls, copy): - return cls( - model_id=copy.model_id if copy else None, - errors=FormRecognizerError._from_generated(copy.errors) if copy else None - ) - - def __repr__(self): - return "CopyModelResult(model_id={}, errors={})".format(self.model_id, self.errors)[:1024] diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/aio/_form_training_client_async.py b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/aio/_form_training_client_async.py index 737919b81ae3..f90febf62120 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/aio/_form_training_client_async.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/aio/_form_training_client_async.py @@ -18,19 +18,24 @@ from azure.core.tracing.decorator_async import distributed_trace_async from azure.core.pipeline.policies import AzureKeyCredentialPolicy from .._generated.aio._form_recognizer_client_async import FormRecognizerClient as FormRecognizer -from .._generated.models import TrainRequest, TrainSourceFilter, Model, CopyRequest, CopyOperationResult +from .._generated.models import ( + TrainRequest, + TrainSourceFilter, + Model, + CopyRequest, + CopyOperationResult +) from .._helpers import error_map, POLLING_INTERVAL, COGNITIVE_KEY_HEADER from .._models import ( CustomFormModelInfo, AccountProperties, - CustomFormModel, - CopyAuthorizationResult, - CopyModelResult + CustomFormModel ) from .._user_agent import USER_AGENT from .._polling import TrainingPolling if TYPE_CHECKING: from azure.core.credentials import AzureKeyCredential + from .._generated.models import CopyAuthorizationResult class FormTrainingClient(object): @@ -232,33 +237,30 @@ async def get_custom_model(self, model_id: str, **kwargs: Any) -> CustomFormMode return CustomFormModel._from_generated(response) @distributed_trace_async - async def generate_model_copy_authorization(self, **kwargs: Any) -> CopyAuthorizationResult: + async def _generate_model_copy_authorization(self, **kwargs: Any) -> "CopyAuthorizationResult": """Generate authorization to copy a model into the target Form Recognizer resource. - Generate Copy Authorization. - :return: CopyAuthorizationResult :rtype: ~azure.ai.formrecognizer.CopyAuthorizationResult :raises: ~azure.core.exceptions.HttpResponseError """ - response = await self._client.generate_model_copy_authorization( # type: ignore + return await self._client.generate_model_copy_authorization( # type: ignore cls=lambda pipeline_response, deserialized, response_headers: deserialized, error_map=error_map, **kwargs ) - return CopyAuthorizationResult._from_generated(response) - @distributed_trace_async async def copy_model( self, source_model_id: str, target_resource_id: str, target_resource_region: str, - copy_authorization: CopyAuthorizationResult, + target_endpoint: str, + target_credential: "AzureKeyCredential", **kwargs: Any - ) -> CopyModelResult: + ) -> CustomFormModelInfo: """Copy custom model stored in this resource (the source) to user specified target Form Recognizer resource. Copy Custom Model. @@ -269,19 +271,23 @@ async def copy_model( where the model is copied to. :param str target_resource_region: Location of the target Azure resource. A valid Azure region name supported by Cognitive Services. - :param copy_authorization: Entity that encodes claims to authorize the copy request. - :type copy_authorization: ~azure.ai.formrecognizer.CopyAuthorizationResult + :param str target_endpoint: The target endpoint to transfer the copied model. + :param ~azure.core.credentials.AzureKeyCredential target_credential: + The credential for the target resource. :keyword int polling_interval: Default waiting time between two polls for LRO operations if no Retry-After header is present. - :return: An instance of CopyModelResult - :rtype: ~azure.ai.formrecognizer.CopyModelResult + :return: An instance of CustomFormModelInfo + :rtype: ~azure.ai.formrecognizer.CustomFormModelInfo :raises ~azure.core.exceptions.HttpResponseError: """ polling_interval = kwargs.pop("polling_interval", POLLING_INTERVAL) + target_client = self._get_form_training_client(target_endpoint, target_credential) + copy_authorization = await target_client._generate_model_copy_authorization() + def _copy_callback(raw_response, _, headers): # pylint: disable=unused-argument copy_result = self._client._deserialize(CopyOperationResult, raw_response) - return CopyModelResult._from_generated(copy_result.copy_result) + return CustomFormModelInfo._from_generated_copy(copy_result, copy_authorization.model_id) return await self._client.copy_custom_model( # type: ignore model_id=source_model_id, @@ -296,6 +302,10 @@ def _copy_callback(raw_response, _, headers): # pylint: disable=unused-argument **kwargs ) + @classmethod + def _get_form_training_client(cls, endpoint, credential): + return cls(endpoint, credential) + async def __aenter__(self) -> "FormTrainingClient": await self._client.__aenter__() return self From 24a1636ec6c444f3fbce2011401f6fdf8157753d Mon Sep 17 00:00:00 2001 From: Krista Pratico Date: Tue, 5 May 2020 16:33:54 -0700 Subject: [PATCH 04/22] add copy model samples --- .../async_samples/sample_copy_model_async.py | 69 +++++++++++++++++++ .../samples/sample_copy_model.py | 64 +++++++++++++++++ 2 files changed, 133 insertions(+) create mode 100644 sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_copy_model_async.py create mode 100644 sdk/formrecognizer/azure-ai-formrecognizer/samples/sample_copy_model.py diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_copy_model_async.py b/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_copy_model_async.py new file mode 100644 index 000000000000..ee062ce7ce63 --- /dev/null +++ b/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_copy_model_async.py @@ -0,0 +1,69 @@ +# coding: utf-8 + +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- + +""" +FILE: sample_copy_model_async.py + +DESCRIPTION: + This sample demonstrates how to copy a model from a source Form Recognizer resource + to a target Form Recognizer resource. + +USAGE: + python sample_copy_model_async.py + + Set the environment variables with your own values before running the sample: + 1) AZURE_FORM_RECOGNIZER_SOURCE_ENDPOINT - the endpoint to your source Form Recognizer resource. + 2) AZURE_FORM_RECOGNIZER_SOURCE_KEY - your source Form Recognizer API key + 3) AZURE_FORM_RECOGNIZER_TARGET_ENDPOINT - the endpoint to your target Form Recognizer resource. + 4) AZURE_FORM_RECOGNIZER_TARGET_KEY - your target Form Recognizer API key + 5) AZURE_SOURCE_MODEL_ID - the model ID from the source resource to be copied over to the target resource. + 6) AZURE_FORM_RECOGNIZER_TARGET_REGION - the region the target resource was created in + 7) AZURE_FORM_RECOGNIZER_TARGET_RESOURCE_ID - the entire resource ID to the target resource +""" + +import os +import asyncio + + +class CopyModelSampleAsync(object): + + source_endpoint = os.environ["AZURE_FORM_RECOGNIZER_ENDPOINT"] + source_key = os.environ["AZURE_FORM_RECOGNIZER_KEY"] + target_endpoint = os.environ["AZURE_FORM_RECOGNIZER_TARGET_ENDPOINT"] + target_key = os.environ["AZURE_FORM_RECOGNIZER_TARGET_KEY"] + source_model_id = os.environ["AZURE_SOURCE_MODEL_ID"] + target_region = os.environ["AZURE_FORM_RECOGNIZER_TARGET_REGION"] + target_resource_id = os.environ["AZURE_FORM_RECOGNIZER_TARGET_RESOURCE_ID"] + + async def copy_model(self): + from azure.core.credentials import AzureKeyCredential + from azure.ai.formrecognizer.aio import FormTrainingClient + + source_client = FormTrainingClient(endpoint=self.source_endpoint, credential=AzureKeyCredential(self.source_key)) + target_client = FormTrainingClient(endpoint=self.target_endpoint, credential=AzureKeyCredential(self.target_key)) + + copy = await source_client.copy_model( + source_model_id=self.source_model_id, + target_resource_region=self.target_region, + target_resource_id=self.target_resource_id, + target_endpoint=self.target_endpoint, + target_credential=AzureKeyCredential(self.target_key) + ) + + copied_over_model = await target_client.get_custom_model(copy.model_id) + print(copied_over_model) + + +async def main(): + sample = CopyModelSampleAsync() + await sample.copy_model() + + +if __name__ == '__main__': + loop = asyncio.get_event_loop() + loop.run_until_complete(main()) diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/samples/sample_copy_model.py b/sdk/formrecognizer/azure-ai-formrecognizer/samples/sample_copy_model.py new file mode 100644 index 000000000000..1b0c5896b819 --- /dev/null +++ b/sdk/formrecognizer/azure-ai-formrecognizer/samples/sample_copy_model.py @@ -0,0 +1,64 @@ +# coding: utf-8 + +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- + +""" +FILE: sample_copy_model.py + +DESCRIPTION: + This sample demonstrates how to copy a model from a source Form Recognizer resource + to a target Form Recognizer resource. + +USAGE: + python sample_copy_model.py + + Set the environment variables with your own values before running the sample: + 1) AZURE_FORM_RECOGNIZER_SOURCE_ENDPOINT - the endpoint to your source Form Recognizer resource. + 2) AZURE_FORM_RECOGNIZER_SOURCE_KEY - your source Form Recognizer API key + 3) AZURE_FORM_RECOGNIZER_TARGET_ENDPOINT - the endpoint to your target Form Recognizer resource. + 4) AZURE_FORM_RECOGNIZER_TARGET_KEY - your target Form Recognizer API key + 5) AZURE_SOURCE_MODEL_ID - the model ID from the source resource to be copied over to the target resource. + 6) AZURE_FORM_RECOGNIZER_TARGET_REGION - the region the target resource was created in + 7) AZURE_FORM_RECOGNIZER_TARGET_RESOURCE_ID - the entire resource ID to the target resource +""" + +import os + + +class CopyModelSample(object): + + source_endpoint = os.environ["AZURE_FORM_RECOGNIZER_ENDPOINT"] + source_key = os.environ["AZURE_FORM_RECOGNIZER_KEY"] + target_endpoint = os.environ["AZURE_FORM_RECOGNIZER_TARGET_ENDPOINT"] + target_key = os.environ["AZURE_FORM_RECOGNIZER_TARGET_KEY"] + source_model_id = os.environ["AZURE_SOURCE_MODEL_ID"] + target_region = os.environ["AZURE_FORM_RECOGNIZER_TARGET_REGION"] + target_resource_id = os.environ["AZURE_FORM_RECOGNIZER_TARGET_RESOURCE_ID"] + + def begin_copy_model(self): + from azure.core.credentials import AzureKeyCredential + from azure.ai.formrecognizer import FormTrainingClient + + source_client = FormTrainingClient(endpoint=self.source_endpoint, credential=AzureKeyCredential(self.source_key)) + target_client = FormTrainingClient(endpoint=self.target_endpoint, credential=AzureKeyCredential(self.target_key)) + + poller = source_client.begin_copy_model( + source_model_id=self.source_model_id, + target_resource_region=self.target_region, + target_resource_id=self.target_resource_id, + target_endpoint=self.target_endpoint, + target_credential=AzureKeyCredential(self.target_key) + ) + copy = poller.result() + + copied_over_model = target_client.get_custom_model(copy.model_id) + print(copied_over_model) + + +if __name__ == '__main__': + sample = CopyModelSample() + sample.begin_copy_model() From 957cce19c62c2329f0fbfcc747035724ef7cd921 Mon Sep 17 00:00:00 2001 From: Krista Pratico Date: Mon, 11 May 2020 12:21:02 -0700 Subject: [PATCH 05/22] add back get copy auth method and update samples --- .../formrecognizer/_form_training_client.py | 33 ++++++++++++------ .../azure/ai/formrecognizer/_models.py | 34 ++++++++++++++++++- .../aio/_form_training_client_async.py | 31 +++++++++++------ .../async_samples/sample_copy_model_async.py | 24 +++++++++++-- .../samples/sample_copy_model.py | 27 ++++++++++++--- 5 files changed, 120 insertions(+), 29 deletions(-) diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_form_training_client.py b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_form_training_client.py index 725fae6ab52b..1fb811266317 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_form_training_client.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_form_training_client.py @@ -23,13 +23,13 @@ CustomFormModelInfo, AccountProperties, CustomFormModel, + CopyAuthorization ) from ._polling import TrainingPolling from ._user_agent import USER_AGENT if TYPE_CHECKING: from azure.core.credentials import AzureKeyCredential from azure.core.pipeline.transport import HttpResponse - from ._generated.models import CopyAuthorizationResult PipelineResponseType = HttpResponse @@ -225,20 +225,22 @@ def get_custom_model(self, model_id, **kwargs): return CustomFormModel._from_generated(response) @distributed_trace - def _generate_model_copy_authorization(self, **kwargs): - # type: (Any) -> CopyAuthorizationResult + def get_model_copy_authorization(self, **kwargs): + # type: (Any) -> CopyAuthorization """Generate authorization to copy a model into the target Form Recognizer resource. + Generate Copy Authorization. - :return: CopyAuthorizationResult - :rtype: ~azure.ai.formrecognizer.CopyAuthorizationResult + :return: CopyAuthorization + :rtype: ~azure.ai.formrecognizer.CopyAuthorization :raises: ~azure.core.exceptions.HttpResponseError """ - return self._client.generate_model_copy_authorization( # type: ignore + response = self._client.generate_model_copy_authorization( # type: ignore cls=lambda pipeline_response, deserialized, response_headers: deserialized, error_map=error_map, **kwargs ) + return CopyAuthorization._from_generated(response) @distributed_trace def begin_copy_model( @@ -246,8 +248,9 @@ def begin_copy_model( source_model_id, # type: str target_resource_id, # type: str target_resource_region, # type: str - target_endpoint, # type: str - target_credential, # type: AzureKeyCredential + copy_authorization=None, # type: Optional[CopyAuthorization] + target_endpoint_url=None, # type: Optional[str] + target_credential=None, # type: Optional[AzureKeyCredential] **kwargs # type: Any ): # type: (...) -> LROPoller @@ -261,7 +264,11 @@ def begin_copy_model( where the model is copied to. :param str target_resource_region: Location of the target Azure resource. A valid Azure region name supported by Cognitive Services. - :param str target_endpoint: The target endpoint to transfer the copied model. + :param ~azure.ai.formrecognizer.CopyAuthorization copy_authorization: + The copy authorization generated from the target resource's call to + :func:`~get_model_copy_authorization()`. You must pass either copy_authorization + or `target_credential` and `target_endpoint_url`. + :param str target_endpoint_url: The target endpoint to transfer the copied model. :param ~azure.core.credentials.AzureKeyCredential target_credential: The credential for the target resource. :keyword int polling_interval: Default waiting time between two polls for LRO operations if @@ -270,10 +277,14 @@ def begin_copy_model( :rtype: ~azure.core.polling.LROPoller[CustomFormModelInfo] :raises ~azure.core.exceptions.HttpResponseError: """ + polling_interval = kwargs.pop("polling_interval", POLLING_INTERVAL) - target_client = self._get_form_training_client(target_endpoint, target_credential) - copy_authorization = target_client._generate_model_copy_authorization() + if target_endpoint_url and target_credential: + target_client = self._get_form_training_client(target_endpoint_url, target_credential) + copy_authorization = target_client.get_model_copy_authorization() + elif copy_authorization is None: + raise ValueError("Pass only copy_authorization or target_endpoint_url and target_credential.") def _copy_callback(raw_response, _, headers): # pylint: disable=unused-argument copy_result = self._client._deserialize(CopyOperationResult, raw_response) diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_models.py b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_models.py index 5daef7ac11ae..8a2ca26d7a7b 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_models.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_models.py @@ -10,7 +10,7 @@ from collections import namedtuple import re import six -from ._generated.models import CopyAuthorizationResult as GeneratedCopyAuthorizationResult +from ._generated.models import CopyAuthorizationResult def adjust_confidence(score): @@ -894,3 +894,35 @@ def __repr__(self): return "AccountProperties(custom_model_count={}, custom_model_limit={})".format( self.custom_model_count, self.custom_model_limit )[:1024] + + +class CopyAuthorization(CopyAuthorizationResult): + """Request parameter that contains authorization claims for copy operation. + + :ivar str model_id: Model identifier. + :ivar str access_token: Required. Token claim used to authorize the request. + :ivar int expiration_date_time_ticks: The time when the access token expires. The date + is represented as the number of seconds from 1970-01-01T0:0:0Z UTC until the expiration time. + """ + + def __init__( + self, + **kwargs + ): + super(CopyAuthorization, self).__init__(**kwargs) + self.model_id = kwargs.get('model_id', None) + self.access_token = kwargs.get('access_token', None) + self.expiration_date_time_ticks = kwargs.get('expiration_date_time_ticks', None) + + @classmethod + def _from_generated(cls, copy): + return cls( + model_id=copy.model_id, + access_token=copy.access_token, + expiration_date_time_ticks=copy.expiration_date_time_ticks + ) + + def __repr__(self): + return "CopyAuthorization(model_id={}, access_token={}, expiration_date_time_ticks={})".format( + self.model_id, self.access_token, self.expiration_date_time_ticks + )[:1024] diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/aio/_form_training_client_async.py b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/aio/_form_training_client_async.py index f90febf62120..7988a7bc5735 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/aio/_form_training_client_async.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/aio/_form_training_client_async.py @@ -29,13 +29,13 @@ from .._models import ( CustomFormModelInfo, AccountProperties, - CustomFormModel + CustomFormModel, + CopyAuthorization ) from .._user_agent import USER_AGENT from .._polling import TrainingPolling if TYPE_CHECKING: from azure.core.credentials import AzureKeyCredential - from .._generated.models import CopyAuthorizationResult class FormTrainingClient(object): @@ -237,19 +237,20 @@ async def get_custom_model(self, model_id: str, **kwargs: Any) -> CustomFormMode return CustomFormModel._from_generated(response) @distributed_trace_async - async def _generate_model_copy_authorization(self, **kwargs: Any) -> "CopyAuthorizationResult": + async def get_model_copy_authorization(self, **kwargs: Any) -> "CopyAuthorization": """Generate authorization to copy a model into the target Form Recognizer resource. - :return: CopyAuthorizationResult - :rtype: ~azure.ai.formrecognizer.CopyAuthorizationResult + :return: CopyAuthorization + :rtype: ~azure.ai.formrecognizer.CopyAuthorization :raises: ~azure.core.exceptions.HttpResponseError """ - return await self._client.generate_model_copy_authorization( # type: ignore + response = await self._client.generate_model_copy_authorization( # type: ignore cls=lambda pipeline_response, deserialized, response_headers: deserialized, error_map=error_map, **kwargs ) + return CopyAuthorization._from_generated(response) @distributed_trace_async async def copy_model( @@ -257,8 +258,9 @@ async def copy_model( source_model_id: str, target_resource_id: str, target_resource_region: str, - target_endpoint: str, - target_credential: "AzureKeyCredential", + copy_authorization: Optional["CopyAuthorization"] = None, + target_endpoint_url: Optional[str] = None, + target_credential: Optional["AzureKeyCredential"] = None, **kwargs: Any ) -> CustomFormModelInfo: """Copy custom model stored in this resource (the source) to user specified target Form Recognizer resource. @@ -271,7 +273,11 @@ async def copy_model( where the model is copied to. :param str target_resource_region: Location of the target Azure resource. A valid Azure region name supported by Cognitive Services. - :param str target_endpoint: The target endpoint to transfer the copied model. + :param ~azure.ai.formrecognizer.CopyAuthorization copy_authorization: + The copy authorization generated from the target resource's call to + :func:`~get_model_copy_authorization()`. You must pass either copy_authorization + or `target_credential` and `target_endpoint_url`. + :param str target_endpoint_url: The target endpoint to transfer the copied model. :param ~azure.core.credentials.AzureKeyCredential target_credential: The credential for the target resource. :keyword int polling_interval: Default waiting time between two polls for LRO operations if @@ -282,8 +288,11 @@ async def copy_model( """ polling_interval = kwargs.pop("polling_interval", POLLING_INTERVAL) - target_client = self._get_form_training_client(target_endpoint, target_credential) - copy_authorization = await target_client._generate_model_copy_authorization() + if target_endpoint_url and target_credential: + target_client = self._get_form_training_client(target_endpoint_url, target_credential) + copy_authorization = await target_client.get_model_copy_authorization() + elif copy_authorization is None: + raise ValueError("Pass only copy_authorization or target_endpoint_url and target_credential.") def _copy_callback(raw_response, _, headers): # pylint: disable=unused-argument copy_result = self._client._deserialize(CopyOperationResult, raw_response) diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_copy_model_async.py b/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_copy_model_async.py index ee062ce7ce63..d61cde44a8b6 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_copy_model_async.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_copy_model_async.py @@ -40,7 +40,7 @@ class CopyModelSampleAsync(object): target_region = os.environ["AZURE_FORM_RECOGNIZER_TARGET_REGION"] target_resource_id = os.environ["AZURE_FORM_RECOGNIZER_TARGET_RESOURCE_ID"] - async def copy_model(self): + async def copy_model_with_target_credentials(self): from azure.core.credentials import AzureKeyCredential from azure.ai.formrecognizer.aio import FormTrainingClient @@ -58,10 +58,30 @@ async def copy_model(self): copied_over_model = await target_client.get_custom_model(copy.model_id) print(copied_over_model) + async def copy_model_from_copy_auth(self): + from azure.core.credentials import AzureKeyCredential + from azure.ai.formrecognizer.aio import FormTrainingClient + + source_client = FormTrainingClient(endpoint=self.source_endpoint, credential=AzureKeyCredential(self.source_key)) + target_client = FormTrainingClient(endpoint=self.target_endpoint, credential=AzureKeyCredential(self.target_key)) + + copy_auth = await target_client.get_model_copy_authorization() + + copy = await source_client.copy_model( + source_model_id=self.source_model_id, + target_resource_region=self.target_region, + target_resource_id=self.target_resource_id, + copy_authorization=copy_auth + ) + + copied_over_model = await target_client.get_custom_model(copy.model_id) + print(copied_over_model) + async def main(): sample = CopyModelSampleAsync() - await sample.copy_model() + await sample.copy_model_with_target_credentials() + await sample.copy_model_from_copy_auth() if __name__ == '__main__': diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/samples/sample_copy_model.py b/sdk/formrecognizer/azure-ai-formrecognizer/samples/sample_copy_model.py index 1b0c5896b819..24e60887f0dd 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/samples/sample_copy_model.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/samples/sample_copy_model.py @@ -39,21 +39,39 @@ class CopyModelSample(object): target_region = os.environ["AZURE_FORM_RECOGNIZER_TARGET_REGION"] target_resource_id = os.environ["AZURE_FORM_RECOGNIZER_TARGET_RESOURCE_ID"] - def begin_copy_model(self): + def copy_model_with_target_credentials(self): from azure.core.credentials import AzureKeyCredential from azure.ai.formrecognizer import FormTrainingClient source_client = FormTrainingClient(endpoint=self.source_endpoint, credential=AzureKeyCredential(self.source_key)) target_client = FormTrainingClient(endpoint=self.target_endpoint, credential=AzureKeyCredential(self.target_key)) - poller = source_client.begin_copy_model( + copy = source_client.begin_copy_model( source_model_id=self.source_model_id, target_resource_region=self.target_region, target_resource_id=self.target_resource_id, target_endpoint=self.target_endpoint, target_credential=AzureKeyCredential(self.target_key) ) - copy = poller.result() + + copied_over_model = target_client.get_custom_model(copy.model_id) + print(copied_over_model) + + def copy_model_from_copy_auth(self): + from azure.core.credentials import AzureKeyCredential + from azure.ai.formrecognizer import FormTrainingClient + + source_client = FormTrainingClient(endpoint=self.source_endpoint, credential=AzureKeyCredential(self.source_key)) + target_client = FormTrainingClient(endpoint=self.target_endpoint, credential=AzureKeyCredential(self.target_key)) + + copy_auth = target_client.get_model_copy_authorization() + + copy = source_client.begin_copy_model( + source_model_id=self.source_model_id, + target_resource_region=self.target_region, + target_resource_id=self.target_resource_id, + copy_authorization=copy_auth + ) copied_over_model = target_client.get_custom_model(copy.model_id) print(copied_over_model) @@ -61,4 +79,5 @@ def begin_copy_model(self): if __name__ == '__main__': sample = CopyModelSample() - sample.begin_copy_model() + sample.copy_model_with_target_credentials() + sample.copy_model_from_copy_auth() From 3ff9b0b42a091d730148b1650b8fa9020805b7d9 Mon Sep 17 00:00:00 2001 From: Krista Pratico Date: Mon, 11 May 2020 12:25:46 -0700 Subject: [PATCH 06/22] add CopyAuthorization to init --- .../azure/ai/formrecognizer/__init__.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/__init__.py b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/__init__.py index b8225d383dbe..a000e8173de1 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/__init__.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/__init__.py @@ -33,7 +33,8 @@ FormWord, CustomFormModel, CustomFormSubModel, - CustomFormModelField + CustomFormModelField, + CopyAuthorization ) @@ -64,7 +65,8 @@ 'FormWord', 'CustomFormModel', 'CustomFormSubModel', - 'CustomFormModelField' + 'CustomFormModelField', + 'CopyAuthorization' ] __VERSION__ = VERSION From d127002948f5cf2676700652f652fb2264f9eb3b Mon Sep 17 00:00:00 2001 From: Krista Pratico Date: Mon, 11 May 2020 17:28:58 -0700 Subject: [PATCH 07/22] changes from feedback on design --- .../azure/ai/formrecognizer/__init__.py | 4 +- .../formrecognizer/_form_training_client.py | 74 +++++++++---------- .../azure/ai/formrecognizer/_models.py | 26 ++++--- .../aio/_form_training_client_async.py | 70 ++++++++---------- .../async_samples/sample_copy_model_async.py | 54 +++++--------- .../samples/sample_copy_model.py | 55 +++++--------- 6 files changed, 120 insertions(+), 163 deletions(-) diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/__init__.py b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/__init__.py index a000e8173de1..be3db186cee4 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/__init__.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/__init__.py @@ -34,7 +34,7 @@ CustomFormModel, CustomFormSubModel, CustomFormModelField, - CopyAuthorization + TargetInformation ) @@ -66,7 +66,7 @@ 'CustomFormModel', 'CustomFormSubModel', 'CustomFormModelField', - 'CopyAuthorization' + 'TargetInformation' ] __VERSION__ = VERSION diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_form_training_client.py b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_form_training_client.py index 1fb811266317..205686a96531 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_form_training_client.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_form_training_client.py @@ -17,13 +17,20 @@ from azure.core.polling.base_polling import LROBasePolling from azure.core.pipeline.policies import AzureKeyCredentialPolicy from ._generated._form_recognizer_client import FormRecognizerClient as FormRecognizer -from ._generated.models import TrainRequest, TrainSourceFilter, CopyRequest, Model, CopyOperationResult +from ._generated.models import ( + TrainRequest, + TrainSourceFilter, + CopyRequest, + Model, + CopyOperationResult, + CopyAuthorizationResult +) from ._helpers import error_map, POLLING_INTERVAL, COGNITIVE_KEY_HEADER from ._models import ( CustomFormModelInfo, AccountProperties, CustomFormModel, - CopyAuthorization + TargetInformation ) from ._polling import TrainingPolling from ._user_agent import USER_AGENT @@ -225,13 +232,16 @@ def get_custom_model(self, model_id, **kwargs): return CustomFormModel._from_generated(response) @distributed_trace - def get_model_copy_authorization(self, **kwargs): - # type: (Any) -> CopyAuthorization + def generate_copy_authorization(self, resource_id, resource_region, **kwargs): + # type: (str, str, Any) -> TargetInformation """Generate authorization to copy a model into the target Form Recognizer resource. - Generate Copy Authorization. - :return: CopyAuthorization - :rtype: ~azure.ai.formrecognizer.CopyAuthorization + :param str resource_id: Azure Resource Id of the target Form Recognizer resource + where the model will be copied to. + :param str resource_region: Location of the target Azure resource. A valid Azure + region name supported by Cognitive Services. + :return: TargetInformation + :rtype: ~azure.ai.formrecognizer.TargetInformation :raises: ~azure.core.exceptions.HttpResponseError """ @@ -240,17 +250,13 @@ def get_model_copy_authorization(self, **kwargs): error_map=error_map, **kwargs ) - return CopyAuthorization._from_generated(response) + return TargetInformation._from_generated(response, resource_id=resource_id, resource_region=resource_region) @distributed_trace def begin_copy_model( self, - source_model_id, # type: str - target_resource_id, # type: str - target_resource_region, # type: str - copy_authorization=None, # type: Optional[CopyAuthorization] - target_endpoint_url=None, # type: Optional[str] - target_credential=None, # type: Optional[AzureKeyCredential] + model_id, # type: str + target, # type: TargetInformation **kwargs # type: Any ): # type: (...) -> LROPoller @@ -258,19 +264,11 @@ def begin_copy_model( Copy Custom Model. - :param source_model_id: Model identifier. - :type source_model_id: str - :param str target_resource_id: Azure Resource Id of the target Form Recognizer resource - where the model is copied to. - :param str target_resource_region: Location of the target Azure resource. A valid Azure - region name supported by Cognitive Services. - :param ~azure.ai.formrecognizer.CopyAuthorization copy_authorization: + :param model_id: Model identifier of the model to copy to target resource. + :type model_id: str + :param ~azure.ai.formrecognizer.TargetInformation target: The copy authorization generated from the target resource's call to - :func:`~get_model_copy_authorization()`. You must pass either copy_authorization - or `target_credential` and `target_endpoint_url`. - :param str target_endpoint_url: The target endpoint to transfer the copied model. - :param ~azure.core.credentials.AzureKeyCredential target_credential: - The credential for the target resource. + :func:`~generate_copy_authorization()`. :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 @@ -280,22 +278,20 @@ def begin_copy_model( polling_interval = kwargs.pop("polling_interval", POLLING_INTERVAL) - if target_endpoint_url and target_credential: - target_client = self._get_form_training_client(target_endpoint_url, target_credential) - copy_authorization = target_client.get_model_copy_authorization() - elif copy_authorization is None: - raise ValueError("Pass only copy_authorization or target_endpoint_url and target_credential.") - def _copy_callback(raw_response, _, headers): # pylint: disable=unused-argument copy_result = self._client._deserialize(CopyOperationResult, raw_response) - return CustomFormModelInfo._from_generated_copy(copy_result, copy_authorization.model_id) + return CustomFormModelInfo._from_generated_copy(copy_result, target.model_id) return self._client.begin_copy_custom_model( # type: ignore - model_id=source_model_id, + model_id=model_id, copy_request=CopyRequest( - target_resource_id=target_resource_id, - target_resource_region=target_resource_region, - copy_authorization=copy_authorization + target_resource_id=target.resource_id, + target_resource_region=target.resource_region, + copy_authorization=CopyAuthorizationResult( + model_id=target.model_id, + access_token=target.access_token, + expiration_date_time_ticks=target.expiration_date_time_ticks + ) ), cls=kwargs.pop("cls", _copy_callback), polling=LROBasePolling(timeout=polling_interval, **kwargs), @@ -303,10 +299,6 @@ def _copy_callback(raw_response, _, headers): # pylint: disable=unused-argument **kwargs ) - @classmethod - def _get_form_training_client(cls, endpoint, credential): - return cls(endpoint, credential) - def close(self): # type: () -> None """Close the :class:`~azure.ai.formrecognizer.FormTrainingClient` session. diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_models.py b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_models.py index 8a2ca26d7a7b..d09a9255a4cd 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_models.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_models.py @@ -10,7 +10,6 @@ from collections import namedtuple import re import six -from ._generated.models import CopyAuthorizationResult def adjust_confidence(score): @@ -896,11 +895,16 @@ def __repr__(self): )[:1024] -class CopyAuthorization(CopyAuthorizationResult): - """Request parameter that contains authorization claims for copy operation. +class TargetInformation(object): + """Information about target Form Recognizer resource that contains + authorization claims for copy operation. :ivar str model_id: Model identifier. - :ivar str access_token: Required. Token claim used to authorize the request. + :ivar str access_token: Token claim used to authorize the request. + :ivar str resource_id: Azure Resource Id of the target Form Recognizer resource + where the model will be copied to. + :ivar str resource_region: Location of the target Azure resource. A valid Azure + region name supported by Cognitive Services. :ivar int expiration_date_time_ticks: The time when the access token expires. The date is represented as the number of seconds from 1970-01-01T0:0:0Z UTC until the expiration time. """ @@ -909,20 +913,24 @@ def __init__( self, **kwargs ): - super(CopyAuthorization, self).__init__(**kwargs) self.model_id = kwargs.get('model_id', None) + self.resource_id = kwargs.get('resource_id', None) + self.resource_region = kwargs.get('resource_region', None) self.access_token = kwargs.get('access_token', None) self.expiration_date_time_ticks = kwargs.get('expiration_date_time_ticks', None) @classmethod - def _from_generated(cls, copy): + def _from_generated(cls, copy, resource_id, resource_region): return cls( model_id=copy.model_id, + resource_id=resource_id, + resource_region=resource_region, access_token=copy.access_token, expiration_date_time_ticks=copy.expiration_date_time_ticks ) def __repr__(self): - return "CopyAuthorization(model_id={}, access_token={}, expiration_date_time_ticks={})".format( - self.model_id, self.access_token, self.expiration_date_time_ticks - )[:1024] + return "TargetInformation(model_id={}, resource_id={}, resource_region={}, access_token={}, " \ + "expiration_date_time_ticks={})".format( + self.model_id, self.resource_id, self.resource_region, self.access_token, + self.expiration_date_time_ticks)[:1024] diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/aio/_form_training_client_async.py b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/aio/_form_training_client_async.py index 7988a7bc5735..9b1b102064ec 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/aio/_form_training_client_async.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/aio/_form_training_client_async.py @@ -23,14 +23,15 @@ TrainSourceFilter, Model, CopyRequest, - CopyOperationResult + CopyOperationResult, + CopyAuthorizationResult ) from .._helpers import error_map, POLLING_INTERVAL, COGNITIVE_KEY_HEADER from .._models import ( CustomFormModelInfo, AccountProperties, CustomFormModel, - CopyAuthorization + TargetInformation ) from .._user_agent import USER_AGENT from .._polling import TrainingPolling @@ -237,11 +238,20 @@ async def get_custom_model(self, model_id: str, **kwargs: Any) -> CustomFormMode return CustomFormModel._from_generated(response) @distributed_trace_async - async def get_model_copy_authorization(self, **kwargs: Any) -> "CopyAuthorization": + async def generate_copy_authorization( + self, + resource_id: str, + resource_region: str, + **kwargs: Any + ) -> "TargetInformation": """Generate authorization to copy a model into the target Form Recognizer resource. - :return: CopyAuthorization - :rtype: ~azure.ai.formrecognizer.CopyAuthorization + :param str resource_id: Azure Resource Id of the target Form Recognizer resource + where the model will be copied to. + :param str resource_region: Location of the target Azure resource. A valid Azure + region name supported by Cognitive Services. + :return: TargetInformation + :rtype: ~azure.ai.formrecognizer.TargetInformation :raises: ~azure.core.exceptions.HttpResponseError """ @@ -250,36 +260,24 @@ async def get_model_copy_authorization(self, **kwargs: Any) -> "CopyAuthorizatio error_map=error_map, **kwargs ) - return CopyAuthorization._from_generated(response) + return TargetInformation._from_generated(response, resource_id=resource_id, resource_region=resource_region) @distributed_trace_async async def copy_model( self, - source_model_id: str, - target_resource_id: str, - target_resource_region: str, - copy_authorization: Optional["CopyAuthorization"] = None, - target_endpoint_url: Optional[str] = None, - target_credential: Optional["AzureKeyCredential"] = None, + model_id: str, + target: "TargetInformation", **kwargs: Any ) -> CustomFormModelInfo: """Copy custom model stored in this resource (the source) to user specified target Form Recognizer resource. Copy Custom Model. - :param source_model_id: Model identifier. - :type source_model_id: str - :param str target_resource_id: Azure Resource Id of the target Form Recognizer resource - where the model is copied to. - :param str target_resource_region: Location of the target Azure resource. A valid Azure - region name supported by Cognitive Services. - :param ~azure.ai.formrecognizer.CopyAuthorization copy_authorization: + :param model_id: Model identifier of the model to copy to target resource. + :type model_id: str + :param ~azure.ai.formrecognizer.TargetInformation target: The copy authorization generated from the target resource's call to - :func:`~get_model_copy_authorization()`. You must pass either copy_authorization - or `target_credential` and `target_endpoint_url`. - :param str target_endpoint_url: The target endpoint to transfer the copied model. - :param ~azure.core.credentials.AzureKeyCredential target_credential: - The credential for the target resource. + :func:`~generate_copy_authorization()`. :keyword int polling_interval: Default waiting time between two polls for LRO operations if no Retry-After header is present. :return: An instance of CustomFormModelInfo @@ -288,22 +286,20 @@ async def copy_model( """ polling_interval = kwargs.pop("polling_interval", POLLING_INTERVAL) - if target_endpoint_url and target_credential: - target_client = self._get_form_training_client(target_endpoint_url, target_credential) - copy_authorization = await target_client.get_model_copy_authorization() - elif copy_authorization is None: - raise ValueError("Pass only copy_authorization or target_endpoint_url and target_credential.") - def _copy_callback(raw_response, _, headers): # pylint: disable=unused-argument copy_result = self._client._deserialize(CopyOperationResult, raw_response) - return CustomFormModelInfo._from_generated_copy(copy_result, copy_authorization.model_id) + return CustomFormModelInfo._from_generated_copy(copy_result, target.model_id) return await self._client.copy_custom_model( # type: ignore - model_id=source_model_id, + model_id=model_id, copy_request=CopyRequest( - target_resource_id=target_resource_id, - target_resource_region=target_resource_region, - copy_authorization=copy_authorization + target_resource_id=target.resource_id, + target_resource_region=target.resource_region, + copy_authorization=CopyAuthorizationResult( + model_id=target.model_id, + access_token=target.access_token, + expiration_date_time_ticks=target.expiration_date_time_ticks + ) ), cls=kwargs.pop("cls", _copy_callback), polling=AsyncLROBasePolling(timeout=polling_interval, **kwargs), @@ -311,10 +307,6 @@ def _copy_callback(raw_response, _, headers): # pylint: disable=unused-argument **kwargs ) - @classmethod - def _get_form_training_client(cls, endpoint, credential): - return cls(endpoint, credential) - async def __aenter__(self) -> "FormTrainingClient": await self._client.__aenter__() return self diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_copy_model_async.py b/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_copy_model_async.py index d61cde44a8b6..7d139e24f604 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_copy_model_async.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_copy_model_async.py @@ -32,56 +32,38 @@ class CopyModelSampleAsync(object): - source_endpoint = os.environ["AZURE_FORM_RECOGNIZER_ENDPOINT"] - source_key = os.environ["AZURE_FORM_RECOGNIZER_KEY"] - target_endpoint = os.environ["AZURE_FORM_RECOGNIZER_TARGET_ENDPOINT"] - target_key = os.environ["AZURE_FORM_RECOGNIZER_TARGET_KEY"] - source_model_id = os.environ["AZURE_SOURCE_MODEL_ID"] - target_region = os.environ["AZURE_FORM_RECOGNIZER_TARGET_REGION"] - target_resource_id = os.environ["AZURE_FORM_RECOGNIZER_TARGET_RESOURCE_ID"] - - async def copy_model_with_target_credentials(self): + async def copy_model_async(self): from azure.core.credentials import AzureKeyCredential from azure.ai.formrecognizer.aio import FormTrainingClient - source_client = FormTrainingClient(endpoint=self.source_endpoint, credential=AzureKeyCredential(self.source_key)) - target_client = FormTrainingClient(endpoint=self.target_endpoint, credential=AzureKeyCredential(self.target_key)) + source_endpoint = os.environ["AZURE_FORM_RECOGNIZER_ENDPOINT"] + source_key = os.environ["AZURE_FORM_RECOGNIZER_KEY"] + target_endpoint = os.environ["AZURE_FORM_RECOGNIZER_TARGET_ENDPOINT"] + target_key = os.environ["AZURE_FORM_RECOGNIZER_TARGET_KEY"] + source_model_id = os.environ["AZURE_SOURCE_MODEL_ID"] + target_region = os.environ["AZURE_FORM_RECOGNIZER_TARGET_REGION"] + target_resource_id = os.environ["AZURE_FORM_RECOGNIZER_TARGET_RESOURCE_ID"] - copy = await source_client.copy_model( - source_model_id=self.source_model_id, - target_resource_region=self.target_region, - target_resource_id=self.target_resource_id, - target_endpoint=self.target_endpoint, - target_credential=AzureKeyCredential(self.target_key) - ) + source_client = FormTrainingClient(endpoint=source_endpoint, credential=AzureKeyCredential(source_key)) + target_client = FormTrainingClient(endpoint=target_endpoint, credential=AzureKeyCredential(target_key)) - copied_over_model = await target_client.get_custom_model(copy.model_id) - print(copied_over_model) - - async def copy_model_from_copy_auth(self): - from azure.core.credentials import AzureKeyCredential - from azure.ai.formrecognizer.aio import FormTrainingClient - - source_client = FormTrainingClient(endpoint=self.source_endpoint, credential=AzureKeyCredential(self.source_key)) - target_client = FormTrainingClient(endpoint=self.target_endpoint, credential=AzureKeyCredential(self.target_key)) - - copy_auth = await target_client.get_model_copy_authorization() + target = await target_client.generate_copy_authorization( + resource_region=target_region, + resource_id=target_resource_id + ) copy = await source_client.copy_model( - source_model_id=self.source_model_id, - target_resource_region=self.target_region, - target_resource_id=self.target_resource_id, - copy_authorization=copy_auth + model_id=source_model_id, + target=target ) - copied_over_model = await target_client.get_custom_model(copy.model_id) + copied_over_model = target_client.get_custom_model(copy.model_id) print(copied_over_model) async def main(): sample = CopyModelSampleAsync() - await sample.copy_model_with_target_credentials() - await sample.copy_model_from_copy_auth() + await sample.copy_model_async() if __name__ == '__main__': diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/samples/sample_copy_model.py b/sdk/formrecognizer/azure-ai-formrecognizer/samples/sample_copy_model.py index 24e60887f0dd..c902eecdcfc6 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/samples/sample_copy_model.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/samples/sample_copy_model.py @@ -31,47 +31,31 @@ class CopyModelSample(object): - source_endpoint = os.environ["AZURE_FORM_RECOGNIZER_ENDPOINT"] - source_key = os.environ["AZURE_FORM_RECOGNIZER_KEY"] - target_endpoint = os.environ["AZURE_FORM_RECOGNIZER_TARGET_ENDPOINT"] - target_key = os.environ["AZURE_FORM_RECOGNIZER_TARGET_KEY"] - source_model_id = os.environ["AZURE_SOURCE_MODEL_ID"] - target_region = os.environ["AZURE_FORM_RECOGNIZER_TARGET_REGION"] - target_resource_id = os.environ["AZURE_FORM_RECOGNIZER_TARGET_RESOURCE_ID"] - - def copy_model_with_target_credentials(self): + def copy_model(self): from azure.core.credentials import AzureKeyCredential from azure.ai.formrecognizer import FormTrainingClient - source_client = FormTrainingClient(endpoint=self.source_endpoint, credential=AzureKeyCredential(self.source_key)) - target_client = FormTrainingClient(endpoint=self.target_endpoint, credential=AzureKeyCredential(self.target_key)) + source_endpoint = os.environ["AZURE_FORM_RECOGNIZER_ENDPOINT"] + source_key = os.environ["AZURE_FORM_RECOGNIZER_KEY"] + target_endpoint = os.environ["AZURE_FORM_RECOGNIZER_TARGET_ENDPOINT"] + target_key = os.environ["AZURE_FORM_RECOGNIZER_TARGET_KEY"] + source_model_id = os.environ["AZURE_SOURCE_MODEL_ID"] + target_region = os.environ["AZURE_FORM_RECOGNIZER_TARGET_REGION"] + target_resource_id = os.environ["AZURE_FORM_RECOGNIZER_TARGET_RESOURCE_ID"] - copy = source_client.begin_copy_model( - source_model_id=self.source_model_id, - target_resource_region=self.target_region, - target_resource_id=self.target_resource_id, - target_endpoint=self.target_endpoint, - target_credential=AzureKeyCredential(self.target_key) - ) + source_client = FormTrainingClient(endpoint=source_endpoint, credential=AzureKeyCredential(source_key)) + target_client = FormTrainingClient(endpoint=target_endpoint, credential=AzureKeyCredential(target_key)) - copied_over_model = target_client.get_custom_model(copy.model_id) - print(copied_over_model) - - def copy_model_from_copy_auth(self): - from azure.core.credentials import AzureKeyCredential - from azure.ai.formrecognizer import FormTrainingClient - - source_client = FormTrainingClient(endpoint=self.source_endpoint, credential=AzureKeyCredential(self.source_key)) - target_client = FormTrainingClient(endpoint=self.target_endpoint, credential=AzureKeyCredential(self.target_key)) - - copy_auth = target_client.get_model_copy_authorization() + target = target_client.generate_copy_authorization( + resource_region=target_region, + resource_id=target_resource_id + ) - copy = source_client.begin_copy_model( - source_model_id=self.source_model_id, - target_resource_region=self.target_region, - target_resource_id=self.target_resource_id, - copy_authorization=copy_auth + poller = source_client.begin_copy_model( + model_id=source_model_id, + target=target ) + copy = poller.result() copied_over_model = target_client.get_custom_model(copy.model_id) print(copied_over_model) @@ -79,5 +63,4 @@ def copy_model_from_copy_auth(self): if __name__ == '__main__': sample = CopyModelSample() - sample.copy_model_with_target_credentials() - sample.copy_model_from_copy_auth() + sample.copy_model() From a8ac624bcb71d0620c529f76b1582fd4e37b066f Mon Sep 17 00:00:00 2001 From: Krista Pratico Date: Mon, 11 May 2020 18:09:56 -0700 Subject: [PATCH 08/22] raise better error messages in polling for failed copying --- .../formrecognizer/_form_training_client.py | 4 +-- .../azure/ai/formrecognizer/_polling.py | 36 +++++++++++++++++++ .../aio/_form_training_client_async.py | 4 +-- 3 files changed, 40 insertions(+), 4 deletions(-) diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_form_training_client.py b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_form_training_client.py index 205686a96531..4e8ce350ef5c 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_form_training_client.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_form_training_client.py @@ -32,7 +32,7 @@ CustomFormModel, TargetInformation ) -from ._polling import TrainingPolling +from ._polling import TrainingPolling, CopyPolling from ._user_agent import USER_AGENT if TYPE_CHECKING: from azure.core.credentials import AzureKeyCredential @@ -294,7 +294,7 @@ def _copy_callback(raw_response, _, headers): # pylint: disable=unused-argument ) ), cls=kwargs.pop("cls", _copy_callback), - polling=LROBasePolling(timeout=polling_interval, **kwargs), + polling=LROBasePolling(timeout=polling_interval, lro_algorithms=[CopyPolling()], **kwargs), error_map=error_map, **kwargs ) diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_polling.py b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_polling.py index 15785d0aae18..d2e8bf3903f5 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_polling.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_polling.py @@ -83,3 +83,39 @@ def get_status(self, pipeline_response): # pylint: disable=no-self-use message += "({}) {}\n".format(err.get("code"), err.get("message")) raise HttpResponseError(message) return status + + +class CopyPolling(OperationResourcePolling): + """Polling method overrides for copy endpoint. + + """ + + def get_status(self, pipeline_response): # pylint: disable=no-self-use + # type: (PipelineResponse) -> str + """Process the latest status update retrieved from an "Operation-Location" header. + Raise errors for issues occurring during the copy model operation. + + :param azure.core.pipeline.PipelineResponse pipeline_response: The response to extract the status. + :raises: BadResponse if response has no body, or body does not contain status. + HttpResponseError if there is an error with the input document. + """ + response = pipeline_response.http_response + if _is_empty(response): + raise BadResponse( + "The response from long running operation does not contain a body." + ) + + body = _as_json(response) + status = body.get("status") + if not status: + raise BadResponse("No status found in body") + if status.lower() == "failed": + copy_result = body.get("copyResult") + if copy_result: + errors = copy_result.get("errors") + if errors: + message = "" + for err in errors: + message += "({}) {}\n".format(err.get("code"), err.get("message")) + raise HttpResponseError(message) + return status diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/aio/_form_training_client_async.py b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/aio/_form_training_client_async.py index 9b1b102064ec..f56db98cf2e3 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/aio/_form_training_client_async.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/aio/_form_training_client_async.py @@ -34,7 +34,7 @@ TargetInformation ) from .._user_agent import USER_AGENT -from .._polling import TrainingPolling +from .._polling import TrainingPolling, CopyPolling if TYPE_CHECKING: from azure.core.credentials import AzureKeyCredential @@ -302,7 +302,7 @@ def _copy_callback(raw_response, _, headers): # pylint: disable=unused-argument ) ), cls=kwargs.pop("cls", _copy_callback), - polling=AsyncLROBasePolling(timeout=polling_interval, **kwargs), + polling=AsyncLROBasePolling(timeout=polling_interval, lro_algorithms=[CopyPolling()], **kwargs), error_map=error_map, **kwargs ) From 19c77c74b6a3544167151a7b87e9097eb9b5bc20 Mon Sep 17 00:00:00 2001 From: Krista Pratico Date: Tue, 12 May 2020 09:09:14 -0700 Subject: [PATCH 09/22] update readme/changelog --- sdk/formrecognizer/azure-ai-formrecognizer/CHANGELOG.md | 3 +++ sdk/formrecognizer/azure-ai-formrecognizer/README.md | 5 +++++ sdk/formrecognizer/azure-ai-formrecognizer/samples/README.md | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/CHANGELOG.md b/sdk/formrecognizer/azure-ai-formrecognizer/CHANGELOG.md index 2a276e3a36c5..d41d32e10d97 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/CHANGELOG.md +++ b/sdk/formrecognizer/azure-ai-formrecognizer/CHANGELOG.md @@ -2,6 +2,9 @@ ## 1.0.0b3 (Unreleased) +**New features** + +- Copy API is now supported to copy a model from one Form Recognizer resource to another ## 1.0.0b2 (2020-05-06) diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/README.md b/sdk/formrecognizer/azure-ai-formrecognizer/README.md index c38e74bd645d..202475e620b1 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/README.md +++ b/sdk/formrecognizer/azure-ai-formrecognizer/README.md @@ -100,8 +100,10 @@ form_recognizer_client = FormRecognizerClient(endpoint, credential) - Training custom models to recognize all fields and values found in your custom forms. A `CustomFormModel` is returned indicating the form types the model will recognize, and the fields it will extract for each form type. See the [service's documents][fr-train-without-labels] for a more detailed explanation. - Training custom models to recognize specific fields and values you specify by labeling your custom forms. A `CustomFormModel` is returned indicating the fields the model will extract, as well as the estimated accuracy for each field. See the [service's documents][fr-train-with-labels] for a more detailed explanation. - Managing models created in your account. +- Copying a model from one Form Recognizer resource to another. Please note that models can also be trained using a graphical user interface such as the [Form Recognizer Labeling Tool][fr-labeling-tool]. + ### Long-Running Operations Long-running operations are operations which consist of an initial request sent to the service to start an operation, followed by polling the service at intervals to determine whether the operation has completed or failed, and if it has @@ -356,6 +358,7 @@ with Form Recognizer and require Python 3.5 or later. * Train a model without labels: [sample_train_model_without_labels.py][sample_train_model_without_labels] ([async version][sample_train_model_without_labels_async]) * Train a model with labels: [sample_train_model_with_labels.py][sample_train_model_with_labels] ([async version][sample_train_model_with_labels_async]) * Manage custom models: [sample_manage_custom_models.py][sample_manage_custom_models] ([async_version][sample_manage_custom_models_async]) +* Copy a model between Form Recognizer resources: [sample_copy_model.py][sample_copy_model] ([async_version][sample_copy_model_async]) ### Additional documentation @@ -424,3 +427,5 @@ This project has adopted the [Microsoft Open Source Code of Conduct][code_of_con [sample_train_model_with_labels_async]: https://github.com/Azure/azure-sdk-for-python/tree/master/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_train_model_with_labels_async.py [sample_train_model_without_labels]: https://github.com/Azure/azure-sdk-for-python/tree/master/sdk/formrecognizer/azure-ai-formrecognizer/samples/sample_train_model_without_labels.py [sample_train_model_without_labels_async]: https://github.com/Azure/azure-sdk-for-python/tree/master/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_train_model_without_labels_async.py +[sample_copy_model]: https://github.com/Azure/azure-sdk-for-python/tree/master/sdk/formrecognizer/azure-ai-formrecognizer/samples/sample_copy_model.py +[sample_copy_model_async]: https://github.com/Azure/azure-sdk-for-python/tree/master/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_copy_model_async.py diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/samples/README.md b/sdk/formrecognizer/azure-ai-formrecognizer/samples/README.md index 6ba5a7ebf6b3..c81e1e7a38f3 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/samples/README.md +++ b/sdk/formrecognizer/azure-ai-formrecognizer/samples/README.md @@ -26,6 +26,8 @@ All of these samples need the endpoint to your Form Recognizer resource ([instru |[sample_train_model_without_labels.py][sample_train_model_without_labels] and [sample_train_model_without_labels_async.py][sample_train_model_without_labels_async]|Train a custom model with unlabeled data| |[sample_train_model_with_labels.py][sample_train_model_with_labels] and [sample_train_model_with_labels_async.py][sample_train_model_with_labels_async]|Train a custom model with labeled data| |[sample_manage_custom_models.py][sample_manage_custom_models] and [sample_manage_custom_models_async.py][sample_manage_custom_models_async]|Manage the custom models in your account| +|[sample_copy_model.py][sample_copy_model] and [sample_copy_model_async.py][sample_copy_model_async]|Copy a model from one Form Recognizer resource to another| + ## Prerequisites * Python 2.7, or 3.5 or later is required to use this package (3.5 or later if using asyncio) @@ -87,3 +89,5 @@ what you can do with the Azure Form Recognizer client library. [sample_train_model_with_labels_async]: https://github.com/Azure/azure-sdk-for-python/tree/master/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_train_model_with_labels_async.py [sample_train_model_without_labels]: https://github.com/Azure/azure-sdk-for-python/tree/master/sdk/formrecognizer/azure-ai-formrecognizer/samples/sample_train_model_without_labels.py [sample_train_model_without_labels_async]: https://github.com/Azure/azure-sdk-for-python/tree/master/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_train_model_without_labels_async.py +[sample_copy_model]: https://github.com/Azure/azure-sdk-for-python/tree/master/sdk/formrecognizer/azure-ai-formrecognizer/samples/sample_copy_model.py +[sample_copy_model_async]: https://github.com/Azure/azure-sdk-for-python/tree/master/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_copy_model_async.py \ No newline at end of file From 40ac0064292233b0235be6a81613115c3f356e1e Mon Sep 17 00:00:00 2001 From: Krista Pratico Date: Tue, 12 May 2020 12:42:37 -0700 Subject: [PATCH 10/22] updating sample snippets --- .../formrecognizer/_form_training_client.py | 27 +++++++++++++++-- .../aio/_form_training_client_async.py | 27 +++++++++++++++-- .../async_samples/sample_copy_model_async.py | 30 ++++++++++++------- .../samples/sample_copy_model.py | 9 ++++-- 4 files changed, 74 insertions(+), 19 deletions(-) diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_form_training_client.py b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_form_training_client.py index 4e8ce350ef5c..28047947c35a 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_form_training_client.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_form_training_client.py @@ -235,6 +235,8 @@ def get_custom_model(self, model_id, **kwargs): def generate_copy_authorization(self, resource_id, resource_region, **kwargs): # type: (str, str, Any) -> TargetInformation """Generate authorization to copy a model into the target Form Recognizer resource. + This should be called by the target resource (where the model will be copied to) + and the output can be passed into :func:`~begin_copy_model()` :param str resource_id: Azure Resource Id of the target Form Recognizer resource where the model will be copied to. @@ -242,7 +244,16 @@ def generate_copy_authorization(self, resource_id, resource_region, **kwargs): region name supported by Cognitive Services. :return: TargetInformation :rtype: ~azure.ai.formrecognizer.TargetInformation - :raises: ~azure.core.exceptions.HttpResponseError + :raises ~azure.core.exceptions.HttpResponseError: + + .. admonition:: Example: + + .. literalinclude:: ../samples/sample_copy_model.py + :start-after: [START generate_copy_auth] + :end-before: [END generate_copy_auth] + :language: python + :dedent: 8 + :caption: Generate copy authorization with the target resource """ response = self._client.generate_model_copy_authorization( # type: ignore @@ -261,8 +272,9 @@ def begin_copy_model( ): # type: (...) -> LROPoller """Copy custom model stored in this resource (the source) to user specified target Form Recognizer resource. - - Copy Custom Model. + This should be called with the source Form Recognizer resource (with model that is intended to be copied). + The `target` parameter should be supplied from the target resource's output from calling the + :func:`~generate_copy_authorization()` method. :param model_id: Model identifier of the model to copy to target resource. :type model_id: str @@ -274,6 +286,15 @@ def begin_copy_model( :return: An instance of LROPoller :rtype: ~azure.core.polling.LROPoller[CustomFormModelInfo] :raises ~azure.core.exceptions.HttpResponseError: + + .. admonition:: Example: + + .. literalinclude:: ../samples/sample_copy_model.py + :start-after: [START begin_copy_model] + :end-before: [END begin_copy_model] + :language: python + :dedent: 8 + :caption: Copy a model from the source resource to the target resource """ polling_interval = kwargs.pop("polling_interval", POLLING_INTERVAL) diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/aio/_form_training_client_async.py b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/aio/_form_training_client_async.py index f56db98cf2e3..bf00abc27f98 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/aio/_form_training_client_async.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/aio/_form_training_client_async.py @@ -245,6 +245,8 @@ async def generate_copy_authorization( **kwargs: Any ) -> "TargetInformation": """Generate authorization to copy a model into the target Form Recognizer resource. + This should be called by the target resource (where the model will be copied to) + and the output can be passed into :func:`~copy_model()` :param str resource_id: Azure Resource Id of the target Form Recognizer resource where the model will be copied to. @@ -252,7 +254,16 @@ async def generate_copy_authorization( region name supported by Cognitive Services. :return: TargetInformation :rtype: ~azure.ai.formrecognizer.TargetInformation - :raises: ~azure.core.exceptions.HttpResponseError + :raises ~azure.core.exceptions.HttpResponseError: + + .. admonition:: Example: + + .. literalinclude:: ../samples/async_samples/sample_copy_model_async.py + :start-after: [START generate_copy_auth_async] + :end-before: [END generate_copy_auth_async] + :language: python + :dedent: 8 + :caption: Generate copy authorization with the target resource """ response = await self._client.generate_model_copy_authorization( # type: ignore @@ -270,8 +281,9 @@ async def copy_model( **kwargs: Any ) -> CustomFormModelInfo: """Copy custom model stored in this resource (the source) to user specified target Form Recognizer resource. - - Copy Custom Model. + This should be called with the source Form Recognizer resource (with model that is intended to be copied). + The `target` parameter should be supplied from the target resource's output from calling the + :func:`~generate_copy_authorization()` method. :param model_id: Model identifier of the model to copy to target resource. :type model_id: str @@ -283,6 +295,15 @@ async def copy_model( :return: An instance of CustomFormModelInfo :rtype: ~azure.ai.formrecognizer.CustomFormModelInfo :raises ~azure.core.exceptions.HttpResponseError: + + .. admonition:: Example: + + .. literalinclude:: ../samples/async_samples/sample_copy_model_async.py + :start-after: [START copy_model_async] + :end-before: [END copy_model_async] + :language: python + :dedent: 8 + :caption: Copy a model from the source resource to the target resource """ polling_interval = kwargs.pop("polling_interval", POLLING_INTERVAL) diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_copy_model_async.py b/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_copy_model_async.py index 7d139e24f604..be6c6e96cf26 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_copy_model_async.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_copy_model_async.py @@ -44,22 +44,30 @@ async def copy_model_async(self): target_region = os.environ["AZURE_FORM_RECOGNIZER_TARGET_REGION"] target_resource_id = os.environ["AZURE_FORM_RECOGNIZER_TARGET_RESOURCE_ID"] - source_client = FormTrainingClient(endpoint=source_endpoint, credential=AzureKeyCredential(source_key)) + # [START generate_copy_auth_async] target_client = FormTrainingClient(endpoint=target_endpoint, credential=AzureKeyCredential(target_key)) - target = await target_client.generate_copy_authorization( - resource_region=target_region, - resource_id=target_resource_id - ) + async with target_client: + target = await target_client.generate_copy_authorization( + resource_region=target_region, + resource_id=target_resource_id + ) + # [END generate_copy_auth_async] - copy = await source_client.copy_model( - model_id=source_model_id, - target=target - ) + # [START copy_model_async] + source_client = FormTrainingClient(endpoint=source_endpoint, credential=AzureKeyCredential(source_key)) + target_client = FormTrainingClient(endpoint=target_endpoint, credential=AzureKeyCredential(target_key)) - copied_over_model = target_client.get_custom_model(copy.model_id) - print(copied_over_model) + async with source_client: + copy = await source_client.copy_model( + model_id=source_model_id, + target=target + ) + async with target_client: + copied_over_model = await target_client.get_custom_model(copy.model_id) + print(copied_over_model) + # [END copy_model_async] async def main(): sample = CopyModelSampleAsync() diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/samples/sample_copy_model.py b/sdk/formrecognizer/azure-ai-formrecognizer/samples/sample_copy_model.py index c902eecdcfc6..b614aef4968e 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/samples/sample_copy_model.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/samples/sample_copy_model.py @@ -43,13 +43,18 @@ def copy_model(self): target_region = os.environ["AZURE_FORM_RECOGNIZER_TARGET_REGION"] target_resource_id = os.environ["AZURE_FORM_RECOGNIZER_TARGET_RESOURCE_ID"] - source_client = FormTrainingClient(endpoint=source_endpoint, credential=AzureKeyCredential(source_key)) + # [START generate_copy_auth] target_client = FormTrainingClient(endpoint=target_endpoint, credential=AzureKeyCredential(target_key)) target = target_client.generate_copy_authorization( resource_region=target_region, resource_id=target_resource_id ) + # [END generate_copy_auth] + + # [START begin_copy_model] + source_client = FormTrainingClient(endpoint=source_endpoint, credential=AzureKeyCredential(source_key)) + target_client = FormTrainingClient(endpoint=target_endpoint, credential=AzureKeyCredential(target_key)) poller = source_client.begin_copy_model( model_id=source_model_id, @@ -59,7 +64,7 @@ def copy_model(self): copied_over_model = target_client.get_custom_model(copy.model_id) print(copied_over_model) - + # [END begin_copy_model] if __name__ == '__main__': sample = CopyModelSample() From 464877ff2d65ded48ab6885957fa98cde455e4a6 Mon Sep 17 00:00:00 2001 From: Krista Pratico Date: Tue, 12 May 2020 14:58:46 -0700 Subject: [PATCH 11/22] renames to align with .net --- .../azure/ai/formrecognizer/__init__.py | 4 ++-- .../formrecognizer/_form_training_client.py | 20 +++++++++---------- .../azure/ai/formrecognizer/_models.py | 4 ++-- .../aio/_form_training_client_async.py | 20 +++++++++---------- .../async_samples/sample_copy_model_async.py | 3 ++- .../samples/sample_copy_model.py | 3 ++- 6 files changed, 28 insertions(+), 26 deletions(-) diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/__init__.py b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/__init__.py index be3db186cee4..d4b572b5f314 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/__init__.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/__init__.py @@ -34,7 +34,7 @@ CustomFormModel, CustomFormSubModel, CustomFormModelField, - TargetInformation + CopyTarget ) @@ -66,7 +66,7 @@ 'CustomFormModel', 'CustomFormSubModel', 'CustomFormModelField', - 'TargetInformation' + 'CopyTarget' ] __VERSION__ = VERSION diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_form_training_client.py b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_form_training_client.py index 28047947c35a..7d1eab3e126a 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_form_training_client.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_form_training_client.py @@ -30,7 +30,7 @@ CustomFormModelInfo, AccountProperties, CustomFormModel, - TargetInformation + CopyTarget ) from ._polling import TrainingPolling, CopyPolling from ._user_agent import USER_AGENT @@ -232,8 +232,8 @@ def get_custom_model(self, model_id, **kwargs): return CustomFormModel._from_generated(response) @distributed_trace - def generate_copy_authorization(self, resource_id, resource_region, **kwargs): - # type: (str, str, Any) -> TargetInformation + def authorize_copy_target(self, resource_id, resource_region, **kwargs): + # type: (str, str, Any) -> CopyTarget """Generate authorization to copy a model into the target Form Recognizer resource. This should be called by the target resource (where the model will be copied to) and the output can be passed into :func:`~begin_copy_model()` @@ -242,8 +242,8 @@ def generate_copy_authorization(self, resource_id, resource_region, **kwargs): where the model will be copied to. :param str resource_region: Location of the target Azure resource. A valid Azure region name supported by Cognitive Services. - :return: TargetInformation - :rtype: ~azure.ai.formrecognizer.TargetInformation + :return: CopyTarget + :rtype: ~azure.ai.formrecognizer.CopyTarget :raises ~azure.core.exceptions.HttpResponseError: .. admonition:: Example: @@ -261,26 +261,26 @@ def generate_copy_authorization(self, resource_id, resource_region, **kwargs): error_map=error_map, **kwargs ) - return TargetInformation._from_generated(response, resource_id=resource_id, resource_region=resource_region) + return CopyTarget._from_generated(response, resource_id=resource_id, resource_region=resource_region) @distributed_trace def begin_copy_model( self, model_id, # type: str - target, # type: TargetInformation + target, # type: CopyTarget **kwargs # type: Any ): # type: (...) -> LROPoller """Copy custom model stored in this resource (the source) to user specified target Form Recognizer resource. This should be called with the source Form Recognizer resource (with model that is intended to be copied). The `target` parameter should be supplied from the target resource's output from calling the - :func:`~generate_copy_authorization()` method. + :func:`~authorize_copy_target()` method. :param model_id: Model identifier of the model to copy to target resource. :type model_id: str - :param ~azure.ai.formrecognizer.TargetInformation target: + :param ~azure.ai.formrecognizer.CopyTarget target: The copy authorization generated from the target resource's call to - :func:`~generate_copy_authorization()`. + :func:`~authorize_copy_target()`. :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 diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_models.py b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_models.py index d09a9255a4cd..118c6d7cfc5d 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_models.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_models.py @@ -895,7 +895,7 @@ def __repr__(self): )[:1024] -class TargetInformation(object): +class CopyTarget(object): """Information about target Form Recognizer resource that contains authorization claims for copy operation. @@ -930,7 +930,7 @@ def _from_generated(cls, copy, resource_id, resource_region): ) def __repr__(self): - return "TargetInformation(model_id={}, resource_id={}, resource_region={}, access_token={}, " \ + return "CopyTarget(model_id={}, resource_id={}, resource_region={}, access_token={}, " \ "expiration_date_time_ticks={})".format( self.model_id, self.resource_id, self.resource_region, self.access_token, self.expiration_date_time_ticks)[:1024] diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/aio/_form_training_client_async.py b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/aio/_form_training_client_async.py index bf00abc27f98..e59a3d9399b1 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/aio/_form_training_client_async.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/aio/_form_training_client_async.py @@ -31,7 +31,7 @@ CustomFormModelInfo, AccountProperties, CustomFormModel, - TargetInformation + CopyTarget ) from .._user_agent import USER_AGENT from .._polling import TrainingPolling, CopyPolling @@ -238,12 +238,12 @@ async def get_custom_model(self, model_id: str, **kwargs: Any) -> CustomFormMode return CustomFormModel._from_generated(response) @distributed_trace_async - async def generate_copy_authorization( + async def authorize_copy_target( self, resource_id: str, resource_region: str, **kwargs: Any - ) -> "TargetInformation": + ) -> "CopyTarget": """Generate authorization to copy a model into the target Form Recognizer resource. This should be called by the target resource (where the model will be copied to) and the output can be passed into :func:`~copy_model()` @@ -252,8 +252,8 @@ async def generate_copy_authorization( where the model will be copied to. :param str resource_region: Location of the target Azure resource. A valid Azure region name supported by Cognitive Services. - :return: TargetInformation - :rtype: ~azure.ai.formrecognizer.TargetInformation + :return: CopyTarget + :rtype: ~azure.ai.formrecognizer.CopyTarget :raises ~azure.core.exceptions.HttpResponseError: .. admonition:: Example: @@ -271,25 +271,25 @@ async def generate_copy_authorization( error_map=error_map, **kwargs ) - return TargetInformation._from_generated(response, resource_id=resource_id, resource_region=resource_region) + return CopyTarget._from_generated(response, resource_id=resource_id, resource_region=resource_region) @distributed_trace_async async def copy_model( self, model_id: str, - target: "TargetInformation", + target: "CopyTarget", **kwargs: Any ) -> CustomFormModelInfo: """Copy custom model stored in this resource (the source) to user specified target Form Recognizer resource. This should be called with the source Form Recognizer resource (with model that is intended to be copied). The `target` parameter should be supplied from the target resource's output from calling the - :func:`~generate_copy_authorization()` method. + :func:`~authorize_copy_target()` method. :param model_id: Model identifier of the model to copy to target resource. :type model_id: str - :param ~azure.ai.formrecognizer.TargetInformation target: + :param ~azure.ai.formrecognizer.CopyTarget target: The copy authorization generated from the target resource's call to - :func:`~generate_copy_authorization()`. + :func:`~authorize_copy_target()`. :keyword int polling_interval: Default waiting time between two polls for LRO operations if no Retry-After header is present. :return: An instance of CustomFormModelInfo diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_copy_model_async.py b/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_copy_model_async.py index be6c6e96cf26..955c7745e8ad 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_copy_model_async.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_copy_model_async.py @@ -48,7 +48,7 @@ async def copy_model_async(self): target_client = FormTrainingClient(endpoint=target_endpoint, credential=AzureKeyCredential(target_key)) async with target_client: - target = await target_client.generate_copy_authorization( + target = await target_client.authorize_copy_target( resource_region=target_region, resource_id=target_resource_id ) @@ -69,6 +69,7 @@ async def copy_model_async(self): print(copied_over_model) # [END copy_model_async] + async def main(): sample = CopyModelSampleAsync() await sample.copy_model_async() diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/samples/sample_copy_model.py b/sdk/formrecognizer/azure-ai-formrecognizer/samples/sample_copy_model.py index b614aef4968e..070b5bc488ef 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/samples/sample_copy_model.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/samples/sample_copy_model.py @@ -46,7 +46,7 @@ def copy_model(self): # [START generate_copy_auth] target_client = FormTrainingClient(endpoint=target_endpoint, credential=AzureKeyCredential(target_key)) - target = target_client.generate_copy_authorization( + target = target_client.authorize_copy_target( resource_region=target_region, resource_id=target_resource_id ) @@ -66,6 +66,7 @@ def copy_model(self): print(copied_over_model) # [END begin_copy_model] + if __name__ == '__main__': sample = CopyModelSample() sample.copy_model() From ff525cb106127d2cdfbd9cb4558a94a31addfccd Mon Sep 17 00:00:00 2001 From: Krista Pratico Date: Wed, 13 May 2020 14:19:38 -0700 Subject: [PATCH 12/22] change copy target to dict --- .../azure/ai/formrecognizer/__init__.py | 6 +-- .../formrecognizer/_form_training_client.py | 42 ++++++++++--------- .../azure/ai/formrecognizer/_models.py | 41 ------------------ .../aio/_form_training_client_async.py | 42 ++++++++++--------- 4 files changed, 46 insertions(+), 85 deletions(-) diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/__init__.py b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/__init__.py index d4b572b5f314..b8225d383dbe 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/__init__.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/__init__.py @@ -33,8 +33,7 @@ FormWord, CustomFormModel, CustomFormSubModel, - CustomFormModelField, - CopyTarget + CustomFormModelField ) @@ -65,8 +64,7 @@ 'FormWord', 'CustomFormModel', 'CustomFormSubModel', - 'CustomFormModelField', - 'CopyTarget' + 'CustomFormModelField' ] __VERSION__ = VERSION diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_form_training_client.py b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_form_training_client.py index 7d1eab3e126a..e3bd7feab805 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_form_training_client.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_form_training_client.py @@ -6,10 +6,13 @@ # pylint: disable=protected-access +import json from typing import ( Optional, Any, Iterable, + Dict, + Union, TYPE_CHECKING, ) from azure.core.tracing.decorator import distributed_trace @@ -22,20 +25,19 @@ TrainSourceFilter, CopyRequest, Model, - CopyOperationResult, - CopyAuthorizationResult + CopyOperationResult ) from ._helpers import error_map, POLLING_INTERVAL, COGNITIVE_KEY_HEADER from ._models import ( CustomFormModelInfo, AccountProperties, - CustomFormModel, - CopyTarget + CustomFormModel ) from ._polling import TrainingPolling, CopyPolling from ._user_agent import USER_AGENT if TYPE_CHECKING: from azure.core.credentials import AzureKeyCredential + from azure.core.pipeline import PipelineResponse from azure.core.pipeline.transport import HttpResponse PipelineResponseType = HttpResponse @@ -233,7 +235,7 @@ def get_custom_model(self, model_id, **kwargs): @distributed_trace def authorize_copy_target(self, resource_id, resource_region, **kwargs): - # type: (str, str, Any) -> CopyTarget + # type: (str, str, Any) -> Dict[str, Union[str, int]] """Generate authorization to copy a model into the target Form Recognizer resource. This should be called by the target resource (where the model will be copied to) and the output can be passed into :func:`~begin_copy_model()` @@ -242,8 +244,9 @@ def authorize_copy_target(self, resource_id, resource_region, **kwargs): where the model will be copied to. :param str resource_region: Location of the target Azure resource. A valid Azure region name supported by Cognitive Services. - :return: CopyTarget - :rtype: ~azure.ai.formrecognizer.CopyTarget + :return: A dictionary with values for the model ID, access token, resource ID, + resource region, and expiration datetime ticks. + :rtype: Dict[str, Union[str, int]] :raises ~azure.core.exceptions.HttpResponseError: .. admonition:: Example: @@ -257,17 +260,20 @@ def authorize_copy_target(self, resource_id, resource_region, **kwargs): """ response = self._client.generate_model_copy_authorization( # type: ignore - cls=lambda pipeline_response, deserialized, response_headers: deserialized, + cls=lambda pipeline_response, deserialized, response_headers: pipeline_response, error_map=error_map, **kwargs - ) - return CopyTarget._from_generated(response, resource_id=resource_id, resource_region=resource_region) + ) # type: PipelineResponse + target = json.loads(response.http_response.text()) + target["resourceId"] = resource_id + target["resourceRegion"] = resource_region + return target @distributed_trace def begin_copy_model( self, model_id, # type: str - target, # type: CopyTarget + target, # type: Dict **kwargs # type: Any ): # type: (...) -> LROPoller @@ -278,7 +284,7 @@ def begin_copy_model( :param model_id: Model identifier of the model to copy to target resource. :type model_id: str - :param ~azure.ai.formrecognizer.CopyTarget target: + :param dict target: The copy authorization generated from the target resource's call to :func:`~authorize_copy_target()`. :keyword int polling_interval: Default waiting time between two polls for LRO operations if @@ -301,18 +307,14 @@ def begin_copy_model( def _copy_callback(raw_response, _, headers): # pylint: disable=unused-argument copy_result = self._client._deserialize(CopyOperationResult, raw_response) - return CustomFormModelInfo._from_generated_copy(copy_result, target.model_id) + return CustomFormModelInfo._from_generated_copy(copy_result, target["modelId"]) return self._client.begin_copy_custom_model( # type: ignore model_id=model_id, copy_request=CopyRequest( - target_resource_id=target.resource_id, - target_resource_region=target.resource_region, - copy_authorization=CopyAuthorizationResult( - model_id=target.model_id, - access_token=target.access_token, - expiration_date_time_ticks=target.expiration_date_time_ticks - ) + target_resource_id=target["resourceId"], + target_resource_region=target["resourceRegion"], + copy_authorization=target ), cls=kwargs.pop("cls", _copy_callback), polling=LROBasePolling(timeout=polling_interval, lro_algorithms=[CopyPolling()], **kwargs), diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_models.py b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_models.py index 118c6d7cfc5d..af19a251d467 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_models.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_models.py @@ -893,44 +893,3 @@ def __repr__(self): return "AccountProperties(custom_model_count={}, custom_model_limit={})".format( self.custom_model_count, self.custom_model_limit )[:1024] - - -class CopyTarget(object): - """Information about target Form Recognizer resource that contains - authorization claims for copy operation. - - :ivar str model_id: Model identifier. - :ivar str access_token: Token claim used to authorize the request. - :ivar str resource_id: Azure Resource Id of the target Form Recognizer resource - where the model will be copied to. - :ivar str resource_region: Location of the target Azure resource. A valid Azure - region name supported by Cognitive Services. - :ivar int expiration_date_time_ticks: The time when the access token expires. The date - is represented as the number of seconds from 1970-01-01T0:0:0Z UTC until the expiration time. - """ - - def __init__( - self, - **kwargs - ): - self.model_id = kwargs.get('model_id', None) - self.resource_id = kwargs.get('resource_id', None) - self.resource_region = kwargs.get('resource_region', None) - self.access_token = kwargs.get('access_token', None) - self.expiration_date_time_ticks = kwargs.get('expiration_date_time_ticks', None) - - @classmethod - def _from_generated(cls, copy, resource_id, resource_region): - return cls( - model_id=copy.model_id, - resource_id=resource_id, - resource_region=resource_region, - access_token=copy.access_token, - expiration_date_time_ticks=copy.expiration_date_time_ticks - ) - - def __repr__(self): - return "CopyTarget(model_id={}, resource_id={}, resource_region={}, access_token={}, " \ - "expiration_date_time_ticks={})".format( - self.model_id, self.resource_id, self.resource_region, self.access_token, - self.expiration_date_time_ticks)[:1024] diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/aio/_form_training_client_async.py b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/aio/_form_training_client_async.py index e59a3d9399b1..ce901a07d76c 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/aio/_form_training_client_async.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/aio/_form_training_client_async.py @@ -6,10 +6,13 @@ # pylint: disable=protected-access +import json from typing import ( Optional, Any, AsyncIterable, + Dict, + Union, TYPE_CHECKING, ) from azure.core.polling import async_poller @@ -23,19 +26,18 @@ TrainSourceFilter, Model, CopyRequest, - CopyOperationResult, - CopyAuthorizationResult + CopyOperationResult ) from .._helpers import error_map, POLLING_INTERVAL, COGNITIVE_KEY_HEADER from .._models import ( CustomFormModelInfo, AccountProperties, - CustomFormModel, - CopyTarget + CustomFormModel ) from .._user_agent import USER_AGENT from .._polling import TrainingPolling, CopyPolling if TYPE_CHECKING: + from azure.core.pipeline import PipelineResponse from azure.core.credentials import AzureKeyCredential @@ -243,7 +245,7 @@ async def authorize_copy_target( resource_id: str, resource_region: str, **kwargs: Any - ) -> "CopyTarget": + ) -> Dict[str, Union[str, int]]: """Generate authorization to copy a model into the target Form Recognizer resource. This should be called by the target resource (where the model will be copied to) and the output can be passed into :func:`~copy_model()` @@ -252,8 +254,9 @@ async def authorize_copy_target( where the model will be copied to. :param str resource_region: Location of the target Azure resource. A valid Azure region name supported by Cognitive Services. - :return: CopyTarget - :rtype: ~azure.ai.formrecognizer.CopyTarget + :return: A dictionary with values for the model ID, access token, resource ID, + resource region, and expiration datetime ticks. + :rtype: Dict[str, Union[str, int]] :raises ~azure.core.exceptions.HttpResponseError: .. admonition:: Example: @@ -267,17 +270,20 @@ async def authorize_copy_target( """ response = await self._client.generate_model_copy_authorization( # type: ignore - cls=lambda pipeline_response, deserialized, response_headers: deserialized, + cls=lambda pipeline_response, deserialized, response_headers: pipeline_response, error_map=error_map, **kwargs - ) - return CopyTarget._from_generated(response, resource_id=resource_id, resource_region=resource_region) + ) # type: PipelineResponse + target = json.loads(response.http_response.text()) + target["resourceId"] = resource_id + target["resourceRegion"] = resource_region + return target @distributed_trace_async async def copy_model( self, model_id: str, - target: "CopyTarget", + target: dict, **kwargs: Any ) -> CustomFormModelInfo: """Copy custom model stored in this resource (the source) to user specified target Form Recognizer resource. @@ -287,7 +293,7 @@ async def copy_model( :param model_id: Model identifier of the model to copy to target resource. :type model_id: str - :param ~azure.ai.formrecognizer.CopyTarget target: + :param dict target: The copy authorization generated from the target resource's call to :func:`~authorize_copy_target()`. :keyword int polling_interval: Default waiting time between two polls for LRO operations if @@ -309,18 +315,14 @@ async def copy_model( def _copy_callback(raw_response, _, headers): # pylint: disable=unused-argument copy_result = self._client._deserialize(CopyOperationResult, raw_response) - return CustomFormModelInfo._from_generated_copy(copy_result, target.model_id) + return CustomFormModelInfo._from_generated_copy(copy_result, target["modelId"]) return await self._client.copy_custom_model( # type: ignore model_id=model_id, copy_request=CopyRequest( - target_resource_id=target.resource_id, - target_resource_region=target.resource_region, - copy_authorization=CopyAuthorizationResult( - model_id=target.model_id, - access_token=target.access_token, - expiration_date_time_ticks=target.expiration_date_time_ticks - ) + target_resource_id=target["resourceId"], + target_resource_region=target["resourceRegion"], + copy_authorization=target ), cls=kwargs.pop("cls", _copy_callback), polling=AsyncLROBasePolling(timeout=polling_interval, lro_algorithms=[CopyPolling()], **kwargs), From d65ab3ef9686a4bf8bdaca61d7bf11a7d3ab9638 Mon Sep 17 00:00:00 2001 From: Krista Pratico Date: Wed, 13 May 2020 18:16:53 -0700 Subject: [PATCH 13/22] add copy sync/async tests --- .../test_copy_model.test_copy_model_fail.yaml | 361 ++++++++++++++++ ...copy_model.test_copy_model_successful.yaml | 402 ++++++++++++++++++ ..._copy_model.test_copy_model_transform.yaml | 244 +++++++++++ ...copy_model_async.test_copy_model_fail.yaml | 252 +++++++++++ ...odel_async.test_copy_model_successful.yaml | 208 +++++++++ ...model_async.test_copy_model_transform.yaml | 246 +++++++++++ .../tests/test_copy_model.py | 80 ++++ .../tests/test_copy_model_async.py | 75 ++++ .../azure-ai-formrecognizer/tests/testcase.py | 61 ++- 9 files changed, 1926 insertions(+), 3 deletions(-) create mode 100644 sdk/formrecognizer/azure-ai-formrecognizer/tests/recordings/test_copy_model.test_copy_model_fail.yaml create mode 100644 sdk/formrecognizer/azure-ai-formrecognizer/tests/recordings/test_copy_model.test_copy_model_successful.yaml create mode 100644 sdk/formrecognizer/azure-ai-formrecognizer/tests/recordings/test_copy_model.test_copy_model_transform.yaml create mode 100644 sdk/formrecognizer/azure-ai-formrecognizer/tests/recordings/test_copy_model_async.test_copy_model_fail.yaml create mode 100644 sdk/formrecognizer/azure-ai-formrecognizer/tests/recordings/test_copy_model_async.test_copy_model_successful.yaml create mode 100644 sdk/formrecognizer/azure-ai-formrecognizer/tests/recordings/test_copy_model_async.test_copy_model_transform.yaml create mode 100644 sdk/formrecognizer/azure-ai-formrecognizer/tests/test_copy_model.py create mode 100644 sdk/formrecognizer/azure-ai-formrecognizer/tests/test_copy_model_async.py diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/tests/recordings/test_copy_model.test_copy_model_fail.yaml b/sdk/formrecognizer/azure-ai-formrecognizer/tests/recordings/test_copy_model.test_copy_model_fail.yaml new file mode 100644 index 000000000000..0120b1902049 --- /dev/null +++ b/sdk/formrecognizer/azure-ai-formrecognizer/tests/recordings/test_copy_model.test_copy_model_fail.yaml @@ -0,0 +1,361 @@ +interactions: +- request: + body: 'b''b\''{"source": "containersasurl", "sourceFilter": {"prefix": "", "includeSubFolders": + false}, "useLabelFile": false}\''''' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '288' + Content-Type: + - application/json + User-Agent: + - azsdk-python-ai-formrecognizer/1.0.0b3 Python/3.7.3 (Windows-10-10.0.18362-SP0) + Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: POST + uri: https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models + response: + body: + string: '' + headers: + apim-request-id: + - 4380f150-98ac-4265-8275-9e7e2c23a149 + content-length: + - '0' + date: + - Thu, 14 May 2020 01:01:51 GMT + location: + - https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models/b7cc00ef-0ead-4f28-8619-445cba528b91 + strict-transport-security: + - max-age=31536000; includeSubDomains; preload + x-content-type-options: + - nosniff + x-envoy-upstream-service-time: + - '5205' + status: + code: 201 + message: Created +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - azsdk-python-ai-formrecognizer/1.0.0b3 Python/3.7.3 (Windows-10-10.0.18362-SP0) + Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: GET + uri: https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models/b7cc00ef-0ead-4f28-8619-445cba528b91?includeKeys=true + response: + body: + string: '{"modelInfo": {"modelId": "b7cc00ef-0ead-4f28-8619-445cba528b91", "status": + "creating", "createdDateTime": "2020-05-14T01:01:52Z", "lastUpdatedDateTime": + "2020-05-14T01:01:52Z"}, "accessToken": "redacted"}' + headers: + apim-request-id: + - f54580b2-8b7d-4320-a0eb-595204ece538 + content-type: + - application/json; charset=utf-8 + date: + - Thu, 14 May 2020 01:01:57 GMT + strict-transport-security: + - max-age=31536000; includeSubDomains; preload + transfer-encoding: + - chunked + x-content-type-options: + - nosniff + x-envoy-upstream-service-time: + - '112' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - azsdk-python-ai-formrecognizer/1.0.0b3 Python/3.7.3 (Windows-10-10.0.18362-SP0) + Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: GET + uri: https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models/b7cc00ef-0ead-4f28-8619-445cba528b91?includeKeys=true + response: + body: + string: '{"modelInfo": {"modelId": "b7cc00ef-0ead-4f28-8619-445cba528b91", "status": + "ready", "createdDateTime": "2020-05-14T01:01:52Z", "lastUpdatedDateTime": + "2020-05-14T01:02:01Z"}, "keys": {"clusters": {"0": ["Additional Notes:", + "Address:", "Address:", "Company Name:", "Company Phone:", "Dated As:", "Email:", + "Hero Limited", "Name:", "Phone:", "Phone:", "Purchase Order", "Purchase Order", + "Purchase Order #:", "SUBTOTAL", "Seattle, WA 93849 Phone:", "Shipped From", + "Shipped To", "TAX", "TOTAL", "Vendor Name:", "Website:"]}}, "trainResult": + {"trainingDocuments": [{"documentName": "Form_1.jpg", "pages": 1, "errors": + [], "status": "succeeded"}, {"documentName": "Form_2.jpg", "pages": 1, "errors": + [], "status": "succeeded"}, {"documentName": "Form_3.jpg", "pages": 1, "errors": + [], "status": "succeeded"}, {"documentName": "Form_4.jpg", "pages": 1, "errors": + [], "status": "succeeded"}, {"documentName": "Form_5.jpg", "pages": 1, "errors": + [], "status": "succeeded"}], "errors": []}, "accessToken": "redacted"}' + headers: + apim-request-id: + - abc1d480-5568-4110-9a34-9e1162ee3dc2 + content-type: + - application/json; charset=utf-8 + date: + - Thu, 14 May 2020 01:02:02 GMT + strict-transport-security: + - max-age=31536000; includeSubDomains; preload + transfer-encoding: + - chunked + x-content-type-options: + - nosniff + x-envoy-upstream-service-time: + - '128' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '0' + User-Agent: + - azsdk-python-ai-formrecognizer/1.0.0b3 Python/3.7.3 (Windows-10-10.0.18362-SP0) + Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: POST + uri: https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models/copyAuthorization + response: + body: + string: '{"modelId": "a15b3499-7d6b-4b2c-9dc8-8e57b5b6ee51", "accessToken": + "redacted", "expirationDateTimeTicks": 637251013234333452}' + headers: + apim-request-id: + - ad78e1d1-162d-469b-93d8-4d2eb47b1f0f + content-type: + - application/json; charset=utf-8 + date: + - Thu, 14 May 2020 01:02:03 GMT + location: + - https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models/a15b3499-7d6b-4b2c-9dc8-8e57b5b6ee51 + strict-transport-security: + - max-age=31536000; includeSubDomains; preload + transfer-encoding: + - chunked + x-content-type-options: + - nosniff + x-envoy-upstream-service-time: + - '98' + status: + code: 201 + message: Created +- request: + body: 'b''b\''{"targetResourceId": "resource_id", "targetResourceRegion": "eastus", + "copyAuthorization": {"modelId": "a15b3499-7d6b-4b2c-9dc8-8e57b5b6ee51", "accessToken": + 00000000-0000-0000-0000-000000000000, "expirationDateTimeTicks": 637251013234333452}}\''''' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '448' + Content-Type: + - application/json + User-Agent: + - azsdk-python-ai-formrecognizer/1.0.0b3 Python/3.7.3 (Windows-10-10.0.18362-SP0) + Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: POST + uri: https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models/b7cc00ef-0ead-4f28-8619-445cba528b91/copy + response: + body: + string: '' + headers: + apim-request-id: + - 682fa9dc-1b3b-4def-9f38-e98d1a04c7e0 + content-length: + - '0' + date: + - Thu, 14 May 2020 01:02:03 GMT + operation-location: + - https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models/b7cc00ef-0ead-4f28-8619-445cba528b91/copyresults/cd9acbeb-46aa-40b2-ab14-c1c35749167c + strict-transport-security: + - max-age=31536000; includeSubDomains; preload + x-content-type-options: + - nosniff + x-envoy-upstream-service-time: + - '155' + status: + code: 202 + message: Accepted +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - azsdk-python-ai-formrecognizer/1.0.0b3 Python/3.7.3 (Windows-10-10.0.18362-SP0) + Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: GET + uri: https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models/b7cc00ef-0ead-4f28-8619-445cba528b91/copyresults/cd9acbeb-46aa-40b2-ab14-c1c35749167c + response: + body: + string: '{"status": "notStarted", "createdDateTime": "2020-05-14T01:02:03Z", + "lastUpdatedDateTime": "2020-05-14T01:02:03Z", "copyResult": {"modelId": "a15b3499-7d6b-4b2c-9dc8-8e57b5b6ee51"}, + "accessToken": "redacted"}' + headers: + apim-request-id: + - 23c7f328-3010-4212-abf0-41b5a14cb219 + content-type: + - application/json; charset=utf-8 + date: + - Thu, 14 May 2020 01:02:08 GMT + strict-transport-security: + - max-age=31536000; includeSubDomains; preload + transfer-encoding: + - chunked + x-content-type-options: + - nosniff + x-envoy-upstream-service-time: + - '99' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - azsdk-python-ai-formrecognizer/1.0.0b3 Python/3.7.3 (Windows-10-10.0.18362-SP0) + Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: GET + uri: https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models/b7cc00ef-0ead-4f28-8619-445cba528b91/copyresults/cd9acbeb-46aa-40b2-ab14-c1c35749167c + response: + body: + string: '{"status": "notStarted", "createdDateTime": "2020-05-14T01:02:03Z", + "lastUpdatedDateTime": "2020-05-14T01:02:03Z", "copyResult": {"modelId": "a15b3499-7d6b-4b2c-9dc8-8e57b5b6ee51"}, + "accessToken": "redacted"}' + headers: + apim-request-id: + - fc7531d8-e8e2-4856-ae6e-32118966e56b + content-type: + - application/json; charset=utf-8 + date: + - Thu, 14 May 2020 01:02:18 GMT + strict-transport-security: + - max-age=31536000; includeSubDomains; preload + transfer-encoding: + - chunked + x-content-type-options: + - nosniff + x-envoy-upstream-service-time: + - '5303' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - azsdk-python-ai-formrecognizer/1.0.0b3 Python/3.7.3 (Windows-10-10.0.18362-SP0) + Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: GET + uri: https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models/b7cc00ef-0ead-4f28-8619-445cba528b91/copyresults/cd9acbeb-46aa-40b2-ab14-c1c35749167c + response: + body: + string: '{"status": "notStarted", "createdDateTime": "2020-05-14T01:02:03Z", + "lastUpdatedDateTime": "2020-05-14T01:02:03Z", "copyResult": {"modelId": "a15b3499-7d6b-4b2c-9dc8-8e57b5b6ee51"}, + "accessToken": "redacted"}' + headers: + apim-request-id: + - 2c3c4c73-01a7-4399-8071-e15db1044a20 + content-type: + - application/json; charset=utf-8 + date: + - Thu, 14 May 2020 01:02:23 GMT + strict-transport-security: + - max-age=31536000; includeSubDomains; preload + transfer-encoding: + - chunked + x-content-type-options: + - nosniff + x-envoy-upstream-service-time: + - '41' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - azsdk-python-ai-formrecognizer/1.0.0b3 Python/3.7.3 (Windows-10-10.0.18362-SP0) + Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: GET + uri: https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models/b7cc00ef-0ead-4f28-8619-445cba528b91/copyresults/cd9acbeb-46aa-40b2-ab14-c1c35749167c + response: + body: + string: '{"status": "failed", "createdDateTime": "2020-05-14T01:02:30.7732121Z", + "lastUpdatedDateTime": "2020-05-14T01:02:30.7732123Z", "copyResult": {"modelId": + "a15b3499-7d6b-4b2c-9dc8-8e57b5b6ee51", "errors": [{"code": "ResourceResolverError", + "message": "{\"ResourceReferenceProperty\":null,\"ClassName\":\"Microsoft.CloudAI.Containers.ResourceResolverServiceException\",\"Message\":\"One + or more errors occurred. (Could not fetch resource information. Ensure the + resource identifier ''resource_id'' is valid and exists in the specified region + eastus. Error: {\\\"error\\\":{\\\"code\\\":\\\"ResourceNotFound\\\",\\\"message\\\":\\\"The + resource with identifier ''resource_id'' is not found.\\\"}}).\",\"Data\":null,\"InnerException\":null,\"HelpURL\":null,\"StackTraceString\":null,\"RemoteStackTraceString\":null,\"RemoteStackIndex\":0,\"ExceptionMethod\":null,\"HResult\":-2146233088,\"Source\":null,\"WatsonBuckets\":null}"}]}, + "accessToken": "redacted"}' + headers: + apim-request-id: + - 16da8022-2949-4c9a-93e0-22b0488ee5a6 + content-type: + - application/json; charset=utf-8 + date: + - Thu, 14 May 2020 01:02:34 GMT + strict-transport-security: + - max-age=31536000; includeSubDomains; preload + transfer-encoding: + - chunked + x-content-type-options: + - nosniff + x-envoy-upstream-service-time: + - '5044' + status: + code: 200 + message: OK +version: 1 diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/tests/recordings/test_copy_model.test_copy_model_successful.yaml b/sdk/formrecognizer/azure-ai-formrecognizer/tests/recordings/test_copy_model.test_copy_model_successful.yaml new file mode 100644 index 000000000000..4410de1124d7 --- /dev/null +++ b/sdk/formrecognizer/azure-ai-formrecognizer/tests/recordings/test_copy_model.test_copy_model_successful.yaml @@ -0,0 +1,402 @@ +interactions: +- request: + body: 'b''b\''{"source": "containersasurl", "sourceFilter": {"prefix": "", "includeSubFolders": + false}, "useLabelFile": false}\''''' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '288' + Content-Type: + - application/json + User-Agent: + - azsdk-python-ai-formrecognizer/1.0.0b3 Python/3.7.3 (Windows-10-10.0.18362-SP0) + Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: POST + uri: https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models + response: + body: + string: '' + headers: + apim-request-id: + - 1f4f2813-350c-4c4f-8c19-a9a731f90145 + content-length: + - '0' + date: + - Thu, 14 May 2020 00:41:50 GMT + location: + - https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models/c885a510-785f-402b-a69b-650d581331db + strict-transport-security: + - max-age=31536000; includeSubDomains; preload + x-content-type-options: + - nosniff + x-envoy-upstream-service-time: + - '5225' + status: + code: 201 + message: Created +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - azsdk-python-ai-formrecognizer/1.0.0b3 Python/3.7.3 (Windows-10-10.0.18362-SP0) + Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: GET + uri: https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models/c885a510-785f-402b-a69b-650d581331db?includeKeys=true + response: + body: + string: '{"modelInfo": {"modelId": "c885a510-785f-402b-a69b-650d581331db", "status": + "ready", "createdDateTime": "2020-05-14T00:41:51Z", "lastUpdatedDateTime": + "2020-05-14T00:41:58Z"}, "keys": {"clusters": {"0": ["Additional Notes:", + "Address:", "Address:", "Company Name:", "Company Phone:", "Dated As:", "Email:", + "Hero Limited", "Name:", "Phone:", "Phone:", "Purchase Order", "Purchase Order", + "Purchase Order #:", "SUBTOTAL", "Seattle, WA 93849 Phone:", "Shipped From", + "Shipped To", "TAX", "TOTAL", "Vendor Name:", "Website:"]}}, "trainResult": + {"trainingDocuments": [{"documentName": "Form_1.jpg", "pages": 1, "errors": + [], "status": "succeeded"}, {"documentName": "Form_2.jpg", "pages": 1, "errors": + [], "status": "succeeded"}, {"documentName": "Form_3.jpg", "pages": 1, "errors": + [], "status": "succeeded"}, {"documentName": "Form_4.jpg", "pages": 1, "errors": + [], "status": "succeeded"}, {"documentName": "Form_5.jpg", "pages": 1, "errors": + [], "status": "succeeded"}], "errors": []}, "accessToken": "redacted"}' + headers: + apim-request-id: + - 09abe2a5-a145-4d23-b606-155d2e8c2e0d + content-type: + - application/json; charset=utf-8 + date: + - Thu, 14 May 2020 00:42:01 GMT + strict-transport-security: + - max-age=31536000; includeSubDomains; preload + transfer-encoding: + - chunked + x-content-type-options: + - nosniff + x-envoy-upstream-service-time: + - '5243' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '0' + User-Agent: + - azsdk-python-ai-formrecognizer/1.0.0b3 Python/3.7.3 (Windows-10-10.0.18362-SP0) + Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: POST + uri: https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models/copyAuthorization + response: + body: + string: '{"modelId": "a0490d1a-e0d9-4e18-96ed-3bc4ad1df34c", "accessToken": + "redacted", "expirationDateTimeTicks": 637251001221004515}' + headers: + apim-request-id: + - c223d84e-9ac5-4204-8348-3341c4d2be27 + content-type: + - application/json; charset=utf-8 + date: + - Thu, 14 May 2020 00:42:02 GMT + location: + - https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models/a0490d1a-e0d9-4e18-96ed-3bc4ad1df34c + strict-transport-security: + - max-age=31536000; includeSubDomains; preload + transfer-encoding: + - chunked + x-content-type-options: + - nosniff + x-envoy-upstream-service-time: + - '178' + status: + code: 201 + message: Created +- request: + body: 'b''b\''{"targetResourceId": "resource_id", "targetResourceRegion": "westus", + "copyAuthorization": {"modelId": "a0490d1a-e0d9-4e18-96ed-3bc4ad1df34c", "accessToken": + 00000000-0000-0000-0000-000000000000, "expirationDateTimeTicks": 637251001221004515}}\''''' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '448' + Content-Type: + - application/json + User-Agent: + - azsdk-python-ai-formrecognizer/1.0.0b3 Python/3.7.3 (Windows-10-10.0.18362-SP0) + Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: POST + uri: https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models/c885a510-785f-402b-a69b-650d581331db/copy + response: + body: + string: '' + headers: + apim-request-id: + - 9d30186d-72a3-4371-9b87-6fa2c7aacfab + content-length: + - '0' + date: + - Thu, 14 May 2020 00:42:02 GMT + operation-location: + - https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models/c885a510-785f-402b-a69b-650d581331db/copyresults/5fb67559-3e16-4b09-9295-1fe0b3cfec94 + strict-transport-security: + - max-age=31536000; includeSubDomains; preload + x-content-type-options: + - nosniff + x-envoy-upstream-service-time: + - '425' + status: + code: 202 + message: Accepted +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - azsdk-python-ai-formrecognizer/1.0.0b3 Python/3.7.3 (Windows-10-10.0.18362-SP0) + Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: GET + uri: https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models/c885a510-785f-402b-a69b-650d581331db/copyresults/5fb67559-3e16-4b09-9295-1fe0b3cfec94 + response: + body: + string: '{"status": "notStarted", "createdDateTime": "2020-05-14T00:42:02Z", + "lastUpdatedDateTime": "2020-05-14T00:42:02Z", "copyResult": {"modelId": "a0490d1a-e0d9-4e18-96ed-3bc4ad1df34c"}, + "accessToken": "redacted"}' + headers: + apim-request-id: + - 63d27f20-441a-410b-8abb-3c24159f4b9f + content-type: + - application/json; charset=utf-8 + date: + - Thu, 14 May 2020 00:42:07 GMT + strict-transport-security: + - max-age=31536000; includeSubDomains; preload + transfer-encoding: + - chunked + x-content-type-options: + - nosniff + x-envoy-upstream-service-time: + - '108' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - azsdk-python-ai-formrecognizer/1.0.0b3 Python/3.7.3 (Windows-10-10.0.18362-SP0) + Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: GET + uri: https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models/c885a510-785f-402b-a69b-650d581331db/copyresults/5fb67559-3e16-4b09-9295-1fe0b3cfec94 + response: + body: + string: '{"status": "notStarted", "createdDateTime": "2020-05-14T00:42:02Z", + "lastUpdatedDateTime": "2020-05-14T00:42:02Z", "copyResult": {"modelId": "a0490d1a-e0d9-4e18-96ed-3bc4ad1df34c"}, + "accessToken": "redacted"}' + headers: + apim-request-id: + - 40ecd2db-65fc-48c6-9196-850c68391b58 + content-type: + - application/json; charset=utf-8 + date: + - Thu, 14 May 2020 00:42:12 GMT + strict-transport-security: + - max-age=31536000; includeSubDomains; preload + transfer-encoding: + - chunked + x-content-type-options: + - nosniff + x-envoy-upstream-service-time: + - '101' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - azsdk-python-ai-formrecognizer/1.0.0b3 Python/3.7.3 (Windows-10-10.0.18362-SP0) + Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: GET + uri: https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models/c885a510-785f-402b-a69b-650d581331db/copyresults/5fb67559-3e16-4b09-9295-1fe0b3cfec94 + response: + body: + string: '{"status": "notStarted", "createdDateTime": "2020-05-14T00:42:02Z", + "lastUpdatedDateTime": "2020-05-14T00:42:02Z", "copyResult": {"modelId": "a0490d1a-e0d9-4e18-96ed-3bc4ad1df34c"}, + "accessToken": "redacted"}' + headers: + apim-request-id: + - 07b8bdfa-5f42-40d5-b21c-4f73b068f8e5 + content-type: + - application/json; charset=utf-8 + date: + - Thu, 14 May 2020 00:42:17 GMT + strict-transport-security: + - max-age=31536000; includeSubDomains; preload + transfer-encoding: + - chunked + x-content-type-options: + - nosniff + x-envoy-upstream-service-time: + - '274' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - azsdk-python-ai-formrecognizer/1.0.0b3 Python/3.7.3 (Windows-10-10.0.18362-SP0) + Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: GET + uri: https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models/c885a510-785f-402b-a69b-650d581331db/copyresults/5fb67559-3e16-4b09-9295-1fe0b3cfec94 + response: + body: + string: '{"status": "notStarted", "createdDateTime": "2020-05-14T00:42:02Z", + "lastUpdatedDateTime": "2020-05-14T00:42:02Z", "copyResult": {"modelId": "a0490d1a-e0d9-4e18-96ed-3bc4ad1df34c"}, + "accessToken": "redacted"}' + headers: + apim-request-id: + - 2a498014-f8d1-45e3-9438-ba2589b05278 + content-type: + - application/json; charset=utf-8 + date: + - Thu, 14 May 2020 00:42:23 GMT + strict-transport-security: + - max-age=31536000; includeSubDomains; preload + transfer-encoding: + - chunked + x-content-type-options: + - nosniff + x-envoy-upstream-service-time: + - '79' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - azsdk-python-ai-formrecognizer/1.0.0b3 Python/3.7.3 (Windows-10-10.0.18362-SP0) + Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: GET + uri: https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models/c885a510-785f-402b-a69b-650d581331db/copyresults/5fb67559-3e16-4b09-9295-1fe0b3cfec94 + response: + body: + string: '{"status": "succeeded", "createdDateTime": "2020-05-14T00:42:28.4618648Z", + "lastUpdatedDateTime": "2020-05-14T00:42:28.4618651Z", "copyResult": {}, "accessToken": + "redacted"}' + headers: + apim-request-id: + - 50324af7-81b5-4cca-aacc-b32470591d74 + content-type: + - application/json; charset=utf-8 + date: + - Thu, 14 May 2020 00:42:33 GMT + strict-transport-security: + - max-age=31536000; includeSubDomains; preload + transfer-encoding: + - chunked + x-content-type-options: + - nosniff + x-envoy-upstream-service-time: + - '5172' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - azsdk-python-ai-formrecognizer/1.0.0b3 Python/3.7.3 (Windows-10-10.0.18362-SP0) + Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: GET + uri: https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models/a0490d1a-e0d9-4e18-96ed-3bc4ad1df34c?includeKeys=true + response: + body: + string: '{"modelInfo": {"modelId": "a0490d1a-e0d9-4e18-96ed-3bc4ad1df34c", "status": + "ready", "createdDateTime": "2020-05-14T00:41:51Z", "lastUpdatedDateTime": + "2020-05-14T00:41:58Z"}, "keys": {"clusters": {"0": ["Additional Notes:", + "Address:", "Address:", "Company Name:", "Company Phone:", "Dated As:", "Email:", + "Hero Limited", "Name:", "Phone:", "Phone:", "Purchase Order", "Purchase Order", + "Purchase Order #:", "SUBTOTAL", "Seattle, WA 93849 Phone:", "Shipped From", + "Shipped To", "TAX", "TOTAL", "Vendor Name:", "Website:"]}}, "trainResult": + {"trainingDocuments": [{"documentName": "Form_1.jpg", "pages": 1, "errors": + [], "status": "succeeded"}, {"documentName": "Form_2.jpg", "pages": 1, "errors": + [], "status": "succeeded"}, {"documentName": "Form_3.jpg", "pages": 1, "errors": + [], "status": "succeeded"}, {"documentName": "Form_4.jpg", "pages": 1, "errors": + [], "status": "succeeded"}, {"documentName": "Form_5.jpg", "pages": 1, "errors": + [], "status": "succeeded"}], "errors": []}, "accessToken": "redacted"}' + headers: + apim-request-id: + - 3a2ce69b-bbbc-4e55-90b0-f4f6c7851093 + content-type: + - application/json; charset=utf-8 + date: + - Thu, 14 May 2020 00:42:33 GMT + strict-transport-security: + - max-age=31536000; includeSubDomains; preload + transfer-encoding: + - chunked + x-content-type-options: + - nosniff + x-envoy-upstream-service-time: + - '406' + status: + code: 200 + message: OK +version: 1 diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/tests/recordings/test_copy_model.test_copy_model_transform.yaml b/sdk/formrecognizer/azure-ai-formrecognizer/tests/recordings/test_copy_model.test_copy_model_transform.yaml new file mode 100644 index 000000000000..a03d4b0fe3be --- /dev/null +++ b/sdk/formrecognizer/azure-ai-formrecognizer/tests/recordings/test_copy_model.test_copy_model_transform.yaml @@ -0,0 +1,244 @@ +interactions: +- request: + body: 'b''b\''{"source": "containersasurl", "sourceFilter": {"prefix": "", "includeSubFolders": + false}, "useLabelFile": false}\''''' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '288' + Content-Type: + - application/json + User-Agent: + - azsdk-python-ai-formrecognizer/1.0.0b3 Python/3.7.3 (Windows-10-10.0.18362-SP0) + Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: POST + uri: https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models + response: + body: + string: '' + headers: + apim-request-id: + - 04323b91-2063-4e81-b458-428e7833eee2 + content-length: + - '0' + date: + - Thu, 14 May 2020 00:50:41 GMT + location: + - https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models/cf566ace-71ef-4331-9110-82734edf1bc8 + strict-transport-security: + - max-age=31536000; includeSubDomains; preload + x-content-type-options: + - nosniff + x-envoy-upstream-service-time: + - '187' + status: + code: 201 + message: Created +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - azsdk-python-ai-formrecognizer/1.0.0b3 Python/3.7.3 (Windows-10-10.0.18362-SP0) + Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: GET + uri: https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models/cf566ace-71ef-4331-9110-82734edf1bc8?includeKeys=true + response: + body: + string: '{"modelInfo": {"modelId": "cf566ace-71ef-4331-9110-82734edf1bc8", "status": + "creating", "createdDateTime": "2020-05-14T00:50:42Z", "lastUpdatedDateTime": + "2020-05-14T00:50:42Z"}, "accessToken": "redacted"}' + headers: + apim-request-id: + - f12d5552-2242-4242-9cf8-450b8ee09fc4 + content-type: + - application/json; charset=utf-8 + date: + - Thu, 14 May 2020 00:50:46 GMT + strict-transport-security: + - max-age=31536000; includeSubDomains; preload + transfer-encoding: + - chunked + x-content-type-options: + - nosniff + x-envoy-upstream-service-time: + - '148' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - azsdk-python-ai-formrecognizer/1.0.0b3 Python/3.7.3 (Windows-10-10.0.18362-SP0) + Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: GET + uri: https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models/cf566ace-71ef-4331-9110-82734edf1bc8?includeKeys=true + response: + body: + string: '{"modelInfo": {"modelId": "cf566ace-71ef-4331-9110-82734edf1bc8", "status": + "ready", "createdDateTime": "2020-05-14T00:50:42Z", "lastUpdatedDateTime": + "2020-05-14T00:50:51Z"}, "keys": {"clusters": {"0": ["Additional Notes:", + "Address:", "Address:", "Company Name:", "Company Phone:", "Dated As:", "Email:", + "Hero Limited", "Name:", "Phone:", "Phone:", "Purchase Order", "Purchase Order", + "Purchase Order #:", "SUBTOTAL", "Seattle, WA 93849 Phone:", "Shipped From", + "Shipped To", "TAX", "TOTAL", "Vendor Name:", "Website:"]}}, "trainResult": + {"trainingDocuments": [{"documentName": "Form_1.jpg", "pages": 1, "errors": + [], "status": "succeeded"}, {"documentName": "Form_2.jpg", "pages": 1, "errors": + [], "status": "succeeded"}, {"documentName": "Form_3.jpg", "pages": 1, "errors": + [], "status": "succeeded"}, {"documentName": "Form_4.jpg", "pages": 1, "errors": + [], "status": "succeeded"}, {"documentName": "Form_5.jpg", "pages": 1, "errors": + [], "status": "succeeded"}], "errors": []}, "accessToken": "redacted"}' + headers: + apim-request-id: + - 0c4bf41c-3ba8-4c9c-b5d4-65b1fe553382 + content-type: + - application/json; charset=utf-8 + date: + - Thu, 14 May 2020 00:50:53 GMT + strict-transport-security: + - max-age=31536000; includeSubDomains; preload + transfer-encoding: + - chunked + x-content-type-options: + - nosniff + x-envoy-upstream-service-time: + - '130' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '0' + User-Agent: + - azsdk-python-ai-formrecognizer/1.0.0b3 Python/3.7.3 (Windows-10-10.0.18362-SP0) + Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: POST + uri: https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models/copyAuthorization + response: + body: + string: '{"modelId": "459db417-84b4-4588-aa3b-d64762c08200", "accessToken": + "redacted", "expirationDateTimeTicks": 637251006533045470}' + headers: + apim-request-id: + - 2cc2c9ee-a999-4756-a820-ef6aee622d48 + content-type: + - application/json; charset=utf-8 + date: + - Thu, 14 May 2020 00:50:53 GMT + location: + - https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models/459db417-84b4-4588-aa3b-d64762c08200 + strict-transport-security: + - max-age=31536000; includeSubDomains; preload + transfer-encoding: + - chunked + x-content-type-options: + - nosniff + x-envoy-upstream-service-time: + - '124' + status: + code: 201 + message: Created +- request: + body: 'b''b\''{"targetResourceId": "resource_id", "targetResourceRegion": "westus", + "copyAuthorization": {"modelId": "459db417-84b4-4588-aa3b-d64762c08200", "accessToken": + 00000000-0000-0000-0000-000000000000, "expirationDateTimeTicks": 637251006533045470}}\''''' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '448' + Content-Type: + - application/json + User-Agent: + - azsdk-python-ai-formrecognizer/1.0.0b3 Python/3.7.3 (Windows-10-10.0.18362-SP0) + Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: POST + uri: https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models/cf566ace-71ef-4331-9110-82734edf1bc8/copy + response: + body: + string: '' + headers: + apim-request-id: + - eb1736f2-df7e-4545-96a0-befea8de6f80 + content-length: + - '0' + date: + - Thu, 14 May 2020 00:50:53 GMT + operation-location: + - https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models/cf566ace-71ef-4331-9110-82734edf1bc8/copyresults/6e206af9-5eae-4540-a80f-d0f8faf24ead + strict-transport-security: + - max-age=31536000; includeSubDomains; preload + x-content-type-options: + - nosniff + x-envoy-upstream-service-time: + - '73' + status: + code: 202 + message: Accepted +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - azsdk-python-ai-formrecognizer/1.0.0b3 Python/3.7.3 (Windows-10-10.0.18362-SP0) + Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: GET + uri: https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models/cf566ace-71ef-4331-9110-82734edf1bc8/copyresults/6e206af9-5eae-4540-a80f-d0f8faf24ead + response: + body: + string: '{"status": "succeeded", "createdDateTime": "2020-05-14T00:51:00.1376588Z", + "lastUpdatedDateTime": "2020-05-14T00:51:00.1376594Z", "copyResult": {}, "accessToken": + "redacted"}' + headers: + apim-request-id: + - 54152a3e-1267-4401-9f5e-6f3bddded6ab + content-type: + - application/json; charset=utf-8 + date: + - Thu, 14 May 2020 00:51:03 GMT + strict-transport-security: + - max-age=31536000; includeSubDomains; preload + transfer-encoding: + - chunked + x-content-type-options: + - nosniff + x-envoy-upstream-service-time: + - '5168' + status: + code: 200 + message: OK +version: 1 diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/tests/recordings/test_copy_model_async.test_copy_model_fail.yaml b/sdk/formrecognizer/azure-ai-formrecognizer/tests/recordings/test_copy_model_async.test_copy_model_fail.yaml new file mode 100644 index 000000000000..fc41403ca42e --- /dev/null +++ b/sdk/formrecognizer/azure-ai-formrecognizer/tests/recordings/test_copy_model_async.test_copy_model_fail.yaml @@ -0,0 +1,252 @@ +interactions: +- request: + body: 'b''b\''{"source": "containersasurl", "sourceFilter": {"prefix": "", "includeSubFolders": + false}, "useLabelFile": false}\''''' + headers: + Content-Length: + - '288' + Content-Type: + - application/json + User-Agent: + - azsdk-python-ai-formrecognizer/1.0.0b3 Python/3.7.3 (Windows-10-10.0.18362-SP0) + Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: POST + uri: https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models + response: + body: + string: '' + headers: + apim-request-id: 0ef35015-e98c-4980-9b4f-bb9b64c05678 + content-length: '0' + date: Thu, 14 May 2020 01:12:40 GMT + location: https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models/aa33d092-934e-4af9-b835-122492610f5a + strict-transport-security: max-age=31536000; includeSubDomains; preload + x-content-type-options: nosniff + x-envoy-upstream-service-time: '146' + status: + code: 201 + message: Created + url: https://westus.api.cognitive.microsoft.com//formrecognizer/v2.0-preview/custom/models +- request: + body: null + headers: + User-Agent: + - azsdk-python-ai-formrecognizer/1.0.0b3 Python/3.7.3 (Windows-10-10.0.18362-SP0) + Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: GET + uri: https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models/aa33d092-934e-4af9-b835-122492610f5a?includeKeys=true + response: + body: + string: '{"modelInfo": {"modelId": "aa33d092-934e-4af9-b835-122492610f5a", "status": + "creating", "createdDateTime": "2020-05-14T01:12:40Z", "lastUpdatedDateTime": + "2020-05-14T01:12:40Z"}, "accessToken": "redacted"}' + headers: + apim-request-id: 8f251d26-3003-4f06-8974-a94cde8802ce + content-type: application/json; charset=utf-8 + date: Thu, 14 May 2020 01:12:45 GMT + strict-transport-security: max-age=31536000; includeSubDomains; preload + transfer-encoding: chunked + x-content-type-options: nosniff + x-envoy-upstream-service-time: '194' + status: + code: 200 + message: OK + url: https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models/aa33d092-934e-4af9-b835-122492610f5a?includeKeys=true +- request: + body: null + headers: + User-Agent: + - azsdk-python-ai-formrecognizer/1.0.0b3 Python/3.7.3 (Windows-10-10.0.18362-SP0) + Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: GET + uri: https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models/aa33d092-934e-4af9-b835-122492610f5a?includeKeys=true + response: + body: + string: '{"modelInfo": {"modelId": "aa33d092-934e-4af9-b835-122492610f5a", "status": + "ready", "createdDateTime": "2020-05-14T01:12:40Z", "lastUpdatedDateTime": + "2020-05-14T01:12:48Z"}, "keys": {"clusters": {"0": ["Additional Notes:", + "Address:", "Address:", "Company Name:", "Company Phone:", "Dated As:", "Email:", + "Hero Limited", "Name:", "Phone:", "Phone:", "Purchase Order", "Purchase Order", + "Purchase Order #:", "SUBTOTAL", "Seattle, WA 93849 Phone:", "Shipped From", + "Shipped To", "TAX", "TOTAL", "Vendor Name:", "Website:"]}}, "trainResult": + {"trainingDocuments": [{"documentName": "Form_1.jpg", "pages": 1, "errors": + [], "status": "succeeded"}, {"documentName": "Form_2.jpg", "pages": 1, "errors": + [], "status": "succeeded"}, {"documentName": "Form_3.jpg", "pages": 1, "errors": + [], "status": "succeeded"}, {"documentName": "Form_4.jpg", "pages": 1, "errors": + [], "status": "succeeded"}, {"documentName": "Form_5.jpg", "pages": 1, "errors": + [], "status": "succeeded"}], "errors": []}, "accessToken": "redacted"}' + headers: + apim-request-id: 6fe0f81a-aa4b-4922-b8e9-f4d29ead547c + content-type: application/json; charset=utf-8 + date: Thu, 14 May 2020 01:12:50 GMT + strict-transport-security: max-age=31536000; includeSubDomains; preload + transfer-encoding: chunked + x-content-type-options: nosniff + x-envoy-upstream-service-time: '150' + status: + code: 200 + message: OK + url: https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models/aa33d092-934e-4af9-b835-122492610f5a?includeKeys=true +- request: + body: null + headers: + Accept: + - application/json + User-Agent: + - azsdk-python-ai-formrecognizer/1.0.0b3 Python/3.7.3 (Windows-10-10.0.18362-SP0) + Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: POST + uri: https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models/copyAuthorization + response: + body: + string: '{"modelId": "9c8a6245-d918-4507-b29e-6c0b53e6b22f", "accessToken": + "redacted", "expirationDateTimeTicks": 637251019711245795}' + headers: + apim-request-id: 4e64bee8-c932-4391-972c-a95e2aa0dd4f + content-type: application/json; charset=utf-8 + date: Thu, 14 May 2020 01:12:50 GMT + location: https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models/9c8a6245-d918-4507-b29e-6c0b53e6b22f + strict-transport-security: max-age=31536000; includeSubDomains; preload + transfer-encoding: chunked + x-content-type-options: nosniff + x-envoy-upstream-service-time: '175' + status: + code: 201 + message: Created + url: https://westus.api.cognitive.microsoft.com//formrecognizer/v2.0-preview/custom/models/copyAuthorization +- request: + body: 'b''b\''{"targetResourceId": "resource_id", "targetResourceRegion": "eastus", + "copyAuthorization": {"modelId": "9c8a6245-d918-4507-b29e-6c0b53e6b22f", "accessToken": + 00000000-0000-0000-0000-000000000000, "expirationDateTimeTicks": 637251019711245795}}\''''' + headers: + Content-Length: + - '448' + Content-Type: + - application/json + User-Agent: + - azsdk-python-ai-formrecognizer/1.0.0b3 Python/3.7.3 (Windows-10-10.0.18362-SP0) + Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: POST + uri: https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models/aa33d092-934e-4af9-b835-122492610f5a/copy + response: + body: + string: '' + headers: + apim-request-id: d9805313-ec0a-46e9-afab-750164b505c9 + content-length: '0' + date: Thu, 14 May 2020 01:12:50 GMT + operation-location: https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models/aa33d092-934e-4af9-b835-122492610f5a/copyresults/097d8fa2-25cf-4cef-9dea-8657edc95f3f + strict-transport-security: max-age=31536000; includeSubDomains; preload + x-content-type-options: nosniff + x-envoy-upstream-service-time: '167' + status: + code: 202 + message: Accepted + url: https://westus.api.cognitive.microsoft.com//formrecognizer/v2.0-preview/custom/models/aa33d092-934e-4af9-b835-122492610f5a/copy +- request: + body: null + headers: + User-Agent: + - azsdk-python-ai-formrecognizer/1.0.0b3 Python/3.7.3 (Windows-10-10.0.18362-SP0) + Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: GET + uri: https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models/aa33d092-934e-4af9-b835-122492610f5a/copyresults/097d8fa2-25cf-4cef-9dea-8657edc95f3f + response: + body: + string: '{"status": "notStarted", "createdDateTime": "2020-05-14T01:12:51Z", + "lastUpdatedDateTime": "2020-05-14T01:12:51Z", "copyResult": {"modelId": "9c8a6245-d918-4507-b29e-6c0b53e6b22f"}, + "accessToken": "redacted"}' + headers: + apim-request-id: 43f437fc-fcfb-40c1-b2ed-ab84436f79b3 + content-type: application/json; charset=utf-8 + date: Thu, 14 May 2020 01:12:55 GMT + strict-transport-security: max-age=31536000; includeSubDomains; preload + transfer-encoding: chunked + x-content-type-options: nosniff + x-envoy-upstream-service-time: '173' + status: + code: 200 + message: OK + url: https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models/aa33d092-934e-4af9-b835-122492610f5a/copyresults/097d8fa2-25cf-4cef-9dea-8657edc95f3f +- request: + body: null + headers: + User-Agent: + - azsdk-python-ai-formrecognizer/1.0.0b3 Python/3.7.3 (Windows-10-10.0.18362-SP0) + Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: GET + uri: https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models/aa33d092-934e-4af9-b835-122492610f5a/copyresults/097d8fa2-25cf-4cef-9dea-8657edc95f3f + response: + body: + string: '{"status": "notStarted", "createdDateTime": "2020-05-14T01:12:51Z", + "lastUpdatedDateTime": "2020-05-14T01:12:51Z", "copyResult": {"modelId": "9c8a6245-d918-4507-b29e-6c0b53e6b22f"}, + "accessToken": "redacted"}' + headers: + apim-request-id: 26f78b70-03b0-4560-93db-91d4725c0611 + content-type: application/json; charset=utf-8 + date: Thu, 14 May 2020 01:13:00 GMT + strict-transport-security: max-age=31536000; includeSubDomains; preload + transfer-encoding: chunked + x-content-type-options: nosniff + x-envoy-upstream-service-time: '45' + status: + code: 200 + message: OK + url: https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models/aa33d092-934e-4af9-b835-122492610f5a/copyresults/097d8fa2-25cf-4cef-9dea-8657edc95f3f +- request: + body: null + headers: + User-Agent: + - azsdk-python-ai-formrecognizer/1.0.0b3 Python/3.7.3 (Windows-10-10.0.18362-SP0) + Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: GET + uri: https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models/aa33d092-934e-4af9-b835-122492610f5a/copyresults/097d8fa2-25cf-4cef-9dea-8657edc95f3f + response: + body: + string: '{"status": "notStarted", "createdDateTime": "2020-05-14T01:12:51Z", + "lastUpdatedDateTime": "2020-05-14T01:12:51Z", "copyResult": {"modelId": "9c8a6245-d918-4507-b29e-6c0b53e6b22f"}, + "accessToken": "redacted"}' + headers: + apim-request-id: 08126cce-50a2-42a4-ab03-2c42b9835324 + content-type: application/json; charset=utf-8 + date: Thu, 14 May 2020 01:13:06 GMT + strict-transport-security: max-age=31536000; includeSubDomains; preload + transfer-encoding: chunked + x-content-type-options: nosniff + x-envoy-upstream-service-time: '84' + status: + code: 200 + message: OK + url: https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models/aa33d092-934e-4af9-b835-122492610f5a/copyresults/097d8fa2-25cf-4cef-9dea-8657edc95f3f +- request: + body: null + headers: + User-Agent: + - azsdk-python-ai-formrecognizer/1.0.0b3 Python/3.7.3 (Windows-10-10.0.18362-SP0) + Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: GET + uri: https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models/aa33d092-934e-4af9-b835-122492610f5a/copyresults/097d8fa2-25cf-4cef-9dea-8657edc95f3f + response: + body: + string: '{"status": "failed", "createdDateTime": "2020-05-14T01:13:07.0471807Z", + "lastUpdatedDateTime": "2020-05-14T01:13:07.047181Z", "copyResult": {"modelId": + "9c8a6245-d918-4507-b29e-6c0b53e6b22f", "errors": [{"code": "ResourceResolverError", + "message": "{\"ResourceReferenceProperty\":null,\"ClassName\":\"Microsoft.CloudAI.Containers.ResourceResolverServiceException\",\"Message\":\"One + or more errors occurred. (Could not fetch resource information. Ensure the + resource identifier ''resource_id'' is valid and exists in the specified region + eastus. Error: {\\\"error\\\":{\\\"code\\\":\\\"ResourceNotFound\\\",\\\"message\\\":\\\"The + resource with identifier ''resource_id'' is not found.\\\"}}).\",\"Data\":null,\"InnerException\":null,\"HelpURL\":null,\"StackTraceString\":null,\"RemoteStackTraceString\":null,\"RemoteStackIndex\":0,\"ExceptionMethod\":null,\"HResult\":-2146233088,\"Source\":null,\"WatsonBuckets\":null}"}]}, + "accessToken": "redacted"}' + headers: + apim-request-id: 53b90555-e176-4745-88ef-9719ab61f13e + content-type: application/json; charset=utf-8 + date: Thu, 14 May 2020 01:13:11 GMT + strict-transport-security: max-age=31536000; includeSubDomains; preload + transfer-encoding: chunked + x-content-type-options: nosniff + x-envoy-upstream-service-time: '163' + status: + code: 200 + message: OK + url: https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models/aa33d092-934e-4af9-b835-122492610f5a/copyresults/097d8fa2-25cf-4cef-9dea-8657edc95f3f +version: 1 diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/tests/recordings/test_copy_model_async.test_copy_model_successful.yaml b/sdk/formrecognizer/azure-ai-formrecognizer/tests/recordings/test_copy_model_async.test_copy_model_successful.yaml new file mode 100644 index 000000000000..d0052131b670 --- /dev/null +++ b/sdk/formrecognizer/azure-ai-formrecognizer/tests/recordings/test_copy_model_async.test_copy_model_successful.yaml @@ -0,0 +1,208 @@ +interactions: +- request: + body: 'b''b\''{"source": "containersasurl", "sourceFilter": {"prefix": "", "includeSubFolders": + false}, "useLabelFile": false}\''''' + headers: + Content-Length: + - '288' + Content-Type: + - application/json + User-Agent: + - azsdk-python-ai-formrecognizer/1.0.0b3 Python/3.7.3 (Windows-10-10.0.18362-SP0) + Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: POST + uri: https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models + response: + body: + string: '' + headers: + apim-request-id: d86b82bd-c06f-4e15-803d-a91436f38900 + content-length: '0' + date: Thu, 14 May 2020 01:09:10 GMT + location: https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models/a9b558b2-152e-43fc-b060-2f97d0a2fcc6 + strict-transport-security: max-age=31536000; includeSubDomains; preload + x-content-type-options: nosniff + x-envoy-upstream-service-time: '181' + status: + code: 201 + message: Created + url: https://westus.api.cognitive.microsoft.com//formrecognizer/v2.0-preview/custom/models +- request: + body: null + headers: + User-Agent: + - azsdk-python-ai-formrecognizer/1.0.0b3 Python/3.7.3 (Windows-10-10.0.18362-SP0) + Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: GET + uri: https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models/a9b558b2-152e-43fc-b060-2f97d0a2fcc6?includeKeys=true + response: + body: + string: '{"modelInfo": {"modelId": "a9b558b2-152e-43fc-b060-2f97d0a2fcc6", "status": + "creating", "createdDateTime": "2020-05-14T01:09:11Z", "lastUpdatedDateTime": + "2020-05-14T01:09:11Z"}, "accessToken": "redacted"}' + headers: + apim-request-id: 28a8f5c5-0e8e-46a5-814f-829bfebc2dcf + content-type: application/json; charset=utf-8 + date: Thu, 14 May 2020 01:09:16 GMT + strict-transport-security: max-age=31536000; includeSubDomains; preload + transfer-encoding: chunked + x-content-type-options: nosniff + x-envoy-upstream-service-time: '51' + status: + code: 200 + message: OK + url: https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models/a9b558b2-152e-43fc-b060-2f97d0a2fcc6?includeKeys=true +- request: + body: null + headers: + User-Agent: + - azsdk-python-ai-formrecognizer/1.0.0b3 Python/3.7.3 (Windows-10-10.0.18362-SP0) + Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: GET + uri: https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models/a9b558b2-152e-43fc-b060-2f97d0a2fcc6?includeKeys=true + response: + body: + string: '{"modelInfo": {"modelId": "a9b558b2-152e-43fc-b060-2f97d0a2fcc6", "status": + "ready", "createdDateTime": "2020-05-14T01:09:11Z", "lastUpdatedDateTime": + "2020-05-14T01:09:18Z"}, "keys": {"clusters": {"0": ["Additional Notes:", + "Address:", "Address:", "Company Name:", "Company Phone:", "Dated As:", "Email:", + "Hero Limited", "Name:", "Phone:", "Purchase Order", "Purchase Order", "Purchase + Order #:", "SUBTOTAL", "Seattle, WA 93849 Phone:", "Shipped From", "Shipped + To", "TAX", "TOTAL", "Vendor Name:", "Website:"]}}, "trainResult": {"trainingDocuments": + [{"documentName": "Form_1.jpg", "pages": 1, "errors": [], "status": "succeeded"}, + {"documentName": "Form_2.jpg", "pages": 1, "errors": [], "status": "succeeded"}, + {"documentName": "Form_3.jpg", "pages": 1, "errors": [], "status": "succeeded"}, + {"documentName": "Form_4.jpg", "pages": 1, "errors": [], "status": "succeeded"}, + {"documentName": "Form_5.jpg", "pages": 1, "errors": [], "status": "succeeded"}], + "errors": []}, "accessToken": "redacted"}' + headers: + apim-request-id: 82ac1744-b0f0-4aee-9ed3-1a99b48800ef + content-type: application/json; charset=utf-8 + date: Thu, 14 May 2020 01:09:21 GMT + strict-transport-security: max-age=31536000; includeSubDomains; preload + transfer-encoding: chunked + x-content-type-options: nosniff + x-envoy-upstream-service-time: '109' + status: + code: 200 + message: OK + url: https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models/a9b558b2-152e-43fc-b060-2f97d0a2fcc6?includeKeys=true +- request: + body: null + headers: + Accept: + - application/json + User-Agent: + - azsdk-python-ai-formrecognizer/1.0.0b3 Python/3.7.3 (Windows-10-10.0.18362-SP0) + Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: POST + uri: https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models/copyAuthorization + response: + body: + string: '{"modelId": "7c88c4f8-053f-4e37-bc03-ce80e81f49e5", "accessToken": + "redacted", "expirationDateTimeTicks": 637251017619338551}' + headers: + apim-request-id: 5a07d519-1cf2-466c-bcd1-6eaaa771a366 + content-type: application/json; charset=utf-8 + date: Thu, 14 May 2020 01:09:21 GMT + location: https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models/7c88c4f8-053f-4e37-bc03-ce80e81f49e5 + strict-transport-security: max-age=31536000; includeSubDomains; preload + transfer-encoding: chunked + x-content-type-options: nosniff + x-envoy-upstream-service-time: '112' + status: + code: 201 + message: Created + url: https://westus.api.cognitive.microsoft.com//formrecognizer/v2.0-preview/custom/models/copyAuthorization +- request: + body: 'b''b\''{"targetResourceId": "resource_id", "targetResourceRegion": "westus", + "copyAuthorization": {"modelId": "7c88c4f8-053f-4e37-bc03-ce80e81f49e5", "accessToken": + 00000000-0000-0000-0000-000000000000, "expirationDateTimeTicks": 637251017619338551}}\''''' + headers: + Content-Length: + - '448' + Content-Type: + - application/json + User-Agent: + - azsdk-python-ai-formrecognizer/1.0.0b3 Python/3.7.3 (Windows-10-10.0.18362-SP0) + Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: POST + uri: https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models/a9b558b2-152e-43fc-b060-2f97d0a2fcc6/copy + response: + body: + string: '' + headers: + apim-request-id: ce3c30f8-8011-4245-8a27-1c447e5072b8 + content-length: '0' + date: Thu, 14 May 2020 01:09:21 GMT + operation-location: https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models/a9b558b2-152e-43fc-b060-2f97d0a2fcc6/copyresults/fe00dde8-61e6-4fb0-9712-6c3e0b5d61ce + strict-transport-security: max-age=31536000; includeSubDomains; preload + x-content-type-options: nosniff + x-envoy-upstream-service-time: '159' + status: + code: 202 + message: Accepted + url: https://westus.api.cognitive.microsoft.com//formrecognizer/v2.0-preview/custom/models/a9b558b2-152e-43fc-b060-2f97d0a2fcc6/copy +- request: + body: null + headers: + User-Agent: + - azsdk-python-ai-formrecognizer/1.0.0b3 Python/3.7.3 (Windows-10-10.0.18362-SP0) + Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: GET + uri: https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models/a9b558b2-152e-43fc-b060-2f97d0a2fcc6/copyresults/fe00dde8-61e6-4fb0-9712-6c3e0b5d61ce + response: + body: + string: '{"status": "succeeded", "createdDateTime": "2020-05-14T01:09:31.2445585Z", + "lastUpdatedDateTime": "2020-05-14T01:09:31.2445588Z", "copyResult": {}, "accessToken": + "redacted"}' + headers: + apim-request-id: 93992072-32c8-4057-87a0-64a470cb1d6e + content-type: application/json; charset=utf-8 + date: Thu, 14 May 2020 01:09:31 GMT + strict-transport-security: max-age=31536000; includeSubDomains; preload + transfer-encoding: chunked + x-content-type-options: nosniff + x-envoy-upstream-service-time: '5281' + status: + code: 200 + message: OK + url: https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models/a9b558b2-152e-43fc-b060-2f97d0a2fcc6/copyresults/fe00dde8-61e6-4fb0-9712-6c3e0b5d61ce +- request: + body: null + headers: + Accept: + - application/json + User-Agent: + - azsdk-python-ai-formrecognizer/1.0.0b3 Python/3.7.3 (Windows-10-10.0.18362-SP0) + Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: GET + uri: https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models/7c88c4f8-053f-4e37-bc03-ce80e81f49e5?includeKeys=true + response: + body: + string: '{"modelInfo": {"modelId": "7c88c4f8-053f-4e37-bc03-ce80e81f49e5", "status": + "ready", "createdDateTime": "2020-05-14T01:09:11Z", "lastUpdatedDateTime": + "2020-05-14T01:09:18Z"}, "keys": {"clusters": {"0": ["Additional Notes:", + "Address:", "Address:", "Company Name:", "Company Phone:", "Dated As:", "Email:", + "Hero Limited", "Name:", "Phone:", "Purchase Order", "Purchase Order", "Purchase + Order #:", "SUBTOTAL", "Seattle, WA 93849 Phone:", "Shipped From", "Shipped + To", "TAX", "TOTAL", "Vendor Name:", "Website:"]}}, "trainResult": {"trainingDocuments": + [{"documentName": "Form_1.jpg", "pages": 1, "errors": [], "status": "succeeded"}, + {"documentName": "Form_2.jpg", "pages": 1, "errors": [], "status": "succeeded"}, + {"documentName": "Form_3.jpg", "pages": 1, "errors": [], "status": "succeeded"}, + {"documentName": "Form_4.jpg", "pages": 1, "errors": [], "status": "succeeded"}, + {"documentName": "Form_5.jpg", "pages": 1, "errors": [], "status": "succeeded"}], + "errors": []}, "accessToken": "redacted"}' + headers: + apim-request-id: 234ef1cd-09aa-49eb-823b-e899bc2daa18 + content-type: application/json; charset=utf-8 + date: Thu, 14 May 2020 01:09:31 GMT + strict-transport-security: max-age=31536000; includeSubDomains; preload + transfer-encoding: chunked + x-content-type-options: nosniff + x-envoy-upstream-service-time: '112' + status: + code: 200 + message: OK + url: https://westus.api.cognitive.microsoft.com//formrecognizer/v2.0-preview/custom/models/7c88c4f8-053f-4e37-bc03-ce80e81f49e5?includeKeys=true +version: 1 diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/tests/recordings/test_copy_model_async.test_copy_model_transform.yaml b/sdk/formrecognizer/azure-ai-formrecognizer/tests/recordings/test_copy_model_async.test_copy_model_transform.yaml new file mode 100644 index 000000000000..000b3bd9d538 --- /dev/null +++ b/sdk/formrecognizer/azure-ai-formrecognizer/tests/recordings/test_copy_model_async.test_copy_model_transform.yaml @@ -0,0 +1,246 @@ +interactions: +- request: + body: 'b''b\''{"source": "containersasurl", "sourceFilter": {"prefix": "", "includeSubFolders": + false}, "useLabelFile": false}\''''' + headers: + Content-Length: + - '288' + Content-Type: + - application/json + User-Agent: + - azsdk-python-ai-formrecognizer/1.0.0b3 Python/3.7.3 (Windows-10-10.0.18362-SP0) + Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: POST + uri: https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models + response: + body: + string: '' + headers: + apim-request-id: 79122024-c16c-4828-bb84-e3ec65eb7383 + content-length: '0' + date: Thu, 14 May 2020 01:09:32 GMT + location: https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models/f622d63d-9e3d-4a1d-a290-5e3949b932d8 + strict-transport-security: max-age=31536000; includeSubDomains; preload + x-content-type-options: nosniff + x-envoy-upstream-service-time: '76' + status: + code: 201 + message: Created + url: https://westus.api.cognitive.microsoft.com//formrecognizer/v2.0-preview/custom/models +- request: + body: null + headers: + User-Agent: + - azsdk-python-ai-formrecognizer/1.0.0b3 Python/3.7.3 (Windows-10-10.0.18362-SP0) + Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: GET + uri: https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models/f622d63d-9e3d-4a1d-a290-5e3949b932d8?includeKeys=true + response: + body: + string: '{"modelInfo": {"modelId": "f622d63d-9e3d-4a1d-a290-5e3949b932d8", "status": + "creating", "createdDateTime": "2020-05-14T01:09:33Z", "lastUpdatedDateTime": + "2020-05-14T01:09:33Z"}, "accessToken": "redacted"}' + headers: + apim-request-id: 8a045cfe-d6d3-430d-8374-06ab1fad9bfd + content-type: application/json; charset=utf-8 + date: Thu, 14 May 2020 01:09:37 GMT + strict-transport-security: max-age=31536000; includeSubDomains; preload + transfer-encoding: chunked + x-content-type-options: nosniff + x-envoy-upstream-service-time: '139' + status: + code: 200 + message: OK + url: https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models/f622d63d-9e3d-4a1d-a290-5e3949b932d8?includeKeys=true +- request: + body: null + headers: + User-Agent: + - azsdk-python-ai-formrecognizer/1.0.0b3 Python/3.7.3 (Windows-10-10.0.18362-SP0) + Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: GET + uri: https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models/f622d63d-9e3d-4a1d-a290-5e3949b932d8?includeKeys=true + response: + body: + string: '{"modelInfo": {"modelId": "f622d63d-9e3d-4a1d-a290-5e3949b932d8", "status": + "ready", "createdDateTime": "2020-05-14T01:09:33Z", "lastUpdatedDateTime": + "2020-05-14T01:09:40Z"}, "keys": {"clusters": {"0": ["Additional Notes:", + "Address:", "Address:", "Company Name:", "Company Phone:", "Dated As:", "Email:", + "Hero Limited", "Name:", "Phone:", "Phone:", "Purchase Order", "Purchase Order", + "Purchase Order #:", "SUBTOTAL", "Seattle, WA 93849 Phone:", "Shipped From", + "Shipped To", "TAX", "TOTAL", "Vendor Name:", "Website:"]}}, "trainResult": + {"trainingDocuments": [{"documentName": "Form_1.jpg", "pages": 1, "errors": + [], "status": "succeeded"}, {"documentName": "Form_2.jpg", "pages": 1, "errors": + [], "status": "succeeded"}, {"documentName": "Form_3.jpg", "pages": 1, "errors": + [], "status": "succeeded"}, {"documentName": "Form_4.jpg", "pages": 1, "errors": + [], "status": "succeeded"}, {"documentName": "Form_5.jpg", "pages": 1, "errors": + [], "status": "succeeded"}], "errors": []}, "accessToken": "redacted"}' + headers: + apim-request-id: 0cae8ba6-1d8d-40f2-aee7-53f0f6fd3c21 + content-type: application/json; charset=utf-8 + date: Thu, 14 May 2020 01:09:42 GMT + strict-transport-security: max-age=31536000; includeSubDomains; preload + transfer-encoding: chunked + x-content-type-options: nosniff + x-envoy-upstream-service-time: '138' + status: + code: 200 + message: OK + url: https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models/f622d63d-9e3d-4a1d-a290-5e3949b932d8?includeKeys=true +- request: + body: null + headers: + Accept: + - application/json + User-Agent: + - azsdk-python-ai-formrecognizer/1.0.0b3 Python/3.7.3 (Windows-10-10.0.18362-SP0) + Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: POST + uri: https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models/copyAuthorization + response: + body: + string: '{"modelId": "2741351c-66be-4d9a-bffa-f51858f0a1e8", "accessToken": + "redacted", "expirationDateTimeTicks": 637251017835447315}' + headers: + apim-request-id: f5a567ea-38b3-4f3b-af4e-d39fd2294f66 + content-type: application/json; charset=utf-8 + date: Thu, 14 May 2020 01:09:43 GMT + location: https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models/2741351c-66be-4d9a-bffa-f51858f0a1e8 + strict-transport-security: max-age=31536000; includeSubDomains; preload + transfer-encoding: chunked + x-content-type-options: nosniff + x-envoy-upstream-service-time: '18' + status: + code: 201 + message: Created + url: https://westus.api.cognitive.microsoft.com//formrecognizer/v2.0-preview/custom/models/copyAuthorization +- request: + body: 'b''b\''{"targetResourceId": "resource_id", "targetResourceRegion": "westus", + "copyAuthorization": {"modelId": "2741351c-66be-4d9a-bffa-f51858f0a1e8", "accessToken": + 00000000-0000-0000-0000-000000000000, "expirationDateTimeTicks": 637251017835447315}}\''''' + headers: + Content-Length: + - '448' + Content-Type: + - application/json + User-Agent: + - azsdk-python-ai-formrecognizer/1.0.0b3 Python/3.7.3 (Windows-10-10.0.18362-SP0) + Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: POST + uri: https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models/f622d63d-9e3d-4a1d-a290-5e3949b932d8/copy + response: + body: + string: '' + headers: + apim-request-id: 662bc4ad-d4ac-4e85-9942-0208926ea6b1 + content-length: '0' + date: Thu, 14 May 2020 01:09:43 GMT + operation-location: https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models/f622d63d-9e3d-4a1d-a290-5e3949b932d8/copyresults/e3a252d8-f4d0-425b-b313-ebdb4c2aecff + strict-transport-security: max-age=31536000; includeSubDomains; preload + x-content-type-options: nosniff + x-envoy-upstream-service-time: '143' + status: + code: 202 + message: Accepted + url: https://westus.api.cognitive.microsoft.com//formrecognizer/v2.0-preview/custom/models/f622d63d-9e3d-4a1d-a290-5e3949b932d8/copy +- request: + body: null + headers: + User-Agent: + - azsdk-python-ai-formrecognizer/1.0.0b3 Python/3.7.3 (Windows-10-10.0.18362-SP0) + Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: GET + uri: https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models/f622d63d-9e3d-4a1d-a290-5e3949b932d8/copyresults/e3a252d8-f4d0-425b-b313-ebdb4c2aecff + response: + body: + string: '{"status": "notStarted", "createdDateTime": "2020-05-14T01:09:43Z", + "lastUpdatedDateTime": "2020-05-14T01:09:43Z", "copyResult": {"modelId": "2741351c-66be-4d9a-bffa-f51858f0a1e8"}, + "accessToken": "redacted"}' + headers: + apim-request-id: 10ac066d-b0d9-49ba-847a-7c4744183dd8 + content-type: application/json; charset=utf-8 + date: Thu, 14 May 2020 01:09:48 GMT + strict-transport-security: max-age=31536000; includeSubDomains; preload + transfer-encoding: chunked + x-content-type-options: nosniff + x-envoy-upstream-service-time: '183' + status: + code: 200 + message: OK + url: https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models/f622d63d-9e3d-4a1d-a290-5e3949b932d8/copyresults/e3a252d8-f4d0-425b-b313-ebdb4c2aecff +- request: + body: null + headers: + User-Agent: + - azsdk-python-ai-formrecognizer/1.0.0b3 Python/3.7.3 (Windows-10-10.0.18362-SP0) + Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: GET + uri: https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models/f622d63d-9e3d-4a1d-a290-5e3949b932d8/copyresults/e3a252d8-f4d0-425b-b313-ebdb4c2aecff + response: + body: + string: '{"status": "notStarted", "createdDateTime": "2020-05-14T01:09:43Z", + "lastUpdatedDateTime": "2020-05-14T01:09:43Z", "copyResult": {"modelId": "2741351c-66be-4d9a-bffa-f51858f0a1e8"}, + "accessToken": "redacted"}' + headers: + apim-request-id: 0b9eb162-f76a-4346-a07c-0ed7744bbdd1 + content-type: application/json; charset=utf-8 + date: Thu, 14 May 2020 01:09:53 GMT + strict-transport-security: max-age=31536000; includeSubDomains; preload + transfer-encoding: chunked + x-content-type-options: nosniff + x-envoy-upstream-service-time: '109' + status: + code: 200 + message: OK + url: https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models/f622d63d-9e3d-4a1d-a290-5e3949b932d8/copyresults/e3a252d8-f4d0-425b-b313-ebdb4c2aecff +- request: + body: null + headers: + User-Agent: + - azsdk-python-ai-formrecognizer/1.0.0b3 Python/3.7.3 (Windows-10-10.0.18362-SP0) + Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: GET + uri: https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models/f622d63d-9e3d-4a1d-a290-5e3949b932d8/copyresults/e3a252d8-f4d0-425b-b313-ebdb4c2aecff + response: + body: + string: '{"status": "running", "createdDateTime": "2020-05-14T01:10:01.2858546Z", + "lastUpdatedDateTime": "2020-05-14T01:10:01.285855Z", "copyResult": {}, "accessToken": + "redacted"}' + headers: + apim-request-id: 59c62973-c5bc-4181-b50d-13f7868a4aff + content-type: application/json; charset=utf-8 + date: Thu, 14 May 2020 01:10:04 GMT + strict-transport-security: max-age=31536000; includeSubDomains; preload + transfer-encoding: chunked + x-content-type-options: nosniff + x-envoy-upstream-service-time: '5109' + status: + code: 200 + message: OK + url: https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models/f622d63d-9e3d-4a1d-a290-5e3949b932d8/copyresults/e3a252d8-f4d0-425b-b313-ebdb4c2aecff +- request: + body: null + headers: + User-Agent: + - azsdk-python-ai-formrecognizer/1.0.0b3 Python/3.7.3 (Windows-10-10.0.18362-SP0) + Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: GET + uri: https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models/f622d63d-9e3d-4a1d-a290-5e3949b932d8/copyresults/e3a252d8-f4d0-425b-b313-ebdb4c2aecff + response: + body: + string: '{"status": "succeeded", "createdDateTime": "2020-05-14T01:10:06.5336275Z", + "lastUpdatedDateTime": "2020-05-14T01:10:06.5336279Z", "copyResult": {}, "accessToken": + "redacted"}' + headers: + apim-request-id: a0da10bb-1a98-458e-9a16-483ed276d406 + content-type: application/json; charset=utf-8 + date: Thu, 14 May 2020 01:10:13 GMT + strict-transport-security: max-age=31536000; includeSubDomains; preload + transfer-encoding: chunked + x-content-type-options: nosniff + x-envoy-upstream-service-time: '5104' + status: + code: 200 + message: OK + url: https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models/f622d63d-9e3d-4a1d-a290-5e3949b932d8/copyresults/e3a252d8-f4d0-425b-b313-ebdb4c2aecff +version: 1 diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_copy_model.py b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_copy_model.py new file mode 100644 index 000000000000..900202d3139a --- /dev/null +++ b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_copy_model.py @@ -0,0 +1,80 @@ +# coding=utf-8 +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ + +import functools +from azure.core.exceptions import HttpResponseError +from azure.ai.formrecognizer._generated.models import CopyOperationResult +from azure.ai.formrecognizer import CustomFormModelInfo +from azure.ai.formrecognizer import FormTrainingClient +from testcase import FormRecognizerTest, GlobalFormRecognizerAccountPreparer +from testcase import GlobalTrainingAccountPreparer as _GlobalTrainingAccountPreparer + +GlobalTrainingAccountPreparer = functools.partial(_GlobalTrainingAccountPreparer, FormTrainingClient) + + +class TestCopyModel(FormRecognizerTest): + + @GlobalFormRecognizerAccountPreparer() + @GlobalTrainingAccountPreparer(copy=True) + def test_copy_model_successful(self, client, container_sas_url, location, resource_id): + + poller = client.begin_train_model(container_sas_url) + model = poller.result() + + target = client.authorize_copy_target(resource_region=location, resource_id=resource_id) + + poller = client.begin_copy_model(model.model_id, target=target) + copy = poller.result() + + copied_model = client.get_custom_model(copy.model_id) + + self.assertEqual(copy.status, "succeeded") + self.assertIsNotNone(copy.created_on) + self.assertIsNotNone(copy.last_modified) + self.assertEqual(target["modelId"], copy.model_id) + self.assertNotEqual(target["modelId"], model.model_id) + self.assertIsNotNone(copied_model) + + @GlobalFormRecognizerAccountPreparer() + @GlobalTrainingAccountPreparer(copy=True) + def test_copy_model_fail(self, client, container_sas_url, location, resource_id): + + poller = client.begin_train_model(container_sas_url) + model = poller.result() + + # give an incorrect region + target = client.authorize_copy_target(resource_region="eastus", resource_id=resource_id) + + with self.assertRaises(HttpResponseError): + poller = client.begin_copy_model(model.model_id, target=target) + copy = poller.result() + + @GlobalFormRecognizerAccountPreparer() + @GlobalTrainingAccountPreparer(copy=True) + def test_copy_model_transform(self, client, container_sas_url, location, resource_id): + + poller = client.begin_train_model(container_sas_url) + model = poller.result() + + target = client.authorize_copy_target(resource_region=location, resource_id=resource_id) + + raw_response = [] + + def callback(response, _, headers): + copy_result = client._client._deserialize(CopyOperationResult, response) + model_info = CustomFormModelInfo._from_generated_copy(copy_result, target["modelId"]) + raw_response.append(copy_result) + raw_response.append(model_info) + + poller = client.begin_copy_model(model.model_id, target=target, cls=callback) + copy = poller.result() + + actual = raw_response[0] + copy = raw_response[1] + self.assertEqual(copy.created_on, actual.created_date_time) + self.assertEqual(copy.status, actual.status) + self.assertEqual(copy.last_modified, actual.last_updated_date_time) + self.assertEqual(copy.model_id, target["modelId"]) diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_copy_model_async.py b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_copy_model_async.py new file mode 100644 index 000000000000..bef3f2c9c7c6 --- /dev/null +++ b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_copy_model_async.py @@ -0,0 +1,75 @@ +# coding=utf-8 +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ + +import functools +from azure.core.exceptions import HttpResponseError +from azure.ai.formrecognizer._generated.models import CopyOperationResult +from azure.ai.formrecognizer import CustomFormModelInfo +from azure.ai.formrecognizer.aio import FormTrainingClient +from testcase import GlobalFormRecognizerAccountPreparer +from testcase import GlobalTrainingAccountPreparer as _GlobalTrainingAccountPreparer +from asynctestcase import AsyncFormRecognizerTest + +GlobalTrainingAccountPreparer = functools.partial(_GlobalTrainingAccountPreparer, FormTrainingClient) + + +class TestCopyModelAsync(AsyncFormRecognizerTest): + + @GlobalFormRecognizerAccountPreparer() + @GlobalTrainingAccountPreparer(copy=True) + async def test_copy_model_successful(self, client, container_sas_url, location, resource_id): + + model = await client.train_model(container_sas_url) + + target = await client.authorize_copy_target(resource_region=location, resource_id=resource_id) + + copy = await client.copy_model(model.model_id, target=target) + + copied_model = await client.get_custom_model(copy.model_id) + + self.assertEqual(copy.status, "succeeded") + self.assertIsNotNone(copy.created_on) + self.assertIsNotNone(copy.last_modified) + self.assertEqual(target["modelId"], copy.model_id) + self.assertNotEqual(target["modelId"], model.model_id) + self.assertIsNotNone(copied_model) + + @GlobalFormRecognizerAccountPreparer() + @GlobalTrainingAccountPreparer(copy=True) + async def test_copy_model_fail(self, client, container_sas_url, location, resource_id): + + model = await client.train_model(container_sas_url) + + # give an incorrect region + target = await client.authorize_copy_target(resource_region="eastus", resource_id=resource_id) + + with self.assertRaises(HttpResponseError): + copy = await client.copy_model(model.model_id, target=target) + + @GlobalFormRecognizerAccountPreparer() + @GlobalTrainingAccountPreparer(copy=True) + async def test_copy_model_transform(self, client, container_sas_url, location, resource_id): + + model = await client.train_model(container_sas_url) + + target = await client.authorize_copy_target(resource_region=location, resource_id=resource_id) + + raw_response = [] + + def callback(response, _, headers): + copy_result = client._client._deserialize(CopyOperationResult, response) + model_info = CustomFormModelInfo._from_generated_copy(copy_result, target["modelId"]) + raw_response.append(copy_result) + raw_response.append(model_info) + + copy = await client.copy_model(model.model_id, target=target, cls=callback) + + actual = raw_response[0] + copy = raw_response[1] + self.assertEqual(copy.created_on, actual.created_date_time) + self.assertEqual(copy.status, actual.status) + self.assertEqual(copy.last_modified, actual.last_updated_date_time) + self.assertEqual(copy.model_id, target["modelId"]) diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/tests/testcase.py b/sdk/formrecognizer/azure-ai-formrecognizer/tests/testcase.py index df55afcfcf62..d1bb6775b51f 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/tests/testcase.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/tests/testcase.py @@ -18,7 +18,36 @@ ResourceGroupPreparer, ) from devtools_testutils.cognitiveservices_testcase import CognitiveServicesAccountPreparer -from azure_devtools.scenario_tests import ReplayableTest, AzureTestError +from azure_devtools.scenario_tests import ( + RecordingProcessor, + ReplayableTest +) +from azure_devtools.scenario_tests.utilities import is_text_payload + + +class AccessTokenReplacer(RecordingProcessor): + """Replace the access token in a request/response body.""" + + def __init__(self, replacement='redacted'): + self._replacement = replacement + + def process_request(self, request): + import re + if is_text_payload(request) and request.body: + body = str(request.body) + body = re.sub(r'"accessToken": "([0-9a-f-]{36})"', r'"accessToken": 00000000-0000-0000-0000-000000000000', body) + request.body = body + return request + + def process_response(self, response): + import json + try: + body = json.loads(response['body']['string']) + body['accessToken'] = self._replacement + except (KeyError, ValueError): + return response + response['body']['string'] = json.dumps(body) + return response class FormRecognizerTest(AzureTestCase): @@ -26,6 +55,8 @@ class FormRecognizerTest(AzureTestCase): def __init__(self, method_name): super(FormRecognizerTest, self).__init__(method_name) + self.recording_processors.append(AccessTokenReplacer()) + # URL samples self.receipt_url_jpg = "https://raw.githubusercontent.com/Azure/azure-sdk-for-python/master/sdk/formrecognizer/azure-ai-formrecognizer/tests/sample_forms/receipt/contoso-allinone.jpg" self.receipt_url_png = "https://raw.githubusercontent.com/Azure/azure-sdk-for-python/master/sdk/formrecognizer/azure-ai-formrecognizer/tests/sample_forms/receipt/contoso-receipt.png" @@ -338,10 +369,10 @@ def __init__(self): def create_resource(self, name, **kwargs): form_recognizer_account = FormRecognizerTest._FORM_RECOGNIZER_ACCOUNT return { - 'location': 'westus2', + 'location': 'westus', 'resource_group': FormRecognizerTest._RESOURCE_GROUP, 'form_recognizer_account': form_recognizer_account, - 'form_recognizer_account_key': FormRecognizerTest._FORM_RECOGNIZER_KEY, + 'form_recognizer_account_key': FormRecognizerTest._FORM_RECOGNIZER_KEY } @@ -355,6 +386,7 @@ def __init__(self, client_cls, client_kwargs={}, **kwargs): self.client_cls = client_cls self.multipage_test = kwargs.get("multipage", False) self.need_blob_sas_url = kwargs.get("blob_sas_url", False) + self.copy = kwargs.get("copy", False) def _load_settings(self): try: @@ -387,6 +419,28 @@ def create_resource(self, name, **kwargs): return {"client": client, "container_sas_url": container_sas_url, "blob_sas_url": blob_sas_url} + if self.copy: + if self.is_live: + resource_group = kwargs.get("resource_group") + form_recognizer_name = FormRecognizerTest._FORM_RECOGNIZER_NAME + + resource_id = resource_group.id + "/providers/Microsoft.CognitiveServices/accounts/" + form_recognizer_name + resource_location = resource_group.location + self.test_class_instance.scrubber.register_name_pair( + resource_id, + "resource_id" + ) + else: + resource_location = "westus" + resource_id = "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rgname/providers/Microsoft.CognitiveServices/accounts/frname" + + return { + "client": client, + "container_sas_url": container_sas_url, + "location": resource_location, + "resource_id": resource_id + } + else: return {"client": client, "container_sas_url": container_sas_url} @@ -449,6 +503,7 @@ def form_recognizer_account(): test_case, **rg_kwargs) FormRecognizerTest._FORM_RECOGNIZER_ACCOUNT = form_recognizer_kwargs['cognitiveservices_account'] FormRecognizerTest._FORM_RECOGNIZER_KEY = form_recognizer_kwargs['cognitiveservices_account_key'] + FormRecognizerTest._FORM_RECOGNIZER_NAME = form_recognizer_name yield finally: form_recognizer_preparer.remove_resource( From 23b1d3adea849e804698ebebfb4536b02c0af3a5 Mon Sep 17 00:00:00 2001 From: Krista Pratico Date: Wed, 13 May 2020 18:52:19 -0700 Subject: [PATCH 14/22] make mypy happy --- .../azure/ai/formrecognizer/_form_training_client.py | 9 +++++++-- .../ai/formrecognizer/aio/_form_training_client_async.py | 9 +++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_form_training_client.py b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_form_training_client.py index 045e1d213089..39ba9ee1490d 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_form_training_client.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_form_training_client.py @@ -24,7 +24,8 @@ TrainSourceFilter, CopyRequest, Model, - CopyOperationResult + CopyOperationResult, + CopyAuthorizationResult ) from ._helpers import error_map, get_authentication_policy, POLLING_INTERVAL from ._models import ( @@ -324,7 +325,11 @@ def _copy_callback(raw_response, _, headers): # pylint: disable=unused-argument copy_request=CopyRequest( target_resource_id=target["resourceId"], target_resource_region=target["resourceRegion"], - copy_authorization=target + copy_authorization=CopyAuthorizationResult( + access_token=target["accessToken"], + model_id=target["modelId"], + expiration_date_time_ticks=target["expirationDateTimeTicks"] + ) ), cls=kwargs.pop("cls", _copy_callback), polling=LROBasePolling(timeout=polling_interval, lro_algorithms=[CopyPolling()], **kwargs), diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/aio/_form_training_client_async.py b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/aio/_form_training_client_async.py index e111b3b764f1..de31d98a6850 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/aio/_form_training_client_async.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/aio/_form_training_client_async.py @@ -25,7 +25,8 @@ TrainSourceFilter, Model, CopyRequest, - CopyOperationResult + CopyOperationResult, + CopyAuthorizationResult ) from .._helpers import error_map, get_authentication_policy, POLLING_INTERVAL from .._models import ( @@ -333,7 +334,11 @@ def _copy_callback(raw_response, _, headers): # pylint: disable=unused-argument copy_request=CopyRequest( target_resource_id=target["resourceId"], target_resource_region=target["resourceRegion"], - copy_authorization=target + copy_authorization=CopyAuthorizationResult( + access_token=target["accessToken"], + model_id=target["modelId"], + expiration_date_time_ticks=target["expirationDateTimeTicks"] + ) ), cls=kwargs.pop("cls", _copy_callback), polling=AsyncLROBasePolling(timeout=polling_interval, lro_algorithms=[CopyPolling()], **kwargs), From ed4d8e340f90492d0eb5f430df671041f53cf646 Mon Sep 17 00:00:00 2001 From: Krista Pratico Date: Thu, 14 May 2020 12:25:42 -0700 Subject: [PATCH 15/22] update docstrings --- .../formrecognizer/_form_training_client.py | 28 +++++++++---------- .../aio/_form_training_client_async.py | 27 +++++++++--------- .../async_samples/sample_copy_model_async.py | 4 +-- .../samples/sample_copy_model.py | 4 +-- 4 files changed, 31 insertions(+), 32 deletions(-) diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_form_training_client.py b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_form_training_client.py index 39ba9ee1490d..7198b68d2496 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_form_training_client.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_form_training_client.py @@ -247,27 +247,27 @@ def get_custom_model(self, model_id, **kwargs): @distributed_trace def authorize_copy_target(self, resource_id, resource_region, **kwargs): # type: (str, str, Any) -> Dict[str, Union[str, int]] - """Generate authorization to copy a model into the target Form Recognizer resource. + """Generate authorization for copying a model into the target Form Recognizer resource. This should be called by the target resource (where the model will be copied to) - and the output can be passed into :func:`~begin_copy_model()` + and the output can be passed as the `target` parameter into :func:`~begin_copy_model()`. :param str resource_id: Azure Resource Id of the target Form Recognizer resource where the model will be copied to. :param str resource_region: Location of the target Azure resource. A valid Azure region name supported by Cognitive Services. - :return: A dictionary with values for the model ID, access token, resource ID, - resource region, and expiration datetime ticks. + :return: A dictionary with values for the copy authorization - + "modelId", "accessToken", "resourceId", "resourceRegion", and "expirationDateTimeTicks". :rtype: Dict[str, Union[str, int]] :raises ~azure.core.exceptions.HttpResponseError: .. admonition:: Example: .. literalinclude:: ../samples/sample_copy_model.py - :start-after: [START generate_copy_auth] - :end-before: [END generate_copy_auth] + :start-after: [START authorize_copy_target] + :end-before: [END authorize_copy_target] :language: python :dedent: 8 - :caption: Generate copy authorization with the target resource + :caption: Authorize the target resource to receive the copied model """ response = self._client.generate_model_copy_authorization( # type: ignore @@ -288,19 +288,19 @@ def begin_copy_model( **kwargs # type: Any ): # type: (...) -> LROPoller - """Copy custom model stored in this resource (the source) to user specified target Form Recognizer resource. - This should be called with the source Form Recognizer resource (with model that is intended to be copied). - The `target` parameter should be supplied from the target resource's output from calling the - :func:`~authorize_copy_target()` method. + """Copy a custom model stored in this resource (the source) to the user specified + target Form Recognizer resource. This should be called with the source Form Recognizer resource + (with the model that is intended to be copied). The `target` parameter should be supplied from the + target resource's output from calling the :func:`~authorize_copy_target()` method. - :param model_id: Model identifier of the model to copy to target resource. - :type model_id: str + :param str model_id: Model identifier of the model to copy to target resource. :param dict target: The copy authorization generated from the target resource's call to :func:`~authorize_copy_target()`. :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 + :return: An instance of an LROPoller. Call `result()` on the poller + object to return a :class:`~azure.ai.formrecognizer.CustomFormModelInfo`. :rtype: ~azure.core.polling.LROPoller[CustomFormModelInfo] :raises ~azure.core.exceptions.HttpResponseError: diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/aio/_form_training_client_async.py b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/aio/_form_training_client_async.py index de31d98a6850..9de3081afb8d 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/aio/_form_training_client_async.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/aio/_form_training_client_async.py @@ -258,27 +258,27 @@ async def authorize_copy_target( resource_region: str, **kwargs: Any ) -> Dict[str, Union[str, int]]: - """Generate authorization to copy a model into the target Form Recognizer resource. + """Generate authorization for copying a model into the target Form Recognizer resource. This should be called by the target resource (where the model will be copied to) - and the output can be passed into :func:`~copy_model()` + and the output can be passed as the `target` parameter into :func:`~copy_model()`. :param str resource_id: Azure Resource Id of the target Form Recognizer resource where the model will be copied to. :param str resource_region: Location of the target Azure resource. A valid Azure region name supported by Cognitive Services. - :return: A dictionary with values for the model ID, access token, resource ID, - resource region, and expiration datetime ticks. + :return: A dictionary with values for the copy authorization - + "modelId", "accessToken", "resourceId", "resourceRegion", and "expirationDateTimeTicks". :rtype: Dict[str, Union[str, int]] :raises ~azure.core.exceptions.HttpResponseError: .. admonition:: Example: .. literalinclude:: ../samples/async_samples/sample_copy_model_async.py - :start-after: [START generate_copy_auth_async] - :end-before: [END generate_copy_auth_async] + :start-after: [START authorize_copy_target_async] + :end-before: [END authorize_copy_target_async] :language: python :dedent: 8 - :caption: Generate copy authorization with the target resource + :caption: Authorize the target resource to receive the copied model """ response = await self._client.generate_model_copy_authorization( # type: ignore @@ -298,19 +298,18 @@ async def copy_model( target: dict, **kwargs: Any ) -> CustomFormModelInfo: - """Copy custom model stored in this resource (the source) to user specified target Form Recognizer resource. - This should be called with the source Form Recognizer resource (with model that is intended to be copied). - The `target` parameter should be supplied from the target resource's output from calling the - :func:`~authorize_copy_target()` method. + """Copy a custom model stored in this resource (the source) to the user specified + target Form Recognizer resource. This should be called with the source Form Recognizer resource + (with the model that is intended to be copied). The `target` parameter should be supplied from the + target resource's output from calling the :func:`~authorize_copy_target()` method. - :param model_id: Model identifier of the model to copy to target resource. - :type model_id: str + :param str model_id: Model identifier of the model to copy to target resource. :param dict target: The copy authorization generated from the target resource's call to :func:`~authorize_copy_target()`. :keyword int polling_interval: Default waiting time between two polls for LRO operations if no Retry-After header is present. - :return: An instance of CustomFormModelInfo + :return: CustomFormModelInfo :rtype: ~azure.ai.formrecognizer.CustomFormModelInfo :raises ~azure.core.exceptions.HttpResponseError: diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_copy_model_async.py b/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_copy_model_async.py index 955c7745e8ad..330f1d86f0ec 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_copy_model_async.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_copy_model_async.py @@ -44,7 +44,7 @@ async def copy_model_async(self): target_region = os.environ["AZURE_FORM_RECOGNIZER_TARGET_REGION"] target_resource_id = os.environ["AZURE_FORM_RECOGNIZER_TARGET_RESOURCE_ID"] - # [START generate_copy_auth_async] + # [START authorize_copy_target_async] target_client = FormTrainingClient(endpoint=target_endpoint, credential=AzureKeyCredential(target_key)) async with target_client: @@ -52,7 +52,7 @@ async def copy_model_async(self): resource_region=target_region, resource_id=target_resource_id ) - # [END generate_copy_auth_async] + # [END authorize_copy_target_async] # [START copy_model_async] source_client = FormTrainingClient(endpoint=source_endpoint, credential=AzureKeyCredential(source_key)) diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/samples/sample_copy_model.py b/sdk/formrecognizer/azure-ai-formrecognizer/samples/sample_copy_model.py index 070b5bc488ef..40a1f06f764d 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/samples/sample_copy_model.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/samples/sample_copy_model.py @@ -43,14 +43,14 @@ def copy_model(self): target_region = os.environ["AZURE_FORM_RECOGNIZER_TARGET_REGION"] target_resource_id = os.environ["AZURE_FORM_RECOGNIZER_TARGET_RESOURCE_ID"] - # [START generate_copy_auth] + # [START authorize_copy_target] target_client = FormTrainingClient(endpoint=target_endpoint, credential=AzureKeyCredential(target_key)) target = target_client.authorize_copy_target( resource_region=target_region, resource_id=target_resource_id ) - # [END generate_copy_auth] + # [END authorize_copy_target] # [START begin_copy_model] source_client = FormTrainingClient(endpoint=source_endpoint, credential=AzureKeyCredential(source_key)) From a2a5dac742c8340c1631faf113fa8c2ecac7cd14 Mon Sep 17 00:00:00 2001 From: Krista Pratico Date: Mon, 18 May 2020 16:30:02 -0700 Subject: [PATCH 16/22] review feedback --- .../azure-ai-formrecognizer/CHANGELOG.md | 2 +- .../azure-ai-formrecognizer/README.md | 2 +- .../ai/formrecognizer/_form_training_client.py | 4 ++-- .../azure/ai/formrecognizer/_models.py | 15 +++------------ .../azure/ai/formrecognizer/_polling.py | 5 +---- .../aio/_form_training_client_async.py | 2 +- .../async_samples/sample_copy_model_async.py | 3 ++- .../samples/sample_copy_model.py | 3 ++- 8 files changed, 13 insertions(+), 23 deletions(-) diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/CHANGELOG.md b/sdk/formrecognizer/azure-ai-formrecognizer/CHANGELOG.md index d7b1e8a0b1c7..beb60b5aacb7 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/CHANGELOG.md +++ b/sdk/formrecognizer/azure-ai-formrecognizer/CHANGELOG.md @@ -13,7 +13,7 @@ **New features** -- Copy API is now supported to copy a model from one Form Recognizer resource to another +- Support to copy a custom model from one Form Recognizer resource to another - Authentication using `azure-identity` credentials now supported - see the [Azure Identity documentation](https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/identity/azure-identity/README.md) for more information diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/README.md b/sdk/formrecognizer/azure-ai-formrecognizer/README.md index 85dd86496f1f..844819b286c3 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/README.md +++ b/sdk/formrecognizer/azure-ai-formrecognizer/README.md @@ -131,7 +131,7 @@ See the full details regarding [authentication][cognitive_authentication] of cog - Training custom models to recognize all fields and values found in your custom forms. A `CustomFormModel` is returned indicating the form types the model will recognize, and the fields it will extract for each form type. See the [service's documents][fr-train-without-labels] for a more detailed explanation. - Training custom models to recognize specific fields and values you specify by labeling your custom forms. A `CustomFormModel` is returned indicating the fields the model will extract, as well as the estimated accuracy for each field. See the [service's documents][fr-train-with-labels] for a more detailed explanation. - Managing models created in your account. -- Copying a model from one Form Recognizer resource to another. +- Copying a custom model from one Form Recognizer resource to another. Please note that models can also be trained using a graphical user interface such as the [Form Recognizer Labeling Tool][fr-labeling-tool]. diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_form_training_client.py b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_form_training_client.py index 15ccc9bb5279..e7ab982511e4 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_form_training_client.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_form_training_client.py @@ -305,7 +305,7 @@ def begin_copy_model( no Retry-After header is present. :return: An instance of an LROPoller. Call `result()` on the poller object to return a :class:`~azure.ai.formrecognizer.CustomFormModelInfo`. - :rtype: ~azure.core.polling.LROPoller[CustomFormModelInfo] + :rtype: ~azure.core.polling.LROPoller[~azure.ai.formrecognizer.CustomFormModelInfo] :raises ~azure.core.exceptions.HttpResponseError: .. admonition:: Example: @@ -322,7 +322,7 @@ def begin_copy_model( def _copy_callback(raw_response, _, headers): # pylint: disable=unused-argument copy_result = self._client._deserialize(CopyOperationResult, raw_response) - return CustomFormModelInfo._from_generated_copy(copy_result, target["modelId"]) + return CustomFormModelInfo._from_generated(copy_result, target["modelId"]) return self._client.begin_copy_custom_model( # type: ignore model_id=model_id, diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_models.py b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_models.py index af19a251d467..0678694617d8 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_models.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_models.py @@ -287,7 +287,6 @@ def _from_generated(cls, field, value, read_result): page_number=value.page if value else None, ) - @classmethod def _from_generated_unlabeled(cls, field, idx, page, read_result): return cls( @@ -456,6 +455,7 @@ def __repr__(self): self.text, self.bounding_box, repr(self.words), self.page_number )[:1024] + class FormWord(FormContent): """Represents a word recognized from the input document. @@ -848,23 +848,14 @@ def __init__(self, **kwargs): self.last_modified = kwargs.get("last_modified", None) @classmethod - def _from_generated(cls, model): + def _from_generated(cls, model, model_id=None): return cls( - model_id=model.model_id, + model_id=model_id if model_id else model.model_id, status=model.status, created_on=model.created_date_time, last_modified=model.last_updated_date_time ) - @classmethod - def _from_generated_copy(cls, copy, model_id): - return cls( - model_id=model_id, - status=copy.status, - created_on=copy.created_date_time, - last_modified=copy.last_updated_date_time - ) - def __repr__(self): return "CustomFormModelInfo(model_id={}, status={}, created_on={}, last_modified={})".format( self.model_id, self.status, self.created_on, self.last_modified diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_polling.py b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_polling.py index 2f2e074d5932..f1ef5267a283 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_polling.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_polling.py @@ -123,8 +123,5 @@ def get_status(self, pipeline_response): # pylint: disable=no-self-use if copy_result: errors = copy_result.get("errors") if errors: - message = "" - for err in errors: - message += "({}) {}\n".format(err.get("code"), err.get("message")) - raise HttpResponseError(message) + raise_error(response, errors, message="") return status diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/aio/_form_training_client_async.py b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/aio/_form_training_client_async.py index 0a1bd4077415..c8c3d91c36a9 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/aio/_form_training_client_async.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/aio/_form_training_client_async.py @@ -331,7 +331,7 @@ async def copy_model( def _copy_callback(raw_response, _, headers): # pylint: disable=unused-argument copy_result = self._client._deserialize(CopyOperationResult, raw_response) - return CustomFormModelInfo._from_generated_copy(copy_result, target["modelId"]) + return CustomFormModelInfo._from_generated(copy_result, target["modelId"]) return await self._client.copy_custom_model( # type: ignore model_id=model_id, diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_copy_model_async.py b/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_copy_model_async.py index 330f1d86f0ec..38c389664ccd 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_copy_model_async.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_copy_model_async.py @@ -66,7 +66,8 @@ async def copy_model_async(self): async with target_client: copied_over_model = await target_client.get_custom_model(copy.model_id) - print(copied_over_model) + print("Model ID: {}".format(copied_over_model.model_id)) + print("Status: {}".format(copied_over_model.status)) # [END copy_model_async] diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/samples/sample_copy_model.py b/sdk/formrecognizer/azure-ai-formrecognizer/samples/sample_copy_model.py index 40a1f06f764d..135ec7974b46 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/samples/sample_copy_model.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/samples/sample_copy_model.py @@ -63,7 +63,8 @@ def copy_model(self): copy = poller.result() copied_over_model = target_client.get_custom_model(copy.model_id) - print(copied_over_model) + print("Model ID: {}".format(copied_over_model.model_id)) + print("Status: {}".format(copied_over_model.status)) # [END begin_copy_model] From 4736418e12019c086f695b12c54f9a8f7c9682e3 Mon Sep 17 00:00:00 2001 From: Krista Pratico Date: Mon, 18 May 2020 16:37:50 -0700 Subject: [PATCH 17/22] rename authorize_copy_target -> get_copy_authorization --- .../azure/ai/formrecognizer/_form_training_client.py | 10 +++++----- .../formrecognizer/aio/_form_training_client_async.py | 10 +++++----- .../samples/async_samples/sample_copy_model_async.py | 6 +++--- .../samples/sample_copy_model.py | 6 +++--- .../azure-ai-formrecognizer/tests/test_copy_model.py | 8 ++++---- .../tests/test_copy_model_async.py | 8 ++++---- 6 files changed, 24 insertions(+), 24 deletions(-) diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_form_training_client.py b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_form_training_client.py index e7ab982511e4..ecdf40a37a20 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_form_training_client.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_form_training_client.py @@ -249,7 +249,7 @@ def get_custom_model(self, model_id, **kwargs): return CustomFormModel._from_generated(response) @distributed_trace - def authorize_copy_target(self, resource_id, resource_region, **kwargs): + def get_copy_authorization(self, resource_id, resource_region, **kwargs): # type: (str, str, Any) -> Dict[str, Union[str, int]] """Generate authorization for copying a model into the target Form Recognizer resource. This should be called by the target resource (where the model will be copied to) @@ -267,8 +267,8 @@ def authorize_copy_target(self, resource_id, resource_region, **kwargs): .. admonition:: Example: .. literalinclude:: ../samples/sample_copy_model.py - :start-after: [START authorize_copy_target] - :end-before: [END authorize_copy_target] + :start-after: [START get_copy_authorization] + :end-before: [END get_copy_authorization] :language: python :dedent: 8 :caption: Authorize the target resource to receive the copied model @@ -295,12 +295,12 @@ def begin_copy_model( """Copy a custom model stored in this resource (the source) to the user specified target Form Recognizer resource. This should be called with the source Form Recognizer resource (with the model that is intended to be copied). The `target` parameter should be supplied from the - target resource's output from calling the :func:`~authorize_copy_target()` method. + target resource's output from calling the :func:`~get_copy_authorization()` method. :param str model_id: Model identifier of the model to copy to target resource. :param dict target: The copy authorization generated from the target resource's call to - :func:`~authorize_copy_target()`. + :func:`~get_copy_authorization()`. :keyword int polling_interval: Default waiting time between two polls for LRO operations if no Retry-After header is present. :return: An instance of an LROPoller. Call `result()` on the poller diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/aio/_form_training_client_async.py b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/aio/_form_training_client_async.py index c8c3d91c36a9..82a9b1ea4bf5 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/aio/_form_training_client_async.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/aio/_form_training_client_async.py @@ -257,7 +257,7 @@ async def get_custom_model(self, model_id: str, **kwargs: Any) -> CustomFormMode return CustomFormModel._from_generated(response) @distributed_trace_async - async def authorize_copy_target( + async def get_copy_authorization( self, resource_id: str, resource_region: str, @@ -279,8 +279,8 @@ async def authorize_copy_target( .. admonition:: Example: .. literalinclude:: ../samples/async_samples/sample_copy_model_async.py - :start-after: [START authorize_copy_target_async] - :end-before: [END authorize_copy_target_async] + :start-after: [START get_copy_authorization_async] + :end-before: [END get_copy_authorization_async] :language: python :dedent: 8 :caption: Authorize the target resource to receive the copied model @@ -306,12 +306,12 @@ async def copy_model( """Copy a custom model stored in this resource (the source) to the user specified target Form Recognizer resource. This should be called with the source Form Recognizer resource (with the model that is intended to be copied). The `target` parameter should be supplied from the - target resource's output from calling the :func:`~authorize_copy_target()` method. + target resource's output from calling the :func:`~get_copy_authorization()` method. :param str model_id: Model identifier of the model to copy to target resource. :param dict target: The copy authorization generated from the target resource's call to - :func:`~authorize_copy_target()`. + :func:`~get_copy_authorization()`. :keyword int polling_interval: Default waiting time between two polls for LRO operations if no Retry-After header is present. :return: CustomFormModelInfo diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_copy_model_async.py b/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_copy_model_async.py index 38c389664ccd..6d272e1de124 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_copy_model_async.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_copy_model_async.py @@ -44,15 +44,15 @@ async def copy_model_async(self): target_region = os.environ["AZURE_FORM_RECOGNIZER_TARGET_REGION"] target_resource_id = os.environ["AZURE_FORM_RECOGNIZER_TARGET_RESOURCE_ID"] - # [START authorize_copy_target_async] + # [START get_copy_authorization_async] target_client = FormTrainingClient(endpoint=target_endpoint, credential=AzureKeyCredential(target_key)) async with target_client: - target = await target_client.authorize_copy_target( + target = await target_client.get_copy_authorization( resource_region=target_region, resource_id=target_resource_id ) - # [END authorize_copy_target_async] + # [END get_copy_authorization_async] # [START copy_model_async] source_client = FormTrainingClient(endpoint=source_endpoint, credential=AzureKeyCredential(source_key)) diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/samples/sample_copy_model.py b/sdk/formrecognizer/azure-ai-formrecognizer/samples/sample_copy_model.py index 135ec7974b46..daef19084868 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/samples/sample_copy_model.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/samples/sample_copy_model.py @@ -43,14 +43,14 @@ def copy_model(self): target_region = os.environ["AZURE_FORM_RECOGNIZER_TARGET_REGION"] target_resource_id = os.environ["AZURE_FORM_RECOGNIZER_TARGET_RESOURCE_ID"] - # [START authorize_copy_target] + # [START get_copy_authorization] target_client = FormTrainingClient(endpoint=target_endpoint, credential=AzureKeyCredential(target_key)) - target = target_client.authorize_copy_target( + target = target_client.get_copy_authorization( resource_region=target_region, resource_id=target_resource_id ) - # [END authorize_copy_target] + # [END get_copy_authorization] # [START begin_copy_model] source_client = FormTrainingClient(endpoint=source_endpoint, credential=AzureKeyCredential(source_key)) diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_copy_model.py b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_copy_model.py index 900202d3139a..04afa2798e54 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_copy_model.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_copy_model.py @@ -24,7 +24,7 @@ def test_copy_model_successful(self, client, container_sas_url, location, resour poller = client.begin_train_model(container_sas_url) model = poller.result() - target = client.authorize_copy_target(resource_region=location, resource_id=resource_id) + target = client.get_copy_authorization(resource_region=location, resource_id=resource_id) poller = client.begin_copy_model(model.model_id, target=target) copy = poller.result() @@ -46,7 +46,7 @@ def test_copy_model_fail(self, client, container_sas_url, location, resource_id) model = poller.result() # give an incorrect region - target = client.authorize_copy_target(resource_region="eastus", resource_id=resource_id) + target = client.get_copy_authorization(resource_region="eastus", resource_id=resource_id) with self.assertRaises(HttpResponseError): poller = client.begin_copy_model(model.model_id, target=target) @@ -59,13 +59,13 @@ def test_copy_model_transform(self, client, container_sas_url, location, resourc poller = client.begin_train_model(container_sas_url) model = poller.result() - target = client.authorize_copy_target(resource_region=location, resource_id=resource_id) + target = client.get_copy_authorization(resource_region=location, resource_id=resource_id) raw_response = [] def callback(response, _, headers): copy_result = client._client._deserialize(CopyOperationResult, response) - model_info = CustomFormModelInfo._from_generated_copy(copy_result, target["modelId"]) + model_info = CustomFormModelInfo._from_generated(copy_result, target["modelId"]) raw_response.append(copy_result) raw_response.append(model_info) diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_copy_model_async.py b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_copy_model_async.py index bef3f2c9c7c6..36f5f1177070 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_copy_model_async.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_copy_model_async.py @@ -24,7 +24,7 @@ async def test_copy_model_successful(self, client, container_sas_url, location, model = await client.train_model(container_sas_url) - target = await client.authorize_copy_target(resource_region=location, resource_id=resource_id) + target = await client.get_copy_authorization(resource_region=location, resource_id=resource_id) copy = await client.copy_model(model.model_id, target=target) @@ -44,7 +44,7 @@ async def test_copy_model_fail(self, client, container_sas_url, location, resour model = await client.train_model(container_sas_url) # give an incorrect region - target = await client.authorize_copy_target(resource_region="eastus", resource_id=resource_id) + target = await client.get_copy_authorization(resource_region="eastus", resource_id=resource_id) with self.assertRaises(HttpResponseError): copy = await client.copy_model(model.model_id, target=target) @@ -55,13 +55,13 @@ async def test_copy_model_transform(self, client, container_sas_url, location, r model = await client.train_model(container_sas_url) - target = await client.authorize_copy_target(resource_region=location, resource_id=resource_id) + target = await client.get_copy_authorization(resource_region=location, resource_id=resource_id) raw_response = [] def callback(response, _, headers): copy_result = client._client._deserialize(CopyOperationResult, response) - model_info = CustomFormModelInfo._from_generated_copy(copy_result, target["modelId"]) + model_info = CustomFormModelInfo._from_generated(copy_result, target["modelId"]) raw_response.append(copy_result) raw_response.append(model_info) From ff26bc6d71b0ec489b6acaa9e1f038f84fe96d98 Mon Sep 17 00:00:00 2001 From: Krista Pratico Date: Tue, 19 May 2020 08:58:03 -0700 Subject: [PATCH 18/22] feedback + add test for copy authorization --- .../formrecognizer/_form_training_client.py | 4 +- .../aio/_form_training_client_async.py | 4 +- .../azure-ai-formrecognizer/samples/README.md | 2 +- ...st_copy_model.test_copy_authorization.yaml | 42 +++++++++++++++++++ ...y_model_async.test_copy_authorization.yaml | 29 +++++++++++++ .../tests/test_copy_model.py | 12 ++++++ .../tests/test_copy_model_async.py | 12 ++++++ 7 files changed, 100 insertions(+), 5 deletions(-) create mode 100644 sdk/formrecognizer/azure-ai-formrecognizer/tests/recordings/test_copy_model.test_copy_authorization.yaml create mode 100644 sdk/formrecognizer/azure-ai-formrecognizer/tests/recordings/test_copy_model_async.test_copy_authorization.yaml diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_form_training_client.py b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_form_training_client.py index ecdf40a37a20..0905b310bbff 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_form_training_client.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_form_training_client.py @@ -251,13 +251,13 @@ def get_custom_model(self, model_id, **kwargs): @distributed_trace def get_copy_authorization(self, resource_id, resource_region, **kwargs): # type: (str, str, Any) -> Dict[str, Union[str, int]] - """Generate authorization for copying a model into the target Form Recognizer resource. + """Generate authorization for copying a custom model into the target Form Recognizer resource. This should be called by the target resource (where the model will be copied to) and the output can be passed as the `target` parameter into :func:`~begin_copy_model()`. :param str resource_id: Azure Resource Id of the target Form Recognizer resource where the model will be copied to. - :param str resource_region: Location of the target Azure resource. A valid Azure + :param str resource_region: Location of the target Form Recognizer resource. A valid Azure region name supported by Cognitive Services. :return: A dictionary with values for the copy authorization - "modelId", "accessToken", "resourceId", "resourceRegion", and "expirationDateTimeTicks". diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/aio/_form_training_client_async.py b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/aio/_form_training_client_async.py index 82a9b1ea4bf5..d12010ea13e5 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/aio/_form_training_client_async.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/aio/_form_training_client_async.py @@ -263,13 +263,13 @@ async def get_copy_authorization( resource_region: str, **kwargs: Any ) -> Dict[str, Union[str, int]]: - """Generate authorization for copying a model into the target Form Recognizer resource. + """Generate authorization for copying a custom model into the target Form Recognizer resource. This should be called by the target resource (where the model will be copied to) and the output can be passed as the `target` parameter into :func:`~copy_model()`. :param str resource_id: Azure Resource Id of the target Form Recognizer resource where the model will be copied to. - :param str resource_region: Location of the target Azure resource. A valid Azure + :param str resource_region: Location of the target Form Recognizer resource. A valid Azure region name supported by Cognitive Services. :return: A dictionary with values for the copy authorization - "modelId", "accessToken", "resourceId", "resourceRegion", and "expirationDateTimeTicks". diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/samples/README.md b/sdk/formrecognizer/azure-ai-formrecognizer/samples/README.md index 3aadf094982f..22312586dfbf 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/samples/README.md +++ b/sdk/formrecognizer/azure-ai-formrecognizer/samples/README.md @@ -27,7 +27,7 @@ All of these samples need the endpoint to your Form Recognizer resource ([instru |[sample_train_model_without_labels.py][sample_train_model_without_labels] and [sample_train_model_without_labels_async.py][sample_train_model_without_labels_async]|Train a custom model with unlabeled data| |[sample_train_model_with_labels.py][sample_train_model_with_labels] and [sample_train_model_with_labels_async.py][sample_train_model_with_labels_async]|Train a custom model with labeled data| |[sample_manage_custom_models.py][sample_manage_custom_models] and [sample_manage_custom_models_async.py][sample_manage_custom_models_async]|Manage the custom models in your account| -|[sample_copy_model.py][sample_copy_model] and [sample_copy_model_async.py][sample_copy_model_async]|Copy a model from one Form Recognizer resource to another| +|[sample_copy_model.py][sample_copy_model] and [sample_copy_model_async.py][sample_copy_model_async]|Copy a custom model from one Form Recognizer resource to another| ## Prerequisites diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/tests/recordings/test_copy_model.test_copy_authorization.yaml b/sdk/formrecognizer/azure-ai-formrecognizer/tests/recordings/test_copy_model.test_copy_authorization.yaml new file mode 100644 index 000000000000..956b96dc8b97 --- /dev/null +++ b/sdk/formrecognizer/azure-ai-formrecognizer/tests/recordings/test_copy_model.test_copy_authorization.yaml @@ -0,0 +1,42 @@ +interactions: +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '0' + User-Agent: + - azsdk-python-ai-formrecognizer/1.0.0b3 Python/3.7.3 (Windows-10-10.0.18362-SP0) + Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: POST + uri: https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models/copyAuthorization + response: + body: + string: '{"modelId": "3a1af284-1187-402d-9869-39ad09181bf5", "accessToken": + "redacted", "expirationDateTimeTicks": 637255865516657423}' + headers: + apim-request-id: + - be03b750-1177-47fa-9473-028489a9ce67 + content-type: + - application/json; charset=utf-8 + date: + - Tue, 19 May 2020 15:49:11 GMT + location: + - https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models/3a1af284-1187-402d-9869-39ad09181bf5 + strict-transport-security: + - max-age=31536000; includeSubDomains; preload + transfer-encoding: + - chunked + x-content-type-options: + - nosniff + x-envoy-upstream-service-time: + - '231' + status: + code: 201 + message: Created +version: 1 diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/tests/recordings/test_copy_model_async.test_copy_authorization.yaml b/sdk/formrecognizer/azure-ai-formrecognizer/tests/recordings/test_copy_model_async.test_copy_authorization.yaml new file mode 100644 index 000000000000..01ff0c8827f0 --- /dev/null +++ b/sdk/formrecognizer/azure-ai-formrecognizer/tests/recordings/test_copy_model_async.test_copy_authorization.yaml @@ -0,0 +1,29 @@ +interactions: +- request: + body: null + headers: + Accept: + - application/json + User-Agent: + - azsdk-python-ai-formrecognizer/1.0.0b3 Python/3.7.3 (Windows-10-10.0.18362-SP0) + Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: POST + uri: https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models/copyAuthorization + response: + body: + string: '{"modelId": "adcd2786-9aa5-4098-9a55-7d68eaeaaf2f", "accessToken": + "redacted", "expirationDateTimeTicks": 637255866617034918}' + headers: + apim-request-id: 99a50a5e-a423-47ae-8e9e-9369a4ac8d90 + content-type: application/json; charset=utf-8 + date: Tue, 19 May 2020 15:51:01 GMT + location: https://westus.api.cognitive.microsoft.com/formrecognizer/v2.0-preview/custom/models/adcd2786-9aa5-4098-9a55-7d68eaeaaf2f + strict-transport-security: max-age=31536000; includeSubDomains; preload + transfer-encoding: chunked + x-content-type-options: nosniff + x-envoy-upstream-service-time: '226' + status: + code: 201 + message: Created + url: https://westus.api.cognitive.microsoft.com//formrecognizer/v2.0-preview/custom/models/copyAuthorization +version: 1 diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_copy_model.py b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_copy_model.py index 04afa2798e54..be9bce84721a 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_copy_model.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_copy_model.py @@ -78,3 +78,15 @@ def callback(response, _, headers): self.assertEqual(copy.status, actual.status) self.assertEqual(copy.last_modified, actual.last_updated_date_time) self.assertEqual(copy.model_id, target["modelId"]) + + @GlobalFormRecognizerAccountPreparer() + @GlobalTrainingAccountPreparer(copy=True) + def test_copy_authorization(self, client, container_sas_url, location, resource_id): + + target = client.get_copy_authorization(resource_region="eastus", resource_id=resource_id) + + self.assertIsNotNone(target["modelId"]) + self.assertIsNotNone(target["accessToken"]) + self.assertIsNotNone(target["expirationDateTimeTicks"]) + self.assertEqual(target["resourceRegion"], "eastus") + self.assertEqual(target["resourceId"], resource_id) diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_copy_model_async.py b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_copy_model_async.py index 36f5f1177070..0b7a2aa0422e 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_copy_model_async.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_copy_model_async.py @@ -73,3 +73,15 @@ def callback(response, _, headers): self.assertEqual(copy.status, actual.status) self.assertEqual(copy.last_modified, actual.last_updated_date_time) self.assertEqual(copy.model_id, target["modelId"]) + + @GlobalFormRecognizerAccountPreparer() + @GlobalTrainingAccountPreparer(copy=True) + async def test_copy_authorization(self, client, container_sas_url, location, resource_id): + + target = await client.get_copy_authorization(resource_region="eastus", resource_id=resource_id) + + self.assertIsNotNone(target["modelId"]) + self.assertIsNotNone(target["accessToken"]) + self.assertIsNotNone(target["expirationDateTimeTicks"]) + self.assertEqual(target["resourceRegion"], "eastus") + self.assertEqual(target["resourceId"], resource_id) From ca642710e74babd6c64b4df3a94718eb2a6af93c Mon Sep 17 00:00:00 2001 From: Krista Pratico Date: Wed, 20 May 2020 12:47:23 -0700 Subject: [PATCH 19/22] fix to testcase --- .../azure-ai-formrecognizer/tests/testcase.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/tests/testcase.py b/sdk/formrecognizer/azure-ai-formrecognizer/tests/testcase.py index 15edfd6088d1..e6227d00fc72 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/tests/testcase.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/tests/testcase.py @@ -10,11 +10,11 @@ import os import pytest import re +from collections import namedtuple from azure.core.credentials import AzureKeyCredential, AccessToken from devtools_testutils import ( AzureTestCase, AzureMgmtPreparer, - FakeResource, ResourceGroupPreparer, ) from devtools_testutils.cognitiveservices_testcase import CognitiveServicesAccountPreparer @@ -24,6 +24,11 @@ ) from azure_devtools.scenario_tests.utilities import is_text_payload +FakeResource = namedtuple( + 'FakeResource', + ['name', 'id', 'location'] +) + class AccessTokenReplacer(RecordingProcessor): """Replace the access token in a request/response body.""" @@ -377,7 +382,8 @@ def create_resource(self, name, **kwargs): else: rg = FakeResource( name="rgname", - id="/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rgname" + id="/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rgname", + location="westus" ) return { From c100972901cb8218c1e7dc38740a945a7ae4107e Mon Sep 17 00:00:00 2001 From: Krista Pratico Date: Wed, 20 May 2020 12:48:16 -0700 Subject: [PATCH 20/22] change description in samples --- .../samples/async_samples/sample_copy_model_async.py | 2 +- .../azure-ai-formrecognizer/samples/sample_copy_model.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_copy_model_async.py b/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_copy_model_async.py index 6d272e1de124..90b0c50ad8b6 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_copy_model_async.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_copy_model_async.py @@ -10,7 +10,7 @@ FILE: sample_copy_model_async.py DESCRIPTION: - This sample demonstrates how to copy a model from a source Form Recognizer resource + This sample demonstrates how to copy a custom model from a source Form Recognizer resource to a target Form Recognizer resource. USAGE: diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/samples/sample_copy_model.py b/sdk/formrecognizer/azure-ai-formrecognizer/samples/sample_copy_model.py index daef19084868..23901a65e856 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/samples/sample_copy_model.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/samples/sample_copy_model.py @@ -10,7 +10,7 @@ FILE: sample_copy_model.py DESCRIPTION: - This sample demonstrates how to copy a model from a source Form Recognizer resource + This sample demonstrates how to copy a custom model from a source Form Recognizer resource to a target Form Recognizer resource. USAGE: From 688c3eb7d6f2590789d54fc3fa9b82ad8a6e63a5 Mon Sep 17 00:00:00 2001 From: Krista Pratico Date: Wed, 20 May 2020 13:16:45 -0700 Subject: [PATCH 21/22] hardcode region --- .../azure-ai-formrecognizer/tests/testcase.py | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/tests/testcase.py b/sdk/formrecognizer/azure-ai-formrecognizer/tests/testcase.py index e6227d00fc72..090232ce8b57 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/tests/testcase.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/tests/testcase.py @@ -10,11 +10,11 @@ import os import pytest import re -from collections import namedtuple from azure.core.credentials import AzureKeyCredential, AccessToken from devtools_testutils import ( AzureTestCase, AzureMgmtPreparer, + FakeResource, ResourceGroupPreparer, ) from devtools_testutils.cognitiveservices_testcase import CognitiveServicesAccountPreparer @@ -24,11 +24,6 @@ ) from azure_devtools.scenario_tests.utilities import is_text_payload -FakeResource = namedtuple( - 'FakeResource', - ['name', 'id', 'location'] -) - class AccessTokenReplacer(RecordingProcessor): """Replace the access token in a request/response body.""" @@ -382,12 +377,11 @@ def create_resource(self, name, **kwargs): else: rg = FakeResource( name="rgname", - id="/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rgname", - location="westus" + id="/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rgname" ) return { - 'location': 'westus2', + 'location': 'westus', 'resource_group': rg, } @@ -458,7 +452,7 @@ def create_resource(self, name, **kwargs): form_recognizer_name = FormRecognizerTest._FORM_RECOGNIZER_NAME resource_id = resource_group.id + "/providers/Microsoft.CognitiveServices/accounts/" + form_recognizer_name - resource_location = resource_group.location + resource_location = "westus" self.test_class_instance.scrubber.register_name_pair( resource_id, "resource_id" @@ -520,7 +514,7 @@ def create_form_client_and_container_sas_url(self, **kwargs): @pytest.fixture(scope="session") def form_recognizer_account(): test_case = AzureTestCase("__init__") - rg_preparer = ResourceGroupPreparer(random_name_enabled=True, name_prefix='pycog') + rg_preparer = ResourceGroupPreparer(random_name_enabled=True, name_prefix='pycog', location="westus") form_recognizer_preparer = CognitiveServicesAccountPreparer( random_name_enabled=True, kind="formrecognizer", From 58a221085bda9d090cf84577ab5909dc5825046d Mon Sep 17 00:00:00 2001 From: Krista Pratico Date: Wed, 20 May 2020 14:02:38 -0700 Subject: [PATCH 22/22] construct resource id in testcase --- sdk/formrecognizer/azure-ai-formrecognizer/tests/test_mgmt.py | 4 ++-- .../azure-ai-formrecognizer/tests/test_mgmt_async.py | 4 ++-- sdk/formrecognizer/azure-ai-formrecognizer/tests/testcase.py | 4 +++- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_mgmt.py b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_mgmt.py index 6eb9be39cc22..4efe9d52e4d5 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_mgmt.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_mgmt.py @@ -79,7 +79,7 @@ def test_mgmt_model_labeled(self, client, container_sas_url): models_list = client.list_custom_models() for model in models_list: self.assertIsNotNone(model.model_id) - self.assertEqual(model.status, "ready") + self.assertIsNotNone(model.status) self.assertIsNotNone(model.created_on) self.assertIsNotNone(model.last_modified) @@ -114,7 +114,7 @@ def test_mgmt_model_unlabeled(self, client, container_sas_url): models_list = client.list_custom_models() for model in models_list: self.assertIsNotNone(model.model_id) - self.assertEqual(model.status, "ready") + self.assertIsNotNone(model.status) self.assertIsNotNone(model.created_on) self.assertIsNotNone(model.last_modified) diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_mgmt_async.py b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_mgmt_async.py index 735875672cb5..2a51556f4a5a 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_mgmt_async.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_mgmt_async.py @@ -79,7 +79,7 @@ async def test_mgmt_model_labeled(self, client, container_sas_url): models_list = client.list_custom_models() async for model in models_list: self.assertIsNotNone(model.model_id) - self.assertEqual(model.status, "ready") + self.assertIsNotNone(model.status) self.assertIsNotNone(model.created_on) self.assertIsNotNone(model.last_modified) @@ -112,7 +112,7 @@ async def test_mgmt_model_unlabeled(self, client, container_sas_url): models_list = client.list_custom_models() async for model in models_list: self.assertIsNotNone(model.model_id) - self.assertEqual(model.status, "ready") + self.assertIsNotNone(model.status) self.assertIsNotNone(model.created_on) self.assertIsNotNone(model.last_modified) diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/tests/testcase.py b/sdk/formrecognizer/azure-ai-formrecognizer/tests/testcase.py index 090232ce8b57..e92978c22f45 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/tests/testcase.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/tests/testcase.py @@ -449,9 +449,11 @@ def create_resource(self, name, **kwargs): if self.copy: if self.is_live: resource_group = kwargs.get("resource_group") + subscription_id = self.get_settings_value("SUBSCRIPTION_ID") form_recognizer_name = FormRecognizerTest._FORM_RECOGNIZER_NAME - resource_id = resource_group.id + "/providers/Microsoft.CognitiveServices/accounts/" + form_recognizer_name + resource_id = "/subscriptions/" + subscription_id + "/resourceGroups/" + resource_group.name + \ + "/providers/Microsoft.CognitiveServices/accounts/" + form_recognizer_name resource_location = "westus" self.test_class_instance.scrubber.register_name_pair( resource_id,