Skip to content

Commit 1bc3354

Browse files
[formrecognizer] fixing error on ModelOperation to include details (Azure#20954)
* fixing error on ModelOperation to include details * lint * update docstring
1 parent 3a13c9c commit 1bc3354

File tree

7 files changed

+322
-22
lines changed

7 files changed

+322
-22
lines changed

sdk/formrecognizer/azure-ai-formrecognizer/CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ This version of the SDK defaults to the latest supported API version, which curr
99
API version to analyze documents, with prebuilt and custom models.
1010
- 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`.
1111
- 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`.
12-
- Added new models to use with the new `DocumentModelAdministrationClient`: `DocumentModel`, `DocumentModelInfo`, `DocTypeInfo`, `ModelOperation`, `ModelOperationInfo`, `AccountInfo`.
12+
- Added new models to use with the new `DocumentModelAdministrationClient`: `DocumentModel`, `DocumentModelInfo`, `DocTypeInfo`, `ModelOperation`, `ModelOperationInfo`, `AccountInfo`, `DocumentAnalysisError`, `DocumentAnalysisInnerError`.
1313
- Added samples using the `DocumentAnalysisClient` and `DocumentModelAdministrationClient` under `/samples/v3.2-beta`.
1414
- Added `DocumentAnalysisApiVersion` to be used with `DocumentAnalysisClient` and `DocumentModelAdministrationClient`.
1515

sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/__init__.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,9 @@
5858
DocumentModel,
5959
DocumentModelInfo,
6060
DocTypeInfo,
61-
AccountInfo
61+
AccountInfo,
62+
DocumentAnalysisError,
63+
DocumentAnalysisInnerError,
6264
)
6365
from ._api_versions import FormRecognizerApiVersion, DocumentAnalysisApiVersion
6466

@@ -118,7 +120,9 @@
118120
"DocumentModel",
119121
"DocumentModelInfo",
120122
"DocTypeInfo",
121-
"AccountInfo"
123+
"AccountInfo",
124+
"DocumentAnalysisError",
125+
"DocumentAnalysisInnerError",
122126
]
123127

124128
__VERSION__ = VERSION

sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_models.py

Lines changed: 151 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1730,15 +1730,6 @@ def _from_generated(cls, err):
17301730
else []
17311731
)
17321732

1733-
@classmethod
1734-
def _from_generated_v3(cls, err):
1735-
if err.innererror:
1736-
return cls(
1737-
code=err.innererror.code,
1738-
message=err.innererror.message,
1739-
)
1740-
return cls(code=err.code, message=err.message)
1741-
17421733
def __repr__(self):
17431734
return "FormRecognizerError(code={}, message={})".format(
17441735
self.code, self.message
@@ -3326,9 +3317,9 @@ class ModelOperation(ModelOperationInfo):
33263317
:vartype kind: str
33273318
:ivar resource_location: URL of the resource targeted by this operation.
33283319
:vartype resource_location: str
3329-
:ivar error: Encountered error, includes the error code and message for why
3320+
:ivar error: Encountered error, includes the error code, message, and details for why
33303321
the operation failed.
3331-
:vartype error: ~azure.ai.formrecognizer.FormRecognizerError
3322+
:vartype error: ~azure.ai.formrecognizer.DocumentAnalysisError
33323323
:ivar result: Operation result upon success. Returns a DocumentModel which contains
33333324
all information about the model including the doc types
33343325
and fields it can analyze from documents.
@@ -3393,7 +3384,7 @@ def from_dict(cls, data):
33933384
kind=data.get("kind", None),
33943385
resource_location=data.get("resource_location", None),
33953386
result=DocumentModel.from_dict(data.get("result")) if data.get("result") else None, # type: ignore
3396-
error=FormRecognizerError.from_dict(data.get("error")) if data.get("error") else None, # type: ignore
3387+
error=DocumentAnalysisError.from_dict(data.get("error")) if data.get("error") else None, # type: ignore
33973388
)
33983389

33993390
@classmethod
@@ -3409,7 +3400,7 @@ def _from_generated(cls, op, api_version): # pylint: disable=arguments-differ
34093400
resource_location=op.resource_location,
34103401
result=DocumentModel._from_generated(deserialize(ModelInfo, op.result))
34113402
if op.result else None,
3412-
error=FormRecognizerError._from_generated_v3(deserialize(Error, op.error))
3403+
error=DocumentAnalysisError._from_generated(deserialize(Error, op.error))
34133404
if op.error else None
34143405
)
34153406

@@ -3898,3 +3889,150 @@ def from_dict(cls, data):
38983889
model_count=data.get("model_count", None),
38993890
model_limit=data.get("model_limit", None),
39003891
)
3892+
3893+
3894+
class DocumentAnalysisError(object):
3895+
"""DocumentAnalysisError contains the details of the error returned by the service.
3896+
3897+
:ivar code: Error code.
3898+
:vartype code: str
3899+
:ivar message: Error message.
3900+
:vartype message: str
3901+
:ivar target: Target of the error.
3902+
:vartype target: str
3903+
:ivar details: List of detailed errors.
3904+
:vartype details: list[~azure.ai.formrecognizer.DocumentAnalysisError]
3905+
:ivar innererror: Detailed error.
3906+
:vartype innererror: ~azure.ai.formrecognizer.DocumentAnalysisInnerError
3907+
"""
3908+
3909+
def __init__(
3910+
self,
3911+
**kwargs
3912+
):
3913+
self.code = kwargs.get('code', None)
3914+
self.message = kwargs.get('message', None)
3915+
self.target = kwargs.get('target', None)
3916+
self.details = kwargs.get('details', None)
3917+
self.innererror = kwargs.get('innererror', None)
3918+
3919+
def __repr__(self):
3920+
return (
3921+
"DocumentAnalysisError(code={}, message={}, target={}, details={}, innererror={})".format(
3922+
self.code,
3923+
self.message,
3924+
self.target,
3925+
repr(self.details),
3926+
repr(self.innererror)
3927+
)
3928+
)
3929+
3930+
@classmethod
3931+
def _from_generated(cls, err):
3932+
return cls(
3933+
code=err.code,
3934+
message=err.message,
3935+
target=err.target,
3936+
details=[DocumentAnalysisError._from_generated(e) for e in err.details] if err.details else [],
3937+
innererror=DocumentAnalysisInnerError._from_generated(err.innererror) if err.innererror else None
3938+
)
3939+
3940+
def to_dict(self):
3941+
# type: () -> dict
3942+
"""Returns a dict representation of DocumentAnalysisError.
3943+
3944+
:return: dict
3945+
:rtype: dict
3946+
"""
3947+
return {
3948+
"code": self.code,
3949+
"message": self.message,
3950+
"target": self.target,
3951+
"details": [detail.to_dict() for detail in self.details] if self.details else [],
3952+
"innererror": self.innererror.to_dict() if self.innererror else None
3953+
}
3954+
3955+
@classmethod
3956+
def from_dict(cls, data):
3957+
# type: (dict) -> DocumentAnalysisError
3958+
"""Converts a dict in the shape of a DocumentAnalysisError to the model itself.
3959+
3960+
:param dict data: A dictionary in the shape of DocumentAnalysisError.
3961+
:return: DocumentAnalysisError
3962+
:rtype: DocumentAnalysisError
3963+
"""
3964+
return cls(
3965+
code=data.get("code", None),
3966+
message=data.get("message", None),
3967+
target=data.get("target", None),
3968+
details=[DocumentAnalysisError.from_dict(e) for e in data.get("details")] # type: ignore
3969+
if data.get("details") else [],
3970+
innererror=DocumentAnalysisInnerError.from_dict(data.get("innererror")) # type: ignore
3971+
if data.get("innererror") else None
3972+
)
3973+
3974+
3975+
class DocumentAnalysisInnerError(object):
3976+
"""Inner error details for the DocumentAnalysisError.
3977+
3978+
:ivar code: Error code.
3979+
:vartype code: str
3980+
:ivar message: Error message.
3981+
:ivar innererror: Detailed error.
3982+
:vartype innererror: ~azure.ai.formrecognizer.DocumentAnalysisInnerError
3983+
"""
3984+
3985+
def __init__(
3986+
self,
3987+
**kwargs
3988+
):
3989+
3990+
self.code = kwargs.get('code', None)
3991+
self.message = kwargs.get('message', None)
3992+
self.innererror = kwargs.get('innererror', None)
3993+
3994+
def __repr__(self):
3995+
return (
3996+
"DocumentAnalysisInnerError(code={}, message={}, innererror={})".format(
3997+
self.code,
3998+
self.message,
3999+
repr(self.innererror)
4000+
)
4001+
)
4002+
4003+
@classmethod
4004+
def _from_generated(cls, ierr):
4005+
return cls(
4006+
code=ierr.code,
4007+
message=ierr.message,
4008+
innererror=DocumentAnalysisInnerError._from_generated(ierr.innererror) if ierr.innererror else None
4009+
)
4010+
4011+
def to_dict(self):
4012+
# type: () -> dict
4013+
"""Returns a dict representation of DocumentAnalysisInnerError.
4014+
4015+
:return: dict
4016+
:rtype: dict
4017+
"""
4018+
return {
4019+
"code": self.code,
4020+
"message": self.message,
4021+
"innererror": self.innererror.to_dict() if self.innererror else None
4022+
}
4023+
4024+
@classmethod
4025+
def from_dict(cls, data):
4026+
# type: (dict) -> DocumentAnalysisInnerError
4027+
"""Converts a dict in the shape of a DocumentAnalysisInnerError to the model itself.
4028+
4029+
:param dict data: A dictionary in the shape of DocumentAnalysisInnerError.
4030+
:return: DocumentAnalysisInnerError
4031+
:rtype: DocumentAnalysisInnerError
4032+
"""
4033+
return cls(
4034+
code=data.get("code", None),
4035+
message=data.get("message", None),
4036+
innererror=DocumentAnalysisInnerError.from_dict(data.get("innererror")) # type: ignore
4037+
if data.get("innererror") else None
4038+
)

sdk/formrecognizer/azure-ai-formrecognizer/tests/test_mgmt.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ def test_get_list_operations(self, client):
167167
error = op.error
168168
assert error.code
169169
assert error.message
170+
assert error.details
170171

171172
@FormRecognizerPreparer()
172173
@DocumentModelAdministrationClientPreparer()

sdk/formrecognizer/azure-ai-formrecognizer/tests/test_mgmt_async.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@ async def test_get_list_operations(self, client):
178178
assert op.result is None
179179
assert error.code
180180
assert error.message
181+
assert error.details
181182

182183
@FormRecognizerPreparer()
183184
@DocumentModelAdministrationClientPreparer()

sdk/formrecognizer/azure-ai-formrecognizer/tests/test_repr.py

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,55 @@ def document_model(doc_type_info):
343343
return model, model_repr
344344

345345

346+
@pytest.fixture
347+
def document_analysis_inner_error():
348+
model = _models.DocumentAnalysisInnerError(
349+
code="ResourceNotFound",
350+
message="Resource was not found",
351+
innererror=_models.DocumentAnalysisInnerError(
352+
code="ResourceNotFound",
353+
message="Resource was not found",
354+
)
355+
)
356+
model_repr = "DocumentAnalysisInnerError(code={}, message={}, innererror={})".format(
357+
"ResourceNotFound",
358+
"Resource was not found",
359+
_models.DocumentAnalysisInnerError(
360+
code="ResourceNotFound",
361+
message="Resource was not found",
362+
))
363+
assert repr(model) == model_repr
364+
return model, model_repr
365+
366+
367+
@pytest.fixture
368+
def document_analysis_error(document_analysis_inner_error):
369+
model = _models.DocumentAnalysisError(
370+
code="ResourceNotFound",
371+
message="Resource was not found",
372+
target="resource",
373+
details=[
374+
_models.DocumentAnalysisError(
375+
code="ResourceNotFound",
376+
message="Resource was not found"
377+
)
378+
],
379+
innererror=document_analysis_inner_error[0]
380+
)
381+
model_repr = "DocumentAnalysisError(code={}, message={}, target={}, details={}, innererror={})".format(
382+
"ResourceNotFound",
383+
"Resource was not found",
384+
"resource",
385+
[_models.DocumentAnalysisError(
386+
code="ResourceNotFound",
387+
message="Resource was not found"
388+
)],
389+
document_analysis_inner_error[1]
390+
)
391+
assert repr(model) == model_repr
392+
return model, model_repr
393+
394+
346395
class TestRepr():
347396
# Not inheriting form FormRecognizerTest because that doesn't allow me to define pytest fixtures in the same file
348397
# Not worth moving pytest fixture definitions to conftest since all I would use is assertEqual and I can just use assert
@@ -403,8 +452,8 @@ def test_analyze_result(self, document_page, document_table, document_key_value_
403452
)
404453
assert repr(model) == model_repr
405454

406-
def test_model_operation(self, form_recognizer_error, document_model):
407-
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])
455+
def test_model_operation(self, document_analysis_error, document_model):
456+
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])
408457
model_repr = "ModelOperation(operation_id={}, status={}, percent_completed={}, created_on={}, last_updated_on={}, kind={}, resource_location={}, result={}, error={})".format(
409458
"id",
410459
"succeeded",
@@ -414,7 +463,7 @@ def test_model_operation(self, form_recognizer_error, document_model):
414463
"documentModelCopyTo",
415464
"westus2",
416465
document_model[1],
417-
form_recognizer_error[1],
466+
document_analysis_error[1],
418467
)
419468
assert repr(model) == model_repr
420469

0 commit comments

Comments
 (0)