Skip to content

Commit

Permalink
ENH: Add Provider base class
Browse files Browse the repository at this point in the history
  • Loading branch information
mferrera committed May 24, 2024
1 parent fe33877 commit 04c8ae3
Show file tree
Hide file tree
Showing 6 changed files with 77 additions and 27 deletions.
43 changes: 27 additions & 16 deletions src/fmu/dataio/_metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
)
from .datastructure._internal import internal
from .datastructure.meta import meta
from .exceptions import InvalidMetadataError
from .providers._filedata import FileDataProvider
from .providers._fmu import FmuProvider
from .providers.objectdata._provider import objectdata_provider_factory
Expand Down Expand Up @@ -70,21 +71,24 @@ def _get_objectdata_provider(
return objdata


def _get_filedata_provider(
def _get_meta_filedata(
dataio: ExportData,
obj: types.Inferrable,
objdata: ObjectDataProvider,
fmudata: FmuProvider | None,
compute_md5: bool,
) -> FileDataProvider:
) -> FileDataProvider | None:
"""Derive metadata for the file."""
return FileDataProvider(
dataio=dataio,
objdata=objdata,
runpath=fmudata.get_runpath() if fmudata else None,
obj=obj,
compute_md5=compute_md5,
)
try:
return FileDataProvider(
dataio=dataio,
objdata=objdata,
runpath=fmudata.get_runpath() if fmudata else None,
obj=obj,
compute_md5=compute_md5,
).get_metadata()
except InvalidMetadataError:
return None


def _get_meta_objectdata(
Expand All @@ -97,6 +101,13 @@ def _get_meta_objectdata(
)


def _get_meta_fmu(fmudata: FmuProvider) -> internal.FMUClassMetaData | None:
try:
return fmudata.get_metadata()
except InvalidMetadataError:
return None


def _get_meta_access(dataio: ExportData) -> meta.SsdlAccess:
return meta.SsdlAccess(
asset=meta.Asset(
Expand Down Expand Up @@ -166,25 +177,25 @@ def generate_export_metadata(
meta_existing = read_metadata_from_file(obj)

objdata = _get_objectdata_provider(obj, dataio, meta_existing)
filedata = _get_filedata_provider(dataio, obj, objdata, fmudata, compute_md5)

masterdata = dataio.config.get("masterdata")

metadata = internal.DataClassMeta(
schema_=TypeAdapter(AnyHttpUrl).validate_strings(SCHEMA), # type: ignore[call-arg]
version=VERSION,
source=SOURCE,
class_=objdata.classname,
fmu=fmudata.get_metadata() if fmudata else None,
fmu=_get_meta_fmu(fmudata) if fmudata else None,
masterdata=_get_meta_masterdata(masterdata) if masterdata else None,
access=_get_meta_access(dataio),
data=_get_meta_objectdata(objdata),
file=filedata.get_metadata(),
file=_get_meta_filedata(dataio, obj, objdata, fmudata, compute_md5),
tracklog=generate_meta_tracklog(),
display=_get_meta_display(dataio, objdata),
preprocessed=_get_meta_preprocessed_info(dataio)
if dataio.fmu_context == FmuContext.PREPROCESSED
else None,
preprocessed=(
_get_meta_preprocessed_info(dataio)
if dataio.fmu_context == FmuContext.PREPROCESSED
else None
),
).model_dump(mode="json", exclude_none=True, by_alias=True)

if skip_null:
Expand Down
5 changes: 5 additions & 0 deletions src/fmu/dataio/exceptions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from __future__ import annotations


class InvalidMetadataError(Exception):
"""Raised when valid metadata cannot be generated or returned."""
18 changes: 18 additions & 0 deletions src/fmu/dataio/providers/_base.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from abc import ABC, abstractmethod

from pydantic import BaseModel


class Provider(ABC):
@abstractmethod
def get_metadata(self) -> BaseModel:
"""Get the Pydantic model of the metadata that a provider is meant
to provide.
Returns:
BaseModel: The Pydantic BaseModel representing metadata.
Raises:
InvalidMetadataError: When the derived metadata is invalid.
"""
raise NotImplementedError
4 changes: 3 additions & 1 deletion src/fmu/dataio/providers/_filedata.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
)
from fmu.dataio.datastructure.meta import meta

from ._base import Provider

logger: Final = null_logger(__name__)

if TYPE_CHECKING:
Expand All @@ -34,7 +36,7 @@ class ShareFolder(str, Enum):


@dataclass
class FileDataProvider:
class FileDataProvider(Provider):
"""Class for providing metadata for the 'files' block in fmu-dataio.
Example::
Expand Down
10 changes: 6 additions & 4 deletions src/fmu/dataio/providers/_fmu.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@
from fmu.dataio._logging import null_logger
from fmu.dataio.datastructure._internal import internal
from fmu.dataio.datastructure.meta import meta
from fmu.dataio.exceptions import InvalidMetadataError

from ._base import Provider

if TYPE_CHECKING:
from uuid import UUID
Expand Down Expand Up @@ -91,7 +94,7 @@ def keyname(self) -> str:


@dataclass
class FmuProvider:
class FmuProvider(Provider):
"""Class for getting the run environment (e.g. an ERT) and provide metadata.
Args:
Expand Down Expand Up @@ -165,13 +168,12 @@ def get_runpath(self) -> Path | None:
"""Return runpath for a FMU run."""
return self._runpath

def get_metadata(self) -> internal.FMUClassMetaData | None:
def get_metadata(self) -> internal.FMUClassMetaData:
"""Construct the metadata FMU block for an ERT forward job."""
logger.debug("Generate ERT metadata...")

if self._casepath is None or self.model is None:
logger.info("Can't return metadata, missing casepath or model description")
return None
raise InvalidMetadataError("Missing casepath or model description")

case_meta = self._get_fmucase_meta()

Expand Down
24 changes: 18 additions & 6 deletions tests/test_units/test_fmuprovider_class.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

# from conftest import pretend_ert_env_run1
from fmu.dataio._definitions import FmuContext
from fmu.dataio.exceptions import InvalidMetadataError
from fmu.dataio.providers._fmu import RESTART_PATH_ENVNAME, FmuEnv, FmuProvider

logger = logging.getLogger(__name__)
Expand All @@ -27,7 +28,10 @@ def test_fmuprovider_no_provider():
include_ertjobs=False,
workflow=WORKFLOW,
)
assert myfmu.get_metadata() is None
with pytest.raises(
InvalidMetadataError, match="Missing casepath or model description"
):
myfmu.get_metadata()


def test_fmuprovider_model_info_in_metadata(fmurun_w_casemetadata):
Expand All @@ -47,8 +51,11 @@ def test_fmuprovider_model_info_in_metadata(fmurun_w_casemetadata):
fmu_context=FmuContext.REALIZATION,
workflow=WORKFLOW,
)
meta = myfmu.get_metadata()
assert meta is None

with pytest.raises(
InvalidMetadataError, match="Missing casepath or model description"
):
meta = myfmu.get_metadata()


def test_fmuprovider_ert_provider_guess_casemeta_path(fmurun):
Expand All @@ -66,8 +73,11 @@ def test_fmuprovider_ert_provider_guess_casemeta_path(fmurun):
workflow=WORKFLOW,
)

assert myfmu.get_metadata() is None
assert myfmu.get_casepath() is None
with pytest.raises(
InvalidMetadataError, match="Missing casepath or model description"
):
myfmu.get_metadata()


def test_fmuprovider_ert_provider_missing_parameter_txt(fmurun_w_casemetadata):
Expand Down Expand Up @@ -207,8 +217,10 @@ def test_fmuprovider_detect_no_case_metadata(fmurun):
model=GLOBAL_CONFIG_MODEL,
fmu_context=FmuContext.REALIZATION,
)
meta = myfmu.get_metadata()
assert meta is None
with pytest.raises(
InvalidMetadataError, match="Missing casepath or model description"
):
myfmu.get_metadata()


def test_fmuprovider_case_run(fmurun_prehook):
Expand Down

0 comments on commit 04c8ae3

Please sign in to comment.