Skip to content

Commit

Permalink
[formrecognizer] fixing error on ModelOperation to include details (A…
Browse files Browse the repository at this point in the history
…zure#20954)

* fixing error on ModelOperation to include details

* lint

* update docstring
  • Loading branch information
kristapratico authored Sep 30, 2021
1 parent 3a13c9c commit 1bc3354
Show file tree
Hide file tree
Showing 7 changed files with 322 additions and 22 deletions.
2 changes: 1 addition & 1 deletion sdk/formrecognizer/azure-ai-formrecognizer/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ This version of the SDK defaults to the latest supported API version, which curr
API version to analyze documents, with prebuilt and custom models.
- Added new models to use with the new `DocumentAnalysisClient`: `AnalyzeResult`, `AnalyzedDocument`, `BoundingRegion`, `DocumentElement`, `DocumentEntity`, `DocumentField`, `DocumentKeyValuePair`, `DocumentKeyValueElement`, `DocumentLine`, `DocumentPage`, `DocumentSelectionMark`, `DocumentSpan`, `DocumentStyle`, `DocumentTable`, `DocumentTableCell`, `DocumentWord`.
- Added new `DocumentModelAdministrationClient` with methods: `begin_build_model`, `begin_create_composed_model`, `begin_copy_model`, `get_copy_authorization`, `get_model`, `delete_model`, `list_models`, `get_operation`, `list_operations`, `get_account_info`, `get_document_analysis_client`.
- Added new models to use with the new `DocumentModelAdministrationClient`: `DocumentModel`, `DocumentModelInfo`, `DocTypeInfo`, `ModelOperation`, `ModelOperationInfo`, `AccountInfo`.
- Added new models to use with the new `DocumentModelAdministrationClient`: `DocumentModel`, `DocumentModelInfo`, `DocTypeInfo`, `ModelOperation`, `ModelOperationInfo`, `AccountInfo`, `DocumentAnalysisError`, `DocumentAnalysisInnerError`.
- Added samples using the `DocumentAnalysisClient` and `DocumentModelAdministrationClient` under `/samples/v3.2-beta`.
- Added `DocumentAnalysisApiVersion` to be used with `DocumentAnalysisClient` and `DocumentModelAdministrationClient`.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,9 @@
DocumentModel,
DocumentModelInfo,
DocTypeInfo,
AccountInfo
AccountInfo,
DocumentAnalysisError,
DocumentAnalysisInnerError,
)
from ._api_versions import FormRecognizerApiVersion, DocumentAnalysisApiVersion

Expand Down Expand Up @@ -118,7 +120,9 @@
"DocumentModel",
"DocumentModelInfo",
"DocTypeInfo",
"AccountInfo"
"AccountInfo",
"DocumentAnalysisError",
"DocumentAnalysisInnerError",
]

__VERSION__ = VERSION
Original file line number Diff line number Diff line change
Expand Up @@ -1730,15 +1730,6 @@ def _from_generated(cls, err):
else []
)

@classmethod
def _from_generated_v3(cls, err):
if err.innererror:
return cls(
code=err.innererror.code,
message=err.innererror.message,
)
return cls(code=err.code, message=err.message)

def __repr__(self):
return "FormRecognizerError(code={}, message={})".format(
self.code, self.message
Expand Down Expand Up @@ -3326,9 +3317,9 @@ class ModelOperation(ModelOperationInfo):
:vartype kind: str
:ivar resource_location: URL of the resource targeted by this operation.
:vartype resource_location: str
:ivar error: Encountered error, includes the error code and message for why
:ivar error: Encountered error, includes the error code, message, and details for why
the operation failed.
:vartype error: ~azure.ai.formrecognizer.FormRecognizerError
:vartype error: ~azure.ai.formrecognizer.DocumentAnalysisError
:ivar result: Operation result upon success. Returns a DocumentModel which contains
all information about the model including the doc types
and fields it can analyze from documents.
Expand Down Expand Up @@ -3393,7 +3384,7 @@ def from_dict(cls, data):
kind=data.get("kind", None),
resource_location=data.get("resource_location", None),
result=DocumentModel.from_dict(data.get("result")) if data.get("result") else None, # type: ignore
error=FormRecognizerError.from_dict(data.get("error")) if data.get("error") else None, # type: ignore
error=DocumentAnalysisError.from_dict(data.get("error")) if data.get("error") else None, # type: ignore
)

@classmethod
Expand All @@ -3409,7 +3400,7 @@ def _from_generated(cls, op, api_version): # pylint: disable=arguments-differ
resource_location=op.resource_location,
result=DocumentModel._from_generated(deserialize(ModelInfo, op.result))
if op.result else None,
error=FormRecognizerError._from_generated_v3(deserialize(Error, op.error))
error=DocumentAnalysisError._from_generated(deserialize(Error, op.error))
if op.error else None
)

Expand Down Expand Up @@ -3898,3 +3889,150 @@ def from_dict(cls, data):
model_count=data.get("model_count", None),
model_limit=data.get("model_limit", None),
)


class DocumentAnalysisError(object):
"""DocumentAnalysisError contains the details of the error returned by the service.
:ivar code: Error code.
:vartype code: str
:ivar message: Error message.
:vartype message: str
:ivar target: Target of the error.
:vartype target: str
:ivar details: List of detailed errors.
:vartype details: list[~azure.ai.formrecognizer.DocumentAnalysisError]
:ivar innererror: Detailed error.
:vartype innererror: ~azure.ai.formrecognizer.DocumentAnalysisInnerError
"""

def __init__(
self,
**kwargs
):
self.code = kwargs.get('code', None)
self.message = kwargs.get('message', None)
self.target = kwargs.get('target', None)
self.details = kwargs.get('details', None)
self.innererror = kwargs.get('innererror', None)

def __repr__(self):
return (
"DocumentAnalysisError(code={}, message={}, target={}, details={}, innererror={})".format(
self.code,
self.message,
self.target,
repr(self.details),
repr(self.innererror)
)
)

@classmethod
def _from_generated(cls, err):
return cls(
code=err.code,
message=err.message,
target=err.target,
details=[DocumentAnalysisError._from_generated(e) for e in err.details] if err.details else [],
innererror=DocumentAnalysisInnerError._from_generated(err.innererror) if err.innererror else None
)

def to_dict(self):
# type: () -> dict
"""Returns a dict representation of DocumentAnalysisError.
:return: dict
:rtype: dict
"""
return {
"code": self.code,
"message": self.message,
"target": self.target,
"details": [detail.to_dict() for detail in self.details] if self.details else [],
"innererror": self.innererror.to_dict() if self.innererror else None
}

@classmethod
def from_dict(cls, data):
# type: (dict) -> DocumentAnalysisError
"""Converts a dict in the shape of a DocumentAnalysisError to the model itself.
:param dict data: A dictionary in the shape of DocumentAnalysisError.
:return: DocumentAnalysisError
:rtype: DocumentAnalysisError
"""
return cls(
code=data.get("code", None),
message=data.get("message", None),
target=data.get("target", None),
details=[DocumentAnalysisError.from_dict(e) for e in data.get("details")] # type: ignore
if data.get("details") else [],
innererror=DocumentAnalysisInnerError.from_dict(data.get("innererror")) # type: ignore
if data.get("innererror") else None
)


class DocumentAnalysisInnerError(object):
"""Inner error details for the DocumentAnalysisError.
:ivar code: Error code.
:vartype code: str
:ivar message: Error message.
:ivar innererror: Detailed error.
:vartype innererror: ~azure.ai.formrecognizer.DocumentAnalysisInnerError
"""

def __init__(
self,
**kwargs
):

self.code = kwargs.get('code', None)
self.message = kwargs.get('message', None)
self.innererror = kwargs.get('innererror', None)

def __repr__(self):
return (
"DocumentAnalysisInnerError(code={}, message={}, innererror={})".format(
self.code,
self.message,
repr(self.innererror)
)
)

@classmethod
def _from_generated(cls, ierr):
return cls(
code=ierr.code,
message=ierr.message,
innererror=DocumentAnalysisInnerError._from_generated(ierr.innererror) if ierr.innererror else None
)

def to_dict(self):
# type: () -> dict
"""Returns a dict representation of DocumentAnalysisInnerError.
:return: dict
:rtype: dict
"""
return {
"code": self.code,
"message": self.message,
"innererror": self.innererror.to_dict() if self.innererror else None
}

@classmethod
def from_dict(cls, data):
# type: (dict) -> DocumentAnalysisInnerError
"""Converts a dict in the shape of a DocumentAnalysisInnerError to the model itself.
:param dict data: A dictionary in the shape of DocumentAnalysisInnerError.
:return: DocumentAnalysisInnerError
:rtype: DocumentAnalysisInnerError
"""
return cls(
code=data.get("code", None),
message=data.get("message", None),
innererror=DocumentAnalysisInnerError.from_dict(data.get("innererror")) # type: ignore
if data.get("innererror") else None
)
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ def test_get_list_operations(self, client):
error = op.error
assert error.code
assert error.message
assert error.details

@FormRecognizerPreparer()
@DocumentModelAdministrationClientPreparer()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ async def test_get_list_operations(self, client):
assert op.result is None
assert error.code
assert error.message
assert error.details

@FormRecognizerPreparer()
@DocumentModelAdministrationClientPreparer()
Expand Down
55 changes: 52 additions & 3 deletions sdk/formrecognizer/azure-ai-formrecognizer/tests/test_repr.py
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,55 @@ def document_model(doc_type_info):
return model, model_repr


@pytest.fixture
def document_analysis_inner_error():
model = _models.DocumentAnalysisInnerError(
code="ResourceNotFound",
message="Resource was not found",
innererror=_models.DocumentAnalysisInnerError(
code="ResourceNotFound",
message="Resource was not found",
)
)
model_repr = "DocumentAnalysisInnerError(code={}, message={}, innererror={})".format(
"ResourceNotFound",
"Resource was not found",
_models.DocumentAnalysisInnerError(
code="ResourceNotFound",
message="Resource was not found",
))
assert repr(model) == model_repr
return model, model_repr


@pytest.fixture
def document_analysis_error(document_analysis_inner_error):
model = _models.DocumentAnalysisError(
code="ResourceNotFound",
message="Resource was not found",
target="resource",
details=[
_models.DocumentAnalysisError(
code="ResourceNotFound",
message="Resource was not found"
)
],
innererror=document_analysis_inner_error[0]
)
model_repr = "DocumentAnalysisError(code={}, message={}, target={}, details={}, innererror={})".format(
"ResourceNotFound",
"Resource was not found",
"resource",
[_models.DocumentAnalysisError(
code="ResourceNotFound",
message="Resource was not found"
)],
document_analysis_inner_error[1]
)
assert repr(model) == model_repr
return model, model_repr


class TestRepr():
# Not inheriting form FormRecognizerTest because that doesn't allow me to define pytest fixtures in the same file
# Not worth moving pytest fixture definitions to conftest since all I would use is assertEqual and I can just use assert
Expand Down Expand Up @@ -403,8 +452,8 @@ def test_analyze_result(self, document_page, document_table, document_key_value_
)
assert repr(model) == model_repr

def test_model_operation(self, form_recognizer_error, document_model):
model = _models.ModelOperation(operation_id="id", status="succeeded", percent_completed=99, created_on=datetime.datetime(2021, 9, 16, 10, 10, 59, 342380), last_updated_on=datetime.datetime(2021, 9, 16, 10, 10, 59, 342380), kind="documentModelCopyTo", resource_location="westus2", error=form_recognizer_error[0], result=document_model[0])
def test_model_operation(self, document_analysis_error, document_model):
model = _models.ModelOperation(operation_id="id", status="succeeded", percent_completed=99, created_on=datetime.datetime(2021, 9, 16, 10, 10, 59, 342380), last_updated_on=datetime.datetime(2021, 9, 16, 10, 10, 59, 342380), kind="documentModelCopyTo", resource_location="westus2", error=document_analysis_error[0], result=document_model[0])
model_repr = "ModelOperation(operation_id={}, status={}, percent_completed={}, created_on={}, last_updated_on={}, kind={}, resource_location={}, result={}, error={})".format(
"id",
"succeeded",
Expand All @@ -414,7 +463,7 @@ def test_model_operation(self, form_recognizer_error, document_model):
"documentModelCopyTo",
"westus2",
document_model[1],
form_recognizer_error[1],
document_analysis_error[1],
)
assert repr(model) == model_repr

Expand Down
Loading

0 comments on commit 1bc3354

Please sign in to comment.