From e174a25585e64eb1b0759440cad48d642dd31829 Mon Sep 17 00:00:00 2001 From: Matthias Baumgartner Date: Fri, 25 Nov 2022 14:31:29 +0100 Subject: use schema and predicate types in extractors --- bsie/base/errors.py | 13 ++++++++++--- bsie/base/extractor.py | 51 ++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 55 insertions(+), 9 deletions(-) (limited to 'bsie/base') diff --git a/bsie/base/errors.py b/bsie/base/errors.py index f86ffb2..eedce3b 100644 --- a/bsie/base/errors.py +++ b/bsie/base/errors.py @@ -8,15 +8,22 @@ Author: Matthias Baumgartner, 2022 import typing # exports -__all__: typing.Sequence[str] = [] +__all__: typing.Sequence[str] = ( + 'ExtractorError', + ) + + ## code ## -class _BSIE_Error(Exception): +class _BSIEError(Exception): """Generic BSIE error.""" -class ReaderError(_BSIE_Error): +class ExtractorError(_BSIEError): + """The Extractor failed to process the given content.""" + +class ReaderError(_BSIEError): """The Reader failed to read the given file.""" ## EOF ## diff --git a/bsie/base/extractor.py b/bsie/base/extractor.py index ea43925..a6a69c6 100644 --- a/bsie/base/extractor.py +++ b/bsie/base/extractor.py @@ -11,13 +11,38 @@ import typing # inner-module imports from . import reader from bsie.utils import node -from bsie.utils.bsfs import URI, typename +from bsie.utils.bsfs import schema as _schema, typename # exports __all__: typing.Sequence[str] = ( 'Extractor', ) +# constants + +# essential definitions typically used in extractor schemas. +# NOTE: The definition here is only for convenience; Each Extractor must implement its use, if so desired. +SCHEMA_PREAMBLE = ''' + # common external prefixes + prefix owl: + prefix rdf: + prefix rdfs: + prefix xsd: + prefix schema: + + # common bsfs prefixes + prefix bsfs: + prefix bse: + + # essential nodes + bsfs:Entity rdfs:subClassOf bsfs:Node . + + # common definitions + xsd:string rdfs:subClassOf bsfs:Literal . + xsd:integer rdfs:subClassOf bsfs:Literal . + + ''' + ## code ## @@ -27,23 +52,37 @@ class Extractor(abc.ABC): # what type of content is expected (i.e. reader subclass). CONTENT_READER: typing.Optional[typing.Type[reader.Reader]] = None + # extractor schema. + schema: _schema.Schema + + def __init__(self, schema: _schema.Schema): + self.schema = schema + def __str__(self) -> str: return typename(self) def __repr__(self) -> str: return f'{typename(self)}()' - @abc.abstractmethod - def schema(self) -> str: - """Return the schema (predicates and nodes) produced by this Extractor.""" + + def predicates(self) -> typing.Iterator[_schema.Predicate]: + """Return the predicates that may be part of extracted triples.""" + # NOTE: Some predicates in the schema might not occur in actual triples, + # but are defined due to predicate class hierarchy. E.g., bsfs:Predicate + # is part of every schema but should not be used in triples. + # Announcing all predicates might not be the most efficient way, however, + # it is the most safe one. Concrete extractors that produce additional + # predicates (e.g. auxiliary nodes with their own predicates) should + # overwrite this method to only include the principal predicates. + return self.schema.predicates() @abc.abstractmethod def extract( self, subject: node.Node, content: typing.Any, - predicates: typing.Iterable[URI], - ) -> typing.Iterator[typing.Tuple[node.Node, URI, typing.Any]]: + predicates: typing.Iterable[_schema.Predicate], + ) -> typing.Iterator[typing.Tuple[node.Node, _schema.Predicate, typing.Any]]: """Return (node, predicate, value) triples.""" ## EOF ## -- cgit v1.2.3 From b96c6e2096c387b70e2a4c1f0bc53b6044a0dc6f Mon Sep 17 00:00:00 2001 From: Matthias Baumgartner Date: Fri, 25 Nov 2022 14:36:27 +0100 Subject: decouple readers and extractors; use strings for reference and repeated type annotations --- bsie/base/extractor.py | 5 ++--- bsie/base/reader.py | 11 ++--------- 2 files changed, 4 insertions(+), 12 deletions(-) (limited to 'bsie/base') diff --git a/bsie/base/extractor.py b/bsie/base/extractor.py index a6a69c6..7acf2bd 100644 --- a/bsie/base/extractor.py +++ b/bsie/base/extractor.py @@ -8,8 +8,7 @@ Author: Matthias Baumgartner, 2022 import abc import typing -# inner-module imports -from . import reader +# bsie imports from bsie.utils import node from bsie.utils.bsfs import schema as _schema, typename @@ -50,7 +49,7 @@ class Extractor(abc.ABC): """Produce (node, predicate, value)-triples from some content.""" # what type of content is expected (i.e. reader subclass). - CONTENT_READER: typing.Optional[typing.Type[reader.Reader]] = None + CONTENT_READER: typing.Optional[str] = None # extractor schema. schema: _schema.Schema diff --git a/bsie/base/reader.py b/bsie/base/reader.py index f29e451..e59abef 100644 --- a/bsie/base/reader.py +++ b/bsie/base/reader.py @@ -12,12 +12,11 @@ Author: Matthias Baumgartner, 2022 import abc import typing -# inner-module imports +# bsie imports from bsie.utils.bsfs import URI, typename # exports __all__: typing.Sequence[str] = ( - 'Aggregator', 'Reader', ) @@ -27,20 +26,14 @@ __all__: typing.Sequence[str] = ( class Reader(abc.ABC): """Read and return some content from a file.""" - # In what data structure content is returned - CONTENT_TYPE = typing.Union[typing.Any] - # NOTE: Child classes must also assign a typing.Union even if there's - # only one options - def __str__(self) -> str: return typename(self) def __repr__(self) -> str: return f'{typename(self)}()' - # FIXME: How about using contexts instead of calls? @abc.abstractmethod - def __call__(self, path: URI) -> CONTENT_TYPE: + def __call__(self, path: URI) -> typing.Any: """Return some content of the file at *path*. Raises a `ReaderError` if the reader cannot make sense of the file format. """ -- cgit v1.2.3 From 9ce32829b2bb85907a34a543bfcaa9183d1e362c Mon Sep 17 00:00:00 2001 From: Matthias Baumgartner Date: Fri, 25 Nov 2022 14:39:18 +0100 Subject: string conversion and equality checks --- bsie/base/extractor.py | 7 +++++++ bsie/base/reader.py | 6 ++++++ 2 files changed, 13 insertions(+) (limited to 'bsie/base') diff --git a/bsie/base/extractor.py b/bsie/base/extractor.py index 7acf2bd..2fc4f18 100644 --- a/bsie/base/extractor.py +++ b/bsie/base/extractor.py @@ -63,6 +63,13 @@ class Extractor(abc.ABC): def __repr__(self) -> str: return f'{typename(self)}()' + def __eq__(self, other: typing.Any) -> bool: + return isinstance(other, type(self)) \ + and self.CONTENT_READER == other.CONTENT_READER \ + and self.schema == other.schema + + def __hash__(self) -> int: + return hash((type(self), self.CONTENT_READER, self.schema)) def predicates(self) -> typing.Iterator[_schema.Predicate]: """Return the predicates that may be part of extracted triples.""" diff --git a/bsie/base/reader.py b/bsie/base/reader.py index e59abef..b7eabf7 100644 --- a/bsie/base/reader.py +++ b/bsie/base/reader.py @@ -32,6 +32,12 @@ class Reader(abc.ABC): def __repr__(self) -> str: return f'{typename(self)}()' + def __eq__(self, other: typing.Any) -> bool: + return isinstance(other, type(self)) + + def __hash__(self) -> int: + return hash(type(self)) + @abc.abstractmethod def __call__(self, path: URI) -> typing.Any: """Return some content of the file at *path*. -- cgit v1.2.3 From c9a1dea230054f5d6f40b7fd5e3930609c5f6416 Mon Sep 17 00:00:00 2001 From: Matthias Baumgartner Date: Fri, 25 Nov 2022 14:41:38 +0100 Subject: code analysis tool configs and minor fixes --- bsie/base/errors.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'bsie/base') diff --git a/bsie/base/errors.py b/bsie/base/errors.py index eedce3b..a86b7e8 100644 --- a/bsie/base/errors.py +++ b/bsie/base/errors.py @@ -10,11 +10,10 @@ import typing # exports __all__: typing.Sequence[str] = ( 'ExtractorError', + 'ReaderError', ) - - ## code ## class _BSIEError(Exception): -- cgit v1.2.3 From 3e6a69ce7f109f0fd4352507ad60d58d4cbd24a7 Mon Sep 17 00:00:00 2001 From: Matthias Baumgartner Date: Fri, 25 Nov 2022 14:43:12 +0100 Subject: builders and pipeline --- bsie/base/errors.py | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'bsie/base') diff --git a/bsie/base/errors.py b/bsie/base/errors.py index a86b7e8..760351f 100644 --- a/bsie/base/errors.py +++ b/bsie/base/errors.py @@ -9,7 +9,9 @@ import typing # exports __all__: typing.Sequence[str] = ( + 'BuilderError', 'ExtractorError', + 'LoaderError', 'ReaderError', ) @@ -19,6 +21,12 @@ __all__: typing.Sequence[str] = ( class _BSIEError(Exception): """Generic BSIE error.""" +class BuilderError(_BSIEError): + """The Builder failed to create an instance.""" + +class LoaderError(BuilderError): + """Failed to load a module or class.""" + class ExtractorError(_BSIEError): """The Extractor failed to process the given content.""" -- cgit v1.2.3