From 1547032742b97d2fe9a609d0473323a2ed5e7556 Mon Sep 17 00:00:00 2001 From: mferrera Date: Wed, 12 Jun 2024 13:37:05 +0200 Subject: [PATCH] ENH: Make ObjectDataProviders return Pydantic models --- schema/definitions/0.8.0/schema/fmu_meta.json | 212 +++++++++--------- src/fmu/dataio/_definitions.py | 9 - src/fmu/dataio/_metadata.py | 10 +- src/fmu/dataio/dataio.py | 7 +- src/fmu/dataio/datastructure/meta/content.py | 4 +- src/fmu/dataio/datastructure/meta/enums.py | 27 ++- src/fmu/dataio/providers/objectdata/_base.py | 87 +++---- .../dataio/providers/objectdata/_faultroom.py | 4 +- .../dataio/providers/objectdata/_provider.py | 4 +- .../dataio/providers/objectdata/_tables.py | 3 +- src/fmu/dataio/providers/objectdata/_xtgeo.py | 8 +- tests/test_units/test_metadata_class.py | 95 ++++---- .../test_objectdataprovider_class.py | 5 +- 13 files changed, 237 insertions(+), 238 deletions(-) diff --git a/schema/definitions/0.8.0/schema/fmu_meta.json b/schema/definitions/0.8.0/schema/fmu_meta.json index f106d23bc..75beeee4d 100644 --- a/schema/definitions/0.8.0/schema/fmu_meta.json +++ b/schema/definitions/0.8.0/schema/fmu_meta.json @@ -666,7 +666,7 @@ "layout": { "anyOf": [ { - "type": "string" + "$ref": "#/$defs/Layout" }, { "type": "null" @@ -674,9 +674,9 @@ ], "default": null, "examples": [ - "regular" - ], - "title": "Layout" + "regular", + "cornerpoint" + ] }, "name": { "description": "Name of the data object. If stratigraphic, match the entry in the stratigraphic column", @@ -1343,7 +1343,7 @@ "layout": { "anyOf": [ { - "type": "string" + "$ref": "#/$defs/Layout" }, { "type": "null" @@ -1351,9 +1351,9 @@ ], "default": null, "examples": [ - "regular" - ], - "title": "Layout" + "regular", + "cornerpoint" + ] }, "name": { "description": "Name of the data object. If stratigraphic, match the entry in the stratigraphic column", @@ -1625,7 +1625,7 @@ "layout": { "anyOf": [ { - "type": "string" + "$ref": "#/$defs/Layout" }, { "type": "null" @@ -1633,9 +1633,9 @@ ], "default": null, "examples": [ - "regular" - ], - "title": "Layout" + "regular", + "cornerpoint" + ] }, "name": { "description": "Name of the data object. If stratigraphic, match the entry in the stratigraphic column", @@ -1907,7 +1907,7 @@ "layout": { "anyOf": [ { - "type": "string" + "$ref": "#/$defs/Layout" }, { "type": "null" @@ -1915,9 +1915,9 @@ ], "default": null, "examples": [ - "regular" - ], - "title": "Layout" + "regular", + "cornerpoint" + ] }, "name": { "description": "Name of the data object. If stratigraphic, match the entry in the stratigraphic column", @@ -2291,7 +2291,7 @@ "layout": { "anyOf": [ { - "type": "string" + "$ref": "#/$defs/Layout" }, { "type": "null" @@ -2299,9 +2299,9 @@ ], "default": null, "examples": [ - "regular" - ], - "title": "Layout" + "regular", + "cornerpoint" + ] }, "name": { "description": "Name of the data object. If stratigraphic, match the entry in the stratigraphic column", @@ -2592,7 +2592,7 @@ "layout": { "anyOf": [ { - "type": "string" + "$ref": "#/$defs/Layout" }, { "type": "null" @@ -2600,9 +2600,9 @@ ], "default": null, "examples": [ - "regular" - ], - "title": "Layout" + "regular", + "cornerpoint" + ] }, "name": { "description": "Name of the data object. If stratigraphic, match the entry in the stratigraphic column", @@ -2994,7 +2994,7 @@ "layout": { "anyOf": [ { - "type": "string" + "$ref": "#/$defs/Layout" }, { "type": "null" @@ -3002,9 +3002,9 @@ ], "default": null, "examples": [ - "regular" - ], - "title": "Layout" + "regular", + "cornerpoint" + ] }, "name": { "description": "Name of the data object. If stratigraphic, match the entry in the stratigraphic column", @@ -3349,7 +3349,7 @@ "layout": { "anyOf": [ { - "type": "string" + "$ref": "#/$defs/Layout" }, { "type": "null" @@ -3357,9 +3357,9 @@ ], "default": null, "examples": [ - "regular" - ], - "title": "Layout" + "regular", + "cornerpoint" + ] }, "name": { "description": "Name of the data object. If stratigraphic, match the entry in the stratigraphic column", @@ -3568,6 +3568,18 @@ "title": "Layer", "type": "object" }, + "Layout": { + "enum": [ + "regular", + "unset", + "cornerpoint", + "table", + "dictionary", + "faultroom_triangulated" + ], + "title": "Layout", + "type": "string" + }, "LiftCurvesContent": { "properties": { "alias": { @@ -3659,7 +3671,7 @@ "layout": { "anyOf": [ { - "type": "string" + "$ref": "#/$defs/Layout" }, { "type": "null" @@ -3667,9 +3679,9 @@ ], "default": null, "examples": [ - "regular" - ], - "title": "Layout" + "regular", + "cornerpoint" + ] }, "name": { "description": "Name of the data object. If stratigraphic, match the entry in the stratigraphic column", @@ -3953,7 +3965,7 @@ "layout": { "anyOf": [ { - "type": "string" + "$ref": "#/$defs/Layout" }, { "type": "null" @@ -3961,9 +3973,9 @@ ], "default": null, "examples": [ - "regular" - ], - "title": "Layout" + "regular", + "cornerpoint" + ] }, "name": { "description": "Name of the data object. If stratigraphic, match the entry in the stratigraphic column", @@ -4235,7 +4247,7 @@ "layout": { "anyOf": [ { - "type": "string" + "$ref": "#/$defs/Layout" }, { "type": "null" @@ -4243,9 +4255,9 @@ ], "default": null, "examples": [ - "regular" - ], - "title": "Layout" + "regular", + "cornerpoint" + ] }, "name": { "description": "Name of the data object. If stratigraphic, match the entry in the stratigraphic column", @@ -4537,7 +4549,7 @@ "layout": { "anyOf": [ { - "type": "string" + "$ref": "#/$defs/Layout" }, { "type": "null" @@ -4545,9 +4557,9 @@ ], "default": null, "examples": [ - "regular" - ], - "title": "Layout" + "regular", + "cornerpoint" + ] }, "name": { "description": "Name of the data object. If stratigraphic, match the entry in the stratigraphic column", @@ -4819,7 +4831,7 @@ "layout": { "anyOf": [ { - "type": "string" + "$ref": "#/$defs/Layout" }, { "type": "null" @@ -4827,9 +4839,9 @@ ], "default": null, "examples": [ - "regular" - ], - "title": "Layout" + "regular", + "cornerpoint" + ] }, "name": { "description": "Name of the data object. If stratigraphic, match the entry in the stratigraphic column", @@ -5151,7 +5163,7 @@ "layout": { "anyOf": [ { - "type": "string" + "$ref": "#/$defs/Layout" }, { "type": "null" @@ -5159,9 +5171,9 @@ ], "default": null, "examples": [ - "regular" - ], - "title": "Layout" + "regular", + "cornerpoint" + ] }, "name": { "description": "Name of the data object. If stratigraphic, match the entry in the stratigraphic column", @@ -5433,7 +5445,7 @@ "layout": { "anyOf": [ { - "type": "string" + "$ref": "#/$defs/Layout" }, { "type": "null" @@ -5441,9 +5453,9 @@ ], "default": null, "examples": [ - "regular" - ], - "title": "Layout" + "regular", + "cornerpoint" + ] }, "name": { "description": "Name of the data object. If stratigraphic, match the entry in the stratigraphic column", @@ -5770,7 +5782,7 @@ "layout": { "anyOf": [ { - "type": "string" + "$ref": "#/$defs/Layout" }, { "type": "null" @@ -5778,9 +5790,9 @@ ], "default": null, "examples": [ - "regular" - ], - "title": "Layout" + "regular", + "cornerpoint" + ] }, "name": { "description": "Name of the data object. If stratigraphic, match the entry in the stratigraphic column", @@ -6052,7 +6064,7 @@ "layout": { "anyOf": [ { - "type": "string" + "$ref": "#/$defs/Layout" }, { "type": "null" @@ -6060,9 +6072,9 @@ ], "default": null, "examples": [ - "regular" - ], - "title": "Layout" + "regular", + "cornerpoint" + ] }, "name": { "description": "Name of the data object. If stratigraphic, match the entry in the stratigraphic column", @@ -6422,7 +6434,7 @@ "layout": { "anyOf": [ { - "type": "string" + "$ref": "#/$defs/Layout" }, { "type": "null" @@ -6430,9 +6442,9 @@ ], "default": null, "examples": [ - "regular" - ], - "title": "Layout" + "regular", + "cornerpoint" + ] }, "name": { "description": "Name of the data object. If stratigraphic, match the entry in the stratigraphic column", @@ -6818,7 +6830,7 @@ "layout": { "anyOf": [ { - "type": "string" + "$ref": "#/$defs/Layout" }, { "type": "null" @@ -6826,9 +6838,9 @@ ], "default": null, "examples": [ - "regular" - ], - "title": "Layout" + "regular", + "cornerpoint" + ] }, "name": { "description": "Name of the data object. If stratigraphic, match the entry in the stratigraphic column", @@ -7293,7 +7305,7 @@ "layout": { "anyOf": [ { - "type": "string" + "$ref": "#/$defs/Layout" }, { "type": "null" @@ -7301,9 +7313,9 @@ ], "default": null, "examples": [ - "regular" - ], - "title": "Layout" + "regular", + "cornerpoint" + ] }, "name": { "description": "Name of the data object. If stratigraphic, match the entry in the stratigraphic column", @@ -7603,7 +7615,7 @@ "layout": { "anyOf": [ { - "type": "string" + "$ref": "#/$defs/Layout" }, { "type": "null" @@ -7611,9 +7623,9 @@ ], "default": null, "examples": [ - "regular" - ], - "title": "Layout" + "regular", + "cornerpoint" + ] }, "name": { "description": "Name of the data object. If stratigraphic, match the entry in the stratigraphic column", @@ -7885,7 +7897,7 @@ "layout": { "anyOf": [ { - "type": "string" + "$ref": "#/$defs/Layout" }, { "type": "null" @@ -7893,9 +7905,9 @@ ], "default": null, "examples": [ - "regular" - ], - "title": "Layout" + "regular", + "cornerpoint" + ] }, "name": { "description": "Name of the data object. If stratigraphic, match the entry in the stratigraphic column", @@ -8225,7 +8237,7 @@ "layout": { "anyOf": [ { - "type": "string" + "$ref": "#/$defs/Layout" }, { "type": "null" @@ -8233,9 +8245,9 @@ ], "default": null, "examples": [ - "regular" - ], - "title": "Layout" + "regular", + "cornerpoint" + ] }, "name": { "description": "Name of the data object. If stratigraphic, match the entry in the stratigraphic column", @@ -8520,7 +8532,7 @@ "layout": { "anyOf": [ { - "type": "string" + "$ref": "#/$defs/Layout" }, { "type": "null" @@ -8528,9 +8540,9 @@ ], "default": null, "examples": [ - "regular" - ], - "title": "Layout" + "regular", + "cornerpoint" + ] }, "name": { "description": "Name of the data object. If stratigraphic, match the entry in the stratigraphic column", @@ -8802,7 +8814,7 @@ "layout": { "anyOf": [ { - "type": "string" + "$ref": "#/$defs/Layout" }, { "type": "null" @@ -8810,9 +8822,9 @@ ], "default": null, "examples": [ - "regular" - ], - "title": "Layout" + "regular", + "cornerpoint" + ] }, "name": { "description": "Name of the data object. If stratigraphic, match the entry in the stratigraphic column", diff --git a/src/fmu/dataio/_definitions.py b/src/fmu/dataio/_definitions.py index dfdfb188c..f45c20ba3 100644 --- a/src/fmu/dataio/_definitions.py +++ b/src/fmu/dataio/_definitions.py @@ -69,15 +69,6 @@ class ExportFolder(str, Enum): tables = "tables" -class Layout(str, Enum): - regular = "regular" - unset = "unset" - cornerpoint = "cornerpoint" - table = "table" - dictionary = "dictionary" - faultroom_triangulated = "faultroom_triangulated" - - STANDARD_TABLE_INDEX_COLUMNS: Final[dict[str, list[str]]] = { "volumes": ["ZONE", "REGION", "FACIES", "LICENCE"], "rft": ["measured_depth", "well", "time"], diff --git a/src/fmu/dataio/_metadata.py b/src/fmu/dataio/_metadata.py index 1fe05b703..eb314a073 100644 --- a/src/fmu/dataio/_metadata.py +++ b/src/fmu/dataio/_metadata.py @@ -17,7 +17,6 @@ from . import types from ._definitions import SCHEMA, SOURCE, VERSION, FmuContext from ._logging import null_logger -from ._utils import drop_nones from .datastructure._internal import internal from .datastructure.meta import meta from .exceptions import InvalidMetadataError @@ -109,8 +108,7 @@ def generate_export_metadata( dataio: ExportData, fmudata: FmuProvider | None = None, compute_md5: bool = True, - skip_null: bool = True, -) -> dict: # TODO! -> skip_null? +) -> internal.DataClassMeta: """ Main function to generate the full metadata @@ -141,7 +139,7 @@ def generate_export_metadata( objdata = objectdata_provider_factory(obj, dataio) masterdata = dataio.config.get("masterdata") - metadata = internal.DataClassMeta( + return internal.DataClassMeta( schema_=TypeAdapter(AnyHttpUrl).validate_strings(SCHEMA), # type: ignore[call-arg] version=VERSION, source=SOURCE, @@ -154,6 +152,4 @@ def generate_export_metadata( tracklog=generate_meta_tracklog(), display=_get_meta_display(dataio, objdata), preprocessed=dataio.fmu_context == FmuContext.PREPROCESSED, - ).model_dump(mode="json", exclude_none=True, by_alias=True) - - return metadata if not skip_null else drop_nones(metadata) + ) diff --git a/src/fmu/dataio/dataio.py b/src/fmu/dataio/dataio.py index 2d02a13d3..b99786e63 100644 --- a/src/fmu/dataio/dataio.py +++ b/src/fmu/dataio/dataio.py @@ -22,6 +22,7 @@ from ._metadata import generate_export_metadata from ._utils import ( detect_inside_rms, # dataio_examples, + drop_nones, export_file, export_metadata_file, prettyprint_dict, @@ -769,8 +770,10 @@ def generate_metadata( self._update_fmt_flag() fmudata = self._get_fmu_provider() if self._fmurun else None - self._metadata = generate_export_metadata( - obj, self, fmudata, compute_md5=compute_md5 + self._metadata = drop_nones( + generate_export_metadata( + obj, self, fmudata, compute_md5=compute_md5 + ).model_dump(mode="json", exclude_none=True, by_alias=True) ) logger.info("The metadata are now ready!") diff --git a/src/fmu/dataio/datastructure/meta/content.py b/src/fmu/dataio/datastructure/meta/content.py index f1d57bd65..efac252f0 100644 --- a/src/fmu/dataio/datastructure/meta/content.py +++ b/src/fmu/dataio/datastructure/meta/content.py @@ -197,9 +197,9 @@ class Content(BaseModel): is_prediction: bool = Field( title="Is prediction flag", ) - layout: Optional[str] = Field( + layout: Optional[enums.Layout] = Field( default=None, - examples=["regular"], + examples=["regular", "cornerpoint"], ) name: str = Field( description=( diff --git a/src/fmu/dataio/datastructure/meta/enums.py b/src/fmu/dataio/datastructure/meta/enums.py index e28f6df72..f16cf4906 100644 --- a/src/fmu/dataio/datastructure/meta/enums.py +++ b/src/fmu/dataio/datastructure/meta/enums.py @@ -4,6 +4,17 @@ from typing import Type +class AccessLevel(str, Enum): + asset = "asset" + internal = "internal" + restricted = "restricted" + + +class AxisOrientation(IntEnum): + normal = 1 + flipped = -1 + + class ContentEnum(str, Enum): depth = "depth" facies_thickness = "facies_thickness" @@ -52,12 +63,10 @@ class FMUClassEnum(str, Enum): dictionary = "dictionary" -class AccessLevel(str, Enum): - asset = "asset" - internal = "internal" - restricted = "restricted" - - -class AxisOrientation(IntEnum): - normal = 1 - flipped = -1 +class Layout(str, Enum): + regular = "regular" + unset = "unset" + cornerpoint = "cornerpoint" + table = "table" + dictionary = "dictionary" + faultroom_triangulated = "faultroom_triangulated" diff --git a/src/fmu/dataio/providers/objectdata/_base.py b/src/fmu/dataio/providers/objectdata/_base.py index 2adab1637..aab7c2901 100644 --- a/src/fmu/dataio/providers/objectdata/_base.py +++ b/src/fmu/dataio/providers/objectdata/_base.py @@ -4,7 +4,7 @@ from copy import deepcopy from dataclasses import dataclass, field from datetime import datetime -from typing import TYPE_CHECKING, Final +from typing import TYPE_CHECKING, Any, Final from warnings import warn from fmu.dataio._definitions import ConfigurationError, ValidFormats @@ -20,10 +20,9 @@ from fmu.dataio.providers._base import Provider if TYPE_CHECKING: - from fmu.dataio._definitions import Layout from fmu.dataio.dataio import ExportData from fmu.dataio.datastructure.meta.content import BoundingBox2D, BoundingBox3D - from fmu.dataio.datastructure.meta.enums import FMUClassEnum + from fmu.dataio.datastructure.meta.enums import FMUClassEnum, Layout from fmu.dataio.datastructure.meta.specification import AnySpecification from fmu.dataio.types import Inferrable @@ -62,7 +61,7 @@ class ObjectDataProvider(Provider): # result properties; the most important is metadata which IS the 'data' part in # the resulting metadata. But other variables needed later are also given # as instance properties in addition (for simplicity in other classes/functions) - _metadata: dict = field(default_factory=dict) + _metadata: AnyContent | UnsetAnyContent | None = field(default=None) name: str = field(default="") time0: datetime | None = field(default=None) time1: datetime | None = field(default=None) @@ -80,53 +79,44 @@ def __post_init__(self) -> None: content_model = self._get_validated_content(self.dataio.content) named_stratigraphy = self._get_named_stratigraphy() - self.name = named_stratigraphy.name - self._metadata["name"] = self.name - self._metadata["stratigraphic"] = named_stratigraphy.stratigraphic - self._metadata["offset"] = named_stratigraphy.offset - self._metadata["alias"] = named_stratigraphy.alias - self._metadata["top"] = named_stratigraphy.top - self._metadata["base"] = named_stratigraphy.base - - self._metadata["content"] = (usecontent := content_model.content) + + metadata: dict[str, Any] = {} + metadata["name"] = self.name + metadata["stratigraphic"] = named_stratigraphy.stratigraphic + metadata["offset"] = named_stratigraphy.offset + metadata["alias"] = named_stratigraphy.alias + metadata["top"] = named_stratigraphy.top + metadata["base"] = named_stratigraphy.base + + metadata["content"] = (usecontent := content_model.content) if content_model.content_incl_specific: - self._metadata[usecontent] = getattr( + metadata[usecontent] = getattr( content_model.content_incl_specific, usecontent, None ) - self._metadata["tagname"] = self.dataio.tagname - self._metadata["format"] = self.fmt - self._metadata["layout"] = self.layout - self._metadata["unit"] = self.dataio.unit or "" - self._metadata["vertical_domain"] = list(self.dataio.vertical_domain.keys())[0] - self._metadata["depth_reference"] = list(self.dataio.vertical_domain.values())[ - 0 - ] - - self._metadata["spec"] = ( - spec.model_dump(mode="json", exclude_none=True) - if (spec := self.get_spec()) - else None - ) - self._metadata["bbox"] = ( - bbox.model_dump(mode="json", exclude_none=True) - if (bbox := self.get_bbox()) - else None + metadata["tagname"] = self.dataio.tagname + metadata["format"] = self.fmt + metadata["layout"] = self.layout + metadata["unit"] = self.dataio.unit or "" + metadata["vertical_domain"] = list(self.dataio.vertical_domain.keys())[0] + metadata["depth_reference"] = list(self.dataio.vertical_domain.values())[0] + + metadata["spec"] = self.get_spec() + metadata["bbox"] = self.get_bbox() + metadata["time"] = self._get_timedata() + metadata["table_index"] = self.table_index + metadata["undef_is_zero"] = self.dataio.undef_is_zero + + metadata["is_prediction"] = self.dataio.is_prediction + metadata["is_observation"] = self.dataio.is_observation + metadata["description"] = generate_description(self.dataio.description) + + self._metadata = ( + UnsetAnyContent.model_validate(metadata) + if metadata["content"] == "unset" + else AnyContent.model_validate(metadata) ) - self._metadata["time"] = ( - timedata.model_dump(mode="json", exclude_none=True) - if (timedata := self._get_timedata()) - else None - ) - - self._metadata["table_index"] = self.table_index - self._metadata["undef_is_zero"] = self.dataio.undef_is_zero - - # timedata: - self._metadata["is_prediction"] = self.dataio.is_prediction - self._metadata["is_observation"] = self.dataio.is_observation - self._metadata["description"] = generate_description(self.dataio.description) logger.info("Derive all metadata for data object... DONE") @property @@ -168,11 +158,8 @@ def get_spec(self) -> AnySpecification | None: raise NotImplementedError def get_metadata(self) -> AnyContent | UnsetAnyContent: - return ( - UnsetAnyContent.model_validate(self._metadata) - if self._metadata["content"] == "unset" - else AnyContent.model_validate(self._metadata) - ) + assert self._metadata is not None + return self._metadata def _get_validated_content(self, content: str | dict | None) -> AllowedContent: """Check content and return a validated model.""" diff --git a/src/fmu/dataio/providers/objectdata/_faultroom.py b/src/fmu/dataio/providers/objectdata/_faultroom.py index bab355968..dde9acbee 100644 --- a/src/fmu/dataio/providers/objectdata/_faultroom.py +++ b/src/fmu/dataio/providers/objectdata/_faultroom.py @@ -3,10 +3,10 @@ from dataclasses import dataclass from typing import Final -from fmu.dataio._definitions import ExportFolder, Layout, ValidFormats +from fmu.dataio._definitions import ExportFolder, ValidFormats from fmu.dataio._logging import null_logger from fmu.dataio.datastructure.meta.content import BoundingBox3D -from fmu.dataio.datastructure.meta.enums import FMUClassEnum +from fmu.dataio.datastructure.meta.enums import FMUClassEnum, Layout from fmu.dataio.datastructure.meta.specification import FaultRoomSurfaceSpecification from fmu.dataio.readers import FaultRoomSurface diff --git a/src/fmu/dataio/providers/objectdata/_provider.py b/src/fmu/dataio/providers/objectdata/_provider.py index 2f0aff261..3e2530d77 100644 --- a/src/fmu/dataio/providers/objectdata/_provider.py +++ b/src/fmu/dataio/providers/objectdata/_provider.py @@ -92,9 +92,9 @@ import pandas as pd import xtgeo -from fmu.dataio._definitions import ExportFolder, Layout, ValidFormats +from fmu.dataio._definitions import ExportFolder, ValidFormats from fmu.dataio._logging import null_logger -from fmu.dataio.datastructure.meta.enums import FMUClassEnum +from fmu.dataio.datastructure.meta.enums import FMUClassEnum, Layout from fmu.dataio.readers import FaultRoomSurface from ._base import ( diff --git a/src/fmu/dataio/providers/objectdata/_tables.py b/src/fmu/dataio/providers/objectdata/_tables.py index cc0969154..9849f6fce 100644 --- a/src/fmu/dataio/providers/objectdata/_tables.py +++ b/src/fmu/dataio/providers/objectdata/_tables.py @@ -8,11 +8,10 @@ from fmu.dataio._definitions import ( STANDARD_TABLE_INDEX_COLUMNS, ExportFolder, - Layout, ValidFormats, ) from fmu.dataio._logging import null_logger -from fmu.dataio.datastructure.meta.enums import FMUClassEnum +from fmu.dataio.datastructure.meta.enums import FMUClassEnum, Layout from fmu.dataio.datastructure.meta.specification import TableSpecification from ._base import ( diff --git a/src/fmu/dataio/providers/objectdata/_xtgeo.py b/src/fmu/dataio/providers/objectdata/_xtgeo.py index a8f24f105..72fcd919d 100644 --- a/src/fmu/dataio/providers/objectdata/_xtgeo.py +++ b/src/fmu/dataio/providers/objectdata/_xtgeo.py @@ -7,11 +7,11 @@ import pandas as pd import xtgeo -from fmu.dataio._definitions import ExportFolder, Layout, ValidFormats +from fmu.dataio._definitions import ExportFolder, ValidFormats from fmu.dataio._logging import null_logger from fmu.dataio._utils import npfloat_to_float from fmu.dataio.datastructure.meta.content import BoundingBox2D, BoundingBox3D -from fmu.dataio.datastructure.meta.enums import FMUClassEnum +from fmu.dataio.datastructure.meta.enums import FMUClassEnum, Layout from fmu.dataio.datastructure.meta.specification import ( CPGridPropertySpecification, CPGridSpecification, @@ -21,9 +21,7 @@ SurfaceSpecification, ) -from ._base import ( - ObjectDataProvider, -) +from ._base import ObjectDataProvider if TYPE_CHECKING: import pandas as pd diff --git a/tests/test_units/test_metadata_class.py b/tests/test_units/test_metadata_class.py index 1d7c51ad8..2b0397bb6 100644 --- a/tests/test_units/test_metadata_class.py +++ b/tests/test_units/test_metadata_class.py @@ -44,7 +44,7 @@ def test_metadata_dollars(edataobj1, regsurf): def test_generate_meta_tracklog_fmu_dataio_version(regsurf, edataobj1): mymeta = generate_export_metadata(regsurf, edataobj1) - tracklog = mymeta["tracklog"] + tracklog = mymeta.tracklog assert isinstance(tracklog, list) assert len(tracklog) == 1 # assume "created" @@ -67,7 +67,7 @@ def test_generate_meta_tracklog_komodo_version(edataobj1, regsurf, monkeypatch): monkeypatch.setenv("KOMODO_RELEASE", fake_komodo_release) mymeta = generate_export_metadata(regsurf, edataobj1) - tracklog = mymeta["tracklog"] + tracklog = mymeta.tracklog assert isinstance(tracklog, list) assert len(tracklog) == 1 # assume "created" @@ -87,7 +87,7 @@ def test_generate_meta_tracklog_komodo_version(edataobj1, regsurf, monkeypatch): def test_generate_meta_tracklog_operating_system(edataobj1, regsurf): mymeta = generate_export_metadata(regsurf, edataobj1) - tracklog = mymeta["tracklog"] + tracklog = mymeta.tracklog assert isinstance(tracklog, list) assert len(tracklog) == 1 # assume "created" @@ -109,16 +109,13 @@ def test_populate_meta_objectdata(regsurf, edataobj2): objdata = objectdata_provider_factory(regsurf, edataobj2) assert objdata.name == "VOLANTIS GP. Top" - assert mymeta["display"]["name"] == objdata.name + assert mymeta.display.name == objdata.name assert edataobj2.name == "TopVolantis" # surfaces shall have data.spec - assert mymeta["data"] - assert mymeta["data"]["spec"] - assert mymeta["data"]["spec"] == objdata.get_spec().model_dump( - mode="json", - exclude_none=True, - ) + assert mymeta.data + assert mymeta.data.root.spec + assert mymeta.data.root.spec == objdata.get_spec() def test_bbox_zmin_zmax_presence(polygons, edataobj2): @@ -131,8 +128,8 @@ def test_bbox_zmin_zmax_presence(polygons, edataobj2): mymeta = generate_export_metadata(polygons, edataobj2) # polygons shall have data.spec - assert "zmin" in mymeta["data"]["bbox"] - assert "zmax" in mymeta["data"]["bbox"] + assert mymeta.data.root.bbox.zmin + assert mymeta.data.root.bbox.zmax def test_populate_meta_undef_is_zero(regsurf, globalconfig2): @@ -185,10 +182,16 @@ def test_metadata_populate_masterdata_is_present_ok(edataobj1, edataobj2, regsur """Testing the masterdata part with OK metdata.""" mymeta = generate_export_metadata(regsurf, edataobj1) - assert mymeta["masterdata"] == edataobj1.config["masterdata"] + assert ( + mymeta.masterdata.model_dump(mode="json", exclude_none=True) + == edataobj1.config["masterdata"] + ) mymeta = generate_export_metadata(regsurf, edataobj2) - assert mymeta["masterdata"] == edataobj2.config["masterdata"] + assert ( + mymeta.masterdata.model_dump(mode="json", exclude_none=True) + == edataobj2.config["masterdata"] + ) # -------------------------------------------------------------------------------------- @@ -207,14 +210,14 @@ def test_metadata_populate_access_miss_cfg_access(globalconfig1, regsurf): mymeta = generate_export_metadata(regsurf, edata) # check that the default "internal" is used - assert mymeta["access"]["classification"] == "internal" + assert mymeta.access.classification == "internal" def test_metadata_populate_access_ok_config(edataobj2, regsurf): """Testing the access part, now with config ok access.""" mymeta = generate_export_metadata(regsurf, edataobj2) - assert mymeta["access"] == { + assert mymeta.access.model_dump(mode="json", exclude_none=True) == { "asset": {"name": "Drogon"}, "ssdl": {"access_level": "internal", "rep_include": True}, "classification": "internal", @@ -234,7 +237,7 @@ def test_metadata_populate_from_argument(globalconfig1, regsurf): ) mymeta = generate_export_metadata(regsurf, edata) - assert mymeta["access"] == { + assert mymeta.access.model_dump(mode="json", exclude_none=True) == { "asset": {"name": "Test"}, "ssdl": {"access_level": "restricted", "rep_include": True}, "classification": "restricted", # mirroring ssdl.access_level @@ -254,9 +257,9 @@ def test_metadata_populate_partial_access_ssdl(globalconfig1, regsurf): ) mymeta = generate_export_metadata(regsurf, edata) - assert mymeta["access"]["ssdl"]["rep_include"] is True - assert mymeta["access"]["ssdl"]["access_level"] == "internal" # default - assert mymeta["access"]["classification"] == "internal" # default + assert mymeta.access.ssdl.rep_include is True + assert mymeta.access.ssdl.access_level == "internal" # default + assert mymeta.access.classification == "internal" # default # access_level only, but in config edata = dio.ExportData( @@ -265,9 +268,9 @@ def test_metadata_populate_partial_access_ssdl(globalconfig1, regsurf): content="depth", ) mymeta = generate_export_metadata(regsurf, edata) - assert mymeta["access"]["ssdl"]["rep_include"] is False # default - assert mymeta["access"]["ssdl"]["access_level"] == "restricted" - assert mymeta["access"]["classification"] == "restricted" + assert mymeta.access.ssdl.rep_include is False # default + assert mymeta.access.ssdl.access_level == "restricted" + assert mymeta.access.classification == "restricted" def test_metadata_populate_wrong_config(globalconfig1, regsurf): @@ -284,7 +287,7 @@ def test_metadata_populate_wrong_config(globalconfig1, regsurf): # use default 'internal' if wrong in config meta = generate_export_metadata(regsurf, edata) - assert meta["access"]["classification"] == "internal" + assert meta.access.classification == "internal" def test_metadata_populate_wrong_argument(globalconfig1): @@ -307,9 +310,9 @@ def test_metadata_access_correct_input(globalconfig1, regsurf): access_ssdl={"access_level": "restricted", "rep_include": False}, ) mymeta = generate_export_metadata(regsurf, edata) - assert mymeta["access"]["ssdl"]["rep_include"] is False - assert mymeta["access"]["ssdl"]["access_level"] == "restricted" - assert mymeta["access"]["classification"] == "restricted" + assert mymeta.access.ssdl.rep_include is False + assert mymeta.access.ssdl.access_level == "restricted" + assert mymeta.access.classification == "restricted" # Input is "internal" and True - correct use, shall work edata = dio.ExportData( @@ -318,9 +321,9 @@ def test_metadata_access_correct_input(globalconfig1, regsurf): access_ssdl={"access_level": "internal", "rep_include": True}, ) mymeta = generate_export_metadata(regsurf, edata) - assert mymeta["access"]["ssdl"]["rep_include"] is True - assert mymeta["access"]["ssdl"]["access_level"] == "internal" - assert mymeta["access"]["classification"] == "internal" + assert mymeta.access.ssdl.rep_include is True + assert mymeta.access.ssdl.access_level == "internal" + assert mymeta.access.classification == "internal" def test_metadata_access_deprecated_input(globalconfig1, regsurf): @@ -339,8 +342,8 @@ def test_metadata_access_deprecated_input(globalconfig1, regsurf): assert edata._config_is_valid mymeta = generate_export_metadata(regsurf, edata) - assert mymeta["access"]["ssdl"]["access_level"] == "restricted" - assert mymeta["access"]["classification"] == "restricted" + assert mymeta.access.ssdl.access_level == "restricted" + assert mymeta.access.classification == "restricted" def test_metadata_access_illegal_input(globalconfig1): @@ -375,9 +378,9 @@ def test_metadata_access_no_input(globalconfig1, regsurf): configcopy["access"]["ssdl"]["rep_include"] = True edata = dio.ExportData(config=configcopy, content="depth") mymeta = generate_export_metadata(regsurf, edata) - assert mymeta["access"]["ssdl"]["rep_include"] is True - assert mymeta["access"]["ssdl"]["access_level"] == "restricted" - assert mymeta["access"]["classification"] == "restricted" # mirrored + assert mymeta.access.ssdl.rep_include is True + assert mymeta.access.ssdl.access_level == "restricted" + assert mymeta.access.classification == "restricted" # mirrored # No input, no config, shall default to "internal" and False configcopy = deepcopy(globalconfig1) @@ -385,9 +388,9 @@ def test_metadata_access_no_input(globalconfig1, regsurf): del configcopy["access"]["ssdl"]["rep_include"] edata = dio.ExportData(config=globalconfig1, content="depth") mymeta = generate_export_metadata(regsurf, edata) - assert mymeta["access"]["ssdl"]["rep_include"] is False # default - assert mymeta["access"]["ssdl"]["access_level"] == "internal" # default - assert mymeta["access"]["classification"] == "internal" # mirrored + assert mymeta.access.ssdl.rep_include is False # default + assert mymeta.access.ssdl.access_level == "internal" # default + assert mymeta.access.classification == "internal" # mirrored # -------------------------------------------------------------------------------------- @@ -401,8 +404,7 @@ def test_metadata_display_name_not_given(regsurf, edataobj2): mymeta = generate_export_metadata(regsurf, edataobj2) objdata = objectdata_provider_factory(regsurf, edataobj2) - assert "name" in mymeta["display"] - assert mymeta["display"]["name"] == objdata.name + assert mymeta.display.name == objdata.name def test_metadata_display_name_given(regsurf, edataobj2): @@ -413,7 +415,7 @@ def test_metadata_display_name_given(regsurf, edataobj2): mymeta = generate_export_metadata(regsurf, edataobj2) objdata = objectdata_provider_factory(regsurf, edataobj2) - assert mymeta["display"]["name"] == "My Display Name" + assert mymeta.display.name == "My Display Name" assert objdata.name == "VOLANTIS GP. Top" @@ -426,12 +428,13 @@ def test_generate_full_metadata(regsurf, edataobj2): """Generating the full metadata block for a xtgeo surface.""" metadata_result = generate_export_metadata( - regsurf, edataobj2, skip_null=False - ) # want to have None + regsurf, + edataobj2, + ) logger.debug("\n%s", prettyprint_dict(metadata_result)) # check some samples - assert metadata_result["masterdata"]["smda"]["country"][0]["identifier"] == "Norway" - assert metadata_result["access"]["ssdl"]["access_level"] == "internal" - assert metadata_result["data"]["unit"] == "m" + assert metadata_result.masterdata.smda.country[0].identifier == "Norway" + assert metadata_result.access.ssdl.access_level == "internal" + assert metadata_result.data.root.unit == "m" diff --git a/tests/test_units/test_objectdataprovider_class.py b/tests/test_units/test_objectdataprovider_class.py index 28442a630..b4679a7e1 100644 --- a/tests/test_units/test_objectdataprovider_class.py +++ b/tests/test_units/test_objectdataprovider_class.py @@ -86,8 +86,9 @@ def test_objectdata_regularsurface_derive_metadata(regsurf, edataobj1): """Derive all metadata for the 'data' block in fmu-dataio.""" myobj = objectdata_provider_factory(regsurf, edataobj1) - assert myobj._metadata["content"] == "depth" - assert myobj._metadata["alias"] + metadata = myobj.get_metadata() + assert metadata.root.content == "depth" + assert metadata.root.alias def test_objectdata_provider_factory_raises_on_unknown(edataobj1):