diff --git a/src/curies/mixins.py b/src/curies/mixins.py index 72e9d46d..66e0e6e6 100644 --- a/src/curies/mixins.py +++ b/src/curies/mixins.py @@ -10,6 +10,7 @@ from .api import Converter __all__ = [ + "ReverseSemanticallyProcessable", "SemanticallyProcessable", "SemanticallyStandardizable", ] @@ -50,6 +51,36 @@ def process(self, converter: Converter) -> X: raise NotImplementedError +class ReverseSemanticallyProcessable(ABC, Generic[X]): + """A class that can be processed with a converter. + + The goal of this class is to standardize objects that come with + unprocessed URIs that can be processed into references with + respect to a :class:`curies.Converter`. For example, this is + useful for :mod:`obographs` and :mod:`jskos`. + + .. code-block:: python + + from pydantic import BaseModel + from curies import ReverseSemanticallyProcessable + + + class RawEntity(BaseModel): + uri: str + + + class ProcessedEntity(BaseModel, ReverseSemanticallyProcessable[RawEntity]): + reference: Reference + + def unprocess(self, converter: Converter) -> RawEntity: + return RawEntity(uri=converter.expand_reference(self.reference, strict=True)) + """ + + @abstractmethod + def unprocess(self, converter: Converter) -> X: + """Process this raw instance.""" + + class SemanticallyStandardizable(ABC): """An object that can be standardized. diff --git a/tests/test_mixins.py b/tests/test_mixins.py index 4e5a848a..55573f28 100644 --- a/tests/test_mixins.py +++ b/tests/test_mixins.py @@ -7,7 +7,11 @@ import curies from curies import Converter, Reference -from curies.mixins import SemanticallyProcessable, SemanticallyStandardizable +from curies.mixins import ( + ReverseSemanticallyProcessable, + SemanticallyProcessable, + SemanticallyStandardizable, +) class TestMixins(unittest.TestCase): @@ -36,6 +40,29 @@ def process(self, converter: Converter) -> Processed: self.assertIsInstance(p, Processed) self.assertEqual(Reference(prefix="GO", identifier="1234567"), p.reference) + def test_reversesemantically_processable(self) -> None: + """Test processing.""" + + class Raw(BaseModel): + """A raw model, with a URI.""" + + uri: str + + class Processed(BaseModel, ReverseSemanticallyProcessable[Raw]): + """A processed model, with a reference.""" + + reference: Reference + + def unprocess(self, converter: Converter) -> Raw: + """Convert to raw.""" + return Raw(uri=converter.expand_reference(self.reference, strict=True)) + + c = Converter.from_prefix_map({"GO": "http://purl.obolibrary.org/obo/GO_"}) + + p = Processed(reference=Reference(prefix="GO", identifier="1234567")) + r = p.unprocess(c) + self.assertEqual("http://purl.obolibrary.org/obo/GO_1234567", r.uri) + def test_standardizable(self) -> None: """Test standardizable."""