Skip to content

Commit

Permalink
Add protocols to describe a data model
Browse files Browse the repository at this point in the history
  • Loading branch information
WilliamJamieson committed Nov 29, 2024
1 parent ca2040e commit d4cb251
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 5 deletions.
71 changes: 71 additions & 0 deletions src/stpipe/protocols.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
from __future__ import annotations

from abc import abstractmethod
from typing import TYPE_CHECKING, Protocol, runtime_checkable

if TYPE_CHECKING:
from collections.abc import Callable
from os import PathLike


@runtime_checkable
class DataModel(Protocol):
"""
This is a protocol to describe the methods and properties that define a
DataModel for the purposes of stpipe. This is a runtime checkable protocol
meaning that any object can be `isinstance` checked against this protocol
and will succeed even if the object does not inherit from this class.
Moreover, this object will act as an `abc.ABC` class if it is inherited from.
Any datamodel class instance that desires to be considered an instance of
must fully implement the protocol in order to pass the `isinstance` check.
In addition, although it isn't yet checked (the best approach for supporting
this is still being considered), such instances must have a meta.filename
attribute.
"""

@property
@abstractmethod
def crds_observatory(self) -> str:
"""This should return a string identifying the observatory as CRDS expects it"""
...

@property
@abstractmethod
def get_crds_parameters(self) -> dict[str, any]:
"""
This should return a dictionary of key/value pairs corresponding to the
parkey values CRDS is using to match reference files. Typically it returns
all metadata simple values.
"""
...

@abstractmethod
def save(
self,
path: PathLike | Callable[..., PathLike],
dir_path: PathLike | None = None,
*args,
**kwargs,
) -> PathLike:
"""
Save to a file.
Parameters
----------
path : string or callable
File path to save to.
If function, it takes one argument that is
model.meta.filename and returns the full path string.
dir_path : str
Directory to save to. If not None, this will override
any directory information in the ``path``
Returns
-------
output_path: str
The file path the model was saved in.
"""
...
10 changes: 5 additions & 5 deletions tests/test_abstract_datamodel.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

import pytest

from stpipe.datamodel import AbstractDataModel
from stpipe.protocols import DataModel


def test_roman_datamodel():
Expand All @@ -13,13 +13,13 @@ def test_roman_datamodel():

roman_image_tree = mk_level2_image()
image_model = roman_datamodels.ImageModel(roman_image_tree)
assert isinstance(image_model, AbstractDataModel)
assert isinstance(image_model, DataModel)


def test_jwst_datamodel():
jwst_datamodel = pytest.importorskip("stdatamodels.jwst.datamodels")
image_model = jwst_datamodel.ImageModel()
assert isinstance(image_model, AbstractDataModel)
assert isinstance(image_model, DataModel)


class GoodDataModel:
Expand Down Expand Up @@ -49,9 +49,9 @@ def get_crds_parameters(self):

def test_good_datamodel():
gdm = GoodDataModel()
assert isinstance(gdm, AbstractDataModel)
assert isinstance(gdm, DataModel)


def test_bad_datamodel():
gdm = BadDataModel()
assert not isinstance(gdm, AbstractDataModel)
assert not isinstance(gdm, DataModel)

0 comments on commit d4cb251

Please sign in to comment.