From 04aea46d3d28d9b5836f18e3ba018cdab97183e7 Mon Sep 17 00:00:00 2001 From: Nicolas Drebenstedt <897972+cutoffthetop@users.noreply.github.com> Date: Tue, 10 Dec 2024 13:47:09 +0100 Subject: [PATCH] feature/mx-1649 add preview models and api method (#347) ### PR Context - prep for https://github.com/robert-koch-institut/mex-editor/pull/192 - preview models don't care about required fields and length limits for lists - they will be used by the editor to be able to search even for potentially "broken" items - also includes some clean-up of the `mex.common.models` module (imports, exports and docs) ### Added - add preview models for merged items without cardinality validation - BREAKING: preview models are now part of all `mex.common.fields` lookups - add `BackendApiConnector.fetch_preview_items` for fetching previews ### Deprecated - stop using `ExtractedData`, use `AnyExtractedModel` instead - stop using `MergedItem`, use `AnyMergedModel` instead - stop using `AdditiveRule`, use `AnyAdditiveRule` instead - stop using `SubtractiveRule`, use `AnySubtractiveRule` instead - stop using `PreventiveRule`, use `AnyPreventiveRule` instead - stop using `BaseEntity`, use a concrete union instead ### Removed - removed deprecated `BulkInsertResponse` as alias for `IdentifiersResponse` - removed unused module export of `mex.common.models.generate_entity_filter_schema` - removed unused module export of `mex.common.models.generate_mapping_schema` - drop export `models.ExtractedPrimarySourceIdentifier`, import from `types` instead - drop export `models.MergedPrimarySourceIdentifier`, import from `types` instead --- CHANGELOG.md | 17 +++++++ mex/common/backend_api/connector.py | 35 +++++++++++++ mex/common/backend_api/models.py | 9 +++- mex/common/fields.py | 2 + mex/common/models/__init__.py | 54 +++++++++++++++++++-- mex/common/models/access_platform.py | 18 +++++-- mex/common/models/activity.py | 16 ++++-- mex/common/models/base/entity.py | 9 ++-- mex/common/models/base/extracted_data.py | 4 +- mex/common/models/base/preview_item.py | 5 ++ mex/common/models/bibliographic_resource.py | 18 +++++-- mex/common/models/consent.py | 16 ++++-- mex/common/models/contact_point.py | 16 ++++-- mex/common/models/distribution.py | 16 ++++-- mex/common/models/organization.py | 16 ++++-- mex/common/models/organizational_unit.py | 18 +++++-- mex/common/models/person.py | 16 ++++-- mex/common/models/primary_source.py | 16 ++++-- mex/common/models/resource.py | 18 +++++-- mex/common/models/variable.py | 16 ++++-- mex/common/models/variable_group.py | 16 ++++-- tests/backend_api/test_connector.py | 33 ++++++++++++- tests/conftest.py | 11 +++++ tests/models/test_extracted_data.py | 4 +- tests/models/test_filter.py | 3 +- tests/models/test_mapping.py | 3 +- tests/sinks/test_ndjson.py | 14 +++--- tests/test_fields.py | 14 +++--- 28 files changed, 364 insertions(+), 69 deletions(-) create mode 100644 mex/common/models/base/preview_item.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 4974df1f..ce1c3b6b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,12 +9,29 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- add preview models for merged items without cardinality validation +- BREAKING: preview models are now part of all `mex.common.fields` lookups +- add `BackendApiConnector.fetch_preview_items` for fetching previews + ### Changes ### Deprecated +- stop using `ExtractedData`, use `AnyExtractedModel` instead +- stop using `MergedItem`, use `AnyMergedModel` instead +- stop using `AdditiveRule`, use `AnyAdditiveRule` instead +- stop using `SubtractiveRule`, use `AnySubtractiveRule` instead +- stop using `PreventiveRule`, use `AnyPreventiveRule` instead +- stop using `BaseEntity`, use a concrete union instead + ### Removed +- removed deprecated `BulkInsertResponse` as alias for `IdentifiersResponse` +- removed unused module export of `mex.common.models.generate_entity_filter_schema` +- removed unused module export of `mex.common.models.generate_mapping_schema` +- drop export `models.ExtractedPrimarySourceIdentifier`, import from `types` instead +- drop export `models.MergedPrimarySourceIdentifier`, import from `types` instead + ### Fixed ### Security diff --git a/mex/common/backend_api/connector.py b/mex/common/backend_api/connector.py index 2be5ebe0..2e8cb750 100644 --- a/mex/common/backend_api/connector.py +++ b/mex/common/backend_api/connector.py @@ -8,6 +8,7 @@ IdentifiersResponse, MergedItemsResponse, MergedModelTypeAdapter, + PreviewItemsResponse, RuleSetResponseTypeAdapter, ) from mex.common.connector import HTTPConnector @@ -185,6 +186,40 @@ def preview_merged_item( ) return MergedModelTypeAdapter.validate_python(response) + def fetch_preview_items( + self, + query_string: str | None, + entity_type: list[str] | None, + skip: int, + limit: int, + ) -> PreviewItemsResponse: + """Fetch merged item previews that match the given set of filters. + + Args: + query_string: Full-text search query + entity_type: The item's entityType + skip: How many items to skip for pagination + limit: How many items to return in one page + + Raises: + HTTPError: If search was not accepted, crashes or times out + + Returns: + One page of preview items and the total count that was matched + """ + # Note: this is forward-compat for MX-1649, backend might not support this yet! + response = self.request( + method="GET", + endpoint="preview-item", + params={ + "q": query_string, + "entityType": entity_type, + "skip": str(skip), + "limit": str(limit), + }, + ) + return PreviewItemsResponse.model_validate(response) + def get_rule_set( self, stable_target_id: str, diff --git a/mex/common/backend_api/models.py b/mex/common/backend_api/models.py index 2a7057a0..2b37ddbf 100644 --- a/mex/common/backend_api/models.py +++ b/mex/common/backend_api/models.py @@ -5,6 +5,7 @@ from mex.common.models import ( AnyExtractedModel, AnyMergedModel, + AnyPreviewModel, AnyRuleSetResponse, BaseModel, ) @@ -31,6 +32,13 @@ class MergedItemsResponse(BaseModel): total: int +class PreviewItemsResponse(BaseModel): + """Response model for a list of preview items including a total count.""" + + items: list[AnyPreviewModel] + total: int + + class IdentifiersResponse(BaseModel): """Response models for a list of identifiers.""" @@ -43,4 +51,3 @@ class IdentifiersResponse(BaseModel): RuleSetResponseTypeAdapter: TypeAdapter[AnyRuleSetResponse] = TypeAdapter( Annotated[AnyRuleSetResponse, Field(discriminator="entityType")] ) -BulkInsertResponse = IdentifiersResponse # deprecated diff --git a/mex/common/fields.py b/mex/common/fields.py index 55abf0f2..ed51fc6b 100644 --- a/mex/common/fields.py +++ b/mex/common/fields.py @@ -3,6 +3,7 @@ EXTRACTED_MODEL_CLASSES_BY_NAME, MERGED_MODEL_CLASSES_BY_NAME, PREVENTIVE_MODEL_CLASSES_BY_NAME, + PREVIEW_MODEL_CLASSES_BY_NAME, SUBTRACTIVE_MODEL_CLASSES_BY_NAME, ) from mex.common.types import ( @@ -21,6 +22,7 @@ **ADDITIVE_MODEL_CLASSES_BY_NAME, **EXTRACTED_MODEL_CLASSES_BY_NAME, **MERGED_MODEL_CLASSES_BY_NAME, + **PREVIEW_MODEL_CLASSES_BY_NAME, **PREVENTIVE_MODEL_CLASSES_BY_NAME, **SUBTRACTIVE_MODEL_CLASSES_BY_NAME, } diff --git a/mex/common/models/__init__.py b/mex/common/models/__init__.py index 9b5159c8..13962708 100644 --- a/mex/common/models/__init__.py +++ b/mex/common/models/__init__.py @@ -21,6 +21,7 @@ - `BaseT` defines all fields according to `mex-model` except for provenance fields - `ExtractedT` defines an automatically extracted metadata item including provenance - `MergedT` defines the result of merging extracted items and rules into a single item +- `PreviewT` defines a preview of a merged item without enforcing cardinality validation - `AdditiveT` defines a rule to add values to specific fields of a merged item - `SubtractiveT` defines a rule to subtract (or block) specific values for specific @@ -54,6 +55,7 @@ - BaseT: _OptionalLists, _RequiredLists, _OptionalValues, _RequiredValues - ExtractedT: BaseT, ExtractedData - MergedT: BaseT, MergedItem +- PreviewT: _OptionalLists, _SparseLists, _OptionalValues, _SparseValues, PreviewItem - AdditiveT: _OptionalLists, _SparseLists, _OptionalValues, _SparseValues, AdditiveRule - SubtractiveT: _OptionalLists, _SparseLists, _VariadicValues, SubtractiveRule @@ -78,6 +80,7 @@ ExtractedAccessPlatform, MergedAccessPlatform, PreventiveAccessPlatform, + PreviewAccessPlatform, SubtractiveAccessPlatform, ) from mex.common.models.activity import ( @@ -88,6 +91,7 @@ ExtractedActivity, MergedActivity, PreventiveActivity, + PreviewActivity, SubtractiveActivity, ) from mex.common.models.base.extracted_data import ExtractedData @@ -105,6 +109,7 @@ ExtractedBibliographicResource, MergedBibliographicResource, PreventiveBibliographicResource, + PreviewBibliographicResource, SubtractiveBibliographicResource, ) from mex.common.models.consent import ( @@ -115,6 +120,7 @@ ExtractedConsent, MergedConsent, PreventiveConsent, + PreviewConsent, SubtractiveConsent, ) from mex.common.models.contact_point import ( @@ -125,6 +131,7 @@ ExtractedContactPoint, MergedContactPoint, PreventiveContactPoint, + PreviewContactPoint, SubtractiveContactPoint, ) from mex.common.models.distribution import ( @@ -135,6 +142,7 @@ ExtractedDistribution, MergedDistribution, PreventiveDistribution, + PreviewDistribution, SubtractiveDistribution, ) from mex.common.models.organization import ( @@ -145,6 +153,7 @@ OrganizationRuleSetRequest, OrganizationRuleSetResponse, PreventiveOrganization, + PreviewOrganization, SubtractiveOrganization, ) from mex.common.models.organizational_unit import ( @@ -155,6 +164,7 @@ OrganizationalUnitRuleSetRequest, OrganizationalUnitRuleSetResponse, PreventiveOrganizationalUnit, + PreviewOrganizationalUnit, SubtractiveOrganizationalUnit, ) from mex.common.models.person import ( @@ -165,6 +175,7 @@ PersonRuleSetRequest, PersonRuleSetResponse, PreventivePerson, + PreviewPerson, SubtractivePerson, ) from mex.common.models.primary_source import ( @@ -173,6 +184,7 @@ ExtractedPrimarySource, MergedPrimarySource, PreventivePrimarySource, + PreviewPrimarySource, PrimarySourceRuleSetRequest, PrimarySourceRuleSetResponse, SubtractivePrimarySource, @@ -183,6 +195,7 @@ ExtractedResource, MergedResource, PreventiveResource, + PreviewResource, ResourceRuleSetRequest, ResourceRuleSetResponse, SubtractiveResource, @@ -193,6 +206,7 @@ ExtractedVariable, MergedVariable, PreventiveVariable, + PreviewVariable, SubtractiveVariable, VariableRuleSetRequest, VariableRuleSetResponse, @@ -203,6 +217,7 @@ ExtractedVariableGroup, MergedVariableGroup, PreventiveVariableGroup, + PreviewVariableGroup, SubtractiveVariableGroup, VariableGroupRuleSetRequest, VariableGroupRuleSetResponse, @@ -294,7 +309,6 @@ "ExtractedOrganizationalUnit", "ExtractedPerson", "ExtractedPrimarySource", - "ExtractedPrimarySourceIdentifier", "ExtractedResource", "ExtractedVariable", "ExtractedVariableGroup", @@ -310,7 +324,6 @@ "MergedOrganizationalUnit", "MergedPerson", "MergedPrimarySource", - "MergedPrimarySourceIdentifier", "MergedResource", "MergedVariable", "MergedVariableGroup", @@ -334,6 +347,19 @@ "PreventiveRule", "PreventiveVariable", "PreventiveVariableGroup", + "PreviewAccessPlatform", + "PreviewActivity", + "PreviewBibliographicResource", + "PreviewConsent", + "PreviewContactPoint", + "PreviewDistribution", + "PreviewOrganization", + "PreviewOrganizationalUnit", + "PreviewPerson", + "PreviewPrimarySource", + "PreviewResource", + "PreviewVariable", + "PreviewVariableGroup", "PrimarySourceRuleSetRequest", "PrimarySourceRuleSetResponse", "ResourceRuleSetRequest", @@ -356,8 +382,6 @@ "VariableGroupRuleSetResponse", "VariableRuleSetRequest", "VariableRuleSetResponse", - "generate_entity_filter_schema", - "generate_mapping_schema", ) MEX_PRIMARY_SOURCE_IDENTIFIER = ExtractedPrimarySourceIdentifier("00000000000001") @@ -426,6 +450,28 @@ cls.__name__: cls for cls in MERGED_MODEL_CLASSES } +AnyPreviewModel = ( + PreviewAccessPlatform + | PreviewActivity + | PreviewBibliographicResource + | PreviewConsent + | PreviewContactPoint + | PreviewDistribution + | PreviewOrganization + | PreviewOrganizationalUnit + | PreviewPerson + | PreviewPrimarySource + | PreviewResource + | PreviewVariable + | PreviewVariableGroup +) +PREVIEW_MODEL_CLASSES: Final[list[type[AnyPreviewModel]]] = list( + get_args(AnyPreviewModel) +) +PREVIEW_MODEL_CLASSES_BY_NAME: Final[dict[str, type[AnyPreviewModel]]] = { + cls.__name__: cls for cls in PREVIEW_MODEL_CLASSES +} + AnyAdditiveModel = ( AdditiveAccessPlatform | AdditiveActivity diff --git a/mex/common/models/access_platform.py b/mex/common/models/access_platform.py index 12c46e47..54426e9f 100644 --- a/mex/common/models/access_platform.py +++ b/mex/common/models/access_platform.py @@ -7,6 +7,7 @@ from mex.common.models.base.extracted_data import ExtractedData from mex.common.models.base.merged_item import MergedItem from mex.common.models.base.model import BaseModel +from mex.common.models.base.preview_item import PreviewItem from mex.common.models.base.rules import ( AdditiveRule, PreventiveRule, @@ -85,18 +86,18 @@ class ExtractedAccessPlatform(BaseAccessPlatform, ExtractedData): @computed_field # type: ignore[prop-decorator] @property def identifier(self) -> ExtractedAccessPlatformIdentifier: - """Return the computed identifier for this extracted data item.""" + """Return the computed identifier for this extracted item.""" return self._get_identifier(ExtractedAccessPlatformIdentifier) @computed_field # type: ignore[prop-decorator] @property def stableTargetId(self) -> MergedAccessPlatformIdentifier: # noqa: N802 - """Return the computed stableTargetId for this extracted data item.""" + """Return the computed stableTargetId for this extracted item.""" return self._get_stable_target_id(MergedAccessPlatformIdentifier) class MergedAccessPlatform(BaseAccessPlatform, MergedItem): - """The result of merging all extracted data and rules for an access platform.""" + """The result of merging all extracted items and rules for an access platform.""" entityType: Annotated[ Literal["MergedAccessPlatform"], Field(alias="$type", frozen=True) @@ -104,6 +105,17 @@ class MergedAccessPlatform(BaseAccessPlatform, MergedItem): identifier: Annotated[MergedAccessPlatformIdentifier, Field(frozen=True)] +class PreviewAccessPlatform( + _OptionalLists, _OptionalValues, _SparseValues, PreviewItem +): + """Preview for merging all extracted items and rules for an access platform.""" + + entityType: Annotated[ + Literal["PreviewAccessPlatform"], Field(alias="$type", frozen=True) + ] = "PreviewAccessPlatform" + identifier: Annotated[MergedAccessPlatformIdentifier, Field(frozen=True)] + + class AdditiveAccessPlatform( _OptionalLists, _OptionalValues, _SparseValues, AdditiveRule ): diff --git a/mex/common/models/activity.py b/mex/common/models/activity.py index 83db3ead..0258ca60 100644 --- a/mex/common/models/activity.py +++ b/mex/common/models/activity.py @@ -10,6 +10,7 @@ from mex.common.models.base.extracted_data import ExtractedData from mex.common.models.base.merged_item import MergedItem from mex.common.models.base.model import BaseModel +from mex.common.models.base.preview_item import PreviewItem from mex.common.models.base.rules import ( AdditiveRule, PreventiveRule, @@ -110,18 +111,18 @@ class ExtractedActivity(BaseActivity, ExtractedData): @computed_field # type: ignore[prop-decorator] @property def identifier(self) -> ExtractedActivityIdentifier: - """Return the computed identifier for this extracted data item.""" + """Return the computed identifier for this extracted item.""" return self._get_identifier(ExtractedActivityIdentifier) @computed_field # type: ignore[prop-decorator] @property def stableTargetId(self) -> MergedActivityIdentifier: # noqa: N802 - """Return the computed stableTargetId for this extracted data item.""" + """Return the computed stableTargetId for this extracted item.""" return self._get_stable_target_id(MergedActivityIdentifier) class MergedActivity(BaseActivity, MergedItem): - """The result of merging all extracted data and rules for an activity.""" + """The result of merging all extracted items and rules for an activity.""" entityType: Annotated[ Literal["MergedActivity"], Field(alias="$type", frozen=True) @@ -129,6 +130,15 @@ class MergedActivity(BaseActivity, MergedItem): identifier: Annotated[MergedActivityIdentifier, Field(frozen=True)] +class PreviewActivity(_OptionalLists, _SparseLists, PreviewItem): + """Preview for merging all extracted items and rules for an activity.""" + + entityType: Annotated[ + Literal["PreviewActivity"], Field(alias="$type", frozen=True) + ] = "PreviewActivity" + identifier: Annotated[MergedActivityIdentifier, Field(frozen=True)] + + class AdditiveActivity(_OptionalLists, _SparseLists, AdditiveRule): """Rule to add values to merged activity items.""" diff --git a/mex/common/models/base/entity.py b/mex/common/models/base/entity.py index ee0ab0e7..7f4f1450 100644 --- a/mex/common/models/base/entity.py +++ b/mex/common/models/base/entity.py @@ -6,12 +6,11 @@ class BaseEntity(BaseModel): - """Abstract base model for extracted data, merged item and rule set classes. + """Base model for extracted item, preview item, merged item, rule-related classes. - This class gives type hints for an `identifier` field, the frozen `entityType` field - and the frozen class variable `stemType`. - Subclasses should implement all three fields while setting the correct identifier - type as well as the correct literal values for the entity and stem types. + This class gives type hints for the frozen `entityType` field and the frozen class + variable `stemType`. + Subclasses should implement both fields and set the correct literal values. """ model_config = ConfigDict( diff --git a/mex/common/models/base/extracted_data.py b/mex/common/models/base/extracted_data.py index 85a25f95..18432588 100644 --- a/mex/common/models/base/extracted_data.py +++ b/mex/common/models/base/extracted_data.py @@ -14,7 +14,7 @@ class ExtractedData(BaseEntity): - """Base model for all extracted data classes. + """Base model for all extracted item classes. This class adds two important attributes for metadata provenance: `hadPrimarySource` and `identifierInPrimarySource`, which are used to uniquely identify an @@ -98,5 +98,5 @@ def _get_stable_target_id( ) def __hash__(self) -> int: - """Calculates a hash value to make the object cachable.""" + """Calculates a hash value to make the object cacheable.""" return hash(f"{self.hadPrimarySource}\n{self.identifierInPrimarySource}") diff --git a/mex/common/models/base/preview_item.py b/mex/common/models/base/preview_item.py new file mode 100644 index 00000000..a09290c9 --- /dev/null +++ b/mex/common/models/base/preview_item.py @@ -0,0 +1,5 @@ +from mex.common.models.base.entity import BaseEntity + + +class PreviewItem(BaseEntity): + """Base model for previews of merged items.""" diff --git a/mex/common/models/bibliographic_resource.py b/mex/common/models/bibliographic_resource.py index 795cba71..a760e379 100644 --- a/mex/common/models/bibliographic_resource.py +++ b/mex/common/models/bibliographic_resource.py @@ -7,6 +7,7 @@ from mex.common.models.base.extracted_data import ExtractedData from mex.common.models.base.merged_item import MergedItem from mex.common.models.base.model import BaseModel +from mex.common.models.base.preview_item import PreviewItem from mex.common.models.base.rules import ( AdditiveRule, PreventiveRule, @@ -206,18 +207,18 @@ class ExtractedBibliographicResource(BaseBibliographicResource, ExtractedData): @computed_field # type: ignore[prop-decorator] @property def identifier(self) -> ExtractedBibliographicResourceIdentifier: - """Return the computed identifier for this extracted data item.""" + """Return the computed identifier for this extracted item.""" return self._get_identifier(ExtractedBibliographicResourceIdentifier) @computed_field # type: ignore[prop-decorator] @property def stableTargetId(self) -> MergedBibliographicResourceIdentifier: # noqa: N802 - """Return the computed stableTargetId for this extracted data item.""" + """Return the computed stableTargetId for this extracted item.""" return self._get_stable_target_id(MergedBibliographicResourceIdentifier) class MergedBibliographicResource(BaseBibliographicResource, MergedItem): - """The result of merging all extracted data and rules for a bibliographic resource.""" # noqa: E501 + """The result of merging all extracted items and rules for a bibliographic resource.""" # noqa: E501 entityType: Annotated[ Literal["MergedBibliographicResource"], Field(alias="$type", frozen=True) @@ -225,6 +226,17 @@ class MergedBibliographicResource(BaseBibliographicResource, MergedItem): identifier: Annotated[MergedBibliographicResourceIdentifier, Field(frozen=True)] +class PreviewBibliographicResource( + _OptionalLists, _SparseLists, _OptionalValues, _SparseValues, PreviewItem +): + """Preview for merging all extracted items and rules for a bibliographic resource.""" # noqa: E501 + + entityType: Annotated[ + Literal["PreviewBibliographicResource"], Field(alias="$type", frozen=True) + ] = "PreviewBibliographicResource" + identifier: Annotated[MergedBibliographicResourceIdentifier, Field(frozen=True)] + + class AdditiveBibliographicResource( _OptionalLists, _SparseLists, _OptionalValues, _SparseValues, AdditiveRule ): diff --git a/mex/common/models/consent.py b/mex/common/models/consent.py index 36d0b5d7..de224782 100644 --- a/mex/common/models/consent.py +++ b/mex/common/models/consent.py @@ -7,6 +7,7 @@ from mex.common.models.base.extracted_data import ExtractedData from mex.common.models.base.merged_item import MergedItem from mex.common.models.base.model import BaseModel +from mex.common.models.base.preview_item import PreviewItem from mex.common.models.base.rules import ( AdditiveRule, PreventiveRule, @@ -65,18 +66,18 @@ class ExtractedConsent(BaseConsent, ExtractedData): @computed_field # type: ignore[prop-decorator] @property def identifier(self) -> ExtractedConsentIdentifier: - """Return the computed identifier for this extracted data item.""" + """Return the computed identifier for this extracted item.""" return self._get_identifier(ExtractedConsentIdentifier) @computed_field # type: ignore[prop-decorator] @property def stableTargetId(self) -> MergedConsentIdentifier: # noqa: N802 - """Return the computed stableTargetId for this extracted data item.""" + """Return the computed stableTargetId for this extracted item.""" return self._get_stable_target_id(MergedConsentIdentifier) class MergedConsent(BaseConsent, MergedItem): - """The result of merging all extracted data and rules for a consent.""" + """The result of merging all extracted items and rules for a consent.""" entityType: Annotated[ Literal["MergedConsent"], Field(alias="$type", frozen=True) @@ -84,6 +85,15 @@ class MergedConsent(BaseConsent, MergedItem): identifier: Annotated[MergedConsentIdentifier, Field(frozen=True)] +class PreviewConsent(_OptionalValues, _SparseValues, PreviewItem): + """Preview for merging all extracted items and rules for a consent.""" + + entityType: Annotated[ + Literal["PreviewConsent"], Field(alias="$type", frozen=True) + ] = "PreviewConsent" + identifier: Annotated[MergedConsentIdentifier, Field(frozen=True)] + + class AdditiveConsent(_OptionalValues, _SparseValues, AdditiveRule): """Rule to add values to merged consent items.""" diff --git a/mex/common/models/contact_point.py b/mex/common/models/contact_point.py index ea6ba0ab..a788e7ff 100644 --- a/mex/common/models/contact_point.py +++ b/mex/common/models/contact_point.py @@ -7,6 +7,7 @@ from mex.common.models.base.extracted_data import ExtractedData from mex.common.models.base.merged_item import MergedItem from mex.common.models.base.model import BaseModel +from mex.common.models.base.preview_item import PreviewItem from mex.common.models.base.rules import ( AdditiveRule, PreventiveRule, @@ -49,18 +50,18 @@ class ExtractedContactPoint(BaseContactPoint, ExtractedData): @computed_field # type: ignore[prop-decorator] @property def identifier(self) -> ExtractedContactPointIdentifier: - """Return the computed identifier for this extracted data item.""" + """Return the computed identifier for this extracted item.""" return self._get_identifier(ExtractedContactPointIdentifier) @computed_field # type: ignore[prop-decorator] @property def stableTargetId(self) -> MergedContactPointIdentifier: # noqa: N802 - """Return the computed stableTargetId for this extracted data item.""" + """Return the computed stableTargetId for this extracted item.""" return self._get_stable_target_id(MergedContactPointIdentifier) class MergedContactPoint(BaseContactPoint, MergedItem): - """The result of merging all extracted data and rules for a contact point.""" + """The result of merging all extracted items and rules for a contact point.""" entityType: Annotated[ Literal["MergedContactPoint"], Field(alias="$type", frozen=True) @@ -68,6 +69,15 @@ class MergedContactPoint(BaseContactPoint, MergedItem): identifier: Annotated[MergedContactPointIdentifier, Field(frozen=True)] +class PreviewContactPoint(_SparseLists, PreviewItem): + """Preview for merging all extracted items and rules for a contact point.""" + + entityType: Annotated[ + Literal["PreviewContactPoint"], Field(alias="$type", frozen=True) + ] = "PreviewContactPoint" + identifier: Annotated[MergedContactPointIdentifier, Field(frozen=True)] + + class AdditiveContactPoint(_SparseLists, AdditiveRule): """Rule to add values to merged contact point items.""" diff --git a/mex/common/models/distribution.py b/mex/common/models/distribution.py index c83f2b8e..fec758b8 100644 --- a/mex/common/models/distribution.py +++ b/mex/common/models/distribution.py @@ -7,6 +7,7 @@ from mex.common.models.base.extracted_data import ExtractedData from mex.common.models.base.merged_item import MergedItem from mex.common.models.base.model import BaseModel +from mex.common.models.base.preview_item import PreviewItem from mex.common.models.base.rules import ( AdditiveRule, PreventiveRule, @@ -106,18 +107,18 @@ class ExtractedDistribution(BaseDistribution, ExtractedData): @computed_field # type: ignore[prop-decorator] @property def identifier(self) -> ExtractedDistributionIdentifier: - """Return the computed identifier for this extracted data item.""" + """Return the computed identifier for this extracted item.""" return self._get_identifier(ExtractedDistributionIdentifier) @computed_field # type: ignore[prop-decorator] @property def stableTargetId(self) -> MergedDistributionIdentifier: # noqa: N802 - """Return the computed stableTargetId for this extracted data item.""" + """Return the computed stableTargetId for this extracted item.""" return self._get_stable_target_id(MergedDistributionIdentifier) class MergedDistribution(BaseDistribution, MergedItem): - """The result of merging all extracted data and rules for a distribution.""" + """The result of merging all extracted items and rules for a distribution.""" entityType: Annotated[ Literal["MergedDistribution"], Field(alias="$type", frozen=True) @@ -125,6 +126,15 @@ class MergedDistribution(BaseDistribution, MergedItem): identifier: Annotated[MergedDistributionIdentifier, Field(frozen=True)] +class PreviewDistribution(_OptionalLists, _OptionalValues, _SparseValues, PreviewItem): + """Preview for merging all extracted items and rules for a distribution.""" + + entityType: Annotated[ + Literal["PreviewDistribution"], Field(alias="$type", frozen=True) + ] = "PreviewDistribution" + identifier: Annotated[MergedDistributionIdentifier, Field(frozen=True)] + + class AdditiveDistribution( _OptionalLists, _OptionalValues, _SparseValues, AdditiveRule ): diff --git a/mex/common/models/organization.py b/mex/common/models/organization.py index 2b5e9462..c1e2fe0f 100644 --- a/mex/common/models/organization.py +++ b/mex/common/models/organization.py @@ -10,6 +10,7 @@ from mex.common.models.base.extracted_data import ExtractedData from mex.common.models.base.merged_item import MergedItem from mex.common.models.base.model import BaseModel +from mex.common.models.base.preview_item import PreviewItem from mex.common.models.base.rules import ( AdditiveRule, PreventiveRule, @@ -117,18 +118,18 @@ class ExtractedOrganization(BaseOrganization, ExtractedData): @computed_field # type: ignore[prop-decorator] @property def identifier(self) -> ExtractedOrganizationIdentifier: - """Return the computed identifier for this extracted data item.""" + """Return the computed identifier for this extracted item.""" return self._get_identifier(ExtractedOrganizationIdentifier) @computed_field # type: ignore[prop-decorator] @property def stableTargetId(self) -> MergedOrganizationIdentifier: # noqa: N802 - """Return the computed stableTargetId for this extracted data item.""" + """Return the computed stableTargetId for this extracted item.""" return self._get_stable_target_id(MergedOrganizationIdentifier) class MergedOrganization(BaseOrganization, MergedItem): - """The result of merging all extracted data and rules for an organization.""" + """The result of merging all extracted items and rules for an organization.""" entityType: Annotated[ Literal["MergedOrganization"], Field(alias="$type", frozen=True) @@ -136,6 +137,15 @@ class MergedOrganization(BaseOrganization, MergedItem): identifier: Annotated[MergedOrganizationIdentifier, Field(frozen=True)] +class PreviewOrganization(_OptionalLists, _SparseLists, PreviewItem): + """Preview for merging all extracted items and rules for an organization.""" + + entityType: Annotated[ + Literal["PreviewOrganization"], Field(alias="$type", frozen=True) + ] = "PreviewOrganization" + identifier: Annotated[MergedOrganizationIdentifier, Field(frozen=True)] + + class AdditiveOrganization(_OptionalLists, _SparseLists, AdditiveRule): """Rule to add values to merged organization items.""" diff --git a/mex/common/models/organizational_unit.py b/mex/common/models/organizational_unit.py index 6ca4a08d..d89a15ef 100644 --- a/mex/common/models/organizational_unit.py +++ b/mex/common/models/organizational_unit.py @@ -7,6 +7,7 @@ from mex.common.models.base.extracted_data import ExtractedData from mex.common.models.base.merged_item import MergedItem from mex.common.models.base.model import BaseModel +from mex.common.models.base.preview_item import PreviewItem from mex.common.models.base.rules import ( AdditiveRule, PreventiveRule, @@ -68,18 +69,18 @@ class ExtractedOrganizationalUnit(BaseOrganizationalUnit, ExtractedData): @computed_field # type: ignore[prop-decorator] @property def identifier(self) -> ExtractedOrganizationalUnitIdentifier: - """Return the computed identifier for this extracted data item.""" + """Return the computed identifier for this extracted item.""" return self._get_identifier(ExtractedOrganizationalUnitIdentifier) @computed_field # type: ignore[prop-decorator] @property def stableTargetId(self) -> MergedOrganizationalUnitIdentifier: # noqa: N802 - """Return the computed stableTargetId for this extracted data item.""" + """Return the computed stableTargetId for this extracted item.""" return self._get_stable_target_id(MergedOrganizationalUnitIdentifier) class MergedOrganizationalUnit(BaseOrganizationalUnit, MergedItem): - """The result of merging all extracted data and rules for an organizational unit.""" + """The result of merging all extracted items and rules for an organizational unit.""" # noqa: E501 entityType: Annotated[ Literal["MergedOrganizationalUnit"], Field(alias="$type", frozen=True) @@ -87,6 +88,17 @@ class MergedOrganizationalUnit(BaseOrganizationalUnit, MergedItem): identifier: Annotated[MergedOrganizationalUnitIdentifier, Field(frozen=True)] +class PreviewOrganizationalUnit( + _OptionalLists, _SparseLists, _OptionalValues, PreviewItem +): + """Preview for merging all extracted items and rules for an organizational unit.""" + + entityType: Annotated[ + Literal["PreviewOrganizationalUnit"], Field(alias="$type", frozen=True) + ] = "PreviewOrganizationalUnit" + identifier: Annotated[MergedOrganizationalUnitIdentifier, Field(frozen=True)] + + class AdditiveOrganizationalUnit( _OptionalLists, _SparseLists, _OptionalValues, AdditiveRule ): diff --git a/mex/common/models/person.py b/mex/common/models/person.py index 1d8b7c56..482d8941 100644 --- a/mex/common/models/person.py +++ b/mex/common/models/person.py @@ -7,6 +7,7 @@ from mex.common.models.base.extracted_data import ExtractedData from mex.common.models.base.merged_item import MergedItem from mex.common.models.base.model import BaseModel +from mex.common.models.base.preview_item import PreviewItem from mex.common.models.base.rules import ( AdditiveRule, PreventiveRule, @@ -91,18 +92,18 @@ class ExtractedPerson(BasePerson, ExtractedData): @computed_field # type: ignore[prop-decorator] @property def identifier(self) -> ExtractedPersonIdentifier: - """Return the computed identifier for this extracted data item.""" + """Return the computed identifier for this extracted item.""" return self._get_identifier(ExtractedPersonIdentifier) @computed_field # type: ignore[prop-decorator] @property def stableTargetId(self) -> MergedPersonIdentifier: # noqa: N802 - """Return the computed stableTargetId for this extracted data item.""" + """Return the computed stableTargetId for this extracted item.""" return self._get_stable_target_id(MergedPersonIdentifier) class MergedPerson(BasePerson, MergedItem): - """The result of merging all extracted data and rules for a person.""" + """The result of merging all extracted items and rules for a person.""" entityType: Annotated[ Literal["MergedPerson"], Field(alias="$type", frozen=True) @@ -110,6 +111,15 @@ class MergedPerson(BasePerson, MergedItem): identifier: Annotated[MergedPersonIdentifier, Field(frozen=True)] +class PreviewPerson(_OptionalLists, PreviewItem): + """Preview for merging all extracted items and rules for a person.""" + + entityType: Annotated[ + Literal["PreviewPerson"], Field(alias="$type", frozen=True) + ] = "PreviewPerson" + identifier: Annotated[MergedPersonIdentifier, Field(frozen=True)] + + class AdditivePerson(_OptionalLists, AdditiveRule): """Rule to add values to merged person items.""" diff --git a/mex/common/models/primary_source.py b/mex/common/models/primary_source.py index f129c2a6..46fa0945 100644 --- a/mex/common/models/primary_source.py +++ b/mex/common/models/primary_source.py @@ -7,6 +7,7 @@ from mex.common.models.base.extracted_data import ExtractedData from mex.common.models.base.merged_item import MergedItem from mex.common.models.base.model import BaseModel +from mex.common.models.base.preview_item import PreviewItem from mex.common.models.base.rules import ( AdditiveRule, PreventiveRule, @@ -85,18 +86,18 @@ class ExtractedPrimarySource(BasePrimarySource, ExtractedData): @computed_field # type: ignore[prop-decorator] @property def identifier(self) -> ExtractedPrimarySourceIdentifier: - """Return the computed identifier for this extracted data item.""" + """Return the computed identifier for this extracted item.""" return self._get_identifier(ExtractedPrimarySourceIdentifier) @computed_field # type: ignore[prop-decorator] @property def stableTargetId(self) -> MergedPrimarySourceIdentifier: # noqa: N802 - """Return the computed stableTargetId for this extracted data item.""" + """Return the computed stableTargetId for this extracted item.""" return self._get_stable_target_id(MergedPrimarySourceIdentifier) class MergedPrimarySource(BasePrimarySource, MergedItem): - """The result of merging all extracted data and rules for a primary source.""" + """The result of merging all extracted items and rules for a primary source.""" entityType: Annotated[ Literal["MergedPrimarySource"], Field(alias="$type", frozen=True) @@ -104,6 +105,15 @@ class MergedPrimarySource(BasePrimarySource, MergedItem): identifier: Annotated[MergedPrimarySourceIdentifier, Field(frozen=True)] +class PreviewPrimarySource(_OptionalLists, _OptionalValues, PreviewItem): + """Preview for merging all extracted items and rules for a primary source.""" + + entityType: Annotated[ + Literal["PreviewPrimarySource"], Field(alias="$type", frozen=True) + ] = "PreviewPrimarySource" + identifier: Annotated[MergedPrimarySourceIdentifier, Field(frozen=True)] + + class AdditivePrimarySource(_OptionalLists, _OptionalValues, AdditiveRule): """Rule to add values to merged primary source items.""" diff --git a/mex/common/models/resource.py b/mex/common/models/resource.py index 84c96805..86dabb0e 100644 --- a/mex/common/models/resource.py +++ b/mex/common/models/resource.py @@ -7,6 +7,7 @@ from mex.common.models.base.extracted_data import ExtractedData from mex.common.models.base.merged_item import MergedItem from mex.common.models.base.model import BaseModel +from mex.common.models.base.preview_item import PreviewItem from mex.common.models.base.rules import ( AdditiveRule, PreventiveRule, @@ -233,18 +234,18 @@ class ExtractedResource(BaseResource, ExtractedData): @computed_field # type: ignore[prop-decorator] @property def identifier(self) -> ExtractedResourceIdentifier: - """Return the computed identifier for this extracted data item.""" + """Return the computed identifier for this extracted item.""" return self._get_identifier(ExtractedResourceIdentifier) @computed_field # type: ignore[prop-decorator] @property def stableTargetId(self) -> MergedResourceIdentifier: # noqa: N802 - """Return the computed stableTargetId for this extracted data item.""" + """Return the computed stableTargetId for this extracted item.""" return self._get_stable_target_id(MergedResourceIdentifier) class MergedResource(BaseResource, MergedItem): - """The result of merging all extracted data and rules for a resource.""" + """The result of merging all extracted items and rules for a resource.""" entityType: Annotated[ Literal["MergedResource"], Field(alias="$type", frozen=True) @@ -252,6 +253,17 @@ class MergedResource(BaseResource, MergedItem): identifier: Annotated[MergedResourceIdentifier, Field(frozen=True)] +class PreviewResource( + _OptionalLists, _SparseLists, _OptionalValues, _SparseValues, PreviewItem +): + """Preview for merging all extracted items and rules for a resource.""" + + entityType: Annotated[ + Literal["PreviewResource"], Field(alias="$type", frozen=True) + ] = "PreviewResource" + identifier: Annotated[MergedResourceIdentifier, Field(frozen=True)] + + class AdditiveResource( _OptionalLists, _SparseLists, _OptionalValues, _SparseValues, AdditiveRule ): diff --git a/mex/common/models/variable.py b/mex/common/models/variable.py index 34ad31ac..9114d0e6 100644 --- a/mex/common/models/variable.py +++ b/mex/common/models/variable.py @@ -7,6 +7,7 @@ from mex.common.models.base.extracted_data import ExtractedData from mex.common.models.base.merged_item import MergedItem from mex.common.models.base.model import BaseModel +from mex.common.models.base.preview_item import PreviewItem from mex.common.models.base.rules import ( AdditiveRule, PreventiveRule, @@ -108,18 +109,18 @@ class ExtractedVariable(BaseVariable, ExtractedData): @computed_field # type: ignore[prop-decorator] @property def identifier(self) -> ExtractedVariableIdentifier: - """Return the computed identifier for this extracted data item.""" + """Return the computed identifier for this extracted item.""" return self._get_identifier(ExtractedVariableIdentifier) @computed_field # type: ignore[prop-decorator] @property def stableTargetId(self) -> MergedVariableIdentifier: # noqa: N802 - """Return the computed stableTargetId for this extracted data item.""" + """Return the computed stableTargetId for this extracted item.""" return self._get_stable_target_id(MergedVariableIdentifier) class MergedVariable(BaseVariable, MergedItem): - """The result of merging all extracted data and rules for a variable.""" + """The result of merging all extracted items and rules for a variable.""" entityType: Annotated[ Literal["MergedVariable"], Field(alias="$type", frozen=True) @@ -127,6 +128,15 @@ class MergedVariable(BaseVariable, MergedItem): identifier: Annotated[MergedVariableIdentifier, Field(frozen=True)] +class PreviewVariable(_OptionalLists, _SparseLists, _OptionalValues, PreviewItem): + """Preview for merging all extracted items and rules for a variable.""" + + entityType: Annotated[ + Literal["PreviewVariable"], Field(alias="$type", frozen=True) + ] = "PreviewVariable" + identifier: Annotated[MergedVariableIdentifier, Field(frozen=True)] + + class AdditiveVariable(_OptionalLists, _SparseLists, _OptionalValues, AdditiveRule): """Rule to add values to merged variable items.""" diff --git a/mex/common/models/variable_group.py b/mex/common/models/variable_group.py index d4e6f2eb..051b2291 100644 --- a/mex/common/models/variable_group.py +++ b/mex/common/models/variable_group.py @@ -7,6 +7,7 @@ from mex.common.models.base.extracted_data import ExtractedData from mex.common.models.base.merged_item import MergedItem from mex.common.models.base.model import BaseModel +from mex.common.models.base.preview_item import PreviewItem from mex.common.models.base.rules import ( AdditiveRule, PreventiveRule, @@ -52,18 +53,18 @@ class ExtractedVariableGroup(BaseVariableGroup, ExtractedData): @computed_field # type: ignore[prop-decorator] @property def identifier(self) -> ExtractedVariableGroupIdentifier: - """Return the computed identifier for this extracted data item.""" + """Return the computed identifier for this extracted item.""" return self._get_identifier(ExtractedVariableGroupIdentifier) @computed_field # type: ignore[prop-decorator] @property def stableTargetId(self) -> MergedVariableGroupIdentifier: # noqa: N802 - """Return the computed stableTargetId for this extracted data item.""" + """Return the computed stableTargetId for this extracted item.""" return self._get_stable_target_id(MergedVariableGroupIdentifier) class MergedVariableGroup(BaseVariableGroup, MergedItem): - """The result of merging all extracted data and rules for a variable group.""" + """The result of merging all extracted items and rules for a variable group.""" entityType: Annotated[ Literal["MergedVariableGroup"], Field(alias="$type", frozen=True) @@ -71,6 +72,15 @@ class MergedVariableGroup(BaseVariableGroup, MergedItem): identifier: Annotated[MergedVariableGroupIdentifier, Field(frozen=True)] +class PreviewVariableGroup(_SparseLists, PreviewItem): + """Preview for merging all extracted items and rules for a variable group.""" + + entityType: Annotated[ + Literal["PreviewVariableGroup"], Field(alias="$type", frozen=True) + ] = "PreviewVariableGroup" + identifier: Annotated[MergedVariableGroupIdentifier, Field(frozen=True)] + + class AdditiveVariableGroup(_SparseLists, AdditiveRule): """Rule to add values to merged variable group items.""" diff --git a/tests/backend_api/test_connector.py b/tests/backend_api/test_connector.py index a3f52e67..1b7fdf62 100644 --- a/tests/backend_api/test_connector.py +++ b/tests/backend_api/test_connector.py @@ -5,12 +5,13 @@ from requests.exceptions import HTTPError from mex.common.backend_api.connector import BackendApiConnector -from mex.common.backend_api.models import ExtractedItemsRequest +from mex.common.backend_api.models import ExtractedItemsRequest, PreviewItemsResponse from mex.common.models import ( ExtractedPerson, MergedPerson, PersonRuleSetRequest, PersonRuleSetResponse, + PreviewPerson, ) from mex.common.testing import Joker @@ -197,6 +198,36 @@ def test_preview_merged_item_mocked( ) +def test_fetch_preview_items_mocked( + mocked_backend: MagicMock, + preview_person: PreviewPerson, +) -> None: + preview_response = PreviewItemsResponse(items=[preview_person], total=92) + mocked_return = preview_response.model_dump() + mocked_backend.return_value.json.return_value = mocked_return + + connector = BackendApiConnector.get() + response = connector.fetch_preview_items("foobar", None, 1, 0) + + assert response == preview_response + + assert mocked_backend.call_args == call( + "GET", + "http://localhost:8080/v0/preview-item", + { + "q": "foobar", + "entityType": None, + "skip": "1", + "limit": "0", + }, + timeout=10, + headers={ + "Accept": "application/json", + "User-Agent": "rki/mex", + }, + ) + + def test_get_rule_set_mocked( mocked_backend: MagicMock, rule_set_response: PersonRuleSetResponse ) -> None: diff --git a/tests/conftest.py b/tests/conftest.py index 511a5189..227b0795 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -9,6 +9,7 @@ PersonRuleSetRequest, PersonRuleSetResponse, PreventivePerson, + PreviewPerson, SubtractivePerson, ) from mex.common.types import ( @@ -64,6 +65,16 @@ def merged_person() -> MergedPerson: ) +@pytest.fixture +def preview_person() -> PreviewPerson: + """Return a dummy preview person for testing purposes.""" + return PreviewPerson( + identifier=MergedPersonIdentifier.generate(seed=876), + affiliation=[MergedOrganizationIdentifier.generate(seed=300)], + email=[Email("TintzmannM@rki.de")], + ) + + @pytest.fixture def rule_set_request() -> PersonRuleSetRequest: """Return a dummy person rule set request for testing purposes.""" diff --git a/tests/models/test_extracted_data.py b/tests/models/test_extracted_data.py index 3c51f66c..0a7d5fe2 100644 --- a/tests/models/test_extracted_data.py +++ b/tests/models/test_extracted_data.py @@ -40,13 +40,13 @@ class ExtractedThing(BaseThing, ExtractedData): @computed_field # type: ignore[prop-decorator] @property def identifier(self) -> ExtractedThingIdentifier: - """Return the computed identifier for this extracted data item.""" + """Return the computed identifier for this extracted item.""" return self._get_identifier(ExtractedThingIdentifier) @computed_field # type: ignore[prop-decorator] @property def stableTargetId(self) -> MergedThingIdentifier: # noqa: N802 - """Return the computed stableTargetId for this extracted data item.""" + """Return the computed stableTargetId for this extracted item.""" return self._get_stable_target_id(MergedThingIdentifier) diff --git a/tests/models/test_filter.py b/tests/models/test_filter.py index d33e13e7..f3f8d54f 100644 --- a/tests/models/test_filter.py +++ b/tests/models/test_filter.py @@ -2,7 +2,8 @@ from pydantic import Field -from mex.common.models import ExtractedData, generate_entity_filter_schema +from mex.common.models import ExtractedData +from mex.common.models.base.filter import generate_entity_filter_schema from mex.common.types import MergedOrganizationalUnitIdentifier from mex.common.types.email import Email diff --git a/tests/models/test_mapping.py b/tests/models/test_mapping.py index 3c09bb27..d9970694 100644 --- a/tests/models/test_mapping.py +++ b/tests/models/test_mapping.py @@ -2,7 +2,8 @@ from pydantic import Field -from mex.common.models import ExtractedData, generate_mapping_schema +from mex.common.models import ExtractedData +from mex.common.models.base.mapping import generate_mapping_schema from mex.common.types import Email, Identifier, MergedOrganizationalUnitIdentifier diff --git a/tests/sinks/test_ndjson.py b/tests/sinks/test_ndjson.py index c1e6365d..ad9072b9 100644 --- a/tests/sinks/test_ndjson.py +++ b/tests/sinks/test_ndjson.py @@ -13,7 +13,7 @@ class DummyEnum(Enum): NAME = "value" -class Thing(ExtractedData): +class ExtractedThing(ExtractedData): identifier: Identifier str_attr: str enum_attr: DummyEnum | None = None @@ -25,12 +25,14 @@ def test_write_ndjson() -> None: settings = BaseSettings.get() test_models = [ - Thing.model_construct(identifier="1", str_attr="foo"), - Thing.model_construct(identifier="2", str_attr="bar", enum_attr=DummyEnum.NAME), - Thing.model_construct( + ExtractedThing.model_construct(identifier="1", str_attr="foo"), + ExtractedThing.model_construct( + identifier="2", str_attr="bar", enum_attr=DummyEnum.NAME + ), + ExtractedThing.model_construct( identifier="3", str_attr="baz", uuid_attr=UUID(int=42, version=4) ), - Thing.model_construct( + ExtractedThing.model_construct( identifier="4", str_attr="dat", ts_attr=TemporalEntity(2000, 1, 1) ), ] @@ -38,7 +40,7 @@ def test_write_ndjson() -> None: ids = list(write_ndjson(test_models)) assert len(ids) - with open(settings.work_dir / "Thing.ndjson") as handle: + with open(settings.work_dir / "ExtractedThing.ndjson") as handle: output = handle.read() expected = """\ diff --git a/tests/test_fields.py b/tests/test_fields.py index bafde1ad..cd18a261 100644 --- a/tests/test_fields.py +++ b/tests/test_fields.py @@ -20,18 +20,18 @@ def test_all_fields_by_class_names_include_all_classes() -> None: assert { len(lookup) for lookup in ( + EMAIL_FIELDS_BY_CLASS_NAME, + FINAL_FIELDS_BY_CLASS_NAME, FROZEN_FIELDS_BY_CLASS_NAME, + INTEGER_FIELDS_BY_CLASS_NAME, + LINK_FIELDS_BY_CLASS_NAME, LITERAL_FIELDS_BY_CLASS_NAME, + MERGEABLE_FIELDS_BY_CLASS_NAME, + MUTABLE_FIELDS_BY_CLASS_NAME, REFERENCE_FIELDS_BY_CLASS_NAME, - TEXT_FIELDS_BY_CLASS_NAME, - LINK_FIELDS_BY_CLASS_NAME, - EMAIL_FIELDS_BY_CLASS_NAME, - INTEGER_FIELDS_BY_CLASS_NAME, STRING_FIELDS_BY_CLASS_NAME, TEMPORAL_FIELDS_BY_CLASS_NAME, + TEXT_FIELDS_BY_CLASS_NAME, VOCABULARY_FIELDS_BY_CLASS_NAME, - MUTABLE_FIELDS_BY_CLASS_NAME, - MERGEABLE_FIELDS_BY_CLASS_NAME, - FINAL_FIELDS_BY_CLASS_NAME, ) } == {len(ALL_MODEL_CLASSES_BY_NAME)}