From 02cd75f31120a766a35fc0ae00f8d0711c1c0ae9 Mon Sep 17 00:00:00 2001 From: Matthias Baumgartner Date: Wed, 1 Mar 2023 17:04:57 +0100 Subject: schema fixes --- bsie/extractor/base.py | 1 + bsie/extractor/generic/path.py | 2 +- bsie/extractor/generic/stat.py | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) (limited to 'bsie') diff --git a/bsie/extractor/base.py b/bsie/extractor/base.py index 89183f9..d8b86a5 100644 --- a/bsie/extractor/base.py +++ b/bsie/extractor/base.py @@ -48,6 +48,7 @@ SCHEMA_PREAMBLE = ''' # common definitions xsd:string rdfs:subClassOf bsfs:Literal . xsd:integer rdfs:subClassOf bsfs:Number . + xsd:float rdfs:subClassOf bsfs:Number . ''' diff --git a/bsie/extractor/generic/path.py b/bsie/extractor/generic/path.py index c984515..cd8cec9 100644 --- a/bsie/extractor/generic/path.py +++ b/bsie/extractor/generic/path.py @@ -35,7 +35,7 @@ class Path(base.Extractor): rdfs:range xsd:string ; rdfs:label "File name"^^xsd:string ; schema:description "Filename of entity in some filesystem."^^xsd:string ; - bsfs:unique "false"^^xsd:boolean . + bsfs:unique "true"^^xsd:boolean . ''')) self._callmap = { self.schema.predicate(ns.bse.filename): self.__filename, diff --git a/bsie/extractor/generic/stat.py b/bsie/extractor/generic/stat.py index 9394456..f35f8e1 100644 --- a/bsie/extractor/generic/stat.py +++ b/bsie/extractor/generic/stat.py @@ -37,7 +37,7 @@ class Stat(base.Extractor): rdfs:range xsd:integer ; rdfs:label "File size"^^xsd:string ; schema:description "File size of entity in some filesystem."^^xsd:string ; - bsfs:unique "false"^^xsd:boolean . + bsfs:unique "true"^^xsd:boolean . ''')) self._callmap = { self.schema.predicate(ns.bse.filesize): self.__filesize, -- cgit v1.2.3 From 464cc6cb54f55f6255bf0a485533c181d6018303 Mon Sep 17 00:00:00 2001 From: Matthias Baumgartner Date: Wed, 1 Mar 2023 17:07:06 +0100 Subject: load config from file --- bsie/apps/_loader.py | 52 +++++++++++++++++++++++++++++++++++++++++++ bsie/apps/default_config.yaml | 17 ++++++++++++++ bsie/apps/index.py | 44 +++++++----------------------------- bsie/apps/info.py | 43 +++++++---------------------------- 4 files changed, 85 insertions(+), 71 deletions(-) create mode 100644 bsie/apps/_loader.py create mode 100644 bsie/apps/default_config.yaml (limited to 'bsie') diff --git a/bsie/apps/_loader.py b/bsie/apps/_loader.py new file mode 100644 index 0000000..e02bed5 --- /dev/null +++ b/bsie/apps/_loader.py @@ -0,0 +1,52 @@ +""" + +Part of the bsie module. +A copy of the license is provided with the project. +Author: Matthias Baumgartner, 2022 +""" +# standard imports +import typing + +# external imports +import yaml + +# bsie imports +from bsie.extractor import ExtractorBuilder +from bsie.lib import PipelineBuilder +from bsie.lib.pipeline import Pipeline +from bsie.reader import ReaderBuilder + +# constants +DEFAULT_CONFIG_FILE = 'default_config.yaml' + +# exports +__all__: typing.Sequence[str] = ( + 'load', + 'DEFAULT_CONFIG_FILE', + ) + + +## code ## + +def load_pipeline(path: str) -> Pipeline: + """Load a pipeline according to a config at *path*.""" + # load config file + with open(path, 'rt') as ifile: + cfg = yaml.safe_load(ifile) + + # reader builder + rbuild = ReaderBuilder(cfg['ReaderBuilder']) + # extractor builder + ebuild = ExtractorBuilder(cfg['ExtractorBuilder']) + # pipeline builder + pbuild = PipelineBuilder( + rbuild, + ebuild, + ) + # build pipeline + pipeline = pbuild.build() + + # return pipeline + return pipeline + +## EOF ## diff --git a/bsie/apps/default_config.yaml b/bsie/apps/default_config.yaml new file mode 100644 index 0000000..4d99e22 --- /dev/null +++ b/bsie/apps/default_config.yaml @@ -0,0 +1,17 @@ + +ReaderBuilder: {} + +ExtractorBuilder: + + - bsie.extractor.preview.Preview: + max_sides: [50, 100, 200,400] + + - bsie.extractor.generic.path.Path: {} + + - bsie.extractor.generic.stat.Stat: {} + + - bsie.extractor.image.colors_spatial.ColorsSpatial: + width: 2 + height: 2 + exp: 2 + diff --git a/bsie/apps/index.py b/bsie/apps/index.py index 8798c49..2d147c9 100644 --- a/bsie/apps/index.py +++ b/bsie/apps/index.py @@ -10,11 +10,12 @@ import os import typing # bsie imports -from bsie.extractor import ExtractorBuilder -from bsie.lib import BSIE, PipelineBuilder, DefaultNamingPolicy -from bsie.reader import ReaderBuilder +from bsie.lib import BSIE, DefaultNamingPolicy from bsie.utils import bsfs, errors, node as node_ +# inner-module imports +from . import _loader + # exports __all__: typing.Sequence[str] = ( 'main', @@ -26,6 +27,9 @@ __all__: typing.Sequence[str] = ( def main(argv): """Index files or directories into BSFS.""" parser = argparse.ArgumentParser(description=main.__doc__, prog='index') + parser.add_argument('--config', type=str, + default=os.path.join(os.path.dirname(__file__), _loader.DEFAULT_CONFIG_FILE), + help='Path to the config file.') parser.add_argument('--host', type=bsfs.URI, default=bsfs.URI('http://example.com'), help='') parser.add_argument('--user', type=str, default='me', @@ -44,39 +48,8 @@ def main(argv): help='') args = parser.parse_args(argv) - # FIXME: Read reader/extractor configs from a config file - # reader builder - rbuild = ReaderBuilder() - # extractor builder - ebuild = ExtractorBuilder([ - {'bsie.extractor.preview.Preview': { - 'max_sides': [50], - }}, - {'bsie.extractor.generic.path.Path': {}}, - {'bsie.extractor.generic.stat.Stat': {}}, - {'bsie.extractor.generic.constant.Constant': dict( - tuples=[('http://bsfs.ai/schema/Entity#author', 'Me, myself, and I')], - schema=''' - bse:author rdfs:subClassOf bsfs:Predicate ; - rdfs:domain bsfs:Entity ; - rdfs:range xsd:string ; - bsfs:unique "true"^^xsd:boolean . - ''', - )}, - {'bsie.extractor.image.colors_spatial.ColorsSpatial': { - 'width': 2, - 'height': 2, - 'exp': 2, - }}, - ]) - # pipeline builder - pbuild = PipelineBuilder( - rbuild, - ebuild, - ) - # build pipeline - pipeline = pbuild.build() + pipeline = _loader.load_pipeline(args.config) # build the naming policy naming_policy = DefaultNamingPolicy( host=args.host, @@ -127,7 +100,6 @@ def main(argv): return store - ## main ## if __name__ == '__main__': diff --git a/bsie/apps/info.py b/bsie/apps/info.py index 750aedc..363ab30 100644 --- a/bsie/apps/info.py +++ b/bsie/apps/info.py @@ -6,15 +6,16 @@ Author: Matthias Baumgartner, 2022 """ # standard imports import argparse +import os import sys import typing # bsie imports -from bsie.extractor import ExtractorBuilder -from bsie.lib import PipelineBuilder -from bsie.reader import ReaderBuilder from bsie.utils import bsfs, errors +# inner-module imports +from . import _loader + # exports __all__: typing.Sequence[str] = ( 'main', @@ -26,43 +27,15 @@ __all__: typing.Sequence[str] = ( def main(argv): """Show information from BSIE.""" parser = argparse.ArgumentParser(description=main.__doc__, prog='info') + parser.add_argument('--config', type=str, + default=os.path.join(os.path.dirname(__file__), _loader.DEFAULT_CONFIG_FILE), + help='Path to the config file.') parser.add_argument('what', choices=('predicates', 'schema'), help='Select what information to show.') args = parser.parse_args(argv) - # FIXME: Read reader/extractor configs from a config file - # reader builder - rbuild = ReaderBuilder() - # extractor builder - ebuild = ExtractorBuilder([ - {'bsie.extractor.preview.Preview': { - 'max_sides': [50, 200], - }}, - {'bsie.extractor.generic.path.Path': {}}, - {'bsie.extractor.generic.stat.Stat': {}}, - {'bsie.extractor.generic.constant.Constant': dict( - tuples=[('http://bsfs.ai/schema/Entity#author', 'Me, myself, and I')], - schema=''' - bse:author rdfs:subClassOf bsfs:Predicate ; - rdfs:domain bsfs:Entity ; - rdfs:range xsd:string ; - bsfs:unique "true"^^xsd:boolean . - ''', - )}, - {'bsie.extractor.image.colors_spatial.ColorsSpatial': { - 'width': 2, - 'height': 2, - 'exp': 2, - }}, - ]) - # pipeline builder - pbuild = PipelineBuilder( - rbuild, - ebuild, - ) - # build pipeline - pipeline = pbuild.build() + pipeline = _loader.load_pipeline(args.config) # show info if args.what == 'predicates': -- cgit v1.2.3 From ec9105b690974b0246e36769506e735c4edf069a Mon Sep 17 00:00:00 2001 From: Matthias Baumgartner Date: Wed, 1 Mar 2023 21:38:09 +0100 Subject: Exif data reader and extractor --- bsie/apps/default_config.yaml | 8 +- bsie/extractor/image/photometrics.py | 219 +++++++++++++++++++++++++++++++++++ bsie/reader/exif.py | 49 ++++++++ 3 files changed, 273 insertions(+), 3 deletions(-) create mode 100644 bsie/extractor/image/photometrics.py create mode 100644 bsie/reader/exif.py (limited to 'bsie') diff --git a/bsie/apps/default_config.yaml b/bsie/apps/default_config.yaml index 4d99e22..a59b0f3 100644 --- a/bsie/apps/default_config.yaml +++ b/bsie/apps/default_config.yaml @@ -11,7 +11,9 @@ ExtractorBuilder: - bsie.extractor.generic.stat.Stat: {} - bsie.extractor.image.colors_spatial.ColorsSpatial: - width: 2 - height: 2 - exp: 2 + width: 32 + height: 32 + exp: 4 + + - bsie.extractor.image.photometrics.Exif: {} diff --git a/bsie/extractor/image/photometrics.py b/bsie/extractor/image/photometrics.py new file mode 100644 index 0000000..ae0a541 --- /dev/null +++ b/bsie/extractor/image/photometrics.py @@ -0,0 +1,219 @@ +""" + +Part of the bsie module. +A copy of the license is provided with the project. +Author: Matthias Baumgartner, 2022 +""" +# standard imports +from fractions import Fraction +import typing + +# bsie imports +from bsie.utils import bsfs, node, ns + +# inner-module imports +from .. import base + +# exports +__all__: typing.Sequence[str] = ( + 'Exif', + ) + + +## code ## + +def _gps_to_dec(coords: typing.Tuple[float, float, float]) -> float: + """Convert GPS coordinates from exif to float.""" + # unpack args + deg, min, sec = coords + # convert to float + deg = float(Fraction(deg)) + min = float(Fraction(min)) + sec = float(Fraction(sec)) + + if float(sec) > 0: + # format is deg+min+sec + return (float(deg) * 3600 + float(min) * 60 + float(sec)) / 3600 + else: + # format is deg+min + return float(deg) + float(min) / 60 + + +class Exif(base.Extractor): + """Extract information from EXIF/IPTC tags of an image file.""" + + CONTENT_READER = 'bsie.reader.exif.Exif' + + def __init__(self): + super().__init__(bsfs.schema.from_string(base.SCHEMA_PREAMBLE + ''' + #bse:t_capture rdfs:subClassOf bsfs:Predicate ; + # rdfs:domain bsfs:File ; + # rdfs:range xsd:float ; + # bsfs:unique "true"^^xsd:boolean . + bse:exposure rdfs:subClassOf bsfs:Predicate ; + rdfs:domain bsfs:File ; + rdfs:range xsd:float ; + bsfs:unique "true"^^xsd:boolean . + bse:aperture rdfs:subClassOf bsfs:Predicate ; + rdfs:domain bsfs:File ; + rdfs:range xsd:float ; + bsfs:unique "true"^^xsd:boolean . + bse:iso rdfs:subClassOf bsfs:Predicate ; + rdfs:domain bsfs:File ; + rdfs:range xsd:integer ; + bsfs:unique "true"^^xsd:boolean . + bse:focal_length rdfs:subClassOf bsfs:Predicate ; + rdfs:domain bsfs:File ; + rdfs:range xsd:float ; + bsfs:unique "true"^^xsd:boolean . + bse:width rdfs:subClassOf bsfs:Predicate ; + rdfs:domain bsfs:File ; + rdfs:range xsd:integer ; + bsfs:unique "true"^^xsd:boolean . + bse:height rdfs:subClassOf bsfs:Predicate ; + rdfs:domain bsfs:File ; + rdfs:range xsd:integer ; + bsfs:unique "true"^^xsd:boolean . + bse:orientation rdfs:subClassOf bsfs:Predicate ; + rdfs:domain bsfs:File ; + rdfs:range xsd:integer ; + bsfs:unique "true"^^xsd:boolean . + bse:orientation_label rdfs:subClassOf bsfs:Predicate ; + rdfs:domain bsfs:File ; + rdfs:range xsd:string ; + bsfs:unique "true"^^xsd:boolean . + bse:altitude rdfs:subClassOf bsfs:Predicate ; + rdfs:domain bsfs:File ; + rdfs:range xsd:float ; + bsfs:unique "true"^^xsd:boolean . + bse:latitude rdfs:subClassOf bsfs:Predicate ; + rdfs:domain bsfs:File ; + rdfs:range xsd:float ; + bsfs:unique "true"^^xsd:boolean . + bse:longitude rdfs:subClassOf bsfs:Predicate ; + rdfs:domain bsfs:File ; + rdfs:range xsd:float ; + bsfs:unique "true"^^xsd:boolean . + ''')) + # initialize mapping from predicate to callback + self._callmap = { + #self.schema.predicate(ns.bse.t_capture): self._date, + self.schema.predicate(ns.bse.exposure): self._exposure, + self.schema.predicate(ns.bse.aperture): self._aperture, + self.schema.predicate(ns.bse.iso): self._iso, + self.schema.predicate(ns.bse.focal_length): self._focal_length, + self.schema.predicate(ns.bse.width): self._width, + self.schema.predicate(ns.bse.height): self._height, + self.schema.predicate(ns.bse.orientation): self._orientation, + self.schema.predicate(ns.bse.orientation_label): self._orientation_label, + self.schema.predicate(ns.bse.altitude): self._altitude, + self.schema.predicate(ns.bse.latitude): self._latitude, + self.schema.predicate(ns.bse.longitude): self._longitude, + } + + def extract( + self, + subject: node.Node, + content: dict, + principals: typing.Iterable[bsfs.schema.Predicate], + ) -> typing.Iterator[typing.Tuple[node.Node, bsfs.schema.Predicate, typing.Any]]: + for pred in principals: + # find callback + clbk = self._callmap.get(pred) + if clbk is None: + continue + # get value + value = clbk(content) + if value is None: + continue + # produce triple + yield subject, pred, value + + def _date(self, content: dict): # FIXME: Return type annotation + raise NotImplementedError() + #date_keys = ( + # 'Exif.Photo.DateTimeOriginal', + # 'Exif.Photo.DateTimeDigitized', + # 'Exif.Image.DateTime', + # ) + #for key in date_keys: + # if key in content: + # dt = content[key].value + # if dt.tzinfo is None: + # dt = dt.replace(tzinfo=ttime.NoTimeZone) + # return dt + #return None + + + ## photometrics + + def _exposure(self, content: dict) -> typing.Optional[float]: + if 'Exif.Photo.ExposureTime' in content: + return 1.0 / float(Fraction(content['Exif.Photo.ExposureTime'])) + return None + + def _aperture(self, content: dict) -> typing.Optional[float]: + if 'Exif.Photo.FNumber' in content: + return float(Fraction(content['Exif.Photo.FNumber'])) + return None + + def _iso(self, content: dict) -> typing.Optional[int]: + if 'Exif.Photo.ISOSpeedRatings' in content: + return int(content['Exif.Photo.ISOSpeedRatings']) + return None + + def _focal_length(self, content: dict) -> typing.Optional[float]: + if 'Exif.Photo.FocalLength' in content: + return float(Fraction(content['Exif.Photo.FocalLength'])) + return None + + + ## image dimensions + + def _width(self, content: dict) -> typing.Optional[int]: + # FIXME: consider orientation! + if 'Exif.Photo.PixelXDimension' in content: + return int(content['Exif.Photo.PixelXDimension']) + return None + + def _height(self, content: dict) -> typing.Optional[int]: + # FIXME: consider orientation! + if 'Exif.Photo.PixelYDimension' in content: + return int(content['Exif.Photo.PixelYDimension']) + return None + + def _orientation(self, content: dict) -> typing.Optional[int]: + if 'Exif.Image.Orientation' in content: + return int(content['Exif.Image.Orientation']) + return None + + def _orientation_label(self, content: dict) -> typing.Optional[str]: + width = self._width(content) + height = self._height(content) + ori = self._orientation(content) + if width is not None and height is not None and ori is not None: + if ori <= 4: + return 'landscape' if width >= height else 'portrait' + else: + return 'portrait' if width >= height else 'landscape' + return None + + + ## location + + def _altitude(self, content: dict) -> typing.Optional[float]: + if 'Exif.GPSInfo.GPSAltitude' in content: + return float(Fraction(content['Exif.GPSInfo.GPSAltitude'])) + return None + + def _latitude(self, content: dict) -> typing.Optional[float]: + if 'Exif.GPSInfo.GPSLatitude' in content: + return _gps_to_dec(content['Exif.GPSInfo.GPSLatitude'].split()) + return None + + def _longitude(self, content: dict) -> typing.Optional[float]: + if 'Exif.GPSInfo.GPSLongitude' in content: + return _gps_to_dec(content['Exif.GPSInfo.GPSLongitude'].split()) + return None + +## EOF ## diff --git a/bsie/reader/exif.py b/bsie/reader/exif.py new file mode 100644 index 0000000..e087bec --- /dev/null +++ b/bsie/reader/exif.py @@ -0,0 +1,49 @@ +""" + +Part of the bsie module. +A copy of the license is provided with the project. +Author: Matthias Baumgartner, 2022 +""" +# standard imports +import typing + +# external imports +import pyexiv2 + +# bsie imports +from bsie.utils import errors, filematcher + +# inner-module imports +from . import base + +# constants +MATCH_RULE = 'mime=image/jpeg' + +# exports +__all__: typing.Sequence[str] = ( + 'Exif', + ) + + +## code ## + +class Exif(base.Reader): + """Use pyexiv2 to read exif metadata from image files.""" + + def __init__(self): + self._match = filematcher.parse(MATCH_RULE) + + def __call__(self, path: str) -> dict: + # perform quick checks first + if not self._match(path): + raise errors.UnsupportedFileFormatError(path) + + try: + # open the file + img = pyexiv2.Image(path) + # read metadata + return img.read_exif() + except TypeError as err: + raise errors.ReaderError(path) from err + +## EOF ## -- cgit v1.2.3 From 6eca3af569997f28eee9d169a68cef4bbd6fd789 Mon Sep 17 00:00:00 2001 From: Matthias Baumgartner Date: Wed, 1 Mar 2023 21:50:04 +0100 Subject: Integrate main app into package --- bsie/apps/__init__.py | 40 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) (limited to 'bsie') diff --git a/bsie/apps/__init__.py b/bsie/apps/__init__.py index 1c3d0f9..4c852a9 100644 --- a/bsie/apps/__init__.py +++ b/bsie/apps/__init__.py @@ -1,12 +1,17 @@ -""" +#!/usr/bin/env python3 +"""BSIE tools. Part of the bsie module. A copy of the license is provided with the project. Author: Matthias Baumgartner, 2022 """ # standard imports +import argparse import typing +# bsie imports +import bsie + # inner-module imports from .index import main as index from .info import main as info @@ -15,6 +20,39 @@ from .info import main as info __all__: typing.Sequence[str] = ( 'index', 'info', + 'main', ) +# config +apps = { + 'index' : index, + 'info' : info, + } + + +## code ## + +def main(argv=None): + """Black Star File System maintenance tools.""" + parser = argparse.ArgumentParser(description=main.__doc__, prog='bsie') + # version + parser.add_argument('--version', action='version', + version='%(prog)s version {}.{}.{}'.format(*bsie.version_info)) + # application selection + parser.add_argument('app', choices=apps.keys(), + help='Select the application to run.') + # dangling args + parser.add_argument('rest', nargs=argparse.REMAINDER) + # parse + args = parser.parse_args(argv) + # run application + apps[args.app](args.rest) + + +## main ## + +if __name__ == '__main__': + import sys + main(sys.argv[1:]) + ## EOF ## -- cgit v1.2.3 From 4b5c4d486bb4f0f4da2e25ad464e8336a781cdcb Mon Sep 17 00:00:00 2001 From: Matthias Baumgartner Date: Wed, 1 Mar 2023 22:31:03 +0100 Subject: removed module header stubs --- bsie/__init__.py | 4 ---- bsie/apps/__init__.py | 4 ---- bsie/apps/_loader.py | 5 ----- bsie/apps/index.py | 5 ----- bsie/apps/info.py | 5 ----- bsie/extractor/__init__.py | 3 --- bsie/extractor/base.py | 4 ---- bsie/extractor/builder.py | 5 ----- bsie/extractor/generic/__init__.py | 3 --- bsie/extractor/generic/constant.py | 4 ---- bsie/extractor/generic/path.py | 5 ----- bsie/extractor/generic/stat.py | 4 ---- bsie/extractor/image/__init__.py | 5 ----- bsie/extractor/image/colors_spatial.py | 4 ---- bsie/extractor/image/photometrics.py | 5 ----- bsie/extractor/preview.py | 5 ----- bsie/lib/__init__.py | 5 ----- bsie/lib/bsie.py | 5 ----- bsie/lib/builder.py | 5 ----- bsie/lib/naming_policy.py | 5 ----- bsie/lib/pipeline.py | 5 ----- bsie/reader/__init__.py | 8 ++------ bsie/reader/base.py | 9 --------- bsie/reader/builder.py | 5 ----- bsie/reader/chain.py | 5 ----- bsie/reader/exif.py | 5 ----- bsie/reader/image/__init__.py | 5 ----- bsie/reader/image/_pillow.py | 5 ----- bsie/reader/image/_raw.py | 5 ----- bsie/reader/path.py | 4 ---- bsie/reader/preview/__init__.py | 5 ----- bsie/reader/preview/_pg.py | 5 ----- bsie/reader/preview/_pillow.py | 5 ----- bsie/reader/preview/_rawpy.py | 5 ----- bsie/reader/preview/utils.py | 5 ----- bsie/reader/stat.py | 4 ---- bsie/utils/__init__.py | 4 ---- bsie/utils/bsfs.py | 4 ---- bsie/utils/errors.py | 4 ---- bsie/utils/filematcher/__init__.py | 5 ----- bsie/utils/filematcher/matcher.py | 5 ----- bsie/utils/filematcher/parser.py | 5 ----- bsie/utils/loading.py | 5 ----- bsie/utils/namespaces.py | 4 ---- bsie/utils/node.py | 4 ---- 45 files changed, 2 insertions(+), 213 deletions(-) (limited to 'bsie') diff --git a/bsie/__init__.py b/bsie/__init__.py index c253f39..f6f2ff2 100644 --- a/bsie/__init__.py +++ b/bsie/__init__.py @@ -1,8 +1,4 @@ """The BSIE module extracts triples from files for insertion into a BSFS storage. - -Part of the bsie module. -A copy of the license is provided with the project. -Author: Matthias Baumgartner, 2022 """ # standard imports import collections diff --git a/bsie/apps/__init__.py b/bsie/apps/__init__.py index 4c852a9..cec8f84 100644 --- a/bsie/apps/__init__.py +++ b/bsie/apps/__init__.py @@ -1,9 +1,5 @@ #!/usr/bin/env python3 """BSIE tools. - -Part of the bsie module. -A copy of the license is provided with the project. -Author: Matthias Baumgartner, 2022 """ # standard imports import argparse diff --git a/bsie/apps/_loader.py b/bsie/apps/_loader.py index e02bed5..36dd8a6 100644 --- a/bsie/apps/_loader.py +++ b/bsie/apps/_loader.py @@ -1,9 +1,4 @@ -""" -Part of the bsie module. -A copy of the license is provided with the project. -Author: Matthias Baumgartner, 2022 -""" # standard imports import typing diff --git a/bsie/apps/index.py b/bsie/apps/index.py index 2d147c9..d64e8c2 100644 --- a/bsie/apps/index.py +++ b/bsie/apps/index.py @@ -1,9 +1,4 @@ -""" -Part of the bsie module. -A copy of the license is provided with the project. -Author: Matthias Baumgartner, 2022 -""" # standard imports import argparse import os diff --git a/bsie/apps/info.py b/bsie/apps/info.py index 363ab30..e27b70b 100644 --- a/bsie/apps/info.py +++ b/bsie/apps/info.py @@ -1,9 +1,4 @@ -""" -Part of the bsie module. -A copy of the license is provided with the project. -Author: Matthias Baumgartner, 2022 -""" # standard imports import argparse import os diff --git a/bsie/extractor/__init__.py b/bsie/extractor/__init__.py index 5f385ee..36fa9ba 100644 --- a/bsie/extractor/__init__.py +++ b/bsie/extractor/__init__.py @@ -2,9 +2,6 @@ Each Extractor class is linked to the Reader class whose content it requires. -Part of the bsie module. -A copy of the license is provided with the project. -Author: Matthias Baumgartner, 2022 """ # standard imports import typing diff --git a/bsie/extractor/base.py b/bsie/extractor/base.py index d8b86a5..3759c68 100644 --- a/bsie/extractor/base.py +++ b/bsie/extractor/base.py @@ -1,8 +1,4 @@ """The Extractor classes transform content into triples. - -Part of the bsie module. -A copy of the license is provided with the project. -Author: Matthias Baumgartner, 2022 """ # standard imports import abc diff --git a/bsie/extractor/builder.py b/bsie/extractor/builder.py index 0fd3685..d691b0e 100644 --- a/bsie/extractor/builder.py +++ b/bsie/extractor/builder.py @@ -1,9 +1,4 @@ -""" -Part of the bsie module. -A copy of the license is provided with the project. -Author: Matthias Baumgartner, 2022 -""" # standard imports import typing diff --git a/bsie/extractor/generic/__init__.py b/bsie/extractor/generic/__init__.py index 4783949..46a4bd6 100644 --- a/bsie/extractor/generic/__init__.py +++ b/bsie/extractor/generic/__init__.py @@ -3,9 +3,6 @@ files. Examples include file system information (file name and size, mime type, etc.) and information that is independent of the actual file (constant triples, host platform infos, current time, etc.). -Part of the bsie module. -A copy of the license is provided with the project. -Author: Matthias Baumgartner, 2022 """ # standard imports import typing diff --git a/bsie/extractor/generic/constant.py b/bsie/extractor/generic/constant.py index 938e20c..7acbe95 100644 --- a/bsie/extractor/generic/constant.py +++ b/bsie/extractor/generic/constant.py @@ -1,8 +1,4 @@ """The Constant extractor produces pre-specified triples. - -Part of the bsie module. -A copy of the license is provided with the project. -Author: Matthias Baumgartner, 2022 """ # standard imports import typing diff --git a/bsie/extractor/generic/path.py b/bsie/extractor/generic/path.py index cd8cec9..8b01933 100644 --- a/bsie/extractor/generic/path.py +++ b/bsie/extractor/generic/path.py @@ -1,9 +1,4 @@ -""" -Part of the bsie module. -A copy of the license is provided with the project. -Author: Matthias Baumgartner, 2022 -""" # standard imports import os import typing diff --git a/bsie/extractor/generic/stat.py b/bsie/extractor/generic/stat.py index f35f8e1..50821a7 100644 --- a/bsie/extractor/generic/stat.py +++ b/bsie/extractor/generic/stat.py @@ -1,8 +1,4 @@ """Extract information from the file system, such as filesize. - -Part of the bsie module. -A copy of the license is provided with the project. -Author: Matthias Baumgartner, 2022 """ # standard imports import os diff --git a/bsie/extractor/image/__init__.py b/bsie/extractor/image/__init__.py index 75b118d..f82424a 100644 --- a/bsie/extractor/image/__init__.py +++ b/bsie/extractor/image/__init__.py @@ -1,9 +1,4 @@ -""" -Part of the bsie module. -A copy of the license is provided with the project. -Author: Matthias Baumgartner, 2022 -""" # standard imports import typing diff --git a/bsie/extractor/image/colors_spatial.py b/bsie/extractor/image/colors_spatial.py index 15fd281..34cd615 100644 --- a/bsie/extractor/image/colors_spatial.py +++ b/bsie/extractor/image/colors_spatial.py @@ -1,8 +1,4 @@ """Spatial color features. - -Part of the bsie module. -A copy of the license is provided with the project. -Author: Matthias Baumgartner, 2022 """ # standard imports import typing diff --git a/bsie/extractor/image/photometrics.py b/bsie/extractor/image/photometrics.py index ae0a541..525f207 100644 --- a/bsie/extractor/image/photometrics.py +++ b/bsie/extractor/image/photometrics.py @@ -1,9 +1,4 @@ -""" -Part of the bsie module. -A copy of the license is provided with the project. -Author: Matthias Baumgartner, 2022 -""" # standard imports from fractions import Fraction import typing diff --git a/bsie/extractor/preview.py b/bsie/extractor/preview.py index 1531d62..7e4a171 100644 --- a/bsie/extractor/preview.py +++ b/bsie/extractor/preview.py @@ -1,9 +1,4 @@ -""" -Part of the bsie module. -A copy of the license is provided with the project. -Author: Matthias Baumgartner, 2022 -""" # imports import io import typing diff --git a/bsie/lib/__init__.py b/bsie/lib/__init__.py index 48379de..f44fb74 100644 --- a/bsie/lib/__init__.py +++ b/bsie/lib/__init__.py @@ -1,9 +1,4 @@ -""" -Part of the bsie module. -A copy of the license is provided with the project. -Author: Matthias Baumgartner, 2022 -""" # standard imports import typing diff --git a/bsie/lib/bsie.py b/bsie/lib/bsie.py index a572525..b02e707 100644 --- a/bsie/lib/bsie.py +++ b/bsie/lib/bsie.py @@ -1,9 +1,4 @@ -""" -Part of the bsie module. -A copy of the license is provided with the project. -Author: Matthias Baumgartner, 2022 -""" # standard imports import typing diff --git a/bsie/lib/builder.py b/bsie/lib/builder.py index 39da441..3a15311 100644 --- a/bsie/lib/builder.py +++ b/bsie/lib/builder.py @@ -1,9 +1,4 @@ -""" -Part of the bsie module. -A copy of the license is provided with the project. -Author: Matthias Baumgartner, 2022 -""" # standard imports import logging import typing diff --git a/bsie/lib/naming_policy.py b/bsie/lib/naming_policy.py index 131a70b..c99f8c8 100644 --- a/bsie/lib/naming_policy.py +++ b/bsie/lib/naming_policy.py @@ -1,9 +1,4 @@ -""" -Part of the bsie module. -A copy of the license is provided with the project. -Author: Matthias Baumgartner, 2022 -""" # standard imports import abc import os diff --git a/bsie/lib/pipeline.py b/bsie/lib/pipeline.py index 0bc5109..128eecc 100644 --- a/bsie/lib/pipeline.py +++ b/bsie/lib/pipeline.py @@ -1,9 +1,4 @@ -""" -Part of the bsie module. -A copy of the license is provided with the project. -Author: Matthias Baumgartner, 2022 -""" # standard imports from collections import defaultdict import logging diff --git a/bsie/reader/__init__.py b/bsie/reader/__init__.py index 4163d1c..a1c38a9 100644 --- a/bsie/reader/__init__.py +++ b/bsie/reader/__init__.py @@ -1,8 +1,8 @@ """The Reader classes return high-level content structures from files. The Reader fulfills two purposes: - First, it brokers between multiple libraries and file formats. - Second, it separates multiple aspects of a file into distinct content types. +First, it brokers between multiple libraries and file formats. +Second, it separates multiple aspects of a file into distinct content types. Often, different libraries focus on reading different types of content from a file. E.g. one would use different modules to read file system infos than to @@ -11,9 +11,6 @@ type. Each distinct type can be implemented in a file or submodule that provides a Reader implementation. Through utilization of submodules, different file formats can be supported. -Part of the bsie module. -A copy of the license is provided with the project. -Author: Matthias Baumgartner, 2022 """ # standard imports import typing @@ -29,4 +26,3 @@ __all__: typing.Sequence[str] = ( ) ## EOF ## -## EOF ## diff --git a/bsie/reader/base.py b/bsie/reader/base.py index 099a327..a775701 100644 --- a/bsie/reader/base.py +++ b/bsie/reader/base.py @@ -1,13 +1,4 @@ -"""The Reader classes return high-level content structures from files. -The Reader fulfills two purposes: - First, it brokers between multiple libraries and file formats. - Second, it separates multiple aspects of a file into distinct content types. - -Part of the bsie module. -A copy of the license is provided with the project. -Author: Matthias Baumgartner, 2022 -""" # standard imports import abc import typing diff --git a/bsie/reader/builder.py b/bsie/reader/builder.py index 8699e75..d32700b 100644 --- a/bsie/reader/builder.py +++ b/bsie/reader/builder.py @@ -1,9 +1,4 @@ -""" -Part of the bsie module. -A copy of the license is provided with the project. -Author: Matthias Baumgartner, 2022 -""" # standard imports import typing diff --git a/bsie/reader/chain.py b/bsie/reader/chain.py index 1dbc52b..79b44b4 100644 --- a/bsie/reader/chain.py +++ b/bsie/reader/chain.py @@ -1,9 +1,4 @@ -""" -Part of the bsie module. -A copy of the license is provided with the project. -Author: Matthias Baumgartner, 2022 -""" # standard imports import logging import typing diff --git a/bsie/reader/exif.py b/bsie/reader/exif.py index e087bec..8c74462 100644 --- a/bsie/reader/exif.py +++ b/bsie/reader/exif.py @@ -1,9 +1,4 @@ -""" -Part of the bsie module. -A copy of the license is provided with the project. -Author: Matthias Baumgartner, 2022 -""" # standard imports import typing diff --git a/bsie/reader/image/__init__.py b/bsie/reader/image/__init__.py index c5d2a2a..89642f2 100644 --- a/bsie/reader/image/__init__.py +++ b/bsie/reader/image/__init__.py @@ -1,9 +1,4 @@ -""" -Part of the bsie module. -A copy of the license is provided with the project. -Author: Matthias Baumgartner, 2022 -""" # standard imports import typing diff --git a/bsie/reader/image/_pillow.py b/bsie/reader/image/_pillow.py index 5b2bdf2..0611d3c 100644 --- a/bsie/reader/image/_pillow.py +++ b/bsie/reader/image/_pillow.py @@ -1,9 +1,4 @@ -""" -Part of the bsie module. -A copy of the license is provided with the project. -Author: Matthias Baumgartner, 2022 -""" # standard imports import typing diff --git a/bsie/reader/image/_raw.py b/bsie/reader/image/_raw.py index 257fdb3..e5745aa 100644 --- a/bsie/reader/image/_raw.py +++ b/bsie/reader/image/_raw.py @@ -1,9 +1,4 @@ -""" -Part of the bsie module. -A copy of the license is provided with the project. -Author: Matthias Baumgartner, 2022 -""" # standard imports import typing diff --git a/bsie/reader/path.py b/bsie/reader/path.py index 1ca05a0..45eb127 100644 --- a/bsie/reader/path.py +++ b/bsie/reader/path.py @@ -1,8 +1,4 @@ """The Path reader produces a file path. - -Part of the bsie module. -A copy of the license is provided with the project. -Author: Matthias Baumgartner, 2022 """ # standard imports import typing diff --git a/bsie/reader/preview/__init__.py b/bsie/reader/preview/__init__.py index 3e69a4a..791a133 100644 --- a/bsie/reader/preview/__init__.py +++ b/bsie/reader/preview/__init__.py @@ -1,9 +1,4 @@ -""" -Part of the bsie module. -A copy of the license is provided with the project. -Author: Matthias Baumgartner, 2022 -""" # imports import typing diff --git a/bsie/reader/preview/_pg.py b/bsie/reader/preview/_pg.py index 097c513..401b33d 100644 --- a/bsie/reader/preview/_pg.py +++ b/bsie/reader/preview/_pg.py @@ -1,9 +1,4 @@ -""" -Part of the bsie module. -A copy of the license is provided with the project. -Author: Matthias Baumgartner, 2022 -""" # standard imports from functools import partial import contextlib diff --git a/bsie/reader/preview/_pillow.py b/bsie/reader/preview/_pillow.py index 174d509..15c1c6d 100644 --- a/bsie/reader/preview/_pillow.py +++ b/bsie/reader/preview/_pillow.py @@ -1,9 +1,4 @@ -""" -Part of the bsie module. -A copy of the license is provided with the project. -Author: Matthias Baumgartner, 2022 -""" # standard imports from functools import partial import typing diff --git a/bsie/reader/preview/_rawpy.py b/bsie/reader/preview/_rawpy.py index 2c20a48..16e8675 100644 --- a/bsie/reader/preview/_rawpy.py +++ b/bsie/reader/preview/_rawpy.py @@ -1,9 +1,4 @@ -""" -Part of the bsie module. -A copy of the license is provided with the project. -Author: Matthias Baumgartner, 2022 -""" # standard imports from functools import partial import typing diff --git a/bsie/reader/preview/utils.py b/bsie/reader/preview/utils.py index 2ef1562..82ecc31 100644 --- a/bsie/reader/preview/utils.py +++ b/bsie/reader/preview/utils.py @@ -1,9 +1,4 @@ -""" -Part of the tagit module. -A copy of the license is provided with the project. -Author: Matthias Baumgartner, 2022 -""" # standard imports import typing diff --git a/bsie/reader/stat.py b/bsie/reader/stat.py index 706dc47..f42e7fb 100644 --- a/bsie/reader/stat.py +++ b/bsie/reader/stat.py @@ -1,8 +1,4 @@ """The Stat reader produces filesystem stat information. - -Part of the bsie module. -A copy of the license is provided with the project. -Author: Matthias Baumgartner, 2022 """ # standard imports import os diff --git a/bsie/utils/__init__.py b/bsie/utils/__init__.py index 9cb60ed..18c8db7 100644 --- a/bsie/utils/__init__.py +++ b/bsie/utils/__init__.py @@ -1,8 +1,4 @@ """Common tools and definitions. - -Part of the bsie module. -A copy of the license is provided with the project. -Author: Matthias Baumgartner, 2022 """ # standard imports import typing diff --git a/bsie/utils/bsfs.py b/bsie/utils/bsfs.py index ef5db31..fc045cc 100644 --- a/bsie/utils/bsfs.py +++ b/bsie/utils/bsfs.py @@ -1,8 +1,4 @@ """BSFS bridge, provides BSFS bindings for BSIE. - -Part of the bsie module. -A copy of the license is provided with the project. -Author: Matthias Baumgartner, 2022 """ # standard imports import typing diff --git a/bsie/utils/errors.py b/bsie/utils/errors.py index 8133cd4..e71fc60 100644 --- a/bsie/utils/errors.py +++ b/bsie/utils/errors.py @@ -1,8 +1,4 @@ """Common BSIE exceptions. - -Part of the bsie module. -A copy of the license is provided with the project. -Author: Matthias Baumgartner, 2022 """ # standard imports import typing diff --git a/bsie/utils/filematcher/__init__.py b/bsie/utils/filematcher/__init__.py index 1e23e4e..908de78 100644 --- a/bsie/utils/filematcher/__init__.py +++ b/bsie/utils/filematcher/__init__.py @@ -1,9 +1,4 @@ -""" -Part of the bsie module. -A copy of the license is provided with the project. -Author: Matthias Baumgartner, 2022 -""" # standard imports import typing diff --git a/bsie/utils/filematcher/matcher.py b/bsie/utils/filematcher/matcher.py index a279a4b..1fa308e 100644 --- a/bsie/utils/filematcher/matcher.py +++ b/bsie/utils/filematcher/matcher.py @@ -1,9 +1,4 @@ -""" -Part of the bsie module. -A copy of the license is provided with the project. -Author: Matthias Baumgartner, 2021 -""" # standard imports from collections.abc import Callable, Collection, Hashable import abc diff --git a/bsie/utils/filematcher/parser.py b/bsie/utils/filematcher/parser.py index 2f82875..dc28a0d 100644 --- a/bsie/utils/filematcher/parser.py +++ b/bsie/utils/filematcher/parser.py @@ -1,9 +1,4 @@ -""" -Part of the bsie module. -A copy of the license is provided with the project. -Author: Matthias Baumgartner, 2021 -""" # standard imports import typing diff --git a/bsie/utils/loading.py b/bsie/utils/loading.py index eb05c35..3c5c7c1 100644 --- a/bsie/utils/loading.py +++ b/bsie/utils/loading.py @@ -1,9 +1,4 @@ -""" -Part of the bsie module. -A copy of the license is provided with the project. -Author: Matthias Baumgartner, 2022 -""" # standard imports import importlib import typing diff --git a/bsie/utils/namespaces.py b/bsie/utils/namespaces.py index 0af8ece..310aa3f 100644 --- a/bsie/utils/namespaces.py +++ b/bsie/utils/namespaces.py @@ -1,8 +1,4 @@ """Default namespaces used throughout BSIE. - -Part of the bsie module. -A copy of the license is provided with the project. -Author: Matthias Baumgartner, 2022 """ # standard imports import typing diff --git a/bsie/utils/node.py b/bsie/utils/node.py index aa62c06..fa34b2e 100644 --- a/bsie/utils/node.py +++ b/bsie/utils/node.py @@ -1,8 +1,4 @@ """Lighweight Node to bridge to BSFS. - -Part of the bsie module. -A copy of the license is provided with the project. -Author: Matthias Baumgartner, 2022 """ # standard imports import typing -- cgit v1.2.3 From 70d77819a84c73292825b81f952e162bb30753d7 Mon Sep 17 00:00:00 2001 From: Matthias Baumgartner Date: Thu, 2 Mar 2023 08:56:57 +0100 Subject: reader error: untangle generic from unsupported format errors --- bsie/reader/exif.py | 2 +- bsie/reader/preview/_pillow.py | 2 +- bsie/utils/errors.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'bsie') diff --git a/bsie/reader/exif.py b/bsie/reader/exif.py index 8c74462..2d0428b 100644 --- a/bsie/reader/exif.py +++ b/bsie/reader/exif.py @@ -38,7 +38,7 @@ class Exif(base.Reader): img = pyexiv2.Image(path) # read metadata return img.read_exif() - except TypeError as err: + except (TypeError, OSError, RuntimeError) as err: raise errors.ReaderError(path) from err ## EOF ## diff --git a/bsie/reader/preview/_pillow.py b/bsie/reader/preview/_pillow.py index 15c1c6d..2b797c6 100644 --- a/bsie/reader/preview/_pillow.py +++ b/bsie/reader/preview/_pillow.py @@ -33,7 +33,7 @@ class PillowPreviewReader(base.Reader): except PIL.UnidentifiedImageError as err: # failed to open, skip file raise errors.UnsupportedFileFormatError(path) from err - except IOError as err: + except OSError as err: raise errors.ReaderError(path) from err # EOF ## diff --git a/bsie/utils/errors.py b/bsie/utils/errors.py index e71fc60..7c7e6ed 100644 --- a/bsie/utils/errors.py +++ b/bsie/utils/errors.py @@ -38,7 +38,7 @@ class UnreachableError(ProgrammingError): class ParserError(_BSIEError): """Failed to parse due to invalid syntax or structures.""" -class UnsupportedFileFormatError(ReaderError): +class UnsupportedFileFormatError(_BSIEError): """Failed to read a file format.""" ## EOF ## -- cgit v1.2.3 From ba6329bbe14c832d42773dee2fe30bd7669ca255 Mon Sep 17 00:00:00 2001 From: Matthias Baumgartner Date: Thu, 2 Mar 2023 08:58:29 +0100 Subject: various minor fixes --- bsie/apps/__init__.py | 2 +- bsie/apps/_loader.py | 4 ++-- bsie/extractor/image/photometrics.py | 37 +++++++++++++++++------------------- 3 files changed, 20 insertions(+), 23 deletions(-) (limited to 'bsie') diff --git a/bsie/apps/__init__.py b/bsie/apps/__init__.py index cec8f84..2fe4795 100644 --- a/bsie/apps/__init__.py +++ b/bsie/apps/__init__.py @@ -33,7 +33,7 @@ def main(argv=None): parser = argparse.ArgumentParser(description=main.__doc__, prog='bsie') # version parser.add_argument('--version', action='version', - version='%(prog)s version {}.{}.{}'.format(*bsie.version_info)) + version='%(prog)s version {}.{}.{}'.format(*bsie.version_info)) # pylint: disable=C0209 # application selection parser.add_argument('app', choices=apps.keys(), help='Select the application to run.') diff --git a/bsie/apps/_loader.py b/bsie/apps/_loader.py index 36dd8a6..6411f10 100644 --- a/bsie/apps/_loader.py +++ b/bsie/apps/_loader.py @@ -16,8 +16,8 @@ DEFAULT_CONFIG_FILE = 'default_config.yaml' # exports __all__: typing.Sequence[str] = ( - 'load', 'DEFAULT_CONFIG_FILE', + 'load_pipeline', ) @@ -26,7 +26,7 @@ __all__: typing.Sequence[str] = ( def load_pipeline(path: str) -> Pipeline: """Load a pipeline according to a config at *path*.""" # load config file - with open(path, 'rt') as ifile: + with open(path, 'rt', encoding='utf-8') as ifile: cfg = yaml.safe_load(ifile) # reader builder diff --git a/bsie/extractor/image/photometrics.py b/bsie/extractor/image/photometrics.py index 525f207..c5254ab 100644 --- a/bsie/extractor/image/photometrics.py +++ b/bsie/extractor/image/photometrics.py @@ -20,7 +20,7 @@ __all__: typing.Sequence[str] = ( def _gps_to_dec(coords: typing.Tuple[float, float, float]) -> float: """Convert GPS coordinates from exif to float.""" # unpack args - deg, min, sec = coords + deg, min, sec = coords # pylint: disable=redefined-builtin # min # convert to float deg = float(Fraction(deg)) min = float(Fraction(min)) @@ -29,9 +29,8 @@ def _gps_to_dec(coords: typing.Tuple[float, float, float]) -> float: if float(sec) > 0: # format is deg+min+sec return (float(deg) * 3600 + float(min) * 60 + float(sec)) / 3600 - else: - # format is deg+min - return float(deg) + float(min) / 60 + # format is deg+min + return float(deg) + float(min) / 60 class Exif(base.Extractor): @@ -124,20 +123,19 @@ class Exif(base.Extractor): # produce triple yield subject, pred, value - def _date(self, content: dict): # FIXME: Return type annotation - raise NotImplementedError() - #date_keys = ( - # 'Exif.Photo.DateTimeOriginal', - # 'Exif.Photo.DateTimeDigitized', - # 'Exif.Image.DateTime', - # ) - #for key in date_keys: - # if key in content: - # dt = content[key].value - # if dt.tzinfo is None: - # dt = dt.replace(tzinfo=ttime.NoTimeZone) - # return dt - #return None + #def _date(self, content: dict): # FIXME: Return type annotation + # date_keys = ( + # 'Exif.Photo.DateTimeOriginal', + # 'Exif.Photo.DateTimeDigitized', + # 'Exif.Image.DateTime', + # ) + # for key in date_keys: + # if key in content: + # dt = content[key].value + # if dt.tzinfo is None: + # dt = dt.replace(tzinfo=ttime.NoTimeZone) + # return dt + # return None ## photometrics @@ -189,8 +187,7 @@ class Exif(base.Extractor): if width is not None and height is not None and ori is not None: if ori <= 4: return 'landscape' if width >= height else 'portrait' - else: - return 'portrait' if width >= height else 'landscape' + return 'portrait' if width >= height else 'landscape' return None -- cgit v1.2.3 From d2052e77210e0ace2c5f06e48afe2a8acb412965 Mon Sep 17 00:00:00 2001 From: Matthias Baumgartner Date: Sat, 4 Mar 2023 13:41:13 +0100 Subject: namespace refactoring and cleanup --- bsie/extractor/base.py | 33 +++++++++++++++++++-------------- bsie/extractor/generic/path.py | 2 +- bsie/extractor/generic/stat.py | 2 +- bsie/extractor/image/colors_spatial.py | 12 ++++++------ bsie/extractor/image/photometrics.py | 24 ++++++++++++------------ bsie/extractor/preview.py | 22 ++++++++++++---------- bsie/lib/naming_policy.py | 8 ++++---- bsie/lib/pipeline.py | 2 +- bsie/utils/namespaces.py | 28 ++++++++++++++++++++-------- 9 files changed, 76 insertions(+), 57 deletions(-) (limited to 'bsie') diff --git a/bsie/extractor/base.py b/bsie/extractor/base.py index 3759c68..f92d7cc 100644 --- a/bsie/extractor/base.py +++ b/bsie/extractor/base.py @@ -24,27 +24,32 @@ SCHEMA_PREAMBLE = ''' prefix schema: # common bsfs prefixes - prefix bsfs: - prefix bse: - prefix bsp: + prefix bsfs: + prefix bsl: + prefix bsa: + prefix bsd: + + prefix bsie: + prefix bsn: + prefix bse: + prefix bsp: # default definitions - bsfs:Array rdfs:subClassOf bsfs:Literal . - bsfs:Number rdfs:subClassOf bsfs:Literal . - bsfs:Time rdfs:subClassOf bsfs:Literal . - bsfs:Feature rdfs:subClassOf bsfs:Array ; + bsl:Array rdfs:subClassOf bsfs:Literal . + bsl:Number rdfs:subClassOf bsfs:Literal . + bsl:Time rdfs:subClassOf bsfs:Literal . + bsa:Feature rdfs:subClassOf bsl:Array ; bsfs:dimension "1"^^xsd:integer ; - bsfs:dtype bsfs:f16 ; - bsfs:distance bsfs:euclidean . + bsfs:dtype ; + bsfs:distance bsd:euclidean . # essential nodes - bsfs:Entity rdfs:subClassOf bsfs:Node . - bsfs:File rdfs:subClassOf bsfs:Entity . + bsn:Entity rdfs:subClassOf bsfs:Node . # common definitions xsd:string rdfs:subClassOf bsfs:Literal . - xsd:integer rdfs:subClassOf bsfs:Number . - xsd:float rdfs:subClassOf bsfs:Number . + xsd:integer rdfs:subClassOf bsl:Number . + xsd:float rdfs:subClassOf bsl:Number . ''' @@ -90,7 +95,7 @@ class Extractor(abc.ABC): @property def principals(self) -> typing.Iterator[bsfs.schema.Predicate]: """Return the principal predicates, i.e., relations from/to the extraction subject.""" - ent = self.schema.node(ns.bsfs.Entity) + ent = self.schema.node(ns.bsn.Entity) return ( pred for pred diff --git a/bsie/extractor/generic/path.py b/bsie/extractor/generic/path.py index 8b01933..00c1121 100644 --- a/bsie/extractor/generic/path.py +++ b/bsie/extractor/generic/path.py @@ -26,7 +26,7 @@ class Path(base.Extractor): def __init__(self): super().__init__(bsfs.schema.from_string(base.SCHEMA_PREAMBLE + ''' bse:filename rdfs:subClassOf bsfs:Predicate ; - rdfs:domain bsfs:File ; + rdfs:domain bsn:Entity ; rdfs:range xsd:string ; rdfs:label "File name"^^xsd:string ; schema:description "Filename of entity in some filesystem."^^xsd:string ; diff --git a/bsie/extractor/generic/stat.py b/bsie/extractor/generic/stat.py index 50821a7..92b51f3 100644 --- a/bsie/extractor/generic/stat.py +++ b/bsie/extractor/generic/stat.py @@ -29,7 +29,7 @@ class Stat(base.Extractor): def __init__(self): super().__init__(bsfs.schema.from_string(base.SCHEMA_PREAMBLE + ''' bse:filesize rdfs:subClassOf bsfs:Predicate ; - rdfs:domain bsfs:File ; + rdfs:domain bsn:Entity ; rdfs:range xsd:integer ; rdfs:label "File size"^^xsd:string ; schema:description "File size of entity in some filesystem."^^xsd:string ; diff --git a/bsie/extractor/image/colors_spatial.py b/bsie/extractor/image/colors_spatial.py index 34cd615..e6661a9 100644 --- a/bsie/extractor/image/colors_spatial.py +++ b/bsie/extractor/image/colors_spatial.py @@ -14,8 +14,7 @@ from bsie.utils import bsfs, node, ns from .. import base # constants -FEATURE_NAME = ns.bsf + 'ColorsSpatial' -PREDICATE_NAME = ns.bse + 'colors_spatial' +FEATURE_NAME = ns.bsf.ColorsSpatial() # exports __all__: typing.Sequence[str] = ( @@ -58,16 +57,17 @@ class ColorsSpatial(base.Extractor): 'exp': exp, }) # determine symbol names - instance_name = FEATURE_NAME[uuid] - predicate_name = PREDICATE_NAME[uuid] + instance_name = getattr(FEATURE_NAME, uuid) + predicate_name = getattr(ns.bse, 'colors_spatial_' + uuid) # get vector dimension dimension = self.dimension(width, height, exp) # initialize parent with the schema super().__init__(bsfs.schema.from_string(base.SCHEMA_PREAMBLE + f''' - <{FEATURE_NAME}> rdfs:subClassOf bsfs:Feature ; + <{FEATURE_NAME}> rdfs:subClassOf bsa:Feature ; # annotations rdfs:label "Spatially dominant colors"^^xsd:string ; schema:description "Domiant colors of subregions in an image."^^xsd:string ; + bsfs:distance ; bsfs:dtype xsd:integer . <{instance_name}> rdfs:subClassOf <{FEATURE_NAME}> ; @@ -78,7 +78,7 @@ class ColorsSpatial(base.Extractor): <{FEATURE_NAME}/args#exp> "{exp}"^^xsd:float . <{predicate_name}> rdfs:subClassOf bsfs:Predicate ; - rdfs:domain bsfs:File ; + rdfs:domain bsn:Entity ; rdfs:range <{instance_name}> ; bsfs:unique "true"^^xsd:boolean . diff --git a/bsie/extractor/image/photometrics.py b/bsie/extractor/image/photometrics.py index c5254ab..42eb3c8 100644 --- a/bsie/extractor/image/photometrics.py +++ b/bsie/extractor/image/photometrics.py @@ -41,51 +41,51 @@ class Exif(base.Extractor): def __init__(self): super().__init__(bsfs.schema.from_string(base.SCHEMA_PREAMBLE + ''' #bse:t_capture rdfs:subClassOf bsfs:Predicate ; - # rdfs:domain bsfs:File ; + # rdfs:domain bsn:Entity ; # rdfs:range xsd:float ; # bsfs:unique "true"^^xsd:boolean . bse:exposure rdfs:subClassOf bsfs:Predicate ; - rdfs:domain bsfs:File ; + rdfs:domain bsn:Entity ; rdfs:range xsd:float ; bsfs:unique "true"^^xsd:boolean . bse:aperture rdfs:subClassOf bsfs:Predicate ; - rdfs:domain bsfs:File ; + rdfs:domain bsn:Entity ; rdfs:range xsd:float ; bsfs:unique "true"^^xsd:boolean . bse:iso rdfs:subClassOf bsfs:Predicate ; - rdfs:domain bsfs:File ; + rdfs:domain bsn:Entity ; rdfs:range xsd:integer ; bsfs:unique "true"^^xsd:boolean . bse:focal_length rdfs:subClassOf bsfs:Predicate ; - rdfs:domain bsfs:File ; + rdfs:domain bsn:Entity ; rdfs:range xsd:float ; bsfs:unique "true"^^xsd:boolean . bse:width rdfs:subClassOf bsfs:Predicate ; - rdfs:domain bsfs:File ; + rdfs:domain bsn:Entity ; rdfs:range xsd:integer ; bsfs:unique "true"^^xsd:boolean . bse:height rdfs:subClassOf bsfs:Predicate ; - rdfs:domain bsfs:File ; + rdfs:domain bsn:Entity ; rdfs:range xsd:integer ; bsfs:unique "true"^^xsd:boolean . bse:orientation rdfs:subClassOf bsfs:Predicate ; - rdfs:domain bsfs:File ; + rdfs:domain bsn:Entity ; rdfs:range xsd:integer ; bsfs:unique "true"^^xsd:boolean . bse:orientation_label rdfs:subClassOf bsfs:Predicate ; - rdfs:domain bsfs:File ; + rdfs:domain bsn:Entity ; rdfs:range xsd:string ; bsfs:unique "true"^^xsd:boolean . bse:altitude rdfs:subClassOf bsfs:Predicate ; - rdfs:domain bsfs:File ; + rdfs:domain bsn:Entity ; rdfs:range xsd:float ; bsfs:unique "true"^^xsd:boolean . bse:latitude rdfs:subClassOf bsfs:Predicate ; - rdfs:domain bsfs:File ; + rdfs:domain bsn:Entity ; rdfs:range xsd:float ; bsfs:unique "true"^^xsd:boolean . bse:longitude rdfs:subClassOf bsfs:Predicate ; - rdfs:domain bsfs:File ; + rdfs:domain bsn:Entity ; rdfs:range xsd:float ; bsfs:unique "true"^^xsd:boolean . ''')) diff --git a/bsie/extractor/preview.py b/bsie/extractor/preview.py index 7e4a171..145a01a 100644 --- a/bsie/extractor/preview.py +++ b/bsie/extractor/preview.py @@ -28,28 +28,30 @@ class Preview(base.Extractor): def __init__(self, max_sides: typing.Iterable[int]): super().__init__(bsfs.schema.from_string(base.SCHEMA_PREAMBLE + ''' - bsfs:Preview rdfs:subClassOf bsfs:Node . - bsfs:BinaryBlob rdfs:subClassOf bsfs:Literal . - bsfs:JPEG rdfs:subClassOf bsfs:BinaryBlob . + + + bsn:Preview rdfs:subClassOf bsfs:Node . + bsl:BinaryBlob rdfs:subClassOf bsfs:Literal . + rdfs:subClassOf bsl:BinaryBlob . bse:preview rdfs:subClassOf bsfs:Predicate ; - rdfs:domain bsfs:File ; - rdfs:range bsfs:Preview ; + rdfs:domain bsn:Entity ; + rdfs:range bsn:Preview ; bsfs:unique "false"^^xsd:boolean . bsp:width rdfs:subClassOf bsfs:Predicate ; - rdfs:domain bsfs:Preview ; + rdfs:domain bsn:Preview ; rdfs:range xsd:integer ; bsfs:unique "true"^^xsd:boolean . bsp:height rdfs:subClassOf bsfs:Predicate ; - rdfs:domain bsfs:Preview ; + rdfs:domain bsn:Preview ; rdfs:range xsd:integer ; bsfs:unique "true"^^xsd:boolean . bsp:asset rdfs:subClassOf bsfs:Predicate ; - rdfs:domain bsfs:Preview ; - rdfs:range bsfs:JPEG ; + rdfs:domain bsn:Preview ; + rdfs:range ; bsfs:unique "true"^^xsd:boolean . ''')) @@ -80,7 +82,7 @@ class Preview(base.Extractor): buffer = io.BytesIO() img.save(buffer, format='jpeg') # create a preview node - preview = node.Node(ns.bsfs.Preview, + preview = node.Node(ns.bsn.Preview, ucid=bsfs.uuid.UCID.from_bytes(buffer.getvalue()), size=max_side, source=subject, diff --git a/bsie/lib/naming_policy.py b/bsie/lib/naming_policy.py index c99f8c8..9b9a45d 100644 --- a/bsie/lib/naming_policy.py +++ b/bsie/lib/naming_policy.py @@ -80,9 +80,9 @@ class DefaultNamingPolicy(NamingPolicy): def handle_node(self, node: Node) -> Node: if node.uri is not None: return node - if node.node_type == ns.bsfs.File: + if node.node_type == ns.bsn.Entity : return self.name_file(node) - if node.node_type == ns.bsfs.Preview: + if node.node_type == ns.bsn.Preview: return self.name_preview(node) raise errors.ProgrammingError('no naming policy available for {node.node_type}') @@ -92,7 +92,7 @@ class DefaultNamingPolicy(NamingPolicy): fragment = node.hints['ucid'] else: # random name fragment = self._uuid() - node.uri = (self._prefix + 'file')[fragment] + node.uri = getattr(self._prefix.file(), fragment) return node def name_preview(self, node: Node) -> Node: @@ -109,7 +109,7 @@ class DefaultNamingPolicy(NamingPolicy): fragment = self._uuid() if 'size' in node.hints: # append size fragment += '_s' + str(node.hints['size']) - node.uri = (self._prefix + 'preview')[fragment] + node.uri = getattr(self._prefix.preview(), fragment) return node ## EOF ## diff --git a/bsie/lib/pipeline.py b/bsie/lib/pipeline.py index 128eecc..30fd6fd 100644 --- a/bsie/lib/pipeline.py +++ b/bsie/lib/pipeline.py @@ -104,7 +104,7 @@ class Pipeline(): rdr2ext[rdr].add(ext) # create subject for file - subject = node.Node(ns.bsfs.File, + subject = node.Node(ns.bsn.Entity, ucid=bsfs.uuid.UCID.from_path(path), ) diff --git a/bsie/utils/namespaces.py b/bsie/utils/namespaces.py index 310aa3f..4a66048 100644 --- a/bsie/utils/namespaces.py +++ b/bsie/utils/namespaces.py @@ -6,19 +6,31 @@ import typing # inner-module imports from . import bsfs as _bsfs -# constants -bse = _bsfs.Namespace('http://bsfs.ai/schema/Entity') -bsf = _bsfs.Namespace('http://ie.bsfs.ai/schema/Feature') -bsfs = _bsfs.Namespace('http://bsfs.ai/schema', fsep='/') -bsm = _bsfs.Namespace('http://bsfs.ai/schema/Meta') -bsp = _bsfs.Namespace('http://bsfs.ai/schema/Preview') -xsd = _bsfs.Namespace('http://www.w3.org/2001/XMLSchema') +# generic namespaces +xsd = _bsfs.Namespace('http://www.w3.org/2001/XMLSchema')() + +# core bsfs/bsie namespaces +bsfs = _bsfs.Namespace('https://schema.bsfs.io/core') +bsie = _bsfs.Namespace('https://schema.bsfs.io/ie') + +# auxiliary namespaces +bsd = bsie.distance() +bse = bsie.Node.Entity() +bsf = bsie.Literal.Array.Feature +bsl = bsfs.Literal +bsn = bsie.Node +bsp = bsie.Node.Preview() # export __all__: typing.Sequence[str] = ( + 'bsd', 'bse', + 'bsf', 'bsfs', - 'bsm', + 'bsie', + 'bsl', + 'bsl', + 'bsn', 'bsp', 'xsd', ) -- cgit v1.2.3 From 8b460aa0232cd841af7b7734c91982bc83486e03 Mon Sep 17 00:00:00 2001 From: Matthias Baumgartner Date: Sun, 5 Mar 2023 19:14:11 +0100 Subject: build fixes --- bsie/utils/loading.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'bsie') diff --git a/bsie/utils/loading.py b/bsie/utils/loading.py index 3c5c7c1..58202d1 100644 --- a/bsie/utils/loading.py +++ b/bsie/utils/loading.py @@ -22,14 +22,14 @@ def safe_load(module_name: str, class_name: str): module = importlib.import_module(module_name) except Exception as err: # cannot import module - raise errors.LoaderError(f'cannot load module {module_name}') from err + raise errors.LoaderError(f'cannot load module {module_name} ({err})') from err try: # get the class from the module cls = getattr(module, class_name) except Exception as err: # cannot find the class - raise errors.LoaderError(f'cannot load class {class_name} from module {module_name}') from err + raise errors.LoaderError(f'cannot load class {class_name} from module {module_name} ({err})') from err return cls -- cgit v1.2.3