Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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