diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/CHANGELOG.md b/sdk/formrecognizer/azure-ai-formrecognizer/CHANGELOG.md index 49d598ad0cbd..beb60b5aacb7 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/CHANGELOG.md +++ b/sdk/formrecognizer/azure-ai-formrecognizer/CHANGELOG.md @@ -13,6 +13,7 @@ **New features** +- 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 f3421f5e524e..844819b286c3 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/README.md +++ b/sdk/formrecognizer/azure-ai-formrecognizer/README.md @@ -131,6 +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 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]. @@ -389,6 +390,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 @@ -459,3 +461,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/azure/ai/formrecognizer/_form_training_client.py b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_form_training_client.py index ffca7b40c457..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 @@ -6,30 +6,39 @@ # pylint: disable=protected-access +import json from typing import ( Optional, Any, Iterable, + Dict, Union, TYPE_CHECKING, ) from azure.core.tracing.decorator import distributed_trace from azure.core.polling import LROPoller from azure.core.polling.base_polling import LROBasePolling -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, + CopyAuthorizationResult +) from ._helpers import error_map, get_authentication_policy, POLLING_INTERVAL from ._models import ( CustomFormModelInfo, AccountProperties, CustomFormModel ) -from ._polling import TrainingPolling +from ._polling import TrainingPolling, CopyPolling from ._user_agent import USER_AGENT from ._form_recognizer_client import FormRecognizerClient if TYPE_CHECKING: from azure.core.credentials import AzureKeyCredential, TokenCredential + from azure.core.pipeline import PipelineResponse from azure.core.pipeline.transport import HttpResponse PipelineResponseType = HttpResponse @@ -239,6 +248,99 @@ 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 get_copy_authorization(self, resource_id, resource_region, **kwargs): + # type: (str, str, Any) -> Dict[str, Union[str, int]] + """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 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". + :rtype: Dict[str, Union[str, int]] + :raises ~azure.core.exceptions.HttpResponseError: + + .. admonition:: Example: + + .. literalinclude:: ../samples/sample_copy_model.py + :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 + """ + + response = self._client.generate_model_copy_authorization( # type: ignore + cls=lambda pipeline_response, deserialized, response_headers: pipeline_response, + error_map=error_map, + **kwargs + ) # 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: Dict + **kwargs # type: Any + ): + # type: (...) -> LROPoller + """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:`~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:`~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 + object to return a :class:`~azure.ai.formrecognizer.CustomFormModelInfo`. + :rtype: ~azure.core.polling.LROPoller[~azure.ai.formrecognizer.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) + + def _copy_callback(raw_response, _, headers): # pylint: disable=unused-argument + copy_result = self._client._deserialize(CopyOperationResult, raw_response) + return CustomFormModelInfo._from_generated(copy_result, target["modelId"]) + + return self._client.begin_copy_custom_model( # type: ignore + model_id=model_id, + copy_request=CopyRequest( + target_resource_id=target["resourceId"], + target_resource_region=target["resourceRegion"], + 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), + error_map=error_map, + **kwargs + ) + def get_form_recognizer_client(self, **kwargs): # type: (Any) -> FormRecognizerClient """Get an instance of a FormRecognizerClient from FormTrainingClient. 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 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..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,9 +848,9 @@ 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 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 07717e108c8e..f1ef5267a283 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_polling.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_polling.py @@ -92,3 +92,36 @@ def get_status(self, pipeline_response): # pylint: disable=no-self-use if errors: raise_error(response, errors, 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: + 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 54ef2982ffdc..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 @@ -6,11 +6,13 @@ # pylint: disable=protected-access +import json from typing import ( Optional, Any, - Union, AsyncIterable, + Dict, + Union, TYPE_CHECKING, ) from azure.core.polling import async_poller @@ -19,8 +21,14 @@ from azure.core.tracing.decorator_async import distributed_trace_async from ._form_recognizer_client_async import FormRecognizerClient 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, + CopyAuthorizationResult +) from .._helpers import error_map, get_authentication_policy, POLLING_INTERVAL from .._models import ( CustomFormModelInfo, @@ -28,8 +36,9 @@ CustomFormModel ) from .._user_agent import USER_AGENT -from .._polling import TrainingPolling +from .._polling import TrainingPolling, CopyPolling if TYPE_CHECKING: + from azure.core.pipeline import PipelineResponse from azure.core.credentials import AzureKeyCredential from azure.core.credentials_async import AsyncTokenCredential @@ -247,6 +256,100 @@ async def get_custom_model(self, model_id: str, **kwargs: Any) -> CustomFormMode ) return CustomFormModel._from_generated(response) + @distributed_trace_async + async def get_copy_authorization( + self, + resource_id: str, + resource_region: str, + **kwargs: Any + ) -> Dict[str, Union[str, int]]: + """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 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". + :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 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 + """ + + response = await self._client.generate_model_copy_authorization( # type: ignore + cls=lambda pipeline_response, deserialized, response_headers: pipeline_response, + error_map=error_map, + **kwargs + ) # 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: dict, + **kwargs: Any + ) -> CustomFormModelInfo: + """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:`~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:`~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 + :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) + + def _copy_callback(raw_response, _, headers): # pylint: disable=unused-argument + copy_result = self._client._deserialize(CopyOperationResult, raw_response) + return CustomFormModelInfo._from_generated(copy_result, target["modelId"]) + + return await self._client.copy_custom_model( # type: ignore + model_id=model_id, + copy_request=CopyRequest( + target_resource_id=target["resourceId"], + target_resource_region=target["resourceRegion"], + 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), + error_map=error_map, + **kwargs + ) + def get_form_recognizer_client(self, **kwargs: Any) -> FormRecognizerClient: """Get an instance of a FormRecognizerClient from FormTrainingClient. diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/samples/README.md b/sdk/formrecognizer/azure-ai-formrecognizer/samples/README.md index 8bee2aa4d46e..22312586dfbf 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/samples/README.md +++ b/sdk/formrecognizer/azure-ai-formrecognizer/samples/README.md @@ -27,6 +27,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 custom 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) @@ -90,3 +92,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 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..90b0c50ad8b6 --- /dev/null +++ b/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_copy_model_async.py @@ -0,0 +1,81 @@ +# 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 custom 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): + + async def copy_model_async(self): + from azure.core.credentials import AzureKeyCredential + from azure.ai.formrecognizer.aio import FormTrainingClient + + 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"] + + # [START get_copy_authorization_async] + target_client = FormTrainingClient(endpoint=target_endpoint, credential=AzureKeyCredential(target_key)) + + async with target_client: + target = await target_client.get_copy_authorization( + resource_region=target_region, + resource_id=target_resource_id + ) + # [END get_copy_authorization_async] + + # [START copy_model_async] + source_client = FormTrainingClient(endpoint=source_endpoint, credential=AzureKeyCredential(source_key)) + target_client = FormTrainingClient(endpoint=target_endpoint, credential=AzureKeyCredential(target_key)) + + 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("Model ID: {}".format(copied_over_model.model_id)) + print("Status: {}".format(copied_over_model.status)) + # [END copy_model_async] + + +async def main(): + sample = CopyModelSampleAsync() + await sample.copy_model_async() + + +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..23901a65e856 --- /dev/null +++ b/sdk/formrecognizer/azure-ai-formrecognizer/samples/sample_copy_model.py @@ -0,0 +1,73 @@ +# 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 custom 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): + + def copy_model(self): + from azure.core.credentials import AzureKeyCredential + from azure.ai.formrecognizer import FormTrainingClient + + 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"] + + # [START get_copy_authorization] + target_client = FormTrainingClient(endpoint=target_endpoint, credential=AzureKeyCredential(target_key)) + + target = target_client.get_copy_authorization( + resource_region=target_region, + resource_id=target_resource_id + ) + # [END get_copy_authorization] + + # [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, + target=target + ) + copy = poller.result() + + copied_over_model = target_client.get_custom_model(copy.model_id) + print("Model ID: {}".format(copied_over_model.model_id)) + print("Status: {}".format(copied_over_model.status)) + # [END begin_copy_model] + + +if __name__ == '__main__': + sample = CopyModelSample() + sample.copy_model() 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.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_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/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..be9bce84721a --- /dev/null +++ b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_copy_model.py @@ -0,0 +1,92 @@ +# 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.get_copy_authorization(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.get_copy_authorization(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.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_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"]) + + @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 new file mode 100644 index 000000000000..0b7a2aa0422e --- /dev/null +++ b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_copy_model_async.py @@ -0,0 +1,87 @@ +# 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.get_copy_authorization(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.get_copy_authorization(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.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_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"]) + + @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) 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 3e6aa4ae3e60..e92978c22f45 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 +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 FakeTokenCredential(object): @@ -37,6 +66,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" @@ -350,7 +381,7 @@ def create_resource(self, name, **kwargs): ) return { - 'location': 'westus2', + 'location': 'westus', 'resource_group': rg, } @@ -365,10 +396,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 } @@ -382,6 +413,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: @@ -414,6 +446,30 @@ 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") + subscription_id = self.get_settings_value("SUBSCRIPTION_ID") + form_recognizer_name = FormRecognizerTest._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, + "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} @@ -460,7 +516,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", @@ -476,6 +532,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(