Skip to content

Commit 5952554

Browse files
✨ add object field convenience accessors (#384)
1 parent 23f40bb commit 5952554

File tree

4 files changed

+111
-10
lines changed

4 files changed

+111
-10
lines changed

mindee/parsing/v2/field/object_field.py

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
1+
from typing import TYPE_CHECKING, Dict, cast
12
from mindee.parsing.common.string_dict import StringDict
23
from mindee.parsing.v2.field.base_field import BaseField
34
from mindee.parsing.v2.field.dynamic_field import FieldType
45
from mindee.parsing.v2.field.inference_fields import InferenceFields
56

7+
if TYPE_CHECKING:
8+
from mindee.parsing.v2.field.list_field import ListField
9+
from mindee.parsing.v2.field.simple_field import SimpleField
10+
611

712
class ObjectField(BaseField):
813
"""Object field containing multiple fields."""
@@ -37,5 +42,86 @@ def multi_str(self) -> str:
3742
first = False
3843
return out_str
3944

45+
@property
46+
def simple_fields(self) -> Dict[str, "SimpleField"]:
47+
"""
48+
Extract and return all SimpleField fields from the `fields` attribute.
49+
50+
:return: A dictionary containing all fields that have a type of `FieldType.SIMPLE`.
51+
"""
52+
simple_fields = {}
53+
for field_key, field_value in self.fields.items():
54+
if field_value.field_type == FieldType.SIMPLE:
55+
simple_fields[field_key] = cast("SimpleField", field_value)
56+
return simple_fields
57+
58+
@property
59+
def list_fields(self) -> Dict[str, "ListField"]:
60+
"""
61+
Retrieves all ListField fields from the `fields` attribute.
62+
63+
:return: A dictionary containing all fields of type `LIST`, with keys
64+
representing field keys and values being the corresponding field
65+
objects.
66+
"""
67+
list_fields = {}
68+
for field_key, field_value in self.fields.items():
69+
if field_value.field_type == FieldType.LIST:
70+
list_fields[field_key] = cast("ListField", field_value)
71+
return list_fields
72+
73+
@property
74+
def object_fields(self) -> Dict[str, "ObjectField"]:
75+
"""
76+
Retrieves all ObjectField fields from the `fields` attribute of the instance.
77+
78+
:returns: A dictionary containing fields of type `FieldType.OBJECT`. The keys represent
79+
the field names, and the values are corresponding ObjectField objects.
80+
"""
81+
object_fields = {}
82+
for field_key, field_value in self.fields.items():
83+
if field_value.field_type == FieldType.OBJECT:
84+
object_fields[field_key] = cast("ObjectField", field_value)
85+
return object_fields
86+
87+
def get_simple_field(self, field_name: str) -> "SimpleField":
88+
"""
89+
Retrieves a SimpleField from the provided field name.
90+
91+
:param field_name: The name of the field to retrieve.
92+
:type field_name: str
93+
:return: The SimpleField object corresponding to the given field name.
94+
:raises ValueError: If the specified field is not of type SimpleField.
95+
"""
96+
if self.fields[field_name].field_type != FieldType.SIMPLE:
97+
raise ValueError(f"Field {field_name} is not a SimpleField.")
98+
return cast("SimpleField", self.fields[field_name])
99+
100+
def get_list_field(self, field_name: str) -> "ListField":
101+
"""
102+
Retrieves the ``ListField`` for the specified field name.
103+
104+
:param field_name: The name of the field to retrieve.
105+
:type field_name: str
106+
:return: The corresponding ``ListField`` for the given field name.
107+
:raises ValueError: If the field is not of type ``ListField``.
108+
"""
109+
if self.fields[field_name].field_type != FieldType.LIST:
110+
raise ValueError(f"Field {field_name} is not a ListField.")
111+
return cast("ListField", self.fields[field_name])
112+
113+
def get_object_field(self, field_name: str) -> "ObjectField":
114+
"""
115+
Retrieves the `ObjectField` associated with the specified field name.
116+
117+
:param field_name: The name of the field to retrieve.
118+
:type field_name: str
119+
:return: The `ObjectField` associated with the given field name.
120+
:raises ValueError: If the field specified by `field_name` is not an `ObjectField`.
121+
"""
122+
if self.fields[field_name].field_type != FieldType.OBJECT:
123+
raise ValueError(f"Field {field_name} is not an ObjectField.")
124+
return cast("ObjectField", self.fields[field_name])
125+
40126
def __str__(self) -> str:
41127
return self.single_str()

tests/utils.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717

1818
V2_DATA_DIR = ROOT_DATA_DIR / "v2"
1919
V2_PRODUCT_DATA_DIR = V2_DATA_DIR / "products"
20-
V2_UTILITIES_DATA_DIR = V2_DATA_DIR / "utilities"
2120

2221

2322
def clear_envvars(monkeypatch) -> None:

tests/v2/input/__init__.py

Whitespace-only changes.

tests/v2/product/extraction/test_extraction_response.py

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,10 @@
66

77
from mindee import InferenceResponse
88
from mindee.parsing.v2 import InferenceActiveOptions
9-
from mindee.parsing.v2.field import FieldConfidence, ListField, ObjectField, SimpleField
9+
from mindee.parsing.v2.field.field_confidence import FieldConfidence
10+
from mindee.parsing.v2.field.list_field import ListField
11+
from mindee.parsing.v2.field.object_field import ObjectField
12+
from mindee.parsing.v2.field.simple_field import SimpleField
1013
from mindee.parsing.v2.field.inference_fields import InferenceFields
1114
from mindee.parsing.v2.inference import Inference
1215
from mindee.parsing.v2.inference_file import InferenceFile
@@ -53,42 +56,54 @@ def test_deep_nested_fields():
5356
response.inference.result.fields["field_object"].fields["sub_object_object"],
5457
ObjectField,
5558
)
59+
fields = response.inference.result.fields
60+
assert isinstance(fields.get("field_object"), ObjectField)
5661
assert isinstance(
57-
response.inference.result.fields["field_object"]
58-
.fields["sub_object_object"]
59-
.fields,
62+
fields.get("field_object").get_simple_field("sub_object_simple"), SimpleField
63+
)
64+
assert isinstance(
65+
fields.get("field_object").get_list_field("sub_object_list"), ListField
66+
)
67+
assert isinstance(
68+
fields.get("field_object").get_object_field("sub_object_object"), ObjectField
69+
)
70+
assert len(fields.get("field_object").simple_fields) == 1
71+
assert len(fields.get("field_object").list_fields) == 1
72+
assert len(fields.get("field_object").object_fields) == 1
73+
assert isinstance(
74+
fields["field_object"].fields["sub_object_object"].fields,
6075
dict,
6176
)
6277
assert isinstance(
63-
response.inference.result.fields["field_object"]
78+
fields["field_object"]
6479
.fields["sub_object_object"]
6580
.fields["sub_object_object_sub_object_list"],
6681
ListField,
6782
)
6883
assert isinstance(
69-
response.inference.result.fields["field_object"]
84+
fields["field_object"]
7085
.fields["sub_object_object"]
7186
.fields["sub_object_object_sub_object_list"]
7287
.items,
7388
list,
7489
)
7590
assert isinstance(
76-
response.inference.result.fields["field_object"]
91+
fields["field_object"]
7792
.fields["sub_object_object"]
7893
.fields["sub_object_object_sub_object_list"]
7994
.items[0],
8095
ObjectField,
8196
)
8297
assert isinstance(
83-
response.inference.result.fields["field_object"]
98+
fields["field_object"]
8499
.fields["sub_object_object"]
85100
.fields["sub_object_object_sub_object_list"]
86101
.items[0]
87102
.fields["sub_object_object_sub_object_list_simple"],
88103
SimpleField,
89104
)
90105
assert (
91-
response.inference.result.fields["field_object"]
106+
fields["field_object"]
92107
.fields["sub_object_object"]
93108
.fields["sub_object_object_sub_object_list"]
94109
.items[0]
@@ -103,6 +118,7 @@ def test_standard_field_types():
103118
json_sample, rst_sample = _get_inference_samples("standard_field_types")
104119
response = InferenceResponse(json_sample)
105120
assert isinstance(response.inference, Inference)
121+
106122
field_simple_string = response.inference.result.fields["field_simple_string"]
107123
assert isinstance(field_simple_string, SimpleField)
108124
assert field_simple_string.value == "field_simple_string-value"

0 commit comments

Comments
 (0)