From 01d77c22b9a416474bc9e8123c3c231b3b747f0c Mon Sep 17 00:00:00 2001 From: Runar Ask Johannessen <89020325+equinor-ruaj@users.noreply.github.com> Date: Fri, 20 Sep 2024 11:32:24 +0200 Subject: [PATCH 1/6] ENH: Add realization and iteration object metadata definitions (#785) --- .../definitions/0.8.0/examples/iteration.yml | 64 ++++++ .../0.8.0/examples/realization.yml | 72 +++++++ .../definitions/0.8.0/schema/fmu_results.json | 196 ++++++++++++++++++ src/fmu/dataio/_model/enums.py | 2 + src/fmu/dataio/_model/fields.py | 64 ++++++ src/fmu/dataio/_model/root.py | 40 ++++ tests/test_schema/test_pydantic_logic.py | 60 ++++++ 7 files changed, 498 insertions(+) create mode 100644 schema/definitions/0.8.0/examples/iteration.yml create mode 100644 schema/definitions/0.8.0/examples/realization.yml diff --git a/schema/definitions/0.8.0/examples/iteration.yml b/schema/definitions/0.8.0/examples/iteration.yml new file mode 100644 index 000000000..03ed9eaaf --- /dev/null +++ b/schema/definitions/0.8.0/examples/iteration.yml @@ -0,0 +1,64 @@ +# Example metadata for an FMU Iteration object. + +$schema: https://main-fmu-schemas-dev.radix.equinor.com/schemas/0.8.0/fmu_results.json +version: "0.8.0" +source: fmu +tracklog: + - datetime: 2020-10-28T14:28:02 + user: + id: peesv + event: created + - datetime: 2020-10-28T14:46:14 + user: + id: peesv + event: updated + +class: iteration # class is the main identifier of the data type. + +fmu: # the fmu-block contains information directly related to the FMU context + model: + name: ff + revision: 21.0.0.dev + description: + - detailed description + - optional + + case: + name: MyCaseName + uuid: 8bb56d60-8758-481a-89a4-6bac8561d38e + user: + id: jriv # $USER from ERT + description: + - yet other detailed description + - optional + + context: + stage: iteration + + iteration: + id: 0 + name: iter-0 + uuid: fd6e8f2a-f298-434a-80f4-90f0f6f84688 + +access: + asset: + name: Drogon + classification: internal + +masterdata: + smda: + country: + - identifier: Norway + uuid: ad214d85-8a1d-19da-e053-c918a4889309 + discovery: + - short_identifier: DROGON + uuid: 00000000-0000-0000-0000-000000000000 # mock uuid for Drogon + field: + - identifier: DROGON + uuid: 00000000-0000-0000-0000-000000000000 # mock uuid for Drogon + coordinate_system: + identifier: ST_WGS84_UTM37N_P32637 + uuid: ad214d85-dac7-19da-e053-c918a4889309 + stratigraphic_column: + identifier: DROGON_2020 + uuid: 00000000-0000-0000-0000-000000000000 # mock uuid for Drogon diff --git a/schema/definitions/0.8.0/examples/realization.yml b/schema/definitions/0.8.0/examples/realization.yml new file mode 100644 index 000000000..d66fd9063 --- /dev/null +++ b/schema/definitions/0.8.0/examples/realization.yml @@ -0,0 +1,72 @@ +# Example metadata for an FMU Realization object. + +$schema: https://main-fmu-schemas-dev.radix.equinor.com/schemas/0.8.0/fmu_results.json +version: "0.8.0" +source: fmu +tracklog: + - datetime: 2020-10-28T14:28:02 + user: + id: peesv + event: created + - datetime: 2020-10-28T14:46:14 + user: + id: peesv + event: updated + +class: realization # class is the main identifier of the data type. + +fmu: # the fmu-block contains information directly related to the FMU context + model: + name: ff + revision: 21.0.0.dev + description: + - detailed description + - optional + + case: + name: MyCaseName + uuid: 8bb56d60-8758-481a-89a4-6bac8561d38e + user: + id: jriv # $USER from ERT + description: + - yet other detailed description + - optional + + context: + stage: realization + + iteration: + id: 0 + name: iter-0 + uuid: fd6e8f2a-f298-434a-80f4-90f0f6f84688 + + realization: + id: 0 + name: realization-0 + uuid: 8ba597f5-07e0-a789-b9ad-fd16b1966f58 + parameters: + param1: val1 + param2: val2 + +access: + asset: + name: Drogon + classification: internal + +masterdata: + smda: + country: + - identifier: Norway + uuid: ad214d85-8a1d-19da-e053-c918a4889309 + discovery: + - short_identifier: DROGON + uuid: 00000000-0000-0000-0000-000000000000 # mock uuid for Drogon + field: + - identifier: DROGON + uuid: 00000000-0000-0000-0000-000000000000 # mock uuid for Drogon + coordinate_system: + identifier: ST_WGS84_UTM37N_P32637 + uuid: ad214d85-dac7-19da-e053-c918a4889309 + stratigraphic_column: + identifier: DROGON_2020 + uuid: 00000000-0000-0000-0000-000000000000 # mock uuid for Drogon diff --git a/schema/definitions/0.8.0/schema/fmu_results.json b/schema/definitions/0.8.0/schema/fmu_results.json index b9bf169f4..d63e3c2b1 100644 --- a/schema/definitions/0.8.0/schema/fmu_results.json +++ b/schema/definitions/0.8.0/schema/fmu_results.json @@ -1128,6 +1128,60 @@ "title": "FMUContext", "type": "string" }, + "FMUIteration": { + "description": "The ``fmu`` block contains all attributes specific to FMU. The idea is that the FMU\nresults data model can be applied to data from *other* sources - in which the\nfmu-specific stuff may not make sense or be applicable.\nThis is a specialization of the FMU block for ``iteration`` objects.", + "properties": { + "case": { + "$ref": "#/$defs/Case" + }, + "context": { + "$ref": "#/$defs/IterationContext" + }, + "iteration": { + "$ref": "#/$defs/Iteration" + }, + "model": { + "$ref": "#/$defs/Model" + } + }, + "required": [ + "case", + "model", + "context", + "iteration" + ], + "title": "FMUIteration", + "type": "object" + }, + "FMURealization": { + "description": "The ``fmu`` block contains all attributes specific to FMU. The idea is that the FMU\nresults data model can be applied to data from *other* sources - in which the\nfmu-specific stuff may not make sense or be applicable.\nThis is a specialization of the FMU block for ``realization`` objects.", + "properties": { + "case": { + "$ref": "#/$defs/Case" + }, + "context": { + "$ref": "#/$defs/RealizationContext" + }, + "iteration": { + "$ref": "#/$defs/Iteration" + }, + "model": { + "$ref": "#/$defs/Model" + }, + "realization": { + "$ref": "#/$defs/Realization" + } + }, + "required": [ + "case", + "model", + "context", + "iteration", + "realization" + ], + "title": "FMURealization", + "type": "object" + }, "FaciesThicknessData": { "description": "The ``data`` block contains information about the data contained in this object.\nThis class contains metadata for facies thickness.", "properties": { @@ -3286,6 +3340,74 @@ "title": "Iteration", "type": "object" }, + "IterationContext": { + "description": "The ``fmu.context`` block contains the FMU context in which this data object\nwas produced. Here ``stage`` is required to be ``iteration``.", + "properties": { + "stage": { + "const": "iteration", + "default": "iteration", + "enum": [ + "iteration" + ], + "title": "Stage", + "type": "string" + } + }, + "title": "IterationContext", + "type": "object" + }, + "IterationMetadata": { + "description": "The FMU metadata model for an FMU Iteration.\n\nAn object representing a single Iteration of a specific case.", + "properties": { + "access": { + "$ref": "#/$defs/Access" + }, + "class": { + "const": "iteration", + "enum": [ + "iteration" + ], + "title": "metadata_class", + "type": "string" + }, + "fmu": { + "$ref": "#/$defs/FMUIteration" + }, + "masterdata": { + "$ref": "#/$defs/Masterdata" + }, + "source": { + "const": "fmu", + "enum": [ + "fmu" + ], + "title": "Source", + "type": "string" + }, + "tracklog": { + "$ref": "#/$defs/Tracklog" + }, + "version": { + "const": "0.8.0", + "enum": [ + "0.8.0" + ], + "title": "Version", + "type": "string" + } + }, + "required": [ + "class", + "masterdata", + "tracklog", + "source", + "version", + "fmu", + "access" + ], + "title": "IterationMetadata", + "type": "object" + }, "KPProductData": { "description": "The ``data`` block contains information about the data contained in this object.\nThis class contains metadata for KP products.", "properties": { @@ -6059,6 +6181,74 @@ "title": "Realization", "type": "object" }, + "RealizationContext": { + "description": "The ``fmu.context`` block contains the FMU context in which this data object\nwas produced. Here ``stage`` is required to be ``realization``.", + "properties": { + "stage": { + "const": "realization", + "default": "realization", + "enum": [ + "realization" + ], + "title": "Stage", + "type": "string" + } + }, + "title": "RealizationContext", + "type": "object" + }, + "RealizationMetadata": { + "description": "The FMU metadata model for an FMU Realization.\n\nAn object representing a single Realization of a specific Iteration.", + "properties": { + "access": { + "$ref": "#/$defs/Access" + }, + "class": { + "const": "realization", + "enum": [ + "realization" + ], + "title": "metadata_class", + "type": "string" + }, + "fmu": { + "$ref": "#/$defs/FMURealization" + }, + "masterdata": { + "$ref": "#/$defs/Masterdata" + }, + "source": { + "const": "fmu", + "enum": [ + "fmu" + ], + "title": "Source", + "type": "string" + }, + "tracklog": { + "$ref": "#/$defs/Tracklog" + }, + "version": { + "const": "0.8.0", + "enum": [ + "0.8.0" + ], + "title": "Version", + "type": "string" + } + }, + "required": [ + "class", + "masterdata", + "tracklog", + "source", + "version", + "fmu", + "access" + ], + "title": "RealizationMetadata", + "type": "object" + }, "RegionsData": { "description": "The ``data`` block contains information about the data contained in this object.\nThis class contains metadata for regions.", "properties": { @@ -9632,6 +9822,12 @@ }, { "$ref": "#/$defs/ObjectMetadata" + }, + { + "$ref": "#/$defs/RealizationMetadata" + }, + { + "$ref": "#/$defs/IterationMetadata" } ], "then": { diff --git a/src/fmu/dataio/_model/enums.py b/src/fmu/dataio/_model/enums.py index 38cb34013..e0c8f9476 100644 --- a/src/fmu/dataio/_model/enums.py +++ b/src/fmu/dataio/_model/enums.py @@ -60,6 +60,8 @@ class FMUClass(str, Enum): """The class of a data object by FMU convention or standards.""" case = "case" + realization = "realization" + iteration = "iteration" surface = "surface" table = "table" cpgrid = "cpgrid" diff --git a/src/fmu/dataio/_model/fields.py b/src/fmu/dataio/_model/fields.py index ca2ea29d1..f09bbc125 100644 --- a/src/fmu/dataio/_model/fields.py +++ b/src/fmu/dataio/_model/fields.py @@ -11,6 +11,7 @@ Any, Dict, List, + Literal, Optional, Union, ) @@ -556,6 +557,28 @@ class Context(BaseModel): See :class:`enums.FMUContext`.""" +class IterationContext(Context): + """ + The ``fmu.context`` block contains the FMU context in which this data object + was produced. Here ``stage`` is required to be ``iteration``. + """ + + stage: Literal[enums.FMUContext.iteration] = Field( + default=enums.FMUContext.iteration + ) + + +class RealizationContext(Context): + """ + The ``fmu.context`` block contains the FMU context in which this data object + was produced. Here ``stage`` is required to be ``realization``. + """ + + stage: Literal[enums.FMUContext.realization] = Field( + default=enums.FMUContext.realization + ) + + class FMUBase(BaseModel): """ The ``fmu`` block contains all attributes specific to FMU. The idea is that the FMU @@ -572,6 +595,47 @@ class FMUBase(BaseModel): See :class:`Model`.""" +class FMUIteration(FMUBase): + """ + The ``fmu`` block contains all attributes specific to FMU. The idea is that the FMU + results data model can be applied to data from *other* sources - in which the + fmu-specific stuff may not make sense or be applicable. + This is a specialization of the FMU block for ``iteration`` objects. + """ + + context: IterationContext + """The ``fmu.context`` block contains the FMU context in which this data object + was produced. See :class:`Context`. For ``iteration`` the context is ``iteration``. + """ + + iteration: Iteration + """The ``fmu.iteration`` block contains information about the iteration this data + object belongs to. See :class:`Iteration`. """ + + +class FMURealization(FMUBase): + """ + The ``fmu`` block contains all attributes specific to FMU. The idea is that the FMU + results data model can be applied to data from *other* sources - in which the + fmu-specific stuff may not make sense or be applicable. + This is a specialization of the FMU block for ``realization`` objects. + """ + + context: RealizationContext + """The ``fmu.context`` block contains the FMU context in which this data object + was produced. See :class:`Context`. For ``realization`` the context is always + ``realization``. + """ + + iteration: Iteration + """The ``fmu.iteration`` block contains information about the iteration this data + object belongs to. See :class:`Iteration`. """ + + realization: Realization + """The ``fmu.realization`` block contains information about the realization this + data object belongs to. See :class:`Realization`.""" + + class FMU(FMUBase): """ The ``fmu`` block contains all attributes specific to FMU. The idea is that the FMU diff --git a/src/fmu/dataio/_model/root.py b/src/fmu/dataio/_model/root.py index 699005df5..985fcf1a1 100644 --- a/src/fmu/dataio/_model/root.py +++ b/src/fmu/dataio/_model/root.py @@ -20,6 +20,8 @@ Display, File, FMUBase, + FMUIteration, + FMURealization, Masterdata, SsdlAccess, Tracklog, @@ -72,6 +74,42 @@ class CaseMetadata(MetadataBase): this data object. See :class:`Access`.""" +class IterationMetadata(MetadataBase): + """The FMU metadata model for an FMU Iteration. + + An object representing a single Iteration of a specific case. + """ + + class_: Literal[FMUClass.iteration] = Field(alias="class", title="metadata_class") + """The class of this metadata object. In this case, always an FMU iteration.""" + + fmu: FMUIteration + """The ``fmu`` block contains all attributes specific to FMU. + See :class:`FMU`.""" + + access: Access + """The ``access`` block contains information related to access control for + this data object. See :class:`Access`.""" + + +class RealizationMetadata(MetadataBase): + """The FMU metadata model for an FMU Realization. + + An object representing a single Realization of a specific Iteration. + """ + + class_: Literal[FMUClass.realization] = Field(alias="class", title="metadata_class") + """The class of this metadata object. In this case, always an FMU realization.""" + + fmu: FMURealization + """The ``fmu`` block contains all attributes specific to FMU. + See :class:`FMU`.""" + + access: Access + """The ``access`` block contains information related to access control for + this data object. See :class:`Access`.""" + + class ObjectMetadata(MetadataBase): """The FMU metadata model for a given data object.""" @@ -119,6 +157,8 @@ class Root( Union[ CaseMetadata, ObjectMetadata, + RealizationMetadata, + IterationMetadata, ], Field(discriminator="class_"), ] diff --git a/tests/test_schema/test_pydantic_logic.py b/tests/test_schema/test_pydantic_logic.py index af6d6894b..d7fc7fff6 100644 --- a/tests/test_schema/test_pydantic_logic.py +++ b/tests/test_schema/test_pydantic_logic.py @@ -404,3 +404,63 @@ def test_zmin_zmax_not_present_for_surfaces(metadata_examples): del example_surface["data"]["bbox"]["zmax"] model = Root.model_validate(example_surface) assert isinstance(model.root.data.root.bbox, data.BoundingBox2D) + + +def test_iteration(metadata_examples): + """Asserting validation failure when illegal contents in case example""" + + example = metadata_examples["iteration.yml"] + + # assert validation with no changes + Root.model_validate(example) + + # assert validation error when "fmu" is missing + _example = deepcopy(example) + del _example["fmu"] + + with pytest.raises(ValidationError): + Root.model_validate(_example) + + # assert validation error when "fmu.iteration" is missing + _example = deepcopy(example) + del _example["fmu"]["iteration"] + + with pytest.raises(ValidationError): + Root.model_validate(_example) + + # assert validation error when "fmu.context.stage" is not iteration + _example = deepcopy(example) + _example["fmu"]["context"]["stage"] = "case" + + with pytest.raises(ValidationError): + Root.model_validate(_example) + + +def test_realization(metadata_examples): + """Asserting validation failure when illegal contents in case example""" + + example = metadata_examples["realization.yml"] + + # assert validation with no changes + Root.model_validate(example) + + # assert validation error when "fmu" is missing + _example = deepcopy(example) + del _example["fmu"] + + with pytest.raises(ValidationError): + Root.model_validate(_example) + + # assert validation error when "fmu.realization" is missing + _example = deepcopy(example) + del _example["fmu"]["realization"] + + with pytest.raises(ValidationError): + Root.model_validate(_example) + + # assert validation error when "fmu.context.stage" is not realization + _example = deepcopy(example) + _example["fmu"]["context"]["stage"] = "iteration" + + with pytest.raises(ValidationError): + Root.model_validate(_example) From 2ba7699d4f7c718a20b8332d72bdfe6ba2da6f56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Therese=20Natter=C3=B8y?= <61694854+tnatt@users.noreply.github.com> Date: Wed, 25 Sep 2024 15:42:15 +0200 Subject: [PATCH 2/6] REV: Set depth as default vertical_domain (#807) --- src/fmu/dataio/dataio.py | 12 ++++++------ tests/test_units/test_dataio.py | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/fmu/dataio/dataio.py b/src/fmu/dataio/dataio.py index b6d7e2f64..dc972dab1 100644 --- a/src/fmu/dataio/dataio.py +++ b/src/fmu/dataio/dataio.py @@ -218,7 +218,7 @@ class ExportData: Note also: If missing or empty, export() may still be done, but without a metadata file (this feature may change in future releases). - content: Optional, default is "depth". Is a string or a dictionary with one key. + content: Optional. Is a string or a dictionary with one key. Example is "depth" or {"fluid_contact": {"xxx": "yyy", "zzz": "uuu"}}. Content is checked agains a white-list for validation! @@ -305,10 +305,10 @@ class ExportData: [[20200101, "monitor"], [20180101, "base"]] or just [[2021010]]. The output to metadata will from version 0.9 be different (API change) - vertical_domain: Optional. String with vertical domain either "time" or "depth". - It is also possible to provide a reference for the vertical scale, see the - domain_reference key. Note that if the ``content`` is "depth" or "time" - the vertical_domain will be set accordingly. + vertical_domain: Optional. String with vertical domain either "time" or "depth" + (default). It is also possible to provide a reference for the vertical scale, + see the domain_reference key. Note that if the ``content`` is "depth" or + "time" the vertical_domain will be set accordingly. workflow: Short tag desciption of workflow (as description) @@ -400,7 +400,7 @@ class ExportData: timedata: Optional[List[list]] = None unit: Optional[str] = "" verbosity: str = "DEPRECATED" # remove in version 2 - vertical_domain: Optional[Union[str, dict]] = None # dict input is deprecated + vertical_domain: Union[str, dict] = "depth" # dict input is deprecated workflow: Optional[Union[str, Dict[str, str]]] = None # dict input is deprecated table_index: Optional[list] = None diff --git a/tests/test_units/test_dataio.py b/tests/test_units/test_dataio.py index ac44d7545..4117fafdf 100644 --- a/tests/test_units/test_dataio.py +++ b/tests/test_units/test_dataio.py @@ -547,7 +547,7 @@ def test_vertical_domain(regsurf, globalconfig1): mymeta = ExportData(config=globalconfig1, content="thickness").generate_metadata( regsurf ) - assert "vertical_domain" not in mymeta["data"] + assert mymeta["data"]["vertical_domain"] == "depth" # default value assert mymeta["data"]["domain_reference"] == "msl" # default value # test invalid input From 1114ef33a9e146b7060f405bb1e1b41ee6637856 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Therese=20Natter=C3=B8y?= <61694854+tnatt@users.noreply.github.com> Date: Thu, 26 Sep 2024 08:36:02 +0200 Subject: [PATCH 3/6] BUG: Resolve restart_path correctly (#811) --- src/fmu/dataio/providers/_fmu.py | 40 ++++++++++++++-------- tests/test_units/test_fmuprovider_class.py | 26 +++++++++++++- 2 files changed, 51 insertions(+), 15 deletions(-) diff --git a/src/fmu/dataio/providers/_fmu.py b/src/fmu/dataio/providers/_fmu.py index 6f88d933e..f82d05ea8 100644 --- a/src/fmu/dataio/providers/_fmu.py +++ b/src/fmu/dataio/providers/_fmu.py @@ -36,6 +36,8 @@ from typing import TYPE_CHECKING, Final, Optional, Union from warnings import warn +import pydantic + from fmu.config import utilities as ut from fmu.dataio import _utils from fmu.dataio._logging import null_logger @@ -248,26 +250,36 @@ def _get_restart_data_uuid(self) -> UUID | None: """Load restart_from information""" assert self._runpath is not None logger.debug("Detected a restart run from environment variable") - restart_path = self._runpath / os.environ[RESTART_PATH_ENVNAME] - restart_case_metafile = ( - restart_path.parent.parent / ERT_RELATIVE_CASE_METADATA_FILE - ).resolve() + restart_path = (self._runpath / os.environ[RESTART_PATH_ENVNAME]).resolve() - if not restart_case_metafile.exists(): + if _casepath_has_metadata(restart_path.parent.parent): + restart_case_metafile = ( + restart_path.parent.parent / ERT_RELATIVE_CASE_METADATA_FILE + ) + else: warn( - f"{RESTART_PATH_ENVNAME} environment variable is set to " - f"{os.environ[RESTART_PATH_ENVNAME]} which is invalid. Metadata " - "restart_from will remain empty.", + f"Environment variable {RESTART_PATH_ENVNAME} resolves to the path " + f"{restart_path} which is non existing or points to an ERT run " + "without case metdata. Metadata 'restart_from' will remain empty.", UserWarning, ) return None - restart_metadata = schema.InternalCaseMetadata.model_validate( - ut.yaml_load(restart_case_metafile, loader="standard") - ) - return _utils.uuid_from_string( - f"{restart_metadata.fmu.case.uuid}{restart_path.name}" - ) + try: + restart_metadata = schema.InternalCaseMetadata.model_validate( + ut.yaml_load(restart_case_metafile) + ) + return _utils.uuid_from_string( + f"{restart_metadata.fmu.case.uuid}{restart_path.name}" + ) + except pydantic.ValidationError as err: + warn( + "The case metadata for the restart ensemble is invalid " + f"{restart_case_metafile}. Metadata 'restart_from' will remain empty. " + f"Detailed information: \n {str(err)}", + UserWarning, + ) + return None def _get_ert_parameters(self) -> fields.Parameters | None: logger.debug("Read ERT parameters") diff --git a/tests/test_units/test_fmuprovider_class.py b/tests/test_units/test_fmuprovider_class.py index 635287706..889d872e8 100644 --- a/tests/test_units/test_fmuprovider_class.py +++ b/tests/test_units/test_fmuprovider_class.py @@ -269,6 +269,30 @@ def test_fmuprovider_valid_restart_env(monkeypatch, fmurun_w_casemetadata, fmuru assert meta_restart.iteration.restart_from == meta_restart_from.iteration.uuid +def test_fmuprovider_valid_relative_restart_env( + monkeypatch, fmurun_w_casemetadata, fmurun_pred +): + """ + Test giving a valid RESTART_FROM_PATH environment variable that contains + a relative path from the existing runpath, which is a common use case. + """ + monkeypatch.chdir(fmurun_w_casemetadata) + meta_restart_from = FmuProvider( + model=GLOBAL_CONFIG_MODEL, fmu_context=FMUContext.realization + ).get_metadata() + + # using a relative path as input + monkeypatch.setenv(RESTART_PATH_ENVNAME, "../iter-0") + + monkeypatch.chdir(fmurun_pred) + meta_restart = FmuProvider( + model=GLOBAL_CONFIG_MODEL, fmu_context=FMUContext.realization + ).get_metadata() + + assert meta_restart.iteration.restart_from is not None + assert meta_restart.iteration.restart_from == meta_restart_from.iteration.uuid + + def test_fmuprovider_invalid_restart_env( monkeypatch, fmurun_w_casemetadata, fmurun_pred ): @@ -283,7 +307,7 @@ def test_fmuprovider_invalid_restart_env( monkeypatch.setenv(RESTART_PATH_ENVNAME, "/path/to/somewhere/invalid") os.chdir(fmurun_pred) - with pytest.warns(UserWarning, match="RESTART_FROM_PATH environment variable"): + with pytest.warns(UserWarning, match="non existing"): meta = FmuProvider( model=GLOBAL_CONFIG_MODEL, fmu_context=FMUContext.realization ).get_metadata() From 17cabe22a27ba283e30afa886874147f82a50603 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20C=2E=20Riven=C3=A6s?= Date: Tue, 24 Sep 2024 08:00:44 +0200 Subject: [PATCH 4/6] FIX, DEP: rename function from export_rms_volumetrics to export_volumetrics --- docs/src/rms_oneliners.rst | 6 +++--- src/fmu/dataio/export/rms/__init__.py | 4 ++-- src/fmu/dataio/export/rms/volumetrics.py | 16 +++++++++++++++- .../test_export_rms_volumetrics.py | 4 ++-- 4 files changed, 22 insertions(+), 8 deletions(-) diff --git a/docs/src/rms_oneliners.rst b/docs/src/rms_oneliners.rst index f969c792a..cc61ade91 100644 --- a/docs/src/rms_oneliners.rst +++ b/docs/src/rms_oneliners.rst @@ -18,11 +18,11 @@ Example: .. code-block:: python - from fmu.dataio.export.rms import export_rms_volumetrics + from fmu.dataio.export.rms import export_volumetrics ... # here 'Geogrid' is the grid model name, and 'geogrid_volumes' is the name of the volume job - outfiles = export_rms_volumetrics(project, "Geogrid", "geogrid_volumes") + outfiles = export_volumetrics(project, "Geogrid", "geogrid_volumes") print(f"Output volumes to {outfiles}") @@ -30,7 +30,7 @@ Most ``dataio`` settings are here defaulted, but some keys can be altered option .. code-block:: python - outfiles = export_rms_volumetrics( + outfiles = export_volumetrics( project, "Geogrid", "geogrid_volumes", diff --git a/src/fmu/dataio/export/rms/__init__.py b/src/fmu/dataio/export/rms/__init__.py index 5fcbf3b16..7ee29e580 100644 --- a/src/fmu/dataio/export/rms/__init__.py +++ b/src/fmu/dataio/export/rms/__init__.py @@ -1,3 +1,3 @@ -from .volumetrics import export_rms_volumetrics +from .volumetrics import export_rms_volumetrics, export_volumetrics -__all__ = ["export_rms_volumetrics"] +__all__ = ["export_volumetrics", "export_rms_volumetrics"] diff --git a/src/fmu/dataio/export/rms/volumetrics.py b/src/fmu/dataio/export/rms/volumetrics.py index da81aa427..22e5ca81f 100644 --- a/src/fmu/dataio/export/rms/volumetrics.py +++ b/src/fmu/dataio/export/rms/volumetrics.py @@ -1,5 +1,6 @@ from __future__ import annotations +import warnings from dataclasses import dataclass, field from pathlib import Path from typing import Any, Final @@ -191,7 +192,7 @@ def export(self) -> dict[str, str]: return self._export_volume_table() -def export_rms_volumetrics( +def export_volumetrics( project: Any, grid_name: str, volume_job_name: str, @@ -242,3 +243,16 @@ def export_rms_volumetrics( classification=classification, workflow=workflow, ).export() + + +# keep the old name for now but not log (will be removed soon as we expect close to +# zero usage so far) +def export_rms_volumetrics(*args, **kwargs) -> dict[str, str]: # type: ignore + """Deprecated function. Use export_volumetrics instead.""" + warnings.warn( + "export_rms_volumetrics is deprecated and will be removed in a future release. " + "Use export_volumetrics instead.", + FutureWarning, + stacklevel=2, + ) + return export_volumetrics(*args, **kwargs) diff --git a/tests/test_export_rms/test_export_rms_volumetrics.py b/tests/test_export_rms/test_export_rms_volumetrics.py index 20fd40746..882d1614f 100644 --- a/tests/test_export_rms/test_export_rms_volumetrics.py +++ b/tests/test_export_rms/test_export_rms_volumetrics.py @@ -60,11 +60,11 @@ def test_rms_volumetrics_export_function( ): """Test the public function.""" - from fmu.dataio.export.rms import export_rms_volumetrics + from fmu.dataio.export.rms import export_volumetrics os.chdir(rmssetup_with_fmuconfig) - result = export_rms_volumetrics(mock_project_variable, "Geogrid", "geogrid_volume") + result = export_volumetrics(mock_project_variable, "Geogrid", "geogrid_volume") vol_table_file = result["volume_table"] assert Path(vol_table_file).is_file() From 71d9bb372ea13e7ae1aa42a4b8f5ad31781f7a56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20C=2E=20Riven=C3=A6s?= Date: Tue, 24 Sep 2024 10:25:28 +0200 Subject: [PATCH 5/6] FIX: add experimental decorator on export_volumetrics() --- src/fmu/dataio/export/_decorators.py | 17 +++++++++++++++++ src/fmu/dataio/export/rms/volumetrics.py | 5 +++++ 2 files changed, 22 insertions(+) create mode 100644 src/fmu/dataio/export/_decorators.py diff --git a/src/fmu/dataio/export/_decorators.py b/src/fmu/dataio/export/_decorators.py new file mode 100644 index 000000000..0cb2082aa --- /dev/null +++ b/src/fmu/dataio/export/_decorators.py @@ -0,0 +1,17 @@ +import warnings +from functools import wraps + + +def experimental(func): # type: ignore + """Decorator to mark functions as experimental.""" + + @wraps(func) + def wrapper(*args, **kwargs): # type: ignore + warnings.warn( + f"{func.__name__} is experimental and may change in future versions.", + UserWarning, + stacklevel=2, + ) + return func(*args, **kwargs) + + return wrapper diff --git a/src/fmu/dataio/export/rms/volumetrics.py b/src/fmu/dataio/export/rms/volumetrics.py index 22e5ca81f..100aed45f 100644 --- a/src/fmu/dataio/export/rms/volumetrics.py +++ b/src/fmu/dataio/export/rms/volumetrics.py @@ -13,6 +13,7 @@ from fmu.config.utilities import yaml_load from fmu.dataio._logging import null_logger +from .._decorators import experimental from ._conditional_rms_imports import import_rms_package _modules = import_rms_package() @@ -192,6 +193,7 @@ def export(self) -> dict[str, str]: return self._export_volume_table() +@experimental def export_volumetrics( project: Any, grid_name: str, @@ -229,6 +231,9 @@ def export_volumetrics( classification: Optional. Use 'internal' or 'restricted' (default). workflow: Optional. Information about the work flow; defaulted to 'rms volumetrics'. + + Note: + This function is experimental and may change in future versions. """ return _ExportVolumetricsRMS( From 8f4fb27c3fcc398908f95ad3a2b6b4ab75c86a74 Mon Sep 17 00:00:00 2001 From: Runar Ask Johannessen <89020325+equinor-ruaj@users.noreply.github.com> Date: Wed, 25 Sep 2024 16:02:31 +0200 Subject: [PATCH 6/6] FIX: Use positional arguments for CaseOnDisk (#809) --- src/fmu/dataio/scripts/create_case_metadata.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fmu/dataio/scripts/create_case_metadata.py b/src/fmu/dataio/scripts/create_case_metadata.py index 1a8fa0473..1f2244c2c 100644 --- a/src/fmu/dataio/scripts/create_case_metadata.py +++ b/src/fmu/dataio/scripts/create_case_metadata.py @@ -132,7 +132,7 @@ def register_on_sumo( sumo_conn = SumoConnection(sumo_env) logger.debug("Sumo connection established") - case = CaseOnDisk(case_metadata_path=case_metadata_path, sumo_connection=sumo_conn) + case = CaseOnDisk(case_metadata_path, sumo_conn) sumo_id = case.register() logger.info("Case registered on Sumo with ID: %s", sumo_id)