From 729f025f392d45b621941da9d052834e0d81506e Mon Sep 17 00:00:00 2001 From: Matthias Baumgartner Date: Thu, 8 Dec 2022 16:33:36 +0100 Subject: namespaces --- bsfs/namespace/__init__.py | 21 ++++++++++++ bsfs/namespace/namespace.py | 80 ++++++++++++++++++++++++++++++++++++++++++++ bsfs/namespace/predefined.py | 39 +++++++++++++++++++++ 3 files changed, 140 insertions(+) create mode 100644 bsfs/namespace/__init__.py create mode 100644 bsfs/namespace/namespace.py create mode 100644 bsfs/namespace/predefined.py (limited to 'bsfs/namespace') diff --git a/bsfs/namespace/__init__.py b/bsfs/namespace/__init__.py new file mode 100644 index 0000000..98d472f --- /dev/null +++ b/bsfs/namespace/__init__.py @@ -0,0 +1,21 @@ +""" + +Part of the BlackStar filesystem (bsfs) module. +A copy of the license is provided with the project. +Author: Matthias Baumgartner, 2022 +""" +# imports +import typing + +# inner-module imports +from . import predefined as ns +from .namespace import ClosedNamespace, Namespace + +# exports +__all__: typing.Sequence[str] = ( + 'ClosedNamespace', + 'Namespace', + 'ns', + ) + +## EOF ## diff --git a/bsfs/namespace/namespace.py b/bsfs/namespace/namespace.py new file mode 100644 index 0000000..8080f5d --- /dev/null +++ b/bsfs/namespace/namespace.py @@ -0,0 +1,80 @@ +""" + +Part of the BlackStar filesystem (bsfs) module. +A copy of the license is provided with the project. +Author: Matthias Baumgartner, 2022 +""" +# imports +import typing + +# bsfs imports +from bsfs.utils import URI, typename + +# exports +__all__: typing.Sequence[str] = ( + 'ClosedNamespace', + 'Namespace', + ) + + +## code ## + +class Namespace(): + """A namespace consists of a common prefix that is used in a set of URIs. + + Note that the prefix must include the separator between + path and fragment (typically a '#' or a '/'). + """ + + # namespace prefix. + prefix: URI + + def __init__(self, prefix: URI): + self.prefix = URI(prefix) + + def __eq__(self, other: typing.Any) -> bool: + return isinstance(other, type(self)) and self.prefix == other.prefix + + def __hash__(self) -> int: + return hash((type(self), self.prefix)) + + def __str__(self) -> str: + return f'{typename(self)}({self.prefix})' + + def __repr__(self) -> str: + return f'{typename(self)}({self.prefix})' + + def __getattr__(self, fragment: str) -> URI: + """Return prefix + fragment.""" + return URI(self.prefix + fragment) + + def __getitem__(self, fragment: str) -> URI: + """Alias for getattr(self, fragment).""" + return self.__getattr__(fragment) + + +class ClosedNamespace(Namespace): + """Namespace that covers a restricted set of URIs.""" + + # set of permissible fragments. + fragments: typing.Set[str] + + def __init__(self, prefix: URI, *args: str): + super().__init__(prefix) + self.fragments = set(args) + + def __eq__(self, other: typing.Any) -> bool: + return super().__eq__(other) and self.fragments == other.fragments + + def __hash__(self) -> int: + return hash((type(self), self.prefix, tuple(sorted(self.fragments)))) + + def __getattr__(self, fragment: str) -> URI: + """Return prefix + fragment. + Raises a KeyError if the fragment is not allowed in this namespace. + """ + if fragment not in self.fragments: + raise KeyError('fragment') + return super().__getattr__(fragment) + +## EOF ## diff --git a/bsfs/namespace/predefined.py b/bsfs/namespace/predefined.py new file mode 100644 index 0000000..21ca560 --- /dev/null +++ b/bsfs/namespace/predefined.py @@ -0,0 +1,39 @@ +""" + +Part of the BlackStar filesystem (bsfs) module. +A copy of the license is provided with the project. +Author: Matthias Baumgartner, 2022 +""" +# imports +import typing + +# bsfs imports +from bsfs.utils import URI + +# inner-module imports +from . import namespace + +# essential bsfs namespaces +bsfs: namespace.Namespace = namespace.Namespace(URI('http://bsfs.ai/schema/')) + +# additional bsfs namespaces +bse: namespace.Namespace = namespace.Namespace(URI('http://bsfs.ai/schema/Entity#')) +bsm: namespace.Namespace = namespace.Namespace(URI('http://bsfs.ai/schema/Meta#')) + +# generic namespaces +rdf: namespace.Namespace = namespace.Namespace(URI('http://www.w3.org/1999/02/22-rdf-syntax-ns#')) +rdfs: namespace.Namespace = namespace.Namespace(URI('http://www.w3.org/2000/01/rdf-schema#')) +schema: namespace.Namespace = namespace.Namespace(URI('http://schema.org/')) +xsd: namespace.Namespace = namespace.Namespace(URI('http://www.w3.org/2001/XMLSchema#')) + +__all__: typing.Sequence[str] = ( + 'bse', + 'bsfs', + 'bsm', + 'rdf', + 'rdfs', + 'schema', + 'xsd', + ) + +## EOF ## -- cgit v1.2.3 From 0e52514639b043454425a9cc2317d27e628a1027 Mon Sep 17 00:00:00 2001 From: Matthias Baumgartner Date: Sun, 18 Dec 2022 13:42:34 +0100 Subject: namespace and uri extensions --- bsfs/namespace/namespace.py | 48 +++++++++++++++++++++++++++++++++----------- bsfs/namespace/predefined.py | 14 ++++++------- 2 files changed, 43 insertions(+), 19 deletions(-) (limited to 'bsfs/namespace') diff --git a/bsfs/namespace/namespace.py b/bsfs/namespace/namespace.py index 8080f5d..f652dcd 100644 --- a/bsfs/namespace/namespace.py +++ b/bsfs/namespace/namespace.py @@ -29,29 +29,55 @@ class Namespace(): # namespace prefix. prefix: URI - def __init__(self, prefix: URI): - self.prefix = URI(prefix) + # fragment separator. + fsep: str + + # path separator. + psep: str + + def __init__(self, prefix: URI, fsep: str = '#', psep: str = '/'): + # ensure prefix type + prefix = URI(prefix) + # truncate fragment separator + while prefix.endswith(fsep): + prefix = URI(prefix[:-1]) + # truncate path separator + while prefix.endswith(psep): + prefix = URI(prefix[:-1]) + # store members + self.prefix = prefix + self.fsep = fsep + self.psep = psep def __eq__(self, other: typing.Any) -> bool: - return isinstance(other, type(self)) and self.prefix == other.prefix + return isinstance(other, type(self)) \ + and self.prefix == other.prefix \ + and self.fsep == other.fsep \ + and self.psep == other.psep def __hash__(self) -> int: - return hash((type(self), self.prefix)) + return hash((type(self), self.prefix, self.fsep, self.psep)) def __str__(self) -> str: return f'{typename(self)}({self.prefix})' def __repr__(self) -> str: - return f'{typename(self)}({self.prefix})' + return f'{typename(self)}({self.prefix}, {self.fsep}, {self.psep})' def __getattr__(self, fragment: str) -> URI: """Return prefix + fragment.""" - return URI(self.prefix + fragment) + return URI(self.prefix + self.fsep + fragment) def __getitem__(self, fragment: str) -> URI: """Alias for getattr(self, fragment).""" return self.__getattr__(fragment) + def __add__(self, value: typing.Any) -> 'Namespace': + """Concatenate another namespace to this one.""" + if not isinstance(value, str): + return NotImplemented + return Namespace(self.prefix + self.psep + value, self.fsep, self.psep) + class ClosedNamespace(Namespace): """Namespace that covers a restricted set of URIs.""" @@ -59,8 +85,8 @@ class ClosedNamespace(Namespace): # set of permissible fragments. fragments: typing.Set[str] - def __init__(self, prefix: URI, *args: str): - super().__init__(prefix) + def __init__(self, prefix: URI, *args: str, fsep: str = '#', psep: str = '/'): + super().__init__(prefix, fsep, psep) self.fragments = set(args) def __eq__(self, other: typing.Any) -> bool: @@ -70,11 +96,9 @@ class ClosedNamespace(Namespace): return hash((type(self), self.prefix, tuple(sorted(self.fragments)))) def __getattr__(self, fragment: str) -> URI: - """Return prefix + fragment. - Raises a KeyError if the fragment is not allowed in this namespace. - """ + """Return prefix + fragment or raise a KeyError if the fragment is not part of this namespace.""" if fragment not in self.fragments: - raise KeyError('fragment') + raise KeyError(f'{fragment} is not a valid fragment of namespace {self.prefix}') return super().__getattr__(fragment) ## EOF ## diff --git a/bsfs/namespace/predefined.py b/bsfs/namespace/predefined.py index 21ca560..cd48a46 100644 --- a/bsfs/namespace/predefined.py +++ b/bsfs/namespace/predefined.py @@ -14,17 +14,17 @@ from bsfs.utils import URI from . import namespace # essential bsfs namespaces -bsfs: namespace.Namespace = namespace.Namespace(URI('http://bsfs.ai/schema/')) +bsfs: namespace.Namespace = namespace.Namespace(URI('http://bsfs.ai/schema'), fsep='/') # additional bsfs namespaces -bse: namespace.Namespace = namespace.Namespace(URI('http://bsfs.ai/schema/Entity#')) -bsm: namespace.Namespace = namespace.Namespace(URI('http://bsfs.ai/schema/Meta#')) +bse: namespace.Namespace = namespace.Namespace(URI('http://bsfs.ai/schema/Entity')) +bsm: namespace.Namespace = namespace.Namespace(URI('http://bsfs.ai/schema/Meta')) # generic namespaces -rdf: namespace.Namespace = namespace.Namespace(URI('http://www.w3.org/1999/02/22-rdf-syntax-ns#')) -rdfs: namespace.Namespace = namespace.Namespace(URI('http://www.w3.org/2000/01/rdf-schema#')) -schema: namespace.Namespace = namespace.Namespace(URI('http://schema.org/')) -xsd: namespace.Namespace = namespace.Namespace(URI('http://www.w3.org/2001/XMLSchema#')) +rdf: namespace.Namespace = namespace.Namespace(URI('http://www.w3.org/1999/02/22-rdf-syntax-ns')) +rdfs: namespace.Namespace = namespace.Namespace(URI('http://www.w3.org/2000/01/rdf-schema')) +schema: namespace.Namespace = namespace.Namespace(URI('http://schema.org'), fsep='/') +xsd: namespace.Namespace = namespace.Namespace(URI('http://www.w3.org/2001/XMLSchema')) __all__: typing.Sequence[str] = ( 'bse', -- cgit v1.2.3