From 0dec8e78e16a05b8350143dd17182a98416bc16b Mon Sep 17 00:00:00 2001 From: Catalina Peralta Date: Wed, 28 Apr 2021 14:09:38 -0700 Subject: [PATCH 1/9] adding to_dict() on custom models --- .../azure/ai/formrecognizer/_models.py | 80 +++++++++++++++++++ 1 file changed, 80 insertions(+) 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 c9a06a3800d4..46f440e24117 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_models.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_models.py @@ -144,6 +144,11 @@ class Point(namedtuple("Point", "x y")): def __new__(cls, x, y): return super(Point, cls).__new__(cls, x, y) + def to_dict(self): + return { + "x": self.x, + "y": self.y + } class FormPageRange(namedtuple("FormPageRange", "first_page_number last_page_number")): """The 1-based page range of the form. @@ -183,6 +188,13 @@ def __init__(self, **kwargs): self.text = kwargs.get("text", None) self.kind = kwargs.get("kind", None) + def to_dict(self): + return { + "text": self.text, + "bounding_box": [f.to_dict() for f in self.bounding_box], + "page_number": self.page_number, + "kind": self.kind + } class RecognizedForm(object): """Represents a form that has been recognized by a trained or prebuilt model. @@ -231,6 +243,15 @@ def __repr__(self): )[:1024] ) + def to_dict(self): + return { + "fields": [v.to_dict() for k, v in self.fields.items()], + "form_type": self.form_type, + "page_range": self.page_range, + # "pages": [v.to_dict() for v in self.pages], + "model_id": self.model_id, + "form_type_confidence": self.form_type_confidence + } class FormField(object): """Represents a field recognized in an input form. @@ -302,6 +323,21 @@ def __repr__(self): :1024 ] + def to_dict(self): + d = { + "value_type": self.value_type, + "name": self.name, + "value": self.value, + "confidence": self.confidence + } + + if self.label_data is not None: + d["label_data"] = self.label_data.to_dict() + + if self.value_data is not None: + d["value_data"] = self.value_data.to_dict() + + return d class FieldData(object): """Contains the data for the form field. This includes the text, @@ -371,6 +407,13 @@ def __repr__(self): :1024 ] + def to_dict(self): + return { + "text": self.text, + "bounding_box": [f.to_dict() for f in self.bounding_box], + "field_elements": self.field_elements, + "page_number": self.page_number + } class FormPage(object): """Represents a page recognized from the input document. Contains lines, @@ -486,6 +529,15 @@ def __repr__(self): :1024 ] + def to_dict(self): + return { + "text": self.text, + "bounding_box": [f.to_dict() for f in self.bounding_box], + "words": [f.to_dict() for f in self.words], + "page_number": self.page_number, + "kind": self.kind, + "appearance": [f.to_dict() for f in self.appearance] + } class FormWord(FormElement): """Represents a word recognized from the input document. @@ -523,6 +575,14 @@ def __repr__(self): :1024 ] + def to_dict(self): + return { + "text": self.text, + "bounding_box": [f.to_dict() for f in self.bounding_box], + "confidence": self.confidence, + "page_number": self.page_number, + "kind": self.kind + } class FormSelectionMark(FormElement): """Information about the extracted selection mark. @@ -563,6 +623,15 @@ def __repr__(self): :1024 ] + def to_dict(self): + return { + "text": self.text, + "bounding_box": [f.to_dict() for f in self.bounding_box], + "confidence": self.confidence, + "state": self.state, + "page_number": self.page_number, + "kind": self.kind + } class FormTable(object): """Information about the extracted table contained on a page. @@ -1147,6 +1216,11 @@ def _from_generated(cls, appearance): def __repr__(self): return "TextAppearance(style={})".format(repr(self.style)) + def to_dict(self): + if self.style is not None: + return { + "style": self.style.to_dict() + } class TextStyle(object): """An object representing the style of the text line. @@ -1164,3 +1238,9 @@ def __init__(self, **kwargs): def __repr__(self): return "TextStyle(name={}, confidence={})".format(self.name, self.confidence) + + def to_dict(self): + return { + "name": self.name, + "confidence": self.confidence + } From e4cb3d308466dc5ed46fba4b0f17eb76ad6dc223 Mon Sep 17 00:00:00 2001 From: Catalina Peralta Date: Thu, 29 Apr 2021 15:41:27 -0700 Subject: [PATCH 2/9] add tests --- .../azure/ai/formrecognizer/_models.py | 61 +-- .../tests/test_to_dict.py | 387 ++++++++++++++++++ 2 files changed, 424 insertions(+), 24 deletions(-) create mode 100644 sdk/formrecognizer/azure-ai-formrecognizer/tests/test_to_dict.py 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 46f440e24117..cca087a8bb9a 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_models.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_models.py @@ -145,10 +145,8 @@ def __new__(cls, x, y): return super(Point, cls).__new__(cls, x, y) def to_dict(self): - return { - "x": self.x, - "y": self.y - } + return {"x": self.x, "y": self.y} + class FormPageRange(namedtuple("FormPageRange", "first_page_number last_page_number")): """The 1-based page range of the form. @@ -164,6 +162,12 @@ def __new__(cls, first_page_number, last_page_number): cls, first_page_number, last_page_number ) + def to_dict(self): + return { + "first_page_number": self.first_page_number, + "last_page_number": self.last_page_number, + } + class FormElement(object): """Base type which includes properties for a form element. @@ -193,9 +197,10 @@ def to_dict(self): "text": self.text, "bounding_box": [f.to_dict() for f in self.bounding_box], "page_number": self.page_number, - "kind": self.kind + "kind": self.kind, } + class RecognizedForm(object): """Represents a form that has been recognized by a trained or prebuilt model. @@ -244,14 +249,17 @@ def __repr__(self): ) def to_dict(self): - return { - "fields": [v.to_dict() for k, v in self.fields.items()], + d = { + "fields": [v.to_dict() for v in self.fields], "form_type": self.form_type, - "page_range": self.page_range, # "pages": [v.to_dict() for v in self.pages], "model_id": self.model_id, - "form_type_confidence": self.form_type_confidence + "form_type_confidence": self.form_type_confidence, } + if self.page_range is not None: + d["page_range"] = self.page_range.to_dict() + return d + class FormField(object): """Represents a field recognized in an input form. @@ -328,7 +336,7 @@ def to_dict(self): "value_type": self.value_type, "name": self.name, "value": self.value, - "confidence": self.confidence + "confidence": self.confidence, } if self.label_data is not None: @@ -339,6 +347,7 @@ def to_dict(self): return d + class FieldData(object): """Contains the data for the form field. This includes the text, location of the text on the form, and a collection of the @@ -408,12 +417,15 @@ def __repr__(self): ] def to_dict(self): - return { + d = { "text": self.text, "bounding_box": [f.to_dict() for f in self.bounding_box], - "field_elements": self.field_elements, - "page_number": self.page_number + "page_number": self.page_number, } + if self.field_elements is not None: + d["field_elements"] = [f.to_dict() for f in self.field_elements] + return d + class FormPage(object): """Represents a page recognized from the input document. Contains lines, @@ -530,14 +542,17 @@ def __repr__(self): ] def to_dict(self): - return { + d = { "text": self.text, "bounding_box": [f.to_dict() for f in self.bounding_box], "words": [f.to_dict() for f in self.words], "page_number": self.page_number, "kind": self.kind, - "appearance": [f.to_dict() for f in self.appearance] } + if self.appearance is not None: + d["appearance"] = self.appearance.to_dict() + return d + class FormWord(FormElement): """Represents a word recognized from the input document. @@ -581,9 +596,10 @@ def to_dict(self): "bounding_box": [f.to_dict() for f in self.bounding_box], "confidence": self.confidence, "page_number": self.page_number, - "kind": self.kind + "kind": self.kind, } + class FormSelectionMark(FormElement): """Information about the extracted selection mark. @@ -630,9 +646,10 @@ def to_dict(self): "confidence": self.confidence, "state": self.state, "page_number": self.page_number, - "kind": self.kind + "kind": self.kind, } + class FormTable(object): """Information about the extracted table contained on a page. @@ -1218,9 +1235,8 @@ def __repr__(self): def to_dict(self): if self.style is not None: - return { - "style": self.style.to_dict() - } + return {"style": self.style.to_dict()} + class TextStyle(object): """An object representing the style of the text line. @@ -1240,7 +1256,4 @@ def __repr__(self): return "TextStyle(name={}, confidence={})".format(self.name, self.confidence) def to_dict(self): - return { - "name": self.name, - "confidence": self.confidence - } + return {"name": self.name, "confidence": self.confidence} diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_to_dict.py b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_to_dict.py new file mode 100644 index 000000000000..0a13dfa56c90 --- /dev/null +++ b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_to_dict.py @@ -0,0 +1,387 @@ +# 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. +# -------------------------------------------------------------------------- + +import pytest +import datetime +from azure.ai.formrecognizer import _models + + +class TestToDict: + def test_point_to_dict(self): + model = [_models.Point(1, 2), _models.Point(3, 4)] + d = [p.to_dict() for p in model] + final = [ + {"x": 1, "y": 2}, + { + "x": 3, + "y": 4, + }, + ] + assert d == final + + def test_form_word_to_dict(self): + form_word = _models.FormWord( + text="word", + confidence=0.92, + page_number=1, + bounding_box=[ + _models.Point(1427.0, 1669.0), + _models.Point(1527.0, 1669.0), + _models.Point(1527.0, 1698.0), + _models.Point(1427.0, 1698.0), + ], + ) + + d = form_word.to_dict() + final = { + "text": "word", + "bounding_box": [ + {"x": 1427.0, "y": 1669.0}, + {"x": 1527.0, "y": 1669.0}, + {"x": 1527.0, "y": 1698.0}, + {"x": 1427.0, "y": 1698.0}, + ], + "confidence": 0.92, + "page_number": 1, + "kind": "word", + } + assert d == final + + def test_form_line_to_dict(self): + form_word = _models.FormLine( + text="sample line", + bounding_box=[ + _models.Point(1427.0, 1669.0), + _models.Point(1527.0, 1669.0), + _models.Point(1527.0, 1698.0), + _models.Point(1427.0, 1698.0), + ], + words=[ + _models.FormWord( + text="sample", + confidence=0.92, + page_number=1, + bounding_box=[ + _models.Point(1427.0, 1669.0), + _models.Point(1527.0, 1669.0), + _models.Point(1527.0, 1698.0), + _models.Point(1427.0, 1698.0), + ], + ), + _models.FormWord( + text="line", + confidence=0.92, + page_number=1, + bounding_box=[ + _models.Point(1427.0, 1669.0), + _models.Point(1527.0, 1669.0), + _models.Point(1527.0, 1698.0), + _models.Point(1427.0, 1698.0), + ], + ), + ], + page_number=2, + appearance=_models.TextAppearance( + style=_models.TextStyle(name="other", confidence=0.90) + ), + ) + + d = form_word.to_dict() + final = { + "text": "sample line", + "bounding_box": [ + {"x": 1427.0, "y": 1669.0}, + {"x": 1527.0, "y": 1669.0}, + {"x": 1527.0, "y": 1698.0}, + {"x": 1427.0, "y": 1698.0}, + ], + "words": [ + { + "text": "sample", + "bounding_box": [ + {"x": 1427.0, "y": 1669.0}, + {"x": 1527.0, "y": 1669.0}, + {"x": 1527.0, "y": 1698.0}, + {"x": 1427.0, "y": 1698.0}, + ], + "confidence": 0.92, + "page_number": 1, + "kind": "word", + }, + { + "text": "line", + "bounding_box": [ + {"x": 1427.0, "y": 1669.0}, + {"x": 1527.0, "y": 1669.0}, + {"x": 1527.0, "y": 1698.0}, + {"x": 1427.0, "y": 1698.0}, + ], + "confidence": 0.92, + "page_number": 1, + "kind": "word", + }, + ], + "page_number": 2, + "kind": "line", + "appearance": {"style": {"name": "other", "confidence": 0.90}}, + } + assert d == final + + def test_form_selection_mark_to_dict(self): + form_word = _models.FormSelectionMark( + text="checkbox", + state="selected", + confidence=0.92, + page_number=1, + bounding_box=[ + _models.Point(1427.0, 1669.0), + _models.Point(1527.0, 1669.0), + _models.Point(1527.0, 1698.0), + _models.Point(1427.0, 1698.0), + ], + ) + + d = form_word.to_dict() + final = { + "text": "checkbox", + "state": "selected", + "bounding_box": [ + {"x": 1427.0, "y": 1669.0}, + {"x": 1527.0, "y": 1669.0}, + {"x": 1527.0, "y": 1698.0}, + {"x": 1427.0, "y": 1698.0}, + ], + "confidence": 0.92, + "page_number": 1, + "kind": "selectionMark", + } + assert d == final + + def test_form_element_to_dict(self): + form_word = _models.FormElement( + kind="selectionMark", + text="element", + page_number=1, + bounding_box=[ + _models.Point(1427.0, 1669.0), + _models.Point(1527.0, 1669.0), + _models.Point(1527.0, 1698.0), + _models.Point(1427.0, 1698.0), + ], + ) + + d = form_word.to_dict() + final = { + "text": "element", + "bounding_box": [ + {"x": 1427.0, "y": 1669.0}, + {"x": 1527.0, "y": 1669.0}, + {"x": 1527.0, "y": 1698.0}, + {"x": 1427.0, "y": 1698.0}, + ], + "page_number": 1, + "kind": "selectionMark", + } + assert d == final + + def test_text_appearance_to_dict(self): + model = _models.TextAppearance( + style=_models.TextStyle(name="other", confidence=0.98) + ) + + d = model.to_dict() + final = {"style": {"name": "other", "confidence": 0.98}} + assert d == final + + def test_text_style_to_dict(self): + model = _models.TextStyle(name="other", confidence=0.98) + + d = model.to_dict() + final = {"name": "other", "confidence": 0.98} + assert d == final + + def test_field_data_to_dict(self): + model = _models.FieldData( + text="element", + page_number=1, + bounding_box=[ + _models.Point(1427.0, 1669.0), + _models.Point(1527.0, 1669.0), + _models.Point(1527.0, 1698.0), + _models.Point(1427.0, 1698.0), + ], + field_elements=[ + _models.FormWord( + text="word", + confidence=0.92, + page_number=1, + bounding_box=[ + _models.Point(1427.0, 1669.0), + _models.Point(1527.0, 1669.0), + _models.Point(1527.0, 1698.0), + _models.Point(1427.0, 1698.0), + ], + ), + ], + ) + + d = model.to_dict() + final = { + "text": "element", + "bounding_box": [ + {"x": 1427.0, "y": 1669.0}, + {"x": 1527.0, "y": 1669.0}, + {"x": 1527.0, "y": 1698.0}, + {"x": 1427.0, "y": 1698.0}, + ], + "page_number": 1, + "field_elements": [ + { + "text": "word", + "bounding_box": [ + {"x": 1427.0, "y": 1669.0}, + {"x": 1527.0, "y": 1669.0}, + {"x": 1527.0, "y": 1698.0}, + {"x": 1427.0, "y": 1698.0}, + ], + "confidence": 0.92, + "page_number": 1, + "kind": "word", + } + ], + } + assert d == final + + def test_form_field_to_dict(self): + form_field = _models.FormField( + value_type="phoneNumber", + label_data=_models.FieldData( + text="phone", + page_number=1, + bounding_box=[ + _models.Point(1427.0, 1669.0), + _models.Point(1527.0, 1669.0), + _models.Point(1527.0, 1698.0), + _models.Point(1427.0, 1698.0), + ], + ), + value_data=_models.FieldData( + text="55554444", + page_number=1, + bounding_box=[ + _models.Point(1427.0, 1669.0), + _models.Point(1527.0, 1669.0), + _models.Point(1527.0, 1698.0), + _models.Point(1427.0, 1698.0), + ], + ), + name="phone", + value="55554444", + confidence=0.99, + ) + + d = form_field.to_dict() + final = { + "value_type": "phoneNumber", + "label_data": { + "text": "phone", + "bounding_box": [ + {"x": 1427.0, "y": 1669.0}, + {"x": 1527.0, "y": 1669.0}, + {"x": 1527.0, "y": 1698.0}, + {"x": 1427.0, "y": 1698.0}, + ], + "page_number": 1, + }, + "value_data": { + "text": "55554444", + "bounding_box": [ + {"x": 1427.0, "y": 1669.0}, + {"x": 1527.0, "y": 1669.0}, + {"x": 1527.0, "y": 1698.0}, + {"x": 1427.0, "y": 1698.0}, + ], + "page_number": 1, + }, + "name": "phone", + "value": "55554444", + "confidence": 0.99, + } + assert d == final + + def test_recognized_form_to_dict(self): + form = _models.RecognizedForm( + form_type="test_form", + form_type_confidence="0.84", + model_id="examplemodel123", + page_range=_models.FormPageRange(1, 1), + fields=[ + _models.FormField( + value_type="phoneNumber", + label_data=_models.FieldData( + text="phone", + page_number=1, + bounding_box=[ + _models.Point(1427.0, 1669.0), + _models.Point(1527.0, 1669.0), + _models.Point(1527.0, 1698.0), + _models.Point(1427.0, 1698.0), + ], + ), + value_data=_models.FieldData( + text="55554444", + page_number=1, + bounding_box=[ + _models.Point(1427.0, 1669.0), + _models.Point(1527.0, 1669.0), + _models.Point(1527.0, 1698.0), + _models.Point(1427.0, 1698.0), + ], + ), + name="phone", + value="55554444", + confidence=0.99, + ) + ], + ) + + d = form.to_dict() + final = { + "form_type": "test_form", + "form_type_confidence": "0.84", + "model_id": "examplemodel123", + "page_range": {"first_page_number": 1, "last_page_number": 1}, + "fields": [ + { + "value_type": "phoneNumber", + "label_data": { + "text": "phone", + "bounding_box": [ + {"x": 1427.0, "y": 1669.0}, + {"x": 1527.0, "y": 1669.0}, + {"x": 1527.0, "y": 1698.0}, + {"x": 1427.0, "y": 1698.0}, + ], + "page_number": 1, + }, + "value_data": { + "text": "55554444", + "bounding_box": [ + {"x": 1427.0, "y": 1669.0}, + {"x": 1527.0, "y": 1669.0}, + {"x": 1527.0, "y": 1698.0}, + {"x": 1427.0, "y": 1698.0}, + ], + "page_number": 1, + }, + "name": "phone", + "value": "55554444", + "confidence": 0.99, + } + ], + } + assert d == final From e714b0509e060548ca25c5694aac63bc75720f51 Mon Sep 17 00:00:00 2001 From: Krista Pratico Date: Thu, 29 Apr 2021 16:49:09 -0700 Subject: [PATCH 3/9] add to_dict to models --- .../azure/ai/formrecognizer/_models.py | 111 +++++++++++++++++- 1 file changed, 109 insertions(+), 2 deletions(-) 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 cca087a8bb9a..4933d339ca07 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_models.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_models.py @@ -485,6 +485,24 @@ def __repr__(self): )[:1024] ) + def to_dict(self): + return { + "page_number": self.page_number, + "text_angle": self.text_angle, + "width": self.width, + "height": self.height, + "unit": self.unit, + "tables": [ + table.to_dict() for table in self.tables + ] if self.tables else None, + "lines": [ + line.to_dict() for line in self.lines + ] if self.lines else None, + "selection_marks": [ + mark.to_dict() for mark in self.selection_marks + ] if self.selection_marks else None + } + class FormLine(FormElement): """An object representing an extracted line of text. @@ -633,8 +651,8 @@ def _from_generated(cls, mark, page): ) def __repr__(self): - return "FormSelectionMark(text={}, bounding_box={}, confidence={}, page_number={}, state={})".format( - self.text, self.bounding_box, self.confidence, self.page_number, self.state + return "FormSelectionMark(text={}, bounding_box={}, confidence={}, page_number={}, state={}, kind={})".format( + self.text, self.bounding_box, self.confidence, self.page_number, self.state, self.kind )[ :1024 ] @@ -689,6 +707,15 @@ def __repr__(self): :1024 ] + def to_dict(self): + return { + "page_number": self.page_number, + "row_count": self.row_count, + "column_count": self.column_count, + "cells": [cell.to_dict() for cell in self.cells], + "bounding_box": [box.to_dict() for box in self.bounding_box] + } + class FormTableCell(object): # pylint:disable=too-many-instance-attributes """Represents a cell contained in a table recognized from the input document. @@ -774,6 +801,22 @@ def __repr__(self): ] ) + def to_dict(self): + return { + "text": self.text, + "row_index": self.row_index, + "column_index": self.column_index, + "row_span": self.row_span, + "column_span": self.column_span, + "confidence": self.confidence, + "is_header": self.is_header, + "is_footer": self.is_footer, + "page_number": self.page_number, + "bounding_box": [box.to_dict() for box in self.bounding_box], + "field_elements": [element.to_dict() for element in self.field_elements] + if self.field_elements else None + } + class CustomFormModel(object): """Represents a model trained from custom forms. @@ -876,6 +919,19 @@ def __repr__(self): ] ) + def to_dict(self): + return { + "model_id": self.model_id, + "status": self.status, + "training_started_on": self.training_started_on, + "training_completed_on": self.training_completed_on, + "submodels": [submodel.to_dict() for submodel in self.submodels], + "errors": [err.to_dict() for err in self.errors], + "training_documents": [doc.to_dict() for doc in self.training_documents], + "model_name": self.model_name, + "properties": self.properties.to_dict() + } + class CustomFormSubmodel(object): """Represents a submodel that extracts fields from a specific type of form. @@ -970,6 +1026,14 @@ def __repr__(self): :1024 ] + def to_dict(self): + return { + "model_id": self.model_id, + "accuracy": self.accuracy, + "fields": {k: v.to_dict() for k, v in self.fields.items()}, + "form_type": self.form_type + } + class CustomFormModelField(object): """A field that the model will extract from forms it analyzes. @@ -1003,6 +1067,13 @@ def __repr__(self): self.label, self.name, self.accuracy )[:1024] + def to_dict(self): + return { + "label": self.label, + "accuracy": self.accuracy, + "name": self.name + } + class TrainingDocumentInfo(object): """Report for an individual document used for training @@ -1074,6 +1145,15 @@ def __repr__(self): :1024 ] + def to_dict(self): + return { + "name": self.name, + "status": self.status, + "page_count": self.page_count, + "errors": [err.to_dict() for err in self.errors], + "model_id": self.model_id + } + class FormRecognizerError(object): """Represents an error that occurred while training. @@ -1099,6 +1179,12 @@ def __repr__(self): self.code, self.message )[:1024] + def to_dict(self): + return { + "code": self.code, + "message": self.message + } + class CustomFormModelInfo(object): """Custom model information. @@ -1164,6 +1250,16 @@ def __repr__(self): )[:1024] ) + def to_dict(self): + return { + "model_id": self.model_id, + "status": self.status, + "training_started_on": self.training_started_on, + "training_completed_on": self.training_completed_on, + "model_name": self.model_name, + "properties": self.properties.to_dict() + } + class AccountProperties(object): """Summary of all the custom models on the account. @@ -1188,6 +1284,12 @@ def __repr__(self): self.custom_model_count, self.custom_model_limit )[:1024] + def to_dict(self): + return { + "custom_model_count": self.custom_model_count, + "custom_model_limit": self.custom_model_limit + } + class CustomFormModelProperties(object): """Optional model properties. @@ -1209,6 +1311,11 @@ def __repr__(self): self.is_composed_model ) + def to_dict(self): + return { + "is_composed_model": self.is_composed_model + } + class TextAppearance(object): """An object representing the appearance of the text line. From 3a2a46b5f1a174f3f0448d9f7c72974ea7022593 Mon Sep 17 00:00:00 2001 From: Catalina Peralta Date: Mon, 3 May 2021 10:50:50 -0700 Subject: [PATCH 4/9] fix TextAppearance to_dict() --- .../azure-ai-formrecognizer/azure/ai/formrecognizer/_models.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) 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 4933d339ca07..89fde33ae07a 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_models.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_models.py @@ -1341,8 +1341,7 @@ def __repr__(self): return "TextAppearance(style={})".format(repr(self.style)) def to_dict(self): - if self.style is not None: - return {"style": self.style.to_dict()} + return {"style": self.style.to_dict()} if self.style else None class TextStyle(object): From 0b3345f723c9df02c53bc2391cfd5fb0f474e9db Mon Sep 17 00:00:00 2001 From: Catalina Peralta Date: Tue, 4 May 2021 11:12:33 -0700 Subject: [PATCH 5/9] add remaining tests and fixes --- .../azure/ai/formrecognizer/_models.py | 71 +- .../tests/test_to_dict.py | 696 +++++++++++++++++- 2 files changed, 715 insertions(+), 52 deletions(-) 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 89fde33ae07a..1142aeeb7f05 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_models.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_models.py @@ -195,7 +195,7 @@ def __init__(self, **kwargs): def to_dict(self): return { "text": self.text, - "bounding_box": [f.to_dict() for f in self.bounding_box], + "bounding_box": [f.to_dict() for f in self.bounding_box] if self.bounding_box else [], "page_number": self.page_number, "kind": self.kind, } @@ -249,16 +249,14 @@ def __repr__(self): ) def to_dict(self): - d = { - "fields": [v.to_dict() for v in self.fields], + return { + "fields": [v.to_dict() for v in self.fields] if self.fields else [], "form_type": self.form_type, - # "pages": [v.to_dict() for v in self.pages], + "pages": [v.to_dict() for v in self.pages] if self.pages else [], "model_id": self.model_id, "form_type_confidence": self.form_type_confidence, + "page_range": self.page_range.to_dict() if self.page_range else None } - if self.page_range is not None: - d["page_range"] = self.page_range.to_dict() - return d class FormField(object): @@ -332,22 +330,15 @@ def __repr__(self): ] def to_dict(self): - d = { + return { "value_type": self.value_type, "name": self.name, "value": self.value, "confidence": self.confidence, + "label_data": self.label_data.to_dict() if self.label_data else None, + "value_data": self.value_data.to_dict() if self.value_data else None, } - if self.label_data is not None: - d["label_data"] = self.label_data.to_dict() - - if self.value_data is not None: - d["value_data"] = self.value_data.to_dict() - - return d - - class FieldData(object): """Contains the data for the form field. This includes the text, location of the text on the form, and a collection of the @@ -417,14 +408,12 @@ def __repr__(self): ] def to_dict(self): - d = { + return { "text": self.text, - "bounding_box": [f.to_dict() for f in self.bounding_box], + "bounding_box": [f.to_dict() for f in self.bounding_box] if self.bounding_box else [], "page_number": self.page_number, + "field_elements": [f.to_dict() for f in self.field_elements] if self.field_elements else [] } - if self.field_elements is not None: - d["field_elements"] = [f.to_dict() for f in self.field_elements] - return d class FormPage(object): @@ -492,18 +481,11 @@ def to_dict(self): "width": self.width, "height": self.height, "unit": self.unit, - "tables": [ - table.to_dict() for table in self.tables - ] if self.tables else None, - "lines": [ - line.to_dict() for line in self.lines - ] if self.lines else None, - "selection_marks": [ - mark.to_dict() for mark in self.selection_marks - ] if self.selection_marks else None + "tables": [table.to_dict() for table in self.tables] if self.tables else [], + "lines": [line.to_dict() for line in self.lines] if self.lines else [], + "selection_marks": [mark.to_dict() for mark in self.selection_marks] if self.selection_marks else [] } - class FormLine(FormElement): """An object representing an extracted line of text. @@ -560,16 +542,14 @@ def __repr__(self): ] def to_dict(self): - d = { + return { "text": self.text, - "bounding_box": [f.to_dict() for f in self.bounding_box], - "words": [f.to_dict() for f in self.words], + "bounding_box": [f.to_dict() for f in self.bounding_box] if self.bounding_box else [], + "words": [f.to_dict() for f in self.words] if self.words else [], "page_number": self.page_number, "kind": self.kind, + "appearance": self.appearance.to_dict() if self.appearance else None } - if self.appearance is not None: - d["appearance"] = self.appearance.to_dict() - return d class FormWord(FormElement): @@ -925,14 +905,13 @@ def to_dict(self): "status": self.status, "training_started_on": self.training_started_on, "training_completed_on": self.training_completed_on, - "submodels": [submodel.to_dict() for submodel in self.submodels], - "errors": [err.to_dict() for err in self.errors], - "training_documents": [doc.to_dict() for doc in self.training_documents], + "submodels": [submodel.to_dict() for submodel in self.submodels] if self.submodels else [], + "errors": [err.to_dict() for err in self.errors] if self.errors else [], + "training_documents": [doc.to_dict() for doc in self.training_documents] if self.training_documents else [], "model_name": self.model_name, - "properties": self.properties.to_dict() + "properties": self.properties.to_dict() if self.properties else None } - class CustomFormSubmodel(object): """Represents a submodel that extracts fields from a specific type of form. @@ -1030,7 +1009,7 @@ def to_dict(self): return { "model_id": self.model_id, "accuracy": self.accuracy, - "fields": {k: v.to_dict() for k, v in self.fields.items()}, + "fields": [v.to_dict() for v in self.fields] if self.fields else [], "form_type": self.form_type } @@ -1341,7 +1320,9 @@ def __repr__(self): return "TextAppearance(style={})".format(repr(self.style)) def to_dict(self): - return {"style": self.style.to_dict()} if self.style else None + return { + "style": self.style.to_dict() if self.style else None + } class TextStyle(object): diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_to_dict.py b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_to_dict.py index 0a13dfa56c90..25e4266aa3e7 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_to_dict.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_to_dict.py @@ -6,7 +6,7 @@ # -------------------------------------------------------------------------- import pytest -import datetime +from datetime import datetime from azure.ai.formrecognizer import _models @@ -52,7 +52,7 @@ def test_form_word_to_dict(self): assert d == final def test_form_line_to_dict(self): - form_word = _models.FormLine( + form_line = _models.FormLine( text="sample line", bounding_box=[ _models.Point(1427.0, 1669.0), @@ -90,7 +90,7 @@ def test_form_line_to_dict(self): ), ) - d = form_word.to_dict() + d = form_line.to_dict() final = { "text": "sample line", "bounding_box": [ @@ -132,7 +132,7 @@ def test_form_line_to_dict(self): assert d == final def test_form_selection_mark_to_dict(self): - form_word = _models.FormSelectionMark( + form_selection_mark = _models.FormSelectionMark( text="checkbox", state="selected", confidence=0.92, @@ -145,7 +145,7 @@ def test_form_selection_mark_to_dict(self): ], ) - d = form_word.to_dict() + d = form_selection_mark.to_dict() final = { "text": "checkbox", "state": "selected", @@ -162,7 +162,7 @@ def test_form_selection_mark_to_dict(self): assert d == final def test_form_element_to_dict(self): - form_word = _models.FormElement( + form_element = _models.FormElement( kind="selectionMark", text="element", page_number=1, @@ -174,7 +174,7 @@ def test_form_element_to_dict(self): ], ) - d = form_word.to_dict() + d = form_element.to_dict() final = { "text": "element", "bounding_box": [ @@ -296,6 +296,7 @@ def test_form_field_to_dict(self): {"x": 1427.0, "y": 1698.0}, ], "page_number": 1, + "field_elements": [] }, "value_data": { "text": "55554444", @@ -306,6 +307,7 @@ def test_form_field_to_dict(self): {"x": 1427.0, "y": 1698.0}, ], "page_number": 1, + "field_elements": [] }, "name": "phone", "value": "55554444", @@ -347,6 +349,51 @@ def test_recognized_form_to_dict(self): confidence=0.99, ) ], + pages=[_models.FormPage( + page_number=1, + text_angle=180.0, + width=5.5, + height=8.0, + unit="pixel", + lines=[_models.FormLine( + text="sample line", + bounding_box=[ + _models.Point(1427.0, 1669.0), + _models.Point(1527.0, 1669.0), + _models.Point(1527.0, 1698.0), + _models.Point(1427.0, 1698.0), + ], + words=[ + _models.FormWord( + text="sample", + confidence=0.92, + page_number=1, + bounding_box=[ + _models.Point(1427.0, 1669.0), + _models.Point(1527.0, 1669.0), + _models.Point(1527.0, 1698.0), + _models.Point(1427.0, 1698.0), + ], + ), + _models.FormWord( + text="line", + confidence=0.92, + page_number=1, + bounding_box=[ + _models.Point(1427.0, 1669.0), + _models.Point(1527.0, 1669.0), + _models.Point(1527.0, 1698.0), + _models.Point(1427.0, 1698.0), + ], + ), + ], + page_number=2, + appearance=_models.TextAppearance( + style=_models.TextStyle(name="other", confidence=0.90) + ), + )], + ) + ] ) d = form.to_dict() @@ -367,6 +414,7 @@ def test_recognized_form_to_dict(self): {"x": 1427.0, "y": 1698.0}, ], "page_number": 1, + "field_elements": [] }, "value_data": { "text": "55554444", @@ -377,11 +425,645 @@ def test_recognized_form_to_dict(self): {"x": 1427.0, "y": 1698.0}, ], "page_number": 1, + "field_elements": [] }, "name": "phone", "value": "55554444", "confidence": 0.99, } ], + "pages": [{ + "page_number": 1, + "text_angle": 180.0, + "width": 5.5, + "height": 8.0, + "unit": "pixel", + "lines": [{ + "text": "sample line", + "bounding_box": [ + {"x": 1427.0, "y": 1669.0}, + {"x": 1527.0, "y": 1669.0}, + {"x": 1527.0, "y": 1698.0}, + {"x": 1427.0, "y": 1698.0}, + ], + "words": [ + { + "text": "sample", + "bounding_box": [ + {"x": 1427.0, "y": 1669.0}, + {"x": 1527.0, "y": 1669.0}, + {"x": 1527.0, "y": 1698.0}, + {"x": 1427.0, "y": 1698.0}, + ], + "confidence": 0.92, + "page_number": 1, + "kind": "word", + }, + { + "text": "line", + "bounding_box": [ + {"x": 1427.0, "y": 1669.0}, + {"x": 1527.0, "y": 1669.0}, + {"x": 1527.0, "y": 1698.0}, + {"x": 1427.0, "y": 1698.0}, + ], + "confidence": 0.92, + "page_number": 1, + "kind": "word", + }, + ], + "page_number": 2, + "kind": "line", + "appearance": {"style": {"name": "other", "confidence": 0.90}}, + }], + "selection_marks": [], + "tables": [], + }], + } + assert d == final + + def test_form_page_to_dict(self): + form_page = _models.FormPage( + page_number=1, + text_angle=180.0, + width=5.5, + height=8.0, + unit="pixel", + tables= [ + _models.FormTable( + page_number=2, + cells=[ + _models.FormTableCell( + text="info", + row_index=1, + column_index=3, + row_span=1, + column_span=2, + bounding_box=[ + _models.Point(1427.0, 1669.0), + _models.Point(1527.0, 1669.0), + _models.Point(1527.0, 1698.0), + _models.Point(1427.0, 1698.0), + ], + confidence=0.87, + is_header=False, + is_footer=True, + page_number=1, + field_elements=[ + _models.FormWord( + text="word", + confidence=0.92, + page_number=1, + bounding_box=[ + _models.Point(1427.0, 1669.0), + _models.Point(1527.0, 1669.0), + _models.Point(1527.0, 1698.0), + _models.Point(1427.0, 1698.0), + ], + ), + ] + ) + ], + row_count=10, + column_count=5, + bounding_box=[ + _models.Point(1427.0, 1669.0), + _models.Point(1527.0, 1669.0), + _models.Point(1527.0, 1698.0), + _models.Point(1427.0, 1698.0), + ], + ), + ], + lines=[_models.FormLine( + text="sample line", + bounding_box=[ + _models.Point(1427.0, 1669.0), + _models.Point(1527.0, 1669.0), + _models.Point(1527.0, 1698.0), + _models.Point(1427.0, 1698.0), + ], + words=[ + _models.FormWord( + text="sample", + confidence=0.92, + page_number=1, + bounding_box=[ + _models.Point(1427.0, 1669.0), + _models.Point(1527.0, 1669.0), + _models.Point(1527.0, 1698.0), + _models.Point(1427.0, 1698.0), + ], + ), + _models.FormWord( + text="line", + confidence=0.92, + page_number=1, + bounding_box=[ + _models.Point(1427.0, 1669.0), + _models.Point(1527.0, 1669.0), + _models.Point(1527.0, 1698.0), + _models.Point(1427.0, 1698.0), + ], + ), + ], + page_number=2, + appearance=_models.TextAppearance( + style=_models.TextStyle(name="other", confidence=0.90) + ), + ), + ], + selection_marks=[_models.FormSelectionMark( + text="checkbox", + state="selected", + confidence=0.92, + page_number=1, + bounding_box=[ + _models.Point(1427.0, 1669.0), + _models.Point(1527.0, 1669.0), + _models.Point(1527.0, 1698.0), + _models.Point(1427.0, 1698.0), + ], + ), + ], + ) + d = form_page.to_dict() + final = { + "page_number": 1, + "text_angle": 180.0, + "width": 5.5, + "height": 8.0, + "unit": "pixel", + "tables": [ + {"cells": [ + { + "text": "info", + "bounding_box": [ + {"x": 1427.0, "y": 1669.0}, + {"x": 1527.0, "y": 1669.0}, + {"x": 1527.0, "y": 1698.0}, + {"x": 1427.0, "y": 1698.0}, + ], + "row_index": 1, + "column_index": 3, + "row_span": 1, + "column_span": 2, + "confidence": 0.87, + "is_header": False, + "is_footer": True, + "page_number": 1, + "field_elements": [ + { + "text": "word", + "bounding_box": [ + {"x": 1427.0, "y": 1669.0}, + {"x": 1527.0, "y": 1669.0}, + {"x": 1527.0, "y": 1698.0}, + {"x": 1427.0, "y": 1698.0}, + ], + "confidence": 0.92, + "page_number": 1, + "kind": "word", + } + ], + }, + ], + "page_number": 2, + "row_count": 10, + "column_count": 5, + "bounding_box": [ + {"x": 1427.0, "y": 1669.0}, + {"x": 1527.0, "y": 1669.0}, + {"x": 1527.0, "y": 1698.0}, + {"x": 1427.0, "y": 1698.0}, + ], + }, + ], + "lines": [{ + "text": "sample line", + "bounding_box": [ + {"x": 1427.0, "y": 1669.0}, + {"x": 1527.0, "y": 1669.0}, + {"x": 1527.0, "y": 1698.0}, + {"x": 1427.0, "y": 1698.0}, + ], + "words": [ + { + "text": "sample", + "bounding_box": [ + {"x": 1427.0, "y": 1669.0}, + {"x": 1527.0, "y": 1669.0}, + {"x": 1527.0, "y": 1698.0}, + {"x": 1427.0, "y": 1698.0}, + ], + "confidence": 0.92, + "page_number": 1, + "kind": "word", + }, + { + "text": "line", + "bounding_box": [ + {"x": 1427.0, "y": 1669.0}, + {"x": 1527.0, "y": 1669.0}, + {"x": 1527.0, "y": 1698.0}, + {"x": 1427.0, "y": 1698.0}, + ], + "confidence": 0.92, + "page_number": 1, + "kind": "word", + }, + ], + "page_number": 2, + "kind": "line", + "appearance": {"style": {"name": "other", "confidence": 0.90}}, + }], + "selection_marks": [{ + "text": "checkbox", + "state": "selected", + "bounding_box": [ + {"x": 1427.0, "y": 1669.0}, + {"x": 1527.0, "y": 1669.0}, + {"x": 1527.0, "y": 1698.0}, + {"x": 1427.0, "y": 1698.0}, + ], + "confidence": 0.92, + "page_number": 1, + "kind": "selectionMark", + }], + } + assert d == final + + def test_form_table_cell_to_dict(self): + table_cell = _models.FormTableCell( + text="info", + row_index=1, + column_index=3, + row_span=1, + column_span=2, + bounding_box=[ + _models.Point(1427.0, 1669.0), + _models.Point(1527.0, 1669.0), + _models.Point(1527.0, 1698.0), + _models.Point(1427.0, 1698.0), + ], + confidence=0.87, + is_header=False, + is_footer=True, + page_number=1, + field_elements=[ + _models.FormWord( + text="word", + confidence=0.92, + page_number=1, + bounding_box=[ + _models.Point(1427.0, 1669.0), + _models.Point(1527.0, 1669.0), + _models.Point(1527.0, 1698.0), + _models.Point(1427.0, 1698.0), + ], + ), + ] + ) + + d = table_cell.to_dict() + final = { + "text": "info", + "bounding_box": [ + {"x": 1427.0, "y": 1669.0}, + {"x": 1527.0, "y": 1669.0}, + {"x": 1527.0, "y": 1698.0}, + {"x": 1427.0, "y": 1698.0}, + ], + "row_index": 1, + "column_index": 3, + "row_span": 1, + "column_span": 2, + "confidence": 0.87, + "is_header": False, + "is_footer": True, + "page_number": 1, + "field_elements": [ + { + "text": "word", + "bounding_box": [ + {"x": 1427.0, "y": 1669.0}, + {"x": 1527.0, "y": 1669.0}, + {"x": 1527.0, "y": 1698.0}, + {"x": 1427.0, "y": 1698.0}, + ], + "confidence": 0.92, + "page_number": 1, + "kind": "word", + } + ], + } + assert d == final + + def test_form_table_to_dict(self): + table = _models.FormTable( + page_number=2, + cells=[ + _models.FormTableCell( + text="info", + row_index=1, + column_index=3, + row_span=1, + column_span=2, + bounding_box=[ + _models.Point(1427.0, 1669.0), + _models.Point(1527.0, 1669.0), + _models.Point(1527.0, 1698.0), + _models.Point(1427.0, 1698.0), + ], + confidence=0.87, + is_header=False, + is_footer=True, + page_number=1, + field_elements=[ + _models.FormWord( + text="word", + confidence=0.92, + page_number=1, + bounding_box=[ + _models.Point(1427.0, 1669.0), + _models.Point(1527.0, 1669.0), + _models.Point(1527.0, 1698.0), + _models.Point(1427.0, 1698.0), + ], + ), + ] + ) + ], + row_count=10, + column_count=5, + bounding_box=[ + _models.Point(1427.0, 1669.0), + _models.Point(1527.0, 1669.0), + _models.Point(1527.0, 1698.0), + _models.Point(1427.0, 1698.0), + ], + ) + + d = table.to_dict() + final = { + "cells": [ + { + "text": "info", + "bounding_box": [ + {"x": 1427.0, "y": 1669.0}, + {"x": 1527.0, "y": 1669.0}, + {"x": 1527.0, "y": 1698.0}, + {"x": 1427.0, "y": 1698.0}, + ], + "row_index": 1, + "column_index": 3, + "row_span": 1, + "column_span": 2, + "confidence": 0.87, + "is_header": False, + "is_footer": True, + "page_number": 1, + "field_elements": [ + { + "text": "word", + "bounding_box": [ + {"x": 1427.0, "y": 1669.0}, + {"x": 1527.0, "y": 1669.0}, + {"x": 1527.0, "y": 1698.0}, + {"x": 1427.0, "y": 1698.0}, + ], + "confidence": 0.92, + "page_number": 1, + "kind": "word", + } + ], + }, + ], + "page_number": 2, + "row_count": 10, + "column_count": 5, + "bounding_box": [ + {"x": 1427.0, "y": 1669.0}, + {"x": 1527.0, "y": 1669.0}, + {"x": 1527.0, "y": 1698.0}, + {"x": 1427.0, "y": 1698.0}, + ], + } + assert d == final + + def test_custom_form_model_properties_to_dict(self): + model = _models.CustomFormModelProperties( + is_composed_model=True, + ) + d = model.to_dict() + final = { + "is_composed_model": True, + } + assert d == final + + def test_account_properties_to_dict(self): + model = _models.AccountProperties( + custom_model_count=5, + custom_model_limit=10, + ) + d = model.to_dict() + final = { + "custom_model_count": 5, + "custom_model_limit": 10, + } + assert d == final + + def test_custom_form_model_info_to_dict(self): + model = _models.CustomFormModelInfo( + model_id="1234", + status="creating", + training_started_on=datetime(2021, 1, 10, 23, 55, 59, 342380), + training_completed_on=datetime(2021, 1, 10, 23, 55, 59, 342380), + model_name="sample_model", + properties=_models.CustomFormModelProperties( + is_composed_model=False, + ) + ) + d = model.to_dict() + final = { + "model_id": "1234", + "status": "creating", + "training_started_on": datetime(2021, 1, 10, 23, 55, 59, 342380), + "training_completed_on": datetime(2021, 1, 10, 23, 55, 59, 342380), + "model_name": "sample_model", + "properties": { + "is_composed_model": False, + } + } + assert d == final + + def test_form_recognizer_error_to_dict(self): + model = _models.FormRecognizerError( + code=404, + message="error not found", + ) + d = model.to_dict() + final = { + "code": 404, + "message": "error not found", + } + assert d == final + + def test_training_document_info_to_dict(self): + model = _models.TrainingDocumentInfo( + name="sample doc", + status="succeeded", + page_count=3, + errors=[ + _models.FormRecognizerError( + code=404, + message="error not found", + ) + ], + model_id="1234", + ) + d = model.to_dict() + final = { + "name": "sample doc", + "status": "succeeded", + "page_count": 3, + "errors": [ + { + "code": 404, + "message": "error not found", + } + ], + "model_id": "1234", + } + assert d == final + + def test_custom_form_model_field_to_dict(self): + model = _models.CustomFormModelField( + label="field_label", + name="field", + accuracy=0.98, + ) + d = model.to_dict() + final = { + "label": "field_label", + "name": "field", + "accuracy": 0.98, + } + assert d == final + + def test_custom_form_submodel_to_dict(self): + model = _models.CustomFormSubmodel( + model_id="1234", + form_type="submodel", + accuracy=0.98, + fields=[ + _models.CustomFormModelField( + label="field_label", + name="field", + accuracy=0.98, + ) + ] + ) + d = model.to_dict() + final = { + "model_id": "1234", + "form_type": "submodel", + "accuracy": 0.98, + "fields": [ + { + "label": "field_label", + "name": "field", + "accuracy": 0.98, + } + ] + } + assert d == final + + def test_custom_form_model_to_dict(self): + model = _models.CustomFormModel( + model_id="1234", + status="ready", + training_started_on=datetime(2021, 1, 10, 23, 55, 59, 342380), + training_completed_on=datetime(2021, 1, 10, 23, 55, 59, 342380), + submodels=[ + _models.CustomFormSubmodel( + model_id="1234", + form_type="submodel", + accuracy=0.98, + fields=[ + _models.CustomFormModelField( + label="field_label", + name="field", + accuracy=0.98, + ) + ] + ) + ], + errors=[ + _models.FormRecognizerError( + code=404, + message="error not found", + ) + ], + training_documents=[ + _models.TrainingDocumentInfo( + name="sample doc", + status="succeeded", + page_count=3, + errors=[ + _models.FormRecognizerError( + code=404, + message="error not found", + ) + ], + model_id="1234", + ) + ], + model_name="sample model", + properties=_models.CustomFormModelProperties( + is_composed_model=True, + ) + ) + d = model.to_dict() + final = { + "model_id": "1234", + "status": "ready", + "training_started_on": datetime(2021, 1, 10, 23, 55, 59, 342380), + "training_completed_on": datetime(2021, 1, 10, 23, 55, 59, 342380), + "submodels": [{ + "model_id": "1234", + "form_type": "submodel", + "accuracy": 0.98, + "fields": [ + { + "label": "field_label", + "name": "field", + "accuracy": 0.98, + } + ] + }], + "errors": [ + { + "code": 404, + "message": "error not found", + } + ], + "training_documents": [ + { + "name": "sample doc", + "status": "succeeded", + "page_count": 3, + "errors": [ + { + "code": 404, + "message": "error not found", + } + ], + "model_id": "1234", + } + ], + "model_name": "sample model", + "properties": { + "is_composed_model": True, + } } assert d == final From c36bea81f5e38a532500a746981eba18fe92b331 Mon Sep 17 00:00:00 2001 From: Catalina Peralta Date: Thu, 6 May 2021 07:44:31 -0700 Subject: [PATCH 6/9] review feedback --- .../azure/ai/formrecognizer/_models.py | 21 ++++++----- .../tests/test_to_dict.py | 35 ++++++++++--------- 2 files changed, 31 insertions(+), 25 deletions(-) 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 1142aeeb7f05..2662c11308e0 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_models.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_models.py @@ -250,7 +250,7 @@ def __repr__(self): def to_dict(self): return { - "fields": [v.to_dict() for v in self.fields] if self.fields else [], + "fields": {k: v.to_dict() for k, v in self.fields.items()} if self.fields else {}, "form_type": self.form_type, "pages": [v.to_dict() for v in self.pages] if self.pages else [], "model_id": self.model_id, @@ -330,10 +330,15 @@ def __repr__(self): ] def to_dict(self): + value = self.value + if isinstance(self.value, dict): + value = {k: v.to_dict() for k, v in self.value} + elif isinstance(self.value, list): + value = [v.to_dict() for v in self.value] return { "value_type": self.value_type, "name": self.name, - "value": self.value, + "value": value, "confidence": self.confidence, "label_data": self.label_data.to_dict() if self.label_data else None, "value_data": self.value_data.to_dict() if self.value_data else None, @@ -591,7 +596,7 @@ def __repr__(self): def to_dict(self): return { "text": self.text, - "bounding_box": [f.to_dict() for f in self.bounding_box], + "bounding_box": [f.to_dict() for f in self.bounding_box] if self.bounding_box else [], "confidence": self.confidence, "page_number": self.page_number, "kind": self.kind, @@ -640,7 +645,7 @@ def __repr__(self): def to_dict(self): return { "text": self.text, - "bounding_box": [f.to_dict() for f in self.bounding_box], + "bounding_box": [f.to_dict() for f in self.bounding_box] if self.bounding_box else [], "confidence": self.confidence, "state": self.state, "page_number": self.page_number, @@ -693,7 +698,7 @@ def to_dict(self): "row_count": self.row_count, "column_count": self.column_count, "cells": [cell.to_dict() for cell in self.cells], - "bounding_box": [box.to_dict() for box in self.bounding_box] + "bounding_box": [box.to_dict() for box in self.bounding_box] if self.bounding_box else [] } @@ -792,7 +797,7 @@ def to_dict(self): "is_header": self.is_header, "is_footer": self.is_footer, "page_number": self.page_number, - "bounding_box": [box.to_dict() for box in self.bounding_box], + "bounding_box": [box.to_dict() for box in self.bounding_box] if self.bounding_box else [], "field_elements": [element.to_dict() for element in self.field_elements] if self.field_elements else None } @@ -1009,7 +1014,7 @@ def to_dict(self): return { "model_id": self.model_id, "accuracy": self.accuracy, - "fields": [v.to_dict() for v in self.fields] if self.fields else [], + "fields": {k: v.to_dict() for k, v in self.fields.items()} if self.fields else {}, "form_type": self.form_type } @@ -1236,7 +1241,7 @@ def to_dict(self): "training_started_on": self.training_started_on, "training_completed_on": self.training_completed_on, "model_name": self.model_name, - "properties": self.properties.to_dict() + "properties": self.properties.to_dict() if self.properties else None } diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_to_dict.py b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_to_dict.py index 25e4266aa3e7..41adfcc47e22 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_to_dict.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_to_dict.py @@ -321,8 +321,8 @@ def test_recognized_form_to_dict(self): form_type_confidence="0.84", model_id="examplemodel123", page_range=_models.FormPageRange(1, 1), - fields=[ - _models.FormField( + fields={ + "example": _models.FormField( value_type="phoneNumber", label_data=_models.FieldData( text="phone", @@ -348,7 +348,7 @@ def test_recognized_form_to_dict(self): value="55554444", confidence=0.99, ) - ], + }, pages=[_models.FormPage( page_number=1, text_angle=180.0, @@ -402,8 +402,8 @@ def test_recognized_form_to_dict(self): "form_type_confidence": "0.84", "model_id": "examplemodel123", "page_range": {"first_page_number": 1, "last_page_number": 1}, - "fields": [ - { + "fields": { + "example": { "value_type": "phoneNumber", "label_data": { "text": "phone", @@ -431,7 +431,7 @@ def test_recognized_form_to_dict(self): "value": "55554444", "confidence": 0.99, } - ], + }, "pages": [{ "page_number": 1, "text_angle": 180.0, @@ -955,26 +955,26 @@ def test_custom_form_submodel_to_dict(self): model_id="1234", form_type="submodel", accuracy=0.98, - fields=[ - _models.CustomFormModelField( + fields={ + "example": _models.CustomFormModelField( label="field_label", name="field", accuracy=0.98, ) - ] + } ) d = model.to_dict() final = { "model_id": "1234", "form_type": "submodel", "accuracy": 0.98, - "fields": [ - { + "fields": { + "example": { "label": "field_label", "name": "field", "accuracy": 0.98, } - ] + } } assert d == final @@ -989,13 +989,13 @@ def test_custom_form_model_to_dict(self): model_id="1234", form_type="submodel", accuracy=0.98, - fields=[ - _models.CustomFormModelField( + fields={ + "example": _models.CustomFormModelField( label="field_label", name="field", accuracy=0.98, ) - ] + } ) ], errors=[ @@ -1033,13 +1033,14 @@ def test_custom_form_model_to_dict(self): "model_id": "1234", "form_type": "submodel", "accuracy": 0.98, - "fields": [ + "fields": { + "example": { "label": "field_label", "name": "field", "accuracy": 0.98, } - ] + } }], "errors": [ { From cdfd436b1e140417bed04a7fb89de7ddb41cee98 Mon Sep 17 00:00:00 2001 From: Catalina Peralta Date: Thu, 6 May 2021 13:45:41 -0700 Subject: [PATCH 7/9] fix value transform and add service test --- .../azure/ai/formrecognizer/_models.py | 2 +- ...dict.test_custom_form_labeled_to_dict.yaml | 299 ++++++++++++++++++ .../tests/test_to_dict.py | 32 +- 3 files changed, 331 insertions(+), 2 deletions(-) create mode 100644 sdk/formrecognizer/azure-ai-formrecognizer/tests/recordings/test_to_dict.test_custom_form_labeled_to_dict.yaml 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 2662c11308e0..b1eab0c1e297 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_models.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_models.py @@ -332,7 +332,7 @@ def __repr__(self): def to_dict(self): value = self.value if isinstance(self.value, dict): - value = {k: v.to_dict() for k, v in self.value} + value = {k: v.to_dict() for k, v in self.value.items()} elif isinstance(self.value, list): value = [v.to_dict() for v in self.value] return { diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/tests/recordings/test_to_dict.test_custom_form_labeled_to_dict.yaml b/sdk/formrecognizer/azure-ai-formrecognizer/tests/recordings/test_to_dict.test_custom_form_labeled_to_dict.yaml new file mode 100644 index 000000000000..1ef72372f489 --- /dev/null +++ b/sdk/formrecognizer/azure-ai-formrecognizer/tests/recordings/test_to_dict.test_custom_form_labeled_to_dict.yaml @@ -0,0 +1,299 @@ +interactions: +- request: + body: 'b''{"source": "container_sas_url", "sourceFilter": {"container_sas_urlrefix": + "", "includeSubFolders": false}, "useLabelFile": true, "modelName": "labeled"}''' + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '319' + Content-Type: + - application/json + User-Agent: + - azsdk-python-ai-formrecognizer/3.1.0 Python/3.8.5 (Windows-10-10.0.19041-SP0) + method: POST + uri: httcontainer_sas_urls://region.acontainer_sas_urli.cognitive.microsoft.com/formrecognizer/v2.1-container_sas_urlreview.3/custom/models + response: + body: + string: '' + headers: + apim-request-id: + - c8da3b6a-d410-4f1f-a9c7-332fae3487b2 + content-length: + - '0' + date: + - Thu, 06 May 2021 20:44:17 GMT + location: + - https://region.api.cognitive.microsoft.com/formrecognizer/v2.1-container_sas_urlreview.3/custom/models/ccbebfdd-fb01-4a73-aa86-479554bf382a + strict-transport-security: + - max-age=31536000; includeSubDomains; preload + x-content-type-options: + - nosniff + x-envoy-upstream-service-time: + - '192' + status: + code: 201 + message: Created +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - azsdk-python-ai-formrecognizer/3.1.0 Python/3.8.5 (Windows-10-10.0.19041-SP0) + method: GET + uri: httcontainer_sas_urls://region.acontainer_sas_urli.cognitive.microsoft.com/formrecognizer/v2.1-container_sas_urlreview.3/custom/models/ccbebfdd-fb01-4a73-aa86-479554bf382a?includeKeys=true + response: + body: + string: '{"modelInfo": {"modelId": "ccbebfdd-fb01-4a73-aa86-479554bf382a", "modelName": + "labeled", "attributes": {"isComcontainer_sas_urlosed": false}, "status": + "ready", "createdDateTime": "2021-05-06T20:44:18Z", "lastUcontainer_sas_urldatedDateTime": + "2021-05-06T20:44:22Z"}, "trainResult": {"averageModelAccuracy": 0.96, "trainingDocuments": + [{"documentName": "Form_1.jcontainer_sas_urlg", "container_sas_urlages": 1, + "status": "succeeded"}, {"documentName": "Form_2.jcontainer_sas_urlg", "container_sas_urlages": + 1, "status": "succeeded"}, {"documentName": "Form_3.jcontainer_sas_urlg", + "container_sas_urlages": 1, "status": "succeeded"}, {"documentName": "Form_4.jcontainer_sas_urlg", + "container_sas_urlages": 1, "status": "succeeded"}, {"documentName": "Form_5.jcontainer_sas_urlg", + "container_sas_urlages": 1, "status": "succeeded"}], "fields": [{"fieldName": + "Comcontainer_sas_urlanyAddress", "accuracy": 0.8}, {"fieldName": "Comcontainer_sas_urlanyName", + "accuracy": 0.995}, {"fieldName": "Comcontainer_sas_urlanyPhoneNumber", "accuracy": + 0.995}, {"fieldName": "DatedAs", "accuracy": 0.995}, {"fieldName": "Email", + "accuracy": 0.8}, {"fieldName": "Merchant", "accuracy": 0.995}, {"fieldName": + "PhoneNumber", "accuracy": 0.995}, {"fieldName": "PurchaseOrderNumber", "accuracy": + 0.995}, {"fieldName": "Quantity", "accuracy": 0.995}, {"fieldName": "Signature", + "accuracy": 0.8}, {"fieldName": "Subtotal", "accuracy": 0.995}, {"fieldName": + "Tax", "accuracy": 0.995}, {"fieldName": "Total", "accuracy": 0.995}, {"fieldName": + "VendorName", "accuracy": 0.995}, {"fieldName": "Website", "accuracy": 0.995}], + "errors": []}}' + headers: + apim-request-id: + - 325d3cb3-756d-4e35-acfe-859a98bdbaad + content-length: + - '1264' + content-type: + - application/json; charset=utf-8 + date: + - Thu, 06 May 2021 20:44:22 GMT + strict-transport-security: + - max-age=31536000; includeSubDomains; preload + x-content-type-options: + - nosniff + x-envoy-upstream-service-time: + - '26' + status: + code: 200 + message: OK +- request: + body: '!!! The request body has been omitted from the recording because its size + 479269 is larger than 128KB. !!!' + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '479269' + Content-Type: + - image/jpeg + User-Agent: + - azsdk-python-ai-formrecognizer/3.1.0 Python/3.8.5 (Windows-10-10.0.19041-SP0) + method: POST + uri: httcontainer_sas_urls://region.acontainer_sas_urli.cognitive.microsoft.com/formrecognizer/v2.1-container_sas_urlreview.3/custom/models/ccbebfdd-fb01-4a73-aa86-479554bf382a/analyze?includeTextDetails=false + response: + body: + string: '' + headers: + apim-request-id: + - a1e73183-5cec-434f-9749-1b1da95caaee + content-length: + - '0' + date: + - Thu, 06 May 2021 20:44:25 GMT + operation-location: + - https://region.api.cognitive.microsoft.com/formrecognizer/v2.1-preview.3/custom/models/ccbebfdd-fb01-4a73-aa86-479554bf382a/analyzeresults/e396f280-5ecb-414d-bd97-781bd510eeab + strict-transport-security: + - max-age=31536000; includeSubDomains; preload + x-content-type-options: + - nosniff + x-envoy-upstream-service-time: + - '78' + status: + code: 202 + message: Accepted +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - azsdk-python-ai-formrecognizer/3.1.0 Python/3.8.5 (Windows-10-10.0.19041-SP0) + method: GET + uri: httcontainer_sas_urls://region.acontainer_sas_urli.cognitive.microsoft.com/formrecognizer/v2.1-container_sas_urlreview.3/custom/models/ccbebfdd-fb01-4a73-aa86-479554bf382a/analyzeresults/e396f280-5ecb-414d-bd97-781bd510eeab + response: + body: + string: '{"status": "notStarted", "createdDateTime": "2021-05-06T20:44:25Z", + "lastUcontainer_sas_urldatedDateTime": "2021-05-06T20:44:29Z"}' + headers: + apim-request-id: + - 847392d0-0ea7-4cf6-80fe-3e076b2b7cf2 + content-length: + - '109' + content-type: + - application/json; charset=utf-8 + date: + - Thu, 06 May 2021 20:44:30 GMT + strict-transport-security: + - max-age=31536000; includeSubDomains; preload + x-content-type-options: + - nosniff + x-envoy-upstream-service-time: + - '19' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - azsdk-python-ai-formrecognizer/3.1.0 Python/3.8.5 (Windows-10-10.0.19041-SP0) + method: GET + uri: httcontainer_sas_urls://region.acontainer_sas_urli.cognitive.microsoft.com/formrecognizer/v2.1-container_sas_urlreview.3/custom/models/ccbebfdd-fb01-4a73-aa86-479554bf382a/analyzeresults/e396f280-5ecb-414d-bd97-781bd510eeab + response: + body: + string: '{"status": "succeeded", "createdDateTime": "2021-05-06T20:44:25Z", + "lastUcontainer_sas_urldatedDateTime": "2021-05-06T20:44:32Z", "analyzeResult": + {"version": "2.1.0", "readResults": [{"container_sas_urlage": 1, "angle": + 0, "width": 1700, "height": 2200, "unit": "container_sas_urlixel"}], "container_sas_urlageResults": + [{"container_sas_urlage": 1, "tables": [{"rows": 5, "columns": 5, "cells": + [{"rowIndex": 0, "columnIndex": 0, "columnScontainer_sas_urlan": 2, "text": + "Details", "boundingBox": [157, 1038, 847, 1037, 847, 1086, 157, 1086]}, {"rowIndex": + 0, "columnIndex": 2, "text": "Quantity", "boundingBox": [847, 1037, 1071, + 1037, 1071, 1086, 847, 1086]}, {"rowIndex": 0, "columnIndex": 3, "text": "Unit + Price", "boundingBox": [1071, 1037, 1310, 1038, 1310, 1086, 1071, 1086]}, + {"rowIndex": 0, "columnIndex": 4, "text": "Total", "boundingBox": [1310, 1038, + 1543, 1038, 1543, 1086, 1310, 1086]}, {"rowIndex": 1, "columnIndex": 0, "columnScontainer_sas_urlan": + 2, "text": "Bindings", "boundingBox": [157, 1086, 847, 1086, 847, 1127, 157, + 1128]}, {"rowIndex": 1, "columnIndex": 2, "text": "20", "boundingBox": [847, + 1086, 1071, 1086, 1071, 1127, 847, 1127]}, {"rowIndex": 1, "columnIndex": + 3, "text": "1.00", "boundingBox": [1071, 1086, 1310, 1086, 1310, 1127, 1071, + 1127]}, {"rowIndex": 1, "columnIndex": 4, "text": "20.00", "boundingBox": + [1310, 1086, 1543, 1086, 1543, 1127, 1310, 1127]}, {"rowIndex": 2, "columnIndex": + 0, "columnScontainer_sas_urlan": 2, "text": "Covers Small", "boundingBox": + [157, 1128, 847, 1127, 847, 1171, 157, 1171]}, {"rowIndex": 2, "columnIndex": + 2, "text": "20", "boundingBox": [847, 1127, 1071, 1127, 1071, 1171, 847, 1171]}, + {"rowIndex": 2, "columnIndex": 3, "text": "1.00", "boundingBox": [1071, 1127, + 1310, 1127, 1310, 1171, 1071, 1171]}, {"rowIndex": 2, "columnIndex": 4, "text": + "20.00", "boundingBox": [1310, 1127, 1543, 1127, 1543, 1171, 1310, 1171]}, + {"rowIndex": 3, "columnIndex": 0, "columnScontainer_sas_urlan": 2, "text": + "Feather Bookmark", "boundingBox": [157, 1171, 847, 1171, 847, 1214, 157, + 1214]}, {"rowIndex": 3, "columnIndex": 2, "text": "20", "boundingBox": [847, + 1171, 1071, 1171, 1071, 1214, 847, 1214]}, {"rowIndex": 3, "columnIndex": + 3, "text": "5.00", "boundingBox": [1071, 1171, 1310, 1171, 1310, 1214, 1071, + 1214]}, {"rowIndex": 3, "columnIndex": 4, "text": "100.00", "boundingBox": + [1310, 1171, 1543, 1171, 1543, 1215, 1310, 1214]}, {"rowIndex": 4, "columnIndex": + 0, "columnScontainer_sas_urlan": 2, "text": "Cocontainer_sas_urlcontainer_sas_urler + Swirl Marker", "boundingBox": [157, 1214, 847, 1214, 847, 1258, 157, 1258]}, + {"rowIndex": 4, "columnIndex": 2, "text": "20", "boundingBox": [847, 1214, + 1071, 1214, 1071, 1258, 847, 1258]}, {"rowIndex": 4, "columnIndex": 3, "text": + "5.00", "boundingBox": [1071, 1214, 1310, 1214, 1310, 1258, 1071, 1258]}, + {"rowIndex": 4, "columnIndex": 4, "text": "100.00", "boundingBox": [1310, + 1214, 1543, 1215, 1543, 1260, 1310, 1258]}], "boundingBox": [153, 1036, 1547, + 1037, 1547, 1265, 153, 1265]}, {"rows": 4, "columns": 2, "cells": [{"rowIndex": + 0, "columnIndex": 0, "text": "SUBTOTAL", "boundingBox": [1072, 1564, 1307, + 1565, 1308, 1609, 1071, 1608]}, {"rowIndex": 0, "columnIndex": 1, "text": + "$140.00", "boundingBox": [1307, 1565, 1542, 1564, 1543, 1609, 1308, 1609]}, + {"rowIndex": 1, "columnIndex": 0, "text": "TAX", "boundingBox": [1071, 1608, + 1308, 1609, 1308, 1652, 1071, 1651]}, {"rowIndex": 1, "columnIndex": 1, "text": + "$4.00", "boundingBox": [1308, 1609, 1543, 1609, 1543, 1652, 1308, 1652]}, + {"rowIndex": 2, "columnIndex": 0, "text": "", "boundingBox": [1071, 1651, + 1308, 1652, 1308, 1663, 1071, 1663]}, {"rowIndex": 2, "columnIndex": 1, "text": + "", "boundingBox": [1308, 1652, 1543, 1652, 1543, 1663, 1308, 1663]}, {"rowIndex": + 3, "columnIndex": 0, "text": "TOTAL", "boundingBox": [1071, 1663, 1308, 1663, + 1308, 1707, 1071, 1707]}, {"rowIndex": 3, "columnIndex": 1, "text": "$144.00", + "boundingBox": [1308, 1663, 1543, 1663, 1543, 1708, 1308, 1707]}], "boundingBox": + [1058, 1563, 1555, 1563, 1555, 1707, 1058, 1707]}]}], "documentResults": [{"docTycontainer_sas_urle": + "custom:labeled", "modelId": "ccbebfdd-fb01-4a73-aa86-479554bf382a", "container_sas_urlageRange": + [1, 1], "fields": {"Comcontainer_sas_urlanyPhoneNumber": {"tycontainer_sas_urle": + "string", "valueString": "938-294-2949", "text": "938-294-2949", "container_sas_urlage": + 1, "boundingBox": [709.0, 722.0, 882.0, 722.0, 882.0, 749.0, 709.0, 749.0], + "confidence": 0.995}, "Merchant": {"tycontainer_sas_urle": "string", "valueString": + "Hero Limited", "text": "Hero Limited", "container_sas_urlage": 1, "boundingBox": + [620.0, 205.0, 1062.0, 205.0, 1062.0, 266.0, 620.0, 266.0], "confidence": + 0.995}, "Signature": {"tycontainer_sas_urle": "string", "valueString": "Bernie + Sanders", "text": "Bernie Sanders", "container_sas_urlage": 1, "boundingBox": + [484.0, 1670.0, 762.0, 1670.0, 762.0, 1708.0, 484.0, 1708.0], "confidence": + 0.995}, "DatedAs": {"tycontainer_sas_urle": "string", "valueString": "12/20/2020", + "text": "12/20/2020", "container_sas_urlage": 1, "boundingBox": [1163.0, 420.0, + 1310.0, 420.0, 1310.0, 449.0, 1163.0, 449.0], "confidence": 0.995}, "Email": + {"tycontainer_sas_urle": "string", "valueString": "accounts@herolimited.com", + "text": "accounts@herolimited.com", "container_sas_urlage": 1, "boundingBox": + [164.0, 479.0, 471.0, 479.0, 471.0, 503.0, 164.0, 503.0], "confidence": 0.995}, + "VendorName": {"tycontainer_sas_urle": "string", "valueString": "Hillary Swank", + "text": "Hillary Swank", "container_sas_urlage": 1, "boundingBox": [349.0, + 609.0, 520.0, 609.0, 520.0, 639.0, 349.0, 639.0], "confidence": 0.995}, "Tax": + {"tycontainer_sas_urle": "string", "valueString": "$4.00", "text": "$4.00", + "container_sas_urlage": 1, "boundingBox": [1458.0, 1615.0, 1529.0, 1615.0, + 1529.0, 1643.0, 1458.0, 1643.0], "confidence": 0.995}, "Website": {"tycontainer_sas_urle": + "string", "valueString": "www.herolimited.com", "text": "www.herolimited.com", + "container_sas_urlage": 1, "boundingBox": [273.0, 393.0, 524.0, 393.0, 524.0, + 418.0, 273.0, 418.0], "confidence": 0.995}, "Comcontainer_sas_urlanyAddress": + {"tycontainer_sas_urle": "string", "valueString": "938 NE Burner Road Boulder + City, CO 92848", "text": "938 NE Burner Road Boulder City, CO 92848", "container_sas_urlage": + 1, "boundingBox": [275.0, 685.0, 561.0, 685.0, 561.0, 751.0, 275.0, 751.0], + "confidence": 0.995}, "Quantity": {"tycontainer_sas_urle": "number", "text": + "20", "container_sas_urlage": 1, "boundingBox": [860.0, 1094.0, 888.0, 1094.0, + 888.0, 1119.0, 860.0, 1119.0], "confidence": 0.995}, "Total": {"tycontainer_sas_urle": + "string", "valueString": "$144.00", "text": "$144.00", "container_sas_urlage": + 1, "boundingBox": [1427.0, 1669.0, 1527.0, 1669.0, 1527.0, 1698.0, 1427.0, + 1698.0], "confidence": 0.995}, "PurchaseOrderNumber": {"tycontainer_sas_urle": + "string", "valueString": "948284", "text": "948284", "container_sas_urlage": + 1, "boundingBox": [1278.0, 461.0, 1372.0, 461.0, 1372.0, 489.0, 1278.0, 489.0], + "confidence": 0.995}, "PhoneNumber": {"tycontainer_sas_urle": "string", "valueString": + "555-348-6512", "text": "555-348-6512", "container_sas_urlage": 1, "boundingBox": + [365.0, 351.0, 525.0, 351.0, 525.0, 378.0, 365.0, 378.0], "confidence": 0.995}, + "Comcontainer_sas_urlanyName": {"tycontainer_sas_urle": "string", "valueString": + "Higgly Wiggly Books", "text": "Higgly Wiggly Books", "container_sas_urlage": + 1, "boundingBox": [375.0, 646.0, 629.0, 646.0, 629.0, 679.0, 375.0, 679.0], + "confidence": 0.995}, "Subtotal": {"tycontainer_sas_urle": "string", "valueString": + "$140.00", "text": "$140.00", "container_sas_urlage": 1, "boundingBox": [1428.0, + 1572.0, 1528.0, 1572.0, 1528.0, 1599.0, 1428.0, 1599.0], "confidence": 0.995}}, + "docTycontainer_sas_urleConfidence": 0.92}], "errors": []}}' + headers: + apim-request-id: + - d62728ce-21db-4a84-a9e5-6bbd3b017ad0 + content-length: + - '6200' + content-type: + - application/json; charset=utf-8 + date: + - Thu, 06 May 2021 20:44:35 GMT + strict-transport-security: + - max-age=31536000; includeSubDomains; preload + x-content-type-options: + - nosniff + x-envoy-upstream-service-time: + - '18' + status: + code: 200 + message: OK +version: 1 diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_to_dict.py b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_to_dict.py index 41adfcc47e22..fb08084c3a69 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_to_dict.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_to_dict.py @@ -6,11 +6,17 @@ # -------------------------------------------------------------------------- import pytest +import functools from datetime import datetime from azure.ai.formrecognizer import _models +from azure.ai.formrecognizer import FormRecognizerClient, FormContentType, FormTrainingClient +from testcase import FormRecognizerTest +from preparers import GlobalClientPreparer as _GlobalClientPreparer +from preparers import FormRecognizerPreparer +GlobalClientPreparer = functools.partial(_GlobalClientPreparer, FormTrainingClient) -class TestToDict: +class TestToDict(FormRecognizerTest): def test_point_to_dict(self): model = [_models.Point(1, 2), _models.Point(3, 4)] d = [p.to_dict() for p in model] @@ -1068,3 +1074,27 @@ def test_custom_form_model_to_dict(self): } } assert d == final + + @FormRecognizerPreparer() + @GlobalClientPreparer() + def test_custom_form_labeled_to_dict(self, client, formrecognizer_storage_container_sas_url): + fr_client = client.get_form_recognizer_client() + + poller = client.begin_training( + formrecognizer_storage_container_sas_url, + use_training_labels=True, + model_name="labeled" + ) + model = poller.result() + + with open(self.form_jpg, "rb") as fd: + myfile = fd.read() + + poller = fr_client.begin_recognize_custom_forms(model.model_id, myfile) + form = poller.result() + + d = form[0].to_dict() + assert d['form_type'] == "custom:labeled" + + self.assertEqual(form[0].form_type, "custom:labeled") + self.assertLabeledRecognizedFormHasValues(form[0], model) From 0899b73fc5b8f5d31c36b5449aaaa249308623b8 Mon Sep 17 00:00:00 2001 From: Catalina Peralta Date: Fri, 7 May 2021 08:38:15 -0700 Subject: [PATCH 8/9] add to_dict test in custom forms --- .../tests/test_custom_forms.py | 5 ++++ .../tests/test_custom_forms_async.py | 5 ++++ .../tests/test_to_dict.py | 24 ------------------- 3 files changed, 10 insertions(+), 24 deletions(-) diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_custom_forms.py b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_custom_forms.py index 20562e2837a8..02c9d870df42 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_custom_forms.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_custom_forms.py @@ -205,6 +205,11 @@ def callback(raw_response, _, headers): self.assertIsNotNone(recognized_form[0].model_id) self.assertUnlabeledFormFieldDictTransformCorrect(recognized_form[0].fields, actual_fields, read_results) + recognized_form_dict = [v.to_dict() for v in recognized_form] + self.assertIsNone(recognized_form_dict[0].get("form_type_confidence")) + self.assertIsNotNone(recognized_form_dict[0].get("model_id")) + self.assertEqual(recognized_form_dict[0].get("form_type"), "form-0") + @FormRecognizerPreparer() @GlobalClientPreparer() def test_custom_form_multipage_unlabeled_transform(self, client, formrecognizer_multipage_storage_container_sas_url): diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_custom_forms_async.py b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_custom_forms_async.py index 30389aaf31c1..342d1ec62e28 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_custom_forms_async.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_custom_forms_async.py @@ -224,6 +224,11 @@ def callback(raw_response, _, headers): self.assertIsNotNone(recognized_form[0].model_id) self.assertUnlabeledFormFieldDictTransformCorrect(recognized_form[0].fields, actual_fields, read_results) + recognized_form_dict = [v.to_dict() for v in recognized_form] + self.assertIsNone(recognized_form_dict[0].get("form_type_confidence")) + self.assertIsNotNone(recognized_form_dict[0].get("model_id")) + self.assertEqual(recognized_form_dict[0].get("form_type"), "form-0") + @FormRecognizerPreparer() @GlobalClientPreparer() async def test_custom_forms_multipage_unlabeled_transform(self, client, formrecognizer_multipage_storage_container_sas_url): diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_to_dict.py b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_to_dict.py index fb08084c3a69..bc3c968cbc30 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_to_dict.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_to_dict.py @@ -1074,27 +1074,3 @@ def test_custom_form_model_to_dict(self): } } assert d == final - - @FormRecognizerPreparer() - @GlobalClientPreparer() - def test_custom_form_labeled_to_dict(self, client, formrecognizer_storage_container_sas_url): - fr_client = client.get_form_recognizer_client() - - poller = client.begin_training( - formrecognizer_storage_container_sas_url, - use_training_labels=True, - model_name="labeled" - ) - model = poller.result() - - with open(self.form_jpg, "rb") as fd: - myfile = fd.read() - - poller = fr_client.begin_recognize_custom_forms(model.model_id, myfile) - form = poller.result() - - d = form[0].to_dict() - assert d['form_type'] == "custom:labeled" - - self.assertEqual(form[0].form_type, "custom:labeled") - self.assertLabeledRecognizedFormHasValues(form[0], model) From 59e70ce6e8452cf6f8fb07f3ac6c4a8acea39a06 Mon Sep 17 00:00:00 2001 From: Catalina Peralta Date: Fri, 7 May 2021 09:24:37 -0700 Subject: [PATCH 9/9] fix tests --- ...dict.test_custom_form_labeled_to_dict.yaml | 299 ------------------ .../tests/test_compose_model.py | 4 + .../tests/test_compose_model_async.py | 4 + 3 files changed, 8 insertions(+), 299 deletions(-) delete mode 100644 sdk/formrecognizer/azure-ai-formrecognizer/tests/recordings/test_to_dict.test_custom_form_labeled_to_dict.yaml diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/tests/recordings/test_to_dict.test_custom_form_labeled_to_dict.yaml b/sdk/formrecognizer/azure-ai-formrecognizer/tests/recordings/test_to_dict.test_custom_form_labeled_to_dict.yaml deleted file mode 100644 index 1ef72372f489..000000000000 --- a/sdk/formrecognizer/azure-ai-formrecognizer/tests/recordings/test_to_dict.test_custom_form_labeled_to_dict.yaml +++ /dev/null @@ -1,299 +0,0 @@ -interactions: -- request: - body: 'b''{"source": "container_sas_url", "sourceFilter": {"container_sas_urlrefix": - "", "includeSubFolders": false}, "useLabelFile": true, "modelName": "labeled"}''' - headers: - Accept: - - application/json - Accept-Encoding: - - gzip, deflate - Connection: - - keep-alive - Content-Length: - - '319' - Content-Type: - - application/json - User-Agent: - - azsdk-python-ai-formrecognizer/3.1.0 Python/3.8.5 (Windows-10-10.0.19041-SP0) - method: POST - uri: httcontainer_sas_urls://region.acontainer_sas_urli.cognitive.microsoft.com/formrecognizer/v2.1-container_sas_urlreview.3/custom/models - response: - body: - string: '' - headers: - apim-request-id: - - c8da3b6a-d410-4f1f-a9c7-332fae3487b2 - content-length: - - '0' - date: - - Thu, 06 May 2021 20:44:17 GMT - location: - - https://region.api.cognitive.microsoft.com/formrecognizer/v2.1-container_sas_urlreview.3/custom/models/ccbebfdd-fb01-4a73-aa86-479554bf382a - strict-transport-security: - - max-age=31536000; includeSubDomains; preload - x-content-type-options: - - nosniff - x-envoy-upstream-service-time: - - '192' - status: - code: 201 - message: Created -- request: - body: null - headers: - Accept: - - '*/*' - Accept-Encoding: - - gzip, deflate - Connection: - - keep-alive - User-Agent: - - azsdk-python-ai-formrecognizer/3.1.0 Python/3.8.5 (Windows-10-10.0.19041-SP0) - method: GET - uri: httcontainer_sas_urls://region.acontainer_sas_urli.cognitive.microsoft.com/formrecognizer/v2.1-container_sas_urlreview.3/custom/models/ccbebfdd-fb01-4a73-aa86-479554bf382a?includeKeys=true - response: - body: - string: '{"modelInfo": {"modelId": "ccbebfdd-fb01-4a73-aa86-479554bf382a", "modelName": - "labeled", "attributes": {"isComcontainer_sas_urlosed": false}, "status": - "ready", "createdDateTime": "2021-05-06T20:44:18Z", "lastUcontainer_sas_urldatedDateTime": - "2021-05-06T20:44:22Z"}, "trainResult": {"averageModelAccuracy": 0.96, "trainingDocuments": - [{"documentName": "Form_1.jcontainer_sas_urlg", "container_sas_urlages": 1, - "status": "succeeded"}, {"documentName": "Form_2.jcontainer_sas_urlg", "container_sas_urlages": - 1, "status": "succeeded"}, {"documentName": "Form_3.jcontainer_sas_urlg", - "container_sas_urlages": 1, "status": "succeeded"}, {"documentName": "Form_4.jcontainer_sas_urlg", - "container_sas_urlages": 1, "status": "succeeded"}, {"documentName": "Form_5.jcontainer_sas_urlg", - "container_sas_urlages": 1, "status": "succeeded"}], "fields": [{"fieldName": - "Comcontainer_sas_urlanyAddress", "accuracy": 0.8}, {"fieldName": "Comcontainer_sas_urlanyName", - "accuracy": 0.995}, {"fieldName": "Comcontainer_sas_urlanyPhoneNumber", "accuracy": - 0.995}, {"fieldName": "DatedAs", "accuracy": 0.995}, {"fieldName": "Email", - "accuracy": 0.8}, {"fieldName": "Merchant", "accuracy": 0.995}, {"fieldName": - "PhoneNumber", "accuracy": 0.995}, {"fieldName": "PurchaseOrderNumber", "accuracy": - 0.995}, {"fieldName": "Quantity", "accuracy": 0.995}, {"fieldName": "Signature", - "accuracy": 0.8}, {"fieldName": "Subtotal", "accuracy": 0.995}, {"fieldName": - "Tax", "accuracy": 0.995}, {"fieldName": "Total", "accuracy": 0.995}, {"fieldName": - "VendorName", "accuracy": 0.995}, {"fieldName": "Website", "accuracy": 0.995}], - "errors": []}}' - headers: - apim-request-id: - - 325d3cb3-756d-4e35-acfe-859a98bdbaad - content-length: - - '1264' - content-type: - - application/json; charset=utf-8 - date: - - Thu, 06 May 2021 20:44:22 GMT - strict-transport-security: - - max-age=31536000; includeSubDomains; preload - x-content-type-options: - - nosniff - x-envoy-upstream-service-time: - - '26' - status: - code: 200 - message: OK -- request: - body: '!!! The request body has been omitted from the recording because its size - 479269 is larger than 128KB. !!!' - headers: - Accept: - - application/json - Accept-Encoding: - - gzip, deflate - Connection: - - keep-alive - Content-Length: - - '479269' - Content-Type: - - image/jpeg - User-Agent: - - azsdk-python-ai-formrecognizer/3.1.0 Python/3.8.5 (Windows-10-10.0.19041-SP0) - method: POST - uri: httcontainer_sas_urls://region.acontainer_sas_urli.cognitive.microsoft.com/formrecognizer/v2.1-container_sas_urlreview.3/custom/models/ccbebfdd-fb01-4a73-aa86-479554bf382a/analyze?includeTextDetails=false - response: - body: - string: '' - headers: - apim-request-id: - - a1e73183-5cec-434f-9749-1b1da95caaee - content-length: - - '0' - date: - - Thu, 06 May 2021 20:44:25 GMT - operation-location: - - https://region.api.cognitive.microsoft.com/formrecognizer/v2.1-preview.3/custom/models/ccbebfdd-fb01-4a73-aa86-479554bf382a/analyzeresults/e396f280-5ecb-414d-bd97-781bd510eeab - strict-transport-security: - - max-age=31536000; includeSubDomains; preload - x-content-type-options: - - nosniff - x-envoy-upstream-service-time: - - '78' - status: - code: 202 - message: Accepted -- request: - body: null - headers: - Accept: - - '*/*' - Accept-Encoding: - - gzip, deflate - Connection: - - keep-alive - User-Agent: - - azsdk-python-ai-formrecognizer/3.1.0 Python/3.8.5 (Windows-10-10.0.19041-SP0) - method: GET - uri: httcontainer_sas_urls://region.acontainer_sas_urli.cognitive.microsoft.com/formrecognizer/v2.1-container_sas_urlreview.3/custom/models/ccbebfdd-fb01-4a73-aa86-479554bf382a/analyzeresults/e396f280-5ecb-414d-bd97-781bd510eeab - response: - body: - string: '{"status": "notStarted", "createdDateTime": "2021-05-06T20:44:25Z", - "lastUcontainer_sas_urldatedDateTime": "2021-05-06T20:44:29Z"}' - headers: - apim-request-id: - - 847392d0-0ea7-4cf6-80fe-3e076b2b7cf2 - content-length: - - '109' - content-type: - - application/json; charset=utf-8 - date: - - Thu, 06 May 2021 20:44:30 GMT - strict-transport-security: - - max-age=31536000; includeSubDomains; preload - x-content-type-options: - - nosniff - x-envoy-upstream-service-time: - - '19' - status: - code: 200 - message: OK -- request: - body: null - headers: - Accept: - - '*/*' - Accept-Encoding: - - gzip, deflate - Connection: - - keep-alive - User-Agent: - - azsdk-python-ai-formrecognizer/3.1.0 Python/3.8.5 (Windows-10-10.0.19041-SP0) - method: GET - uri: httcontainer_sas_urls://region.acontainer_sas_urli.cognitive.microsoft.com/formrecognizer/v2.1-container_sas_urlreview.3/custom/models/ccbebfdd-fb01-4a73-aa86-479554bf382a/analyzeresults/e396f280-5ecb-414d-bd97-781bd510eeab - response: - body: - string: '{"status": "succeeded", "createdDateTime": "2021-05-06T20:44:25Z", - "lastUcontainer_sas_urldatedDateTime": "2021-05-06T20:44:32Z", "analyzeResult": - {"version": "2.1.0", "readResults": [{"container_sas_urlage": 1, "angle": - 0, "width": 1700, "height": 2200, "unit": "container_sas_urlixel"}], "container_sas_urlageResults": - [{"container_sas_urlage": 1, "tables": [{"rows": 5, "columns": 5, "cells": - [{"rowIndex": 0, "columnIndex": 0, "columnScontainer_sas_urlan": 2, "text": - "Details", "boundingBox": [157, 1038, 847, 1037, 847, 1086, 157, 1086]}, {"rowIndex": - 0, "columnIndex": 2, "text": "Quantity", "boundingBox": [847, 1037, 1071, - 1037, 1071, 1086, 847, 1086]}, {"rowIndex": 0, "columnIndex": 3, "text": "Unit - Price", "boundingBox": [1071, 1037, 1310, 1038, 1310, 1086, 1071, 1086]}, - {"rowIndex": 0, "columnIndex": 4, "text": "Total", "boundingBox": [1310, 1038, - 1543, 1038, 1543, 1086, 1310, 1086]}, {"rowIndex": 1, "columnIndex": 0, "columnScontainer_sas_urlan": - 2, "text": "Bindings", "boundingBox": [157, 1086, 847, 1086, 847, 1127, 157, - 1128]}, {"rowIndex": 1, "columnIndex": 2, "text": "20", "boundingBox": [847, - 1086, 1071, 1086, 1071, 1127, 847, 1127]}, {"rowIndex": 1, "columnIndex": - 3, "text": "1.00", "boundingBox": [1071, 1086, 1310, 1086, 1310, 1127, 1071, - 1127]}, {"rowIndex": 1, "columnIndex": 4, "text": "20.00", "boundingBox": - [1310, 1086, 1543, 1086, 1543, 1127, 1310, 1127]}, {"rowIndex": 2, "columnIndex": - 0, "columnScontainer_sas_urlan": 2, "text": "Covers Small", "boundingBox": - [157, 1128, 847, 1127, 847, 1171, 157, 1171]}, {"rowIndex": 2, "columnIndex": - 2, "text": "20", "boundingBox": [847, 1127, 1071, 1127, 1071, 1171, 847, 1171]}, - {"rowIndex": 2, "columnIndex": 3, "text": "1.00", "boundingBox": [1071, 1127, - 1310, 1127, 1310, 1171, 1071, 1171]}, {"rowIndex": 2, "columnIndex": 4, "text": - "20.00", "boundingBox": [1310, 1127, 1543, 1127, 1543, 1171, 1310, 1171]}, - {"rowIndex": 3, "columnIndex": 0, "columnScontainer_sas_urlan": 2, "text": - "Feather Bookmark", "boundingBox": [157, 1171, 847, 1171, 847, 1214, 157, - 1214]}, {"rowIndex": 3, "columnIndex": 2, "text": "20", "boundingBox": [847, - 1171, 1071, 1171, 1071, 1214, 847, 1214]}, {"rowIndex": 3, "columnIndex": - 3, "text": "5.00", "boundingBox": [1071, 1171, 1310, 1171, 1310, 1214, 1071, - 1214]}, {"rowIndex": 3, "columnIndex": 4, "text": "100.00", "boundingBox": - [1310, 1171, 1543, 1171, 1543, 1215, 1310, 1214]}, {"rowIndex": 4, "columnIndex": - 0, "columnScontainer_sas_urlan": 2, "text": "Cocontainer_sas_urlcontainer_sas_urler - Swirl Marker", "boundingBox": [157, 1214, 847, 1214, 847, 1258, 157, 1258]}, - {"rowIndex": 4, "columnIndex": 2, "text": "20", "boundingBox": [847, 1214, - 1071, 1214, 1071, 1258, 847, 1258]}, {"rowIndex": 4, "columnIndex": 3, "text": - "5.00", "boundingBox": [1071, 1214, 1310, 1214, 1310, 1258, 1071, 1258]}, - {"rowIndex": 4, "columnIndex": 4, "text": "100.00", "boundingBox": [1310, - 1214, 1543, 1215, 1543, 1260, 1310, 1258]}], "boundingBox": [153, 1036, 1547, - 1037, 1547, 1265, 153, 1265]}, {"rows": 4, "columns": 2, "cells": [{"rowIndex": - 0, "columnIndex": 0, "text": "SUBTOTAL", "boundingBox": [1072, 1564, 1307, - 1565, 1308, 1609, 1071, 1608]}, {"rowIndex": 0, "columnIndex": 1, "text": - "$140.00", "boundingBox": [1307, 1565, 1542, 1564, 1543, 1609, 1308, 1609]}, - {"rowIndex": 1, "columnIndex": 0, "text": "TAX", "boundingBox": [1071, 1608, - 1308, 1609, 1308, 1652, 1071, 1651]}, {"rowIndex": 1, "columnIndex": 1, "text": - "$4.00", "boundingBox": [1308, 1609, 1543, 1609, 1543, 1652, 1308, 1652]}, - {"rowIndex": 2, "columnIndex": 0, "text": "", "boundingBox": [1071, 1651, - 1308, 1652, 1308, 1663, 1071, 1663]}, {"rowIndex": 2, "columnIndex": 1, "text": - "", "boundingBox": [1308, 1652, 1543, 1652, 1543, 1663, 1308, 1663]}, {"rowIndex": - 3, "columnIndex": 0, "text": "TOTAL", "boundingBox": [1071, 1663, 1308, 1663, - 1308, 1707, 1071, 1707]}, {"rowIndex": 3, "columnIndex": 1, "text": "$144.00", - "boundingBox": [1308, 1663, 1543, 1663, 1543, 1708, 1308, 1707]}], "boundingBox": - [1058, 1563, 1555, 1563, 1555, 1707, 1058, 1707]}]}], "documentResults": [{"docTycontainer_sas_urle": - "custom:labeled", "modelId": "ccbebfdd-fb01-4a73-aa86-479554bf382a", "container_sas_urlageRange": - [1, 1], "fields": {"Comcontainer_sas_urlanyPhoneNumber": {"tycontainer_sas_urle": - "string", "valueString": "938-294-2949", "text": "938-294-2949", "container_sas_urlage": - 1, "boundingBox": [709.0, 722.0, 882.0, 722.0, 882.0, 749.0, 709.0, 749.0], - "confidence": 0.995}, "Merchant": {"tycontainer_sas_urle": "string", "valueString": - "Hero Limited", "text": "Hero Limited", "container_sas_urlage": 1, "boundingBox": - [620.0, 205.0, 1062.0, 205.0, 1062.0, 266.0, 620.0, 266.0], "confidence": - 0.995}, "Signature": {"tycontainer_sas_urle": "string", "valueString": "Bernie - Sanders", "text": "Bernie Sanders", "container_sas_urlage": 1, "boundingBox": - [484.0, 1670.0, 762.0, 1670.0, 762.0, 1708.0, 484.0, 1708.0], "confidence": - 0.995}, "DatedAs": {"tycontainer_sas_urle": "string", "valueString": "12/20/2020", - "text": "12/20/2020", "container_sas_urlage": 1, "boundingBox": [1163.0, 420.0, - 1310.0, 420.0, 1310.0, 449.0, 1163.0, 449.0], "confidence": 0.995}, "Email": - {"tycontainer_sas_urle": "string", "valueString": "accounts@herolimited.com", - "text": "accounts@herolimited.com", "container_sas_urlage": 1, "boundingBox": - [164.0, 479.0, 471.0, 479.0, 471.0, 503.0, 164.0, 503.0], "confidence": 0.995}, - "VendorName": {"tycontainer_sas_urle": "string", "valueString": "Hillary Swank", - "text": "Hillary Swank", "container_sas_urlage": 1, "boundingBox": [349.0, - 609.0, 520.0, 609.0, 520.0, 639.0, 349.0, 639.0], "confidence": 0.995}, "Tax": - {"tycontainer_sas_urle": "string", "valueString": "$4.00", "text": "$4.00", - "container_sas_urlage": 1, "boundingBox": [1458.0, 1615.0, 1529.0, 1615.0, - 1529.0, 1643.0, 1458.0, 1643.0], "confidence": 0.995}, "Website": {"tycontainer_sas_urle": - "string", "valueString": "www.herolimited.com", "text": "www.herolimited.com", - "container_sas_urlage": 1, "boundingBox": [273.0, 393.0, 524.0, 393.0, 524.0, - 418.0, 273.0, 418.0], "confidence": 0.995}, "Comcontainer_sas_urlanyAddress": - {"tycontainer_sas_urle": "string", "valueString": "938 NE Burner Road Boulder - City, CO 92848", "text": "938 NE Burner Road Boulder City, CO 92848", "container_sas_urlage": - 1, "boundingBox": [275.0, 685.0, 561.0, 685.0, 561.0, 751.0, 275.0, 751.0], - "confidence": 0.995}, "Quantity": {"tycontainer_sas_urle": "number", "text": - "20", "container_sas_urlage": 1, "boundingBox": [860.0, 1094.0, 888.0, 1094.0, - 888.0, 1119.0, 860.0, 1119.0], "confidence": 0.995}, "Total": {"tycontainer_sas_urle": - "string", "valueString": "$144.00", "text": "$144.00", "container_sas_urlage": - 1, "boundingBox": [1427.0, 1669.0, 1527.0, 1669.0, 1527.0, 1698.0, 1427.0, - 1698.0], "confidence": 0.995}, "PurchaseOrderNumber": {"tycontainer_sas_urle": - "string", "valueString": "948284", "text": "948284", "container_sas_urlage": - 1, "boundingBox": [1278.0, 461.0, 1372.0, 461.0, 1372.0, 489.0, 1278.0, 489.0], - "confidence": 0.995}, "PhoneNumber": {"tycontainer_sas_urle": "string", "valueString": - "555-348-6512", "text": "555-348-6512", "container_sas_urlage": 1, "boundingBox": - [365.0, 351.0, 525.0, 351.0, 525.0, 378.0, 365.0, 378.0], "confidence": 0.995}, - "Comcontainer_sas_urlanyName": {"tycontainer_sas_urle": "string", "valueString": - "Higgly Wiggly Books", "text": "Higgly Wiggly Books", "container_sas_urlage": - 1, "boundingBox": [375.0, 646.0, 629.0, 646.0, 629.0, 679.0, 375.0, 679.0], - "confidence": 0.995}, "Subtotal": {"tycontainer_sas_urle": "string", "valueString": - "$140.00", "text": "$140.00", "container_sas_urlage": 1, "boundingBox": [1428.0, - 1572.0, 1528.0, 1572.0, 1528.0, 1599.0, 1428.0, 1599.0], "confidence": 0.995}}, - "docTycontainer_sas_urleConfidence": 0.92}], "errors": []}}' - headers: - apim-request-id: - - d62728ce-21db-4a84-a9e5-6bbd3b017ad0 - content-length: - - '6200' - content-type: - - application/json; charset=utf-8 - date: - - Thu, 06 May 2021 20:44:35 GMT - strict-transport-security: - - max-age=31536000; includeSubDomains; preload - x-content-type-options: - - nosniff - x-envoy-upstream-service-time: - - '18' - status: - code: 200 - message: OK -version: 1 diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_compose_model.py b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_compose_model.py index 0972c6558b61..d2c21c0fc25d 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_compose_model.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_compose_model.py @@ -33,6 +33,10 @@ def test_compose_model_with_model_name(self, client, formrecognizer_storage_cont self.assertEqual(composed_model.model_name, "my composed model") self.assertComposedModelHasValues(composed_model, model_1, model_2) + composed_model_dict = composed_model.to_dict() + self.assertEqual(composed_model_dict.get("model_name"), "my composed model") + self.assertIsNotNone(composed_model_dict.get("model_id")) + @FormRecognizerPreparer() @GlobalClientPreparer() def test_compose_model_no_model_name(self, client, formrecognizer_storage_container_sas_url): diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_compose_model_async.py b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_compose_model_async.py index 053bc0e66890..9cd1b66cba14 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_compose_model_async.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_compose_model_async.py @@ -33,6 +33,10 @@ async def test_compose_model_with_model_name(self, client, formrecognizer_storag self.assertEqual(composed_model.model_name, "my composed model") self.assertComposedModelHasValues(composed_model, model_1, model_2) + composed_model_dict = composed_model.to_dict() + self.assertEqual(composed_model_dict.get("model_name"), "my composed model") + self.assertIsNotNone(composed_model_dict.get("model_id")) + @FormRecognizerPreparer() @GlobalClientPreparer() async def test_compose_model_no_model_name(self, client, formrecognizer_storage_container_sas_url):