aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias Baumgartner <dev@igsor.net>2023-03-05 19:22:46 +0100
committerMatthias Baumgartner <dev@igsor.net>2023-03-05 19:22:46 +0100
commitaf81318ae9311fd0b0e16949cef3cfaf7996970b (patch)
treefb220da28bb7248ebf37ce09af5de88f2c1aaad4
parent7bf6b33fa6d6b901e4933bfe0b2a9939d7b3f3f3 (diff)
parent8b460aa0232cd841af7b7734c91982bc83486e03 (diff)
downloadbsie-af81318ae9311fd0b0e16949cef3cfaf7996970b.tar.gz
bsie-af81318ae9311fd0b0e16949cef3cfaf7996970b.tar.bz2
bsie-af81318ae9311fd0b0e16949cef3cfaf7996970b.zip
Merge branch 'mb/diogenes' into develop
-rw-r--r--.gitignore1
-rw-r--r--.pylintrc17
-rw-r--r--CHANGELOG.md20
-rw-r--r--MANIFEST.in1
-rw-r--r--README56
-rw-r--r--README.md88
-rwxr-xr-xbsie.app49
-rw-r--r--bsie.toml11
-rw-r--r--bsie/__init__.py4
-rw-r--r--bsie/apps/__init__.py44
-rw-r--r--bsie/apps/_loader.py47
-rw-r--r--bsie/apps/default_config.yaml19
-rw-r--r--bsie/apps/index.py49
-rw-r--r--bsie/apps/info.py48
-rw-r--r--bsie/extractor/__init__.py3
-rw-r--r--bsie/extractor/base.py36
-rw-r--r--bsie/extractor/builder.py5
-rw-r--r--bsie/extractor/generic/__init__.py3
-rw-r--r--bsie/extractor/generic/constant.py4
-rw-r--r--bsie/extractor/generic/path.py9
-rw-r--r--bsie/extractor/generic/stat.py8
-rw-r--r--bsie/extractor/image/__init__.py5
-rw-r--r--bsie/extractor/image/colors_spatial.py16
-rw-r--r--bsie/extractor/image/photometrics.py211
-rw-r--r--bsie/extractor/preview.py27
-rw-r--r--bsie/lib/__init__.py5
-rw-r--r--bsie/lib/bsie.py5
-rw-r--r--bsie/lib/builder.py5
-rw-r--r--bsie/lib/naming_policy.py13
-rw-r--r--bsie/lib/pipeline.py7
-rw-r--r--bsie/reader/__init__.py8
-rw-r--r--bsie/reader/base.py9
-rw-r--r--bsie/reader/builder.py5
-rw-r--r--bsie/reader/chain.py5
-rw-r--r--bsie/reader/exif.py44
-rw-r--r--bsie/reader/image/__init__.py5
-rw-r--r--bsie/reader/image/_pillow.py5
-rw-r--r--bsie/reader/image/_raw.py5
-rw-r--r--bsie/reader/path.py4
-rw-r--r--bsie/reader/preview/__init__.py5
-rw-r--r--bsie/reader/preview/_pg.py5
-rw-r--r--bsie/reader/preview/_pillow.py7
-rw-r--r--bsie/reader/preview/_rawpy.py5
-rw-r--r--bsie/reader/preview/utils.py5
-rw-r--r--bsie/reader/stat.py4
-rw-r--r--bsie/utils/__init__.py4
-rw-r--r--bsie/utils/bsfs.py4
-rw-r--r--bsie/utils/errors.py6
-rw-r--r--bsie/utils/filematcher/__init__.py5
-rw-r--r--bsie/utils/filematcher/matcher.py5
-rw-r--r--bsie/utils/filematcher/parser.py5
-rw-r--r--bsie/utils/loading.py9
-rw-r--r--bsie/utils/namespaces.py32
-rw-r--r--bsie/utils/node.py4
-rw-r--r--doc/Makefile20
-rw-r--r--doc/make.bat35
-rw-r--r--doc/source/architecture.rst71
-rw-r--r--doc/source/conf.py37
-rw-r--r--doc/source/index.rst26
-rw-r--r--doc/source/installation.rst75
-rw-r--r--setup.py76
-rw-r--r--test/apps/test_index.py271
-rw-r--r--test/apps/test_info.py81
-rw-r--r--test/apps/test_loader.py83
-rw-r--r--test/apps/test_main.py57
-rw-r--r--test/extractor/generic/test_constant.py21
-rw-r--r--test/extractor/generic/test_path.py13
-rw-r--r--test/extractor/generic/test_stat.py13
-rw-r--r--test/extractor/image/test_colors_spatial.py17
-rw-r--r--test/extractor/image/test_photometrics.py143
-rw-r--r--test/extractor/test_base.py13
-rw-r--r--test/extractor/test_builder.py21
-rw-r--r--test/extractor/test_preview.py29
-rw-r--r--test/lib/test_bsie.py45
-rw-r--r--test/lib/test_builder.py9
-rw-r--r--test/lib/test_naming_policy.py45
-rw-r--r--test/lib/test_pipeline.py17
-rw-r--r--test/reader/image/load_nef.py5
-rw-r--r--test/reader/image/test_image.py5
-rw-r--r--test/reader/image/test_pillow.py5
-rw-r--r--test/reader/image/test_raw_image.py9
-rw-r--r--test/reader/preview/load_nef.py5
-rw-r--r--test/reader/preview/test_pg.py6
-rw-r--r--test/reader/preview/test_pillow.py11
-rw-r--r--test/reader/preview/test_preview.py5
-rw-r--r--test/reader/preview/test_rawpy.py5
-rw-r--r--test/reader/preview/test_utils.py5
-rw-r--r--test/reader/test_base.py5
-rw-r--r--test/reader/test_builder.py5
-rw-r--r--test/reader/test_chain.py5
-rw-r--r--test/reader/test_exif.py52
-rw-r--r--test/reader/test_path.py5
-rw-r--r--test/reader/test_stat.py5
-rw-r--r--test/reader/testimage_exif.jpgbin0 -> 719 bytes
-rw-r--r--test/reader/testimage_exif_corrupted.jpgbin0 -> 551 bytes
-rw-r--r--test/utils/filematcher/test_matcher.py5
-rw-r--r--test/utils/filematcher/test_parser.py5
-rw-r--r--test/utils/test_loading.py5
-rw-r--r--test/utils/test_node.py23
99 files changed, 1540 insertions, 865 deletions
diff --git a/.gitignore b/.gitignore
index c046d71..d2785ad 100644
--- a/.gitignore
+++ b/.gitignore
@@ -21,6 +21,7 @@ build/
# doc builds
doc/build/
+doc/source/api
# testing data
test/reader/image/testimage.nef*
diff --git a/.pylintrc b/.pylintrc
index 1b34854..576e81a 100644
--- a/.pylintrc
+++ b/.pylintrc
@@ -145,6 +145,21 @@ logging-format-style=old
+[MESSAGES CONTROL]
+
+# disable similarities check
+disable=raw-checker-failed,
+ bad-inline-option,
+ locally-disabled,
+ file-ignored,
+ suppressed-message,
+ useless-suppression,
+ deprecated-pragma,
+ use-symbolic-message-instead,
+ duplicate-code
+
+
+
[MISCELLANEOUS]
# List of note tags to take in consideration, separated by a comma.
@@ -188,6 +203,4 @@ ignore-none=no
callbacks=clbk,callback
-
-
# Disable: R1735 (use-dict-literal)
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..1240091
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,20 @@
+
+# Changelog
+
+## 0.23.03 (Initial release)
+
+### Added
+
+- Information extraction pipeline essentials
+- Filematcher to check the file type and format
+- Index app to run the IE pipeline
+- Initial documentation
+- Basic extractors
+ - Constant
+ - Filename
+ - Filesize
+ - Previews
+- Image extractors
+ - Exif
+ - Regionally dominant colors
+
diff --git a/MANIFEST.in b/MANIFEST.in
new file mode 100644
index 0000000..c4b7734
--- /dev/null
+++ b/MANIFEST.in
@@ -0,0 +1 @@
+include bsie/apps/default_config.yaml
diff --git a/README b/README
deleted file mode 100644
index 3326196..0000000
--- a/README
+++ /dev/null
@@ -1,56 +0,0 @@
-
-Black Star Information Extraction
-=================================
-
-
-### Developer tools setup
-
-#### Test coverage (coverage)
-
-Resources:
-* https://coverage.readthedocs.io/en/6.5.0/index.html
-* https://nedbatchelder.com/blog/200710/flaws_in_coverage_measurement.html
-
-Commands:
-$ pip install coverage
-$ coverage run ; coverage html ; xdg-open .htmlcov/index.html
-
-
-
-#### Static code analysis (pylint)
-
-Resources:
-* https://github.com/PyCQA/pylint
-* https://pylint.org/
-* https://pylint.pycqa.org/en/latest/user_guide/messages/messages_overview.html#messages-overview
-
-Commands:
-$ pip install pylint
-$ pylint bsie
-
-
-
-#### Type analysis (mypy)
-
-Resources:
-* https://github.com/python/mypy
-* https://mypy.readthedocs.io/en/stable/
-
-Commands:
-$ pip install mypy
-$ mypy
-
-
-
-#### Documentation (sphinx)
-
-Resources:
-*
-*
-
-Commands:
-$ pip install ...
-$
-
-
-
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..eee19f7
--- /dev/null
+++ b/README.md
@@ -0,0 +1,88 @@
+
+# Black Star Information Extraction
+
+The Black Star Information Extraction (BSIE) package provides a pipeline
+to extract metadata and content-derived features from files and stores
+that information in a BSFS storage.
+
+## Installation
+
+You can install BSIE via pip. BSIE comes with support for various file formats.
+For this, it needs to install many external packages. BSIE lets you control
+which of these you want to install. Note that if you choose to not install
+support for some file types, BSIE will show a warning and skip them.
+All other formats will be processed normally.
+
+To install only the minimally required software, use:
+
+ $ pip install --extra-index-url https://pip.bsfs.io bsie
+
+To install all dependencies, use the following shortcut:
+
+ $ pip install --extra-index-url https://pip.bsfs.io bsie[all]
+
+To install a subset of all dependencies, modify the extras part (``[image, preview]``)
+of the follwing command to your liking:
+
+ $ pip install --extra-index-url https://pip.bsfs.io bsie[image,preview]
+
+Currently, BSIE providesthe following extra flags:
+
+* image: Read data from image files.
+ Note that you may also have to install ``exiftool`` through your system's
+ package manager (e.g. ``sudo apt install exiftool``).
+* preview: Create previews from a variety of files.
+ Note that support for various file formats also depends on what
+ system packages you've installed. You should at least install ``imagemagick``
+ through your system's package manager (e.g. ``sudo apt install imagemagick``).
+ See [Preview Generator](https://github.com/algoo/preview-generator) for
+ more detailed instructions.
+* features: Extract feature vectors from images.
+
+
+## Development
+
+Set up a virtual environment:
+
+ $ virtualenv env
+ $ source env/bin/activate
+
+Install bsie as editable from the git repository:
+
+ $ git clone https://git.bsfs.io/bsie.git
+ $ cd bsie
+ $ pip install -e .[all]
+
+If you want to develop (*dev*), run the tests (*test*), edit the
+documentation (*doc*), or build a distributable (*build*),
+install bsfs with the respective extras (in addition to file format extras):
+
+ $ pip install -e .[dev,doc,build,test]
+
+Or, you can manually install the following packages besides BSIE:
+
+ $ pip install coverage mypy pylint
+ $ pip install rdflib requests types-PyYAML
+ $ pip install sphinx sphinx-copybutton furo
+ $ pip install build
+
+To ensure code style discipline, run the following commands:
+
+ $ coverage run ; coverage html ; xdg-open .htmlcov/index.html
+ $ pylint bsie
+ $ mypy
+
+To build the package, do:
+
+ $ python -m build
+
+To run only the tests (without coverage), run the following command from the **test folder**:
+
+ $ python -m unittest
+
+To build the documentation, run the following commands from the **doc folder**:
+
+ $ sphinx-apidoc -f -o source/api ../bsie/ --module-first -d 1 --separate
+ $ make html
+ $ xdg-open build/html/index.html
+
diff --git a/bsie.app b/bsie.app
index d5808e7..0f6f7bc 100755
--- a/bsie.app
+++ b/bsie.app
@@ -1,49 +1,6 @@
-"""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
-import bsie.apps
-
-# exports
-__all__: typing.Sequence[str] = (
- 'main',
- )
-
-# config
-apps = {
- 'index' : bsie.apps.index,
- 'info' : bsie.apps.info,
- }
-
-
-## code ##
-
-def main(argv):
- """Black Star File System maintenance tools."""
- parser = argparse.ArgumentParser(description=main.__doc__, prog='bsie')
- parser.add_argument('--version', action='version',
- version='%(prog)s version {}.{}.{}'.format(*bsie.version_info))
- parser.add_argument('app', choices=apps.keys(),
- help='Select the application to run.')
- parser.add_argument('rest', nargs=argparse.REMAINDER)
- # parse
- args = parser.parse_args()
- # run application
- apps[args.app](args.rest)
-
-
-## main ##
-
+#!/usr/bin/env python3
if __name__ == '__main__':
+ import bsie.apps
import sys
- main(sys.argv[1:])
+ bsie.apps.main(sys.argv[1:])
-## EOF ##
diff --git a/bsie.toml b/bsie.toml
deleted file mode 100644
index 10b0f37..0000000
--- a/bsie.toml
+++ /dev/null
@@ -1,11 +0,0 @@
-[project]
-name = "bsie"
-description = "Extract information from files and store them in a BSFS."
-version = "0.0.1"
-license = {text = "BSD 3-Clause License"}
-authors = [{name='Matthias Baumgartner', email="dev@igsor.net"}]
-dependencies = [
- "rdflib",
- "bsfs",
-]
-requires-python = ">=3.7"
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 1c3d0f9..2fe4795 100644
--- a/bsie/apps/__init__.py
+++ b/bsie/apps/__init__.py
@@ -1,12 +1,13 @@
-"""
-
-Part of the bsie module.
-A copy of the license is provided with the project.
-Author: Matthias Baumgartner, 2022
+#!/usr/bin/env python3
+"""BSIE tools.
"""
# 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 +16,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)) # pylint: disable=C0209
+ # 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 ##
diff --git a/bsie/apps/_loader.py b/bsie/apps/_loader.py
new file mode 100644
index 0000000..6411f10
--- /dev/null
+++ b/bsie/apps/_loader.py
@@ -0,0 +1,47 @@
+
+# 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] = (
+ 'DEFAULT_CONFIG_FILE',
+ 'load_pipeline',
+ )
+
+
+## code ##
+
+def load_pipeline(path: str) -> Pipeline:
+ """Load a pipeline according to a config at *path*."""
+ # load config file
+ with open(path, 'rt', encoding='utf-8') 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..a59b0f3
--- /dev/null
+++ b/bsie/apps/default_config.yaml
@@ -0,0 +1,19 @@
+
+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: 32
+ height: 32
+ exp: 4
+
+ - bsie.extractor.image.photometrics.Exif: {}
+
diff --git a/bsie/apps/index.py b/bsie/apps/index.py
index 8798c49..d64e8c2 100644
--- a/bsie/apps/index.py
+++ b/bsie/apps/index.py
@@ -1,20 +1,16 @@
-"""
-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
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 +22,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 +43,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 +95,6 @@ def main(argv):
return store
-
## main ##
if __name__ == '__main__':
diff --git a/bsie/apps/info.py b/bsie/apps/info.py
index 750aedc..e27b70b 100644
--- a/bsie/apps/info.py
+++ b/bsie/apps/info.py
@@ -1,20 +1,16 @@
-"""
-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
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 +22,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':
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 89183f9..f92d7cc 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
@@ -28,26 +24,32 @@ SCHEMA_PREAMBLE = '''
prefix schema: <http://schema.org/>
# common bsfs prefixes
- prefix bsfs: <http://bsfs.ai/schema/>
- prefix bse: <http://bsfs.ai/schema/Entity#>
- prefix bsp: <http://bsfs.ai/schema/Preview#>
+ prefix bsfs: <https://schema.bsfs.io/core/>
+ prefix bsl: <https://schema.bsfs.io/core/Literal/>
+ prefix bsa: <https://schema.bsfs.io/core/Literal/Array/>
+ prefix bsd: <https://schema.bsfs.io/core/distance#>
+
+ prefix bsie: <https://schema.bsfs.io/ie/>
+ prefix bsn: <https://schema.bsfs.io/ie/Node/>
+ prefix bse: <https://schema.bsfs.io/ie/Node/Entity#>
+ prefix bsp: <https://schema.bsfs.io/ie/Node/Preview#>
# 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 <https://schema.bsfs.io/core/dtype#f16> ;
+ 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:integer rdfs:subClassOf bsl:Number .
+ xsd:float rdfs:subClassOf bsl:Number .
'''
@@ -93,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/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 c984515..00c1121 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
@@ -31,11 +26,11 @@ 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 ;
- 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..92b51f3 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
@@ -33,11 +29,11 @@ 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 ;
- bsfs:unique "false"^^xsd:boolean .
+ bsfs:unique "true"^^xsd:boolean .
'''))
self._callmap = {
self.schema.predicate(ns.bse.filesize): self.__filesize,
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..e6661a9 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
@@ -18,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] = (
@@ -62,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 <https://schema.bsfs.io/core/distance#euclidean> ;
bsfs:dtype xsd:integer .
<{instance_name}> rdfs:subClassOf <{FEATURE_NAME}> ;
@@ -82,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
new file mode 100644
index 0000000..42eb3c8
--- /dev/null
+++ b/bsie/extractor/image/photometrics.py
@@ -0,0 +1,211 @@
+
+# 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 # pylint: disable=redefined-builtin # min
+ # 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
+ # 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 bsn:Entity ;
+ # rdfs:range xsd:float ;
+ # bsfs:unique "true"^^xsd:boolean .
+ bse:exposure rdfs:subClassOf bsfs:Predicate ;
+ rdfs:domain bsn:Entity ;
+ rdfs:range xsd:float ;
+ bsfs:unique "true"^^xsd:boolean .
+ bse:aperture rdfs:subClassOf bsfs:Predicate ;
+ rdfs:domain bsn:Entity ;
+ rdfs:range xsd:float ;
+ bsfs:unique "true"^^xsd:boolean .
+ bse:iso rdfs:subClassOf bsfs:Predicate ;
+ rdfs:domain bsn:Entity ;
+ rdfs:range xsd:integer ;
+ bsfs:unique "true"^^xsd:boolean .
+ bse:focal_length rdfs:subClassOf bsfs:Predicate ;
+ rdfs:domain bsn:Entity ;
+ rdfs:range xsd:float ;
+ bsfs:unique "true"^^xsd:boolean .
+ bse:width rdfs:subClassOf bsfs:Predicate ;
+ rdfs:domain bsn:Entity ;
+ rdfs:range xsd:integer ;
+ bsfs:unique "true"^^xsd:boolean .
+ bse:height rdfs:subClassOf bsfs:Predicate ;
+ rdfs:domain bsn:Entity ;
+ rdfs:range xsd:integer ;
+ bsfs:unique "true"^^xsd:boolean .
+ bse:orientation rdfs:subClassOf bsfs:Predicate ;
+ rdfs:domain bsn:Entity ;
+ rdfs:range xsd:integer ;
+ bsfs:unique "true"^^xsd:boolean .
+ bse:orientation_label rdfs:subClassOf bsfs:Predicate ;
+ rdfs:domain bsn:Entity ;
+ rdfs:range xsd:string ;
+ bsfs:unique "true"^^xsd:boolean .
+ bse:altitude rdfs:subClassOf bsfs:Predicate ;
+ rdfs:domain bsn:Entity ;
+ rdfs:range xsd:float ;
+ bsfs:unique "true"^^xsd:boolean .
+ bse:latitude rdfs:subClassOf bsfs:Predicate ;
+ rdfs:domain bsn:Entity ;
+ rdfs:range xsd:float ;
+ bsfs:unique "true"^^xsd:boolean .
+ bse:longitude rdfs:subClassOf bsfs:Predicate ;
+ rdfs:domain bsn:Entity ;
+ 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
+ # 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'
+ 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/extractor/preview.py b/bsie/extractor/preview.py
index 1531d62..145a01a 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
@@ -33,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 .
+ <https://schema.bsfs.io/ie/Literal/BinaryBlob/JPEG> 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 <https://schema.bsfs.io/ie/Literal/BinaryBlob/JPEG> ;
bsfs:unique "true"^^xsd:boolean .
'''))
@@ -85,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/__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..9b9a45d 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
@@ -85,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}')
@@ -97,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:
@@ -114,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 0bc5109..30fd6fd 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
@@ -109,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/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
new file mode 100644
index 0000000..2d0428b
--- /dev/null
+++ b/bsie/reader/exif.py
@@ -0,0 +1,44 @@
+
+# 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, OSError, RuntimeError) as err:
+ raise errors.ReaderError(path) from err
+
+## EOF ##
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..2b797c6 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
@@ -38,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/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..7c7e6ed 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
@@ -42,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 ##
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..58202d1 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
@@ -27,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
diff --git a/bsie/utils/namespaces.py b/bsie/utils/namespaces.py
index 0af8ece..4a66048 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
@@ -10,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',
)
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
diff --git a/doc/Makefile b/doc/Makefile
new file mode 100644
index 0000000..d0c3cbf
--- /dev/null
+++ b/doc/Makefile
@@ -0,0 +1,20 @@
+# Minimal makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line, and also
+# from the environment for the first two.
+SPHINXOPTS ?=
+SPHINXBUILD ?= sphinx-build
+SOURCEDIR = source
+BUILDDIR = build
+
+# Put it first so that "make" without argument is like "make help".
+help:
+ @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
+
+.PHONY: help Makefile
+
+# Catch-all target: route all unknown targets to Sphinx using the new
+# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
+%: Makefile
+ @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
diff --git a/doc/make.bat b/doc/make.bat
new file mode 100644
index 0000000..747ffb7
--- /dev/null
+++ b/doc/make.bat
@@ -0,0 +1,35 @@
+@ECHO OFF
+
+pushd %~dp0
+
+REM Command file for Sphinx documentation
+
+if "%SPHINXBUILD%" == "" (
+ set SPHINXBUILD=sphinx-build
+)
+set SOURCEDIR=source
+set BUILDDIR=build
+
+%SPHINXBUILD% >NUL 2>NUL
+if errorlevel 9009 (
+ echo.
+ echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
+ echo.installed, then set the SPHINXBUILD environment variable to point
+ echo.to the full path of the 'sphinx-build' executable. Alternatively you
+ echo.may add the Sphinx directory to PATH.
+ echo.
+ echo.If you don't have Sphinx installed, grab it from
+ echo.https://www.sphinx-doc.org/
+ exit /b 1
+)
+
+if "%1" == "" goto help
+
+%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
+goto end
+
+:help
+%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
+
+:end
+popd
diff --git a/doc/source/architecture.rst b/doc/source/architecture.rst
new file mode 100644
index 0000000..750319e
--- /dev/null
+++ b/doc/source/architecture.rst
@@ -0,0 +1,71 @@
+
+Architecture
+============
+
+
+The information extraction pipeline traverses through three stages of abstraction:
+
+1. File format
+2. Content
+3. Predicate-value pairs
+
+For example, an image can be stored in various file formats (JPEG, TIFF, PNG).
+In turn, a file format can store different kinds of information such as the image data (pixels) and additional metadata (image dimensions, EXIF tags).
+Finally, we translate the information read from the file into predicate-value pairs that can be attached to a file node in BSFS, e.g., ``(bse:filesize, 8150000)``, ``(bse:width, 6000)``, ``(bse:height, 4000)``, ``(bse:iso, 100)``, etc.
+
+The extraction pipeline is thus divided into
+:mod:`Readers <bsie.reader>` that abstract from file formats and content types,
+and :mod:`Extractors <bsie.extractor>` which produce predicate-value pairs from content artifacts.
+
+
+Readers
+-------
+
+:mod:`Readers <bsie.reader>` read the actual file (considering different file formats)
+and isolate specific content artifacts therein.
+The content artifact (in an internal representation)
+is then passed to an Extractor for further processing.
+
+For example, the :class:`Image <bsie.reader.image.Image>` reader aims at reading the content (pixels) of an image file.
+It automatically detects which python package (e.g., `rawpy`_, `pillow`_)
+to use when faced with the various existing image file formats.
+The image data is then converted into a PIL.Image instance
+(irrespective of which package was used to read the data),
+and passed on to the extractor.
+
+
+Extractors
+----------
+
+:mod:`Extractors <bsie.extractor>` turn content artifacts into
+predicate-value pairs that can be inserted into a BSFS storage.
+The predicate is defined by each extractor, as prescribed by BSFS' schema handling.
+
+For example, the class :class:`ColorsSpatial <bsie.extractor.image.colors_spatial.ColorsSpatial`
+determines regionally dominant colors from given pixel data.
+It then produces a feature vector and attaches it to the image file via the appropriate predicate.
+
+
+BSIE lib and apps
+-----------------
+
+The advantage of separating the reading and extraction steps is that multiple extractors
+can consume the same content, avoiding multiple re-reads of the same data.
+This close interaction between readers and extractors is encapsulated
+within the :class:`Pipeline <bsie.lib.pipeline.Pipeline>` class.
+
+Also, that having to deal with various file formats and content artifacts
+potentially pulls in a large number of dependencies.
+To make matters worse, many of those might not be needed in a specific scenario,
+e.g., if a user only works with a limited set of file formats.
+BSIE therefore implements a best-effort approach,
+that is modules that cannot be imported due to missing dependencies are ignored.
+
+With these two concerns taken care of,
+BSIE offers a few :mod:`end-user applications <bsie.apps>`
+that reduce the complexity of the task to a relatively simple command.
+
+
+
+.. _pillow: https://python-pillow.org/
+.. _rawpy: https://github.com/letmaik/rawpy
diff --git a/doc/source/conf.py b/doc/source/conf.py
new file mode 100644
index 0000000..017e036
--- /dev/null
+++ b/doc/source/conf.py
@@ -0,0 +1,37 @@
+# Configuration file for the Sphinx documentation builder.
+#
+# For the full list of built-in configuration values, see the documentation:
+# https://www.sphinx-doc.org/en/master/usage/configuration.html
+
+# -- Project information -----------------------------------------------------
+# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
+
+project = 'Black Star Information Extraction'
+copyright = '2023, Matthias Baumgartner'
+author = 'Matthias Baumgartner'
+release = '0.5'
+
+# -- General configuration ---------------------------------------------------
+# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
+
+extensions = [
+ 'sphinx_copybutton',
+ 'sphinx.ext.autodoc',
+ ]
+
+templates_path = ['_templates']
+exclude_patterns = []
+
+
+
+# -- Options for HTML output -------------------------------------------------
+# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
+
+html_theme = 'furo'
+html_static_path = ['_static']
+
+html_title = 'bsie'
+html_theme_options = {
+ 'announcement': '<em>This project is under heavy development and subject to rapid changes. Use at your own discretion.</em>',
+ }
+
diff --git a/doc/source/index.rst b/doc/source/index.rst
new file mode 100644
index 0000000..9cf06fe
--- /dev/null
+++ b/doc/source/index.rst
@@ -0,0 +1,26 @@
+
+Black Star Information Extraction
+=================================
+
+A major advantage of the `Black Star File System (BSFS) <https://www.bsfs.io/bsfs/>`_
+is its ability to store various kinds of (meta)data associated with a file.
+However, the BSFS itself is only a storage solution,
+it does not inspect files or collect information about them.
+
+The Black Star Information Extraction (BSIE) package fills this gap by
+extracting various kinds of information from a file and pushing that data to a BSFS instance.
+
+BSIE has the ability to process numerous file formats,
+and it can turn various aspects of a file into usable information.
+This includes metadata from a source file system,
+metadata stored within the file,
+and even excerpts or feature representations of the file's content itself.
+
+.. toctree::
+ :maxdepth: 1
+
+ installation
+ architecture
+ api/modules
+
+
diff --git a/doc/source/installation.rst b/doc/source/installation.rst
new file mode 100644
index 0000000..ee6fadb
--- /dev/null
+++ b/doc/source/installation.rst
@@ -0,0 +1,75 @@
+
+Installation
+============
+
+You can install *bsie* via pip. BSIE comes with support for various file formats.
+For this, it needs to install many external packages. BSIE lets you control
+which of these you want to install. Note that if you choose to not install
+support for some file types, BSIE will show a warning and skip them.
+All other formats will be processed normally.
+It is recommended to install *bsie* in a virtual environment (via ``virtualenv``).
+
+To install only the minimally required software, use::
+
+ pip install --extra-index-url https://pip.bsfs.io bsie
+
+To install all dependencies, use the following shortcut::
+
+ pip install --extra-index-url https://pip.bsfs.io bsie[all]
+
+To install a subset of all dependencies, modify the extras part (``[image, preview]``)
+of the follwing command to your liking::
+
+ pip install --extra-index-url https://pip.bsfs.io bsie[image,preview]
+
+Currently, BSIE providesthe following extra flags:
+
+* image: Read data from image files.
+ Note that you may also have to install ``exiftool`` through your system's
+ package manager (e.g. ``sudo apt install exiftool``).
+* preview: Create previews from a variety of files.
+ Note that support for various file formats also depends on what
+ system packages you've installed. You should at least install ``imagemagick``
+ through your system's package manager (e.g. ``sudo apt install imagemagick``).
+ See `Preview Generator <https://github.com/algoo/preview-generator>`_ for
+ more detailed instructions.
+* features: Extract feature vectors from images.
+
+
+
+License
+-------
+
+This project is released under the terms of the 3-clause BSD License.
+By downloading or using the application you agree to the license's terms and conditions.
+
+.. literalinclude:: ../../LICENSE
+
+
+Source
+------
+
+Check out our git repository::
+
+ git clone https://git.bsfs.io/bsie.git
+
+You can further install *bsie* via the ususal `setuptools <https://setuptools.pypa.io/en/latest/index.html>`_ commands from your bsie source directory::
+
+ python setup.py develop
+
+For development, you also need to install some additional dependencies::
+
+ # extra packages for tests
+ pip install rdflib requests
+
+ # code style discipline
+ pip install mypy coverage pylint
+ # external type annotations for pyyaml
+ pip install types-PyYAML
+
+ # documentation
+ pip install sphinx sphinx-copybutton furo
+
+ # packaging
+ pip install build
+
diff --git a/setup.py b/setup.py
index d45f178..b1f5b2c 100644
--- a/setup.py
+++ b/setup.py
@@ -1,33 +1,73 @@
-from setuptools import setup
+from setuptools import setup, find_packages
import os
+extras = {
+ # NOTE: an 'all' extra is added automatically
+ 'features': [
+ # image feature extractors
+ 'numpy',
+ ],
+ 'preview': [
+ # preview readers
+ 'preview_generator', # also depends on some system packages
+ 'pillow',
+ 'rawpy',
+ ],
+ 'image': [
+ # image readers
+ 'pillow',
+ 'rawpy',
+ # exif reader
+ 'pyexiv2',
+ ],
+ }
+
+
setup(
+ # package metadata
name='bsie',
- version='0.0.1',
+ version='0.23.03',
author='Matthias Baumgartner',
- author_email='dev@igsor.net',
+ author_email='dev@bsfs.io',
description='Extract information from files and store them in a BSFS.',
- long_description=open(os.path.join(os.path.dirname(__file__), 'README')).read(),
+ long_description=open(os.path.join(os.path.dirname(__file__), 'README.md')).read(),
license='BSD',
license_files=('LICENSE', ),
- url='https://www.igsor.net/projects/blackstar/bsie/',
- download_url='https://pip.igsor.net',
- packages=('bsie', ),
+ url='https://www.bsfs.io/bsie/',
+ download_url='https://pip.bsfs.io',
+
+ # packages
+ packages=find_packages(include=['bsie']),
+ package_dir={'bsie': 'bsie'},
+ # data files are included if mentioned in MANIFEST.in
+ include_package_data=True,
+
+ # entrypoints
+ entry_points={
+ 'console_scripts': [
+ 'bsie = bsie.apps:main',
+ ],
+ },
+
+ # dependencies
+ python_requires=">=3.7",
install_requires=(
'bsfs',
'pyparsing',
'python-magic',
- 'rdflib', # only for tests
- 'requests', # only for tests
- 'preview_generator', # also depends on some system packages
+ 'pyyaml',
),
- python_requires=">=3.7",
- extra_require=(
- # image reader
- 'pillow', 'rawpy',
- # image extractors
- 'numpy',
- )
-)
+ extras_require=dict(
+ # development targets
+ build=['build'],
+ dev=['coverage', 'mypy', 'pylint'],
+ doc=['sphinx', 'sphinx-copybutton', 'furo'],
+ test=['rdflib', 'requests', 'types-PyYAML'],
+ # add 'all'
+ all=list({pkg for ext in extras.values() for pkg in ext}),
+ # add extras
+ **extras
+ ),
+ )
diff --git a/test/apps/test_index.py b/test/apps/test_index.py
index d1e7140..6927044 100644
--- a/test/apps/test_index.py
+++ b/test/apps/test_index.py
@@ -1,17 +1,14 @@
-"""
-Part of the bsie test suite.
-A copy of the license is provided with the project.
-Author: Matthias Baumgartner, 2022
-"""
# standard imports
import contextlib
import io
import os
+import tempfile
import unittest
# external imports
import rdflib
+import yaml
# bsie imports
from bsie.utils import ns
@@ -23,17 +20,52 @@ from bsie.apps.index import main
## code ##
class TestIndex(unittest.TestCase):
+ def setUp(self):
+ config = {
+ 'ReaderBuilder': {},
+ 'ExtractorBuilder': [
+ {'bsie.extractor.preview.Preview': {
+ 'max_sides': [50],
+ }},
+ {'bsie.extractor.generic.path.Path': {}},
+ {'bsie.extractor.generic.constant.Constant': {
+ 'schema': '''
+ bse:author rdfs:subClassOf bsfs:Predicate ;
+ rdfs:domain bsn:Entity ;
+ rdfs:range xsd:string ;
+ bsfs:unique "true"^^xsd:boolean .
+ ''',
+ 'tuples': [['https://schema.bsfs.io/ie/Node/Entity#author', 'Me, myself, and I']],
+ }},
+ {'bsie.extractor.image.colors_spatial.ColorsSpatial': {
+ 'width': 2,
+ 'height': 2,
+ 'exp': 2,
+ }},
+ ]
+ }
+ # create config file
+ _, self.config_path = tempfile.mkstemp(prefix='bsie-test-', suffix='.yaml')
+ with open(self.config_path, 'wt') as cfile:
+ yaml.dump(config, cfile)
+
+ def tearDown(self):
+ if os.path.exists(self.config_path):
+ os.unlink(self.config_path)
+
def test_disclaimer(self):
print('Please wait, this test will take about 25 seconds')
def test_main_invalid(self):
outbuf = io.StringIO()
with contextlib.redirect_stdout(outbuf):
- bsfs = main([os.path.join(os.path.dirname(__file__), 'inexistent-file.t')])
+ bsfs = main(['--config', self.config_path, os.path.join(os.path.dirname(__file__), 'inexistent-file.t')])
self.assertEqual(outbuf.getvalue().strip(), '')
def test_main(self):
bsfs = main([
+ '--config',
+ self.config_path,
'-r',
'--host', 'http://example.com',
'--user', 'me',
@@ -45,60 +77,47 @@ class TestIndex(unittest.TestCase):
pre_preview = 'http://example.com/me/preview#'
self.assertTrue(set(bsfs._backend._graph).issuperset({
# files and properties
- (rdflib.URIRef(pre_file + '2f4109b40107cc50e0884755a1a961ed126887e49b8dbaf0e146b2e226aa6647'), rdflib.RDF.type, rdflib.URIRef(ns.bsfs.File)),
+ (rdflib.URIRef(pre_file + '2f4109b40107cc50e0884755a1a961ed126887e49b8dbaf0e146b2e226aa6647'), rdflib.RDF.type, rdflib.URIRef(ns.bsn.Entity)),
(rdflib.URIRef(pre_file + '2f4109b40107cc50e0884755a1a961ed126887e49b8dbaf0e146b2e226aa6647'), rdflib.URIRef(ns.bse.author), rdflib.Literal('Me, myself, and I', datatype=rdflib.XSD.string)),
(rdflib.URIRef(pre_file + '2f4109b40107cc50e0884755a1a961ed126887e49b8dbaf0e146b2e226aa6647'), rdflib.URIRef(ns.bse.filename), rdflib.Literal('alpha_second', datatype=rdflib.XSD.string)),
- (rdflib.URIRef(pre_file + '2f4109b40107cc50e0884755a1a961ed126887e49b8dbaf0e146b2e226aa6647'), rdflib.URIRef(ns.bse.filesize), rdflib.Literal('696', datatype=rdflib.XSD.integer)),
- (rdflib.URIRef(pre_file + '441f3d10c8ff489fe8e33e639606512f6c463151cc429de7e554b9af670c2ece'), rdflib.RDF.type, rdflib.URIRef(ns.bsfs.File)),
+ (rdflib.URIRef(pre_file + '441f3d10c8ff489fe8e33e639606512f6c463151cc429de7e554b9af670c2ece'), rdflib.RDF.type, rdflib.URIRef(ns.bsn.Entity)),
(rdflib.URIRef(pre_file + '441f3d10c8ff489fe8e33e639606512f6c463151cc429de7e554b9af670c2ece'), rdflib.URIRef(ns.bse.author), rdflib.Literal('Me, myself, and I', datatype=rdflib.XSD.string)),
(rdflib.URIRef(pre_file + '441f3d10c8ff489fe8e33e639606512f6c463151cc429de7e554b9af670c2ece'), rdflib.URIRef(ns.bse.filename), rdflib.Literal('omega_second', datatype=rdflib.XSD.string)),
- (rdflib.URIRef(pre_file + '441f3d10c8ff489fe8e33e639606512f6c463151cc429de7e554b9af670c2ece'), rdflib.URIRef(ns.bse.filesize), rdflib.Literal('503', datatype=rdflib.XSD.integer)),
- (rdflib.URIRef(pre_file + '69b98ecf7aff3e95b09688ba93331678eb8397817111f674c9558e6dd8f5e871'), rdflib.RDF.type, rdflib.URIRef(ns.bsfs.File)),
+ (rdflib.URIRef(pre_file + '69b98ecf7aff3e95b09688ba93331678eb8397817111f674c9558e6dd8f5e871'), rdflib.RDF.type, rdflib.URIRef(ns.bsn.Entity)),
(rdflib.URIRef(pre_file + '69b98ecf7aff3e95b09688ba93331678eb8397817111f674c9558e6dd8f5e871'), rdflib.URIRef(ns.bse.author), rdflib.Literal('Me, myself, and I', datatype=rdflib.XSD.string)),
(rdflib.URIRef(pre_file + '69b98ecf7aff3e95b09688ba93331678eb8397817111f674c9558e6dd8f5e871'), rdflib.URIRef(ns.bse.filename), rdflib.Literal('td_first', datatype=rdflib.XSD.string)),
- (rdflib.URIRef(pre_file + '69b98ecf7aff3e95b09688ba93331678eb8397817111f674c9558e6dd8f5e871'), rdflib.URIRef(ns.bse.filesize), rdflib.Literal('911', datatype=rdflib.XSD.integer)),
- (rdflib.URIRef(pre_file + '78f7eb7f0d8221cdb2cb26c978fa42a11f75eb87becc768f4474134cb1e06926'), rdflib.RDF.type, rdflib.URIRef(ns.bsfs.File)),
+ (rdflib.URIRef(pre_file + '78f7eb7f0d8221cdb2cb26c978fa42a11f75eb87becc768f4474134cb1e06926'), rdflib.RDF.type, rdflib.URIRef(ns.bsn.Entity)),
(rdflib.URIRef(pre_file + '78f7eb7f0d8221cdb2cb26c978fa42a11f75eb87becc768f4474134cb1e06926'), rdflib.URIRef(ns.bse.author), rdflib.Literal('Me, myself, and I', datatype=rdflib.XSD.string)),
(rdflib.URIRef(pre_file + '78f7eb7f0d8221cdb2cb26c978fa42a11f75eb87becc768f4474134cb1e06926'), rdflib.URIRef(ns.bse.filename), rdflib.Literal('testfile', datatype=rdflib.XSD.string)),
- (rdflib.URIRef(pre_file + '78f7eb7f0d8221cdb2cb26c978fa42a11f75eb87becc768f4474134cb1e06926'), rdflib.URIRef(ns.bse.filesize), rdflib.Literal('885', datatype=rdflib.XSD.integer)),
- (rdflib.URIRef(pre_file + '80818b8ec2ee1919116dba9c8a7e0a4608313cf3b463cd88e9ed77a700dd92d3'), rdflib.RDF.type, rdflib.URIRef(ns.bsfs.File)),
+ (rdflib.URIRef(pre_file + '80818b8ec2ee1919116dba9c8a7e0a4608313cf3b463cd88e9ed77a700dd92d3'), rdflib.RDF.type, rdflib.URIRef(ns.bsn.Entity)),
(rdflib.URIRef(pre_file + '80818b8ec2ee1919116dba9c8a7e0a4608313cf3b463cd88e9ed77a700dd92d3'), rdflib.URIRef(ns.bse.author), rdflib.Literal('Me, myself, and I', datatype=rdflib.XSD.string)),
(rdflib.URIRef(pre_file + '80818b8ec2ee1919116dba9c8a7e0a4608313cf3b463cd88e9ed77a700dd92d3'), rdflib.URIRef(ns.bse.filename), rdflib.Literal('bar_first', datatype=rdflib.XSD.string)),
- (rdflib.URIRef(pre_file + '80818b8ec2ee1919116dba9c8a7e0a4608313cf3b463cd88e9ed77a700dd92d3'), rdflib.URIRef(ns.bse.filesize), rdflib.Literal('956', datatype=rdflib.XSD.integer)),
- (rdflib.URIRef(pre_file + '976d2ea0e58488678cc7e435fbfadabfb6eb6cf50ad51862f38f73729ed11795'), rdflib.RDF.type, rdflib.URIRef(ns.bsfs.File)),
+ (rdflib.URIRef(pre_file + '976d2ea0e58488678cc7e435fbfadabfb6eb6cf50ad51862f38f73729ed11795'), rdflib.RDF.type, rdflib.URIRef(ns.bsn.Entity)),
(rdflib.URIRef(pre_file + '976d2ea0e58488678cc7e435fbfadabfb6eb6cf50ad51862f38f73729ed11795'), rdflib.URIRef(ns.bse.author), rdflib.Literal('Me, myself, and I', datatype=rdflib.XSD.string)),
(rdflib.URIRef(pre_file + '976d2ea0e58488678cc7e435fbfadabfb6eb6cf50ad51862f38f73729ed11795'), rdflib.URIRef(ns.bse.filename), rdflib.Literal('omega_first', datatype=rdflib.XSD.string)),
- (rdflib.URIRef(pre_file + '976d2ea0e58488678cc7e435fbfadabfb6eb6cf50ad51862f38f73729ed11795'), rdflib.URIRef(ns.bse.filesize), rdflib.Literal('648', datatype=rdflib.XSD.integer)),
- (rdflib.URIRef(pre_file + '997e2fbb7494a3818ec782d2bc87bf1cffafba6b9c0f658e4a6c18a723e944d3'), rdflib.RDF.type, rdflib.URIRef(ns.bsfs.File)),
+ (rdflib.URIRef(pre_file + '997e2fbb7494a3818ec782d2bc87bf1cffafba6b9c0f658e4a6c18a723e944d3'), rdflib.RDF.type, rdflib.URIRef(ns.bsn.Entity)),
(rdflib.URIRef(pre_file + '997e2fbb7494a3818ec782d2bc87bf1cffafba6b9c0f658e4a6c18a723e944d3'), rdflib.URIRef(ns.bse.author), rdflib.Literal('Me, myself, and I', datatype=rdflib.XSD.string)),
(rdflib.URIRef(pre_file + '997e2fbb7494a3818ec782d2bc87bf1cffafba6b9c0f658e4a6c18a723e944d3'), rdflib.URIRef(ns.bse.filename), rdflib.Literal('alpha_first', datatype=rdflib.XSD.string)),
- (rdflib.URIRef(pre_file + '997e2fbb7494a3818ec782d2bc87bf1cffafba6b9c0f658e4a6c18a723e944d3'), rdflib.URIRef(ns.bse.filesize), rdflib.Literal('754', datatype=rdflib.XSD.integer)),
- (rdflib.URIRef(pre_file + 'a8af899ecdab60dfaea8ec7f934053624c80a1054539e163f2c7eaa986c2777d'), rdflib.RDF.type, rdflib.URIRef(ns.bsfs.File)),
+ (rdflib.URIRef(pre_file + 'a8af899ecdab60dfaea8ec7f934053624c80a1054539e163f2c7eaa986c2777d'), rdflib.RDF.type, rdflib.URIRef(ns.bsn.Entity)),
(rdflib.URIRef(pre_file + 'a8af899ecdab60dfaea8ec7f934053624c80a1054539e163f2c7eaa986c2777d'), rdflib.URIRef(ns.bse.author), rdflib.Literal('Me, myself, and I', datatype=rdflib.XSD.string)),
(rdflib.URIRef(pre_file + 'a8af899ecdab60dfaea8ec7f934053624c80a1054539e163f2c7eaa986c2777d'), rdflib.URIRef(ns.bse.filename), rdflib.Literal('foo_second', datatype=rdflib.XSD.string)),
- (rdflib.URIRef(pre_file + 'a8af899ecdab60dfaea8ec7f934053624c80a1054539e163f2c7eaa986c2777d'), rdflib.URIRef(ns.bse.filesize), rdflib.Literal('585', datatype=rdflib.XSD.integer)),
- (rdflib.URIRef(pre_file + 'b8fd7fba818254166a6043195004138ebda6923e012442f819a2c49671136c70'), rdflib.RDF.type, rdflib.URIRef(ns.bsfs.File)),
+ (rdflib.URIRef(pre_file + 'b8fd7fba818254166a6043195004138ebda6923e012442f819a2c49671136c70'), rdflib.RDF.type, rdflib.URIRef(ns.bsn.Entity)),
(rdflib.URIRef(pre_file + 'b8fd7fba818254166a6043195004138ebda6923e012442f819a2c49671136c70'), rdflib.URIRef(ns.bse.author), rdflib.Literal('Me, myself, and I', datatype=rdflib.XSD.string)),
(rdflib.URIRef(pre_file + 'b8fd7fba818254166a6043195004138ebda6923e012442f819a2c49671136c70'), rdflib.URIRef(ns.bse.filename), rdflib.Literal('bar_second', datatype=rdflib.XSD.string)),
- (rdflib.URIRef(pre_file + 'b8fd7fba818254166a6043195004138ebda6923e012442f819a2c49671136c70'), rdflib.URIRef(ns.bse.filesize), rdflib.Literal('636', datatype=rdflib.XSD.integer)),
- (rdflib.URIRef(pre_file + 'd43758ace82154a1cc10ca0dfef63cb20dd831f9c87edd6dc06539eefe67371d'), rdflib.RDF.type, rdflib.URIRef(ns.bsfs.File)),
+ (rdflib.URIRef(pre_file + 'd43758ace82154a1cc10ca0dfef63cb20dd831f9c87edd6dc06539eefe67371d'), rdflib.RDF.type, rdflib.URIRef(ns.bsn.Entity)),
(rdflib.URIRef(pre_file + 'd43758ace82154a1cc10ca0dfef63cb20dd831f9c87edd6dc06539eefe67371d'), rdflib.URIRef(ns.bse.author), rdflib.Literal('Me, myself, and I', datatype=rdflib.XSD.string)),
(rdflib.URIRef(pre_file + 'd43758ace82154a1cc10ca0dfef63cb20dd831f9c87edd6dc06539eefe67371d'), rdflib.URIRef(ns.bse.filename), rdflib.Literal('foo_first', datatype=rdflib.XSD.string)),
- (rdflib.URIRef(pre_file + 'd43758ace82154a1cc10ca0dfef63cb20dd831f9c87edd6dc06539eefe67371d'), rdflib.URIRef(ns.bse.filesize), rdflib.Literal('546', datatype=rdflib.XSD.integer)),
- (rdflib.URIRef(pre_file + 'd803187cbf3676ae9d38126270a6152c60431589aa3bb3824baf8954e9c097f1'), rdflib.RDF.type, rdflib.URIRef(ns.bsfs.File)),
+ (rdflib.URIRef(pre_file + 'd803187cbf3676ae9d38126270a6152c60431589aa3bb3824baf8954e9c097f1'), rdflib.RDF.type, rdflib.URIRef(ns.bsn.Entity)),
(rdflib.URIRef(pre_file + 'd803187cbf3676ae9d38126270a6152c60431589aa3bb3824baf8954e9c097f1'), rdflib.URIRef(ns.bse.author), rdflib.Literal('Me, myself, and I', datatype=rdflib.XSD.string)),
(rdflib.URIRef(pre_file + 'd803187cbf3676ae9d38126270a6152c60431589aa3bb3824baf8954e9c097f1'), rdflib.URIRef(ns.bse.filename), rdflib.Literal('td_second', datatype=rdflib.XSD.string)),
- (rdflib.URIRef(pre_file + 'd803187cbf3676ae9d38126270a6152c60431589aa3bb3824baf8954e9c097f1'), rdflib.URIRef(ns.bse.filesize), rdflib.Literal('703', datatype=rdflib.XSD.integer)),
- (rdflib.URIRef(pre_file + 'accb115d266ad60c53cd01a7f7130f245886ce8eaf69bc85319febc11d9fe089'), rdflib.RDF.type, rdflib.URIRef(ns.bsfs.File)),
+ (rdflib.URIRef(pre_file + 'accb115d266ad60c53cd01a7f7130f245886ce8eaf69bc85319febc11d9fe089'), rdflib.RDF.type, rdflib.URIRef(ns.bsn.Entity)),
(rdflib.URIRef(pre_file + 'accb115d266ad60c53cd01a7f7130f245886ce8eaf69bc85319febc11d9fe089'), rdflib.URIRef(ns.bse.author), rdflib.Literal('Me, myself, and I', datatype=rdflib.XSD.string)),
(rdflib.URIRef(pre_file + 'accb115d266ad60c53cd01a7f7130f245886ce8eaf69bc85319febc11d9fe089'), rdflib.URIRef(ns.bse.filename), rdflib.Literal('testimage.jpg', datatype=rdflib.XSD.string)),
- (rdflib.URIRef(pre_file + 'accb115d266ad60c53cd01a7f7130f245886ce8eaf69bc85319febc11d9fe089'), rdflib.URIRef(ns.bse.filesize), rdflib.Literal('349264', datatype=rdflib.XSD.integer)),
# features
- (rdflib.URIRef(pre_file + 'accb115d266ad60c53cd01a7f7130f245886ce8eaf69bc85319febc11d9fe089'), rdflib.URIRef('http://bsfs.ai/schema/Entity/colors_spatial#0658f2234a054e1dd59a14462c89f7733e019160419c796356aa831498bd0a04'),
+ (rdflib.URIRef(pre_file + 'accb115d266ad60c53cd01a7f7130f245886ce8eaf69bc85319febc11d9fe089'), rdflib.URIRef('https://schema.bsfs.io/ie/Node/Entity#colors_spatial_0658f2234a054e1dd59a14462c89f7733e019160419c796356aa831498bd0a04'),
rdflib.Literal(
'(91, 127, 121, 94, 138, 167, 163, 134, 190, 138, 170, 156, 121, 142, 159)',
- datatype=rdflib.URIRef('http://ie.bsfs.ai/schema/Feature/ColorsSpatial#0658f2234a054e1dd59a14462c89f7733e019160419c796356aa831498bd0a04'))),
- (rdflib.URIRef(pre_file + 'accb115d266ad60c53cd01a7f7130f245886ce8eaf69bc85319febc11d9fe089'), rdflib.URIRef(ns.bse.filesize), rdflib.Literal('349264', datatype=rdflib.XSD.integer)),
+ datatype=rdflib.URIRef('https://schema.bsfs.io/ie/Literal/Array/Feature/ColorsSpatial#0658f2234a054e1dd59a14462c89f7733e019160419c796356aa831498bd0a04'))),
# links to previews
(rdflib.URIRef(pre_file + '2f4109b40107cc50e0884755a1a961ed126887e49b8dbaf0e146b2e226aa6647'), rdflib.URIRef(ns.bse.preview), rdflib.URIRef(pre_preview + '79cb8a7e6369361a4f4cb7ff729c1ed3fcf87204769623d6fbd6ebfae601e5c7_s50')),
(rdflib.URIRef(pre_file + '441f3d10c8ff489fe8e33e639606512f6c463151cc429de7e554b9af670c2ece'), rdflib.URIRef(ns.bse.preview), rdflib.URIRef(pre_preview + 'a8b3245636074d5370283b690281abda8ffdff12ce8b1af77c8bc0a4c85be860_s50')),
@@ -115,53 +134,53 @@ class TestIndex(unittest.TestCase):
# preview dimensions
(rdflib.URIRef(pre_preview + '2656e303d7218300326df73b64f312d8b37eb980358be27a38b5f63dae259be3_s50'), rdflib.URIRef(ns.bsp.height), rdflib.Literal('33', datatype=rdflib.URIRef('http://www.w3.org/2001/XMLSchema#integer'))),
(rdflib.URIRef(pre_preview + '2656e303d7218300326df73b64f312d8b37eb980358be27a38b5f63dae259be3_s50'), rdflib.URIRef(ns.bsp.width), rdflib.Literal('50', datatype=rdflib.URIRef('http://www.w3.org/2001/XMLSchema#integer'))),
- (rdflib.URIRef(pre_preview + '2656e303d7218300326df73b64f312d8b37eb980358be27a38b5f63dae259be3_s50'), rdflib.RDF.type, rdflib.URIRef(ns.bsfs.Preview)),
+ (rdflib.URIRef(pre_preview + '2656e303d7218300326df73b64f312d8b37eb980358be27a38b5f63dae259be3_s50'), rdflib.RDF.type, rdflib.URIRef(ns.bsn.Preview)),
(rdflib.URIRef(pre_preview + '26f16643b2570ac5b2d1f8c373d492cb724aae2dd8d71a0b63647838ed651254_s50'), rdflib.URIRef(ns.bsp.height), rdflib.Literal('50', datatype=rdflib.URIRef('http://www.w3.org/2001/XMLSchema#integer'))),
(rdflib.URIRef(pre_preview + '26f16643b2570ac5b2d1f8c373d492cb724aae2dd8d71a0b63647838ed651254_s50'), rdflib.URIRef(ns.bsp.width), rdflib.Literal('36', datatype=rdflib.URIRef('http://www.w3.org/2001/XMLSchema#integer'))),
- (rdflib.URIRef(pre_preview + '26f16643b2570ac5b2d1f8c373d492cb724aae2dd8d71a0b63647838ed651254_s50'), rdflib.RDF.type, rdflib.URIRef(ns.bsfs.Preview)),
+ (rdflib.URIRef(pre_preview + '26f16643b2570ac5b2d1f8c373d492cb724aae2dd8d71a0b63647838ed651254_s50'), rdflib.RDF.type, rdflib.URIRef(ns.bsn.Preview)),
(rdflib.URIRef(pre_preview + '567049149769e1d02e6af6cfee3991f7cf0cbc935cbf6a566047f40155fb13a8_s50'), rdflib.URIRef(ns.bsp.height), rdflib.Literal('50', datatype=rdflib.URIRef('http://www.w3.org/2001/XMLSchema#integer'))),
(rdflib.URIRef(pre_preview + '567049149769e1d02e6af6cfee3991f7cf0cbc935cbf6a566047f40155fb13a8_s50'), rdflib.URIRef(ns.bsp.width), rdflib.Literal('36', datatype=rdflib.URIRef('http://www.w3.org/2001/XMLSchema#integer'))),
- (rdflib.URIRef(pre_preview + '567049149769e1d02e6af6cfee3991f7cf0cbc935cbf6a566047f40155fb13a8_s50'), rdflib.RDF.type, rdflib.URIRef(ns.bsfs.Preview)),
+ (rdflib.URIRef(pre_preview + '567049149769e1d02e6af6cfee3991f7cf0cbc935cbf6a566047f40155fb13a8_s50'), rdflib.RDF.type, rdflib.URIRef(ns.bsn.Preview)),
(rdflib.URIRef(pre_preview + '5d1235838c3d501204bb09c2de563d7e4a7fd17b7ec4ff302221c0e88c4741aa_s50'), rdflib.URIRef(ns.bsp.height), rdflib.Literal('50', datatype=rdflib.URIRef('http://www.w3.org/2001/XMLSchema#integer'))),
(rdflib.URIRef(pre_preview + '5d1235838c3d501204bb09c2de563d7e4a7fd17b7ec4ff302221c0e88c4741aa_s50'), rdflib.URIRef(ns.bsp.width), rdflib.Literal('36', datatype=rdflib.URIRef('http://www.w3.org/2001/XMLSchema#integer'))),
- (rdflib.URIRef(pre_preview + '5d1235838c3d501204bb09c2de563d7e4a7fd17b7ec4ff302221c0e88c4741aa_s50'), rdflib.RDF.type, rdflib.URIRef(ns.bsfs.Preview)),
+ (rdflib.URIRef(pre_preview + '5d1235838c3d501204bb09c2de563d7e4a7fd17b7ec4ff302221c0e88c4741aa_s50'), rdflib.RDF.type, rdflib.URIRef(ns.bsn.Preview)),
(rdflib.URIRef(pre_preview + '79cb8a7e6369361a4f4cb7ff729c1ed3fcf87204769623d6fbd6ebfae601e5c7_s50'), rdflib.URIRef(ns.bsp.height), rdflib.Literal('50', datatype=rdflib.URIRef('http://www.w3.org/2001/XMLSchema#integer'))),
(rdflib.URIRef(pre_preview + '79cb8a7e6369361a4f4cb7ff729c1ed3fcf87204769623d6fbd6ebfae601e5c7_s50'), rdflib.URIRef(ns.bsp.width), rdflib.Literal('36', datatype=rdflib.URIRef('http://www.w3.org/2001/XMLSchema#integer'))),
- (rdflib.URIRef(pre_preview + '79cb8a7e6369361a4f4cb7ff729c1ed3fcf87204769623d6fbd6ebfae601e5c7_s50'), rdflib.RDF.type, rdflib.URIRef(ns.bsfs.Preview)),
+ (rdflib.URIRef(pre_preview + '79cb8a7e6369361a4f4cb7ff729c1ed3fcf87204769623d6fbd6ebfae601e5c7_s50'), rdflib.RDF.type, rdflib.URIRef(ns.bsn.Preview)),
(rdflib.URIRef(pre_preview + '7a975385a110c21fcd12e238fab9501550fa02f6328749068a3bffd65e291027_s50'), rdflib.URIRef(ns.bsp.height), rdflib.Literal('50', datatype=rdflib.URIRef('http://www.w3.org/2001/XMLSchema#integer'))),
(rdflib.URIRef(pre_preview + '7a975385a110c21fcd12e238fab9501550fa02f6328749068a3bffd65e291027_s50'), rdflib.URIRef(ns.bsp.width), rdflib.Literal('36', datatype=rdflib.URIRef('http://www.w3.org/2001/XMLSchema#integer'))),
- (rdflib.URIRef(pre_preview + '7a975385a110c21fcd12e238fab9501550fa02f6328749068a3bffd65e291027_s50'), rdflib.RDF.type, rdflib.URIRef(ns.bsfs.Preview)),
+ (rdflib.URIRef(pre_preview + '7a975385a110c21fcd12e238fab9501550fa02f6328749068a3bffd65e291027_s50'), rdflib.RDF.type, rdflib.URIRef(ns.bsn.Preview)),
(rdflib.URIRef(pre_preview + '968b9aa178585bc8d1fca0e4e32b8cf30b3941eff72f34e320584aaae8fd23ac_s50'), rdflib.URIRef(ns.bsp.height), rdflib.Literal('50', datatype=rdflib.URIRef('http://www.w3.org/2001/XMLSchema#integer'))),
(rdflib.URIRef(pre_preview + '968b9aa178585bc8d1fca0e4e32b8cf30b3941eff72f34e320584aaae8fd23ac_s50'), rdflib.URIRef(ns.bsp.width), rdflib.Literal('36', datatype=rdflib.URIRef('http://www.w3.org/2001/XMLSchema#integer'))),
- (rdflib.URIRef(pre_preview + '968b9aa178585bc8d1fca0e4e32b8cf30b3941eff72f34e320584aaae8fd23ac_s50'), rdflib.RDF.type, rdflib.URIRef(ns.bsfs.Preview)),
+ (rdflib.URIRef(pre_preview + '968b9aa178585bc8d1fca0e4e32b8cf30b3941eff72f34e320584aaae8fd23ac_s50'), rdflib.RDF.type, rdflib.URIRef(ns.bsn.Preview)),
(rdflib.URIRef(pre_preview + '9827509a74a60dfceed11936f7f624e9c932f66c8c0d20d355d56f8c3c9b56b1_s50'), rdflib.URIRef(ns.bsp.height), rdflib.Literal('50', datatype=rdflib.URIRef('http://www.w3.org/2001/XMLSchema#integer'))),
(rdflib.URIRef(pre_preview + '9827509a74a60dfceed11936f7f624e9c932f66c8c0d20d355d56f8c3c9b56b1_s50'), rdflib.URIRef(ns.bsp.width), rdflib.Literal('36', datatype=rdflib.URIRef('http://www.w3.org/2001/XMLSchema#integer'))),
- (rdflib.URIRef(pre_preview + '9827509a74a60dfceed11936f7f624e9c932f66c8c0d20d355d56f8c3c9b56b1_s50'), rdflib.RDF.type, rdflib.URIRef(ns.bsfs.Preview)),
+ (rdflib.URIRef(pre_preview + '9827509a74a60dfceed11936f7f624e9c932f66c8c0d20d355d56f8c3c9b56b1_s50'), rdflib.RDF.type, rdflib.URIRef(ns.bsn.Preview)),
(rdflib.URIRef(pre_preview + 'a63c84e647138a2b68113474212f6aee542b3707171ff178551db3c296e59817_s50'), rdflib.URIRef(ns.bsp.height), rdflib.Literal('50', datatype=rdflib.URIRef('http://www.w3.org/2001/XMLSchema#integer'))),
(rdflib.URIRef(pre_preview + 'a63c84e647138a2b68113474212f6aee542b3707171ff178551db3c296e59817_s50'), rdflib.URIRef(ns.bsp.width), rdflib.Literal('36', datatype=rdflib.URIRef('http://www.w3.org/2001/XMLSchema#integer'))),
- (rdflib.URIRef(pre_preview + 'a63c84e647138a2b68113474212f6aee542b3707171ff178551db3c296e59817_s50'), rdflib.RDF.type, rdflib.URIRef(ns.bsfs.Preview)),
+ (rdflib.URIRef(pre_preview + 'a63c84e647138a2b68113474212f6aee542b3707171ff178551db3c296e59817_s50'), rdflib.RDF.type, rdflib.URIRef(ns.bsn.Preview)),
(rdflib.URIRef(pre_preview + 'a8b3245636074d5370283b690281abda8ffdff12ce8b1af77c8bc0a4c85be860_s50'), rdflib.URIRef(ns.bsp.height), rdflib.Literal('50', datatype=rdflib.URIRef('http://www.w3.org/2001/XMLSchema#integer'))),
(rdflib.URIRef(pre_preview + 'a8b3245636074d5370283b690281abda8ffdff12ce8b1af77c8bc0a4c85be860_s50'), rdflib.URIRef(ns.bsp.width), rdflib.Literal('36', datatype=rdflib.URIRef('http://www.w3.org/2001/XMLSchema#integer'))),
- (rdflib.URIRef(pre_preview + 'a8b3245636074d5370283b690281abda8ffdff12ce8b1af77c8bc0a4c85be860_s50'), rdflib.RDF.type, rdflib.URIRef(ns.bsfs.Preview)),
+ (rdflib.URIRef(pre_preview + 'a8b3245636074d5370283b690281abda8ffdff12ce8b1af77c8bc0a4c85be860_s50'), rdflib.RDF.type, rdflib.URIRef(ns.bsn.Preview)),
(rdflib.URIRef(pre_preview + 'dbfd8ebc0557c4925e9ff8411629a74a15eca934a4c2a6bd3134dd81d2f95a36_s50'), rdflib.URIRef(ns.bsp.height), rdflib.Literal('50', datatype=rdflib.URIRef('http://www.w3.org/2001/XMLSchema#integer'))),
(rdflib.URIRef(pre_preview + 'dbfd8ebc0557c4925e9ff8411629a74a15eca934a4c2a6bd3134dd81d2f95a36_s50'), rdflib.URIRef(ns.bsp.width), rdflib.Literal('36', datatype=rdflib.URIRef('http://www.w3.org/2001/XMLSchema#integer'))),
- (rdflib.URIRef(pre_preview + 'dbfd8ebc0557c4925e9ff8411629a74a15eca934a4c2a6bd3134dd81d2f95a36_s50'), rdflib.RDF.type, rdflib.URIRef(ns.bsfs.Preview)),
+ (rdflib.URIRef(pre_preview + 'dbfd8ebc0557c4925e9ff8411629a74a15eca934a4c2a6bd3134dd81d2f95a36_s50'), rdflib.RDF.type, rdflib.URIRef(ns.bsn.Preview)),
(rdflib.URIRef(pre_preview + 'df2185d8927ccef65c92fc90b94e800b02791354d8dede9dd9aa0e2c2cb1e91e_s50'), rdflib.URIRef(ns.bsp.height), rdflib.Literal('50', datatype=rdflib.URIRef('http://www.w3.org/2001/XMLSchema#integer'))),
(rdflib.URIRef(pre_preview + 'df2185d8927ccef65c92fc90b94e800b02791354d8dede9dd9aa0e2c2cb1e91e_s50'), rdflib.URIRef(ns.bsp.width), rdflib.Literal('36', datatype=rdflib.URIRef('http://www.w3.org/2001/XMLSchema#integer'))),
- (rdflib.URIRef(pre_preview + 'df2185d8927ccef65c92fc90b94e800b02791354d8dede9dd9aa0e2c2cb1e91e_s50'), rdflib.RDF.type, rdflib.URIRef(ns.bsfs.Preview)),
+ (rdflib.URIRef(pre_preview + 'df2185d8927ccef65c92fc90b94e800b02791354d8dede9dd9aa0e2c2cb1e91e_s50'), rdflib.RDF.type, rdflib.URIRef(ns.bsn.Preview)),
# assets
- (rdflib.URIRef(pre_preview + '2656e303d7218300326df73b64f312d8b37eb980358be27a38b5f63dae259be3_s50'), rdflib.URIRef(ns.bsp.asset), rdflib.Literal('/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCAAhADIDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDi9Ktb+O3khZTg/wAB7VSGnKkkhkAR85weteo3Vl9mvLtWjVWEJaN/9rsD7HkVwNza3kmsn7RYsDuzsdSVb/GvLo15W9rKNkVDmvzKN0dx4L1Sb+x2S7jZ7aM7BKF+XPoffkVdOpWDSSI9sGizk5HWuE8S69q0NnHptnB9ms7Nh8lr+6SSXALhsHJUcY7kitPTLi51nR0nMKpO6ZkCHABxngdq1xGKnSs1Kyvrc7qEMW2/Zrz/AKudnbXXhuaEiO3jjY9TtxVG8ht3mQwgOnaubuVmtbFV2gSjjn1q1prajJF+9dEQdMVjPHKtFxaXqc9fE1JXpzjr+J0Is7fA+VaKwmludx/0xevrRXLaH8xyfVZdjpNFsgsUlpryPkjyVuVJ6AnH8z/I1flS30m2ezvdt3bbd1teRL8yntu/xGfeua1zXtbs7dh5I8mRdhkD7mYEY5GOf51Jp+vW8Vnu1KT7FJKMmO5b5JcdwDxn1HFfR1KUZRd1v93zPoaFfD1J+5Kz+79DjfEV9Dc3E0hk5Zi5ZR1btx+NYNlrn9nllhkKgnPpnjr9Of1H0rrdc0bQtTvgsWbSRiwJjk2K+ADwrZ9RyOOa4/U/AWs21y0mmhL60dyI5IpVLduGGeCM/jXmPL201N3NK9SpfngrryOr0y+i1fT4lvZ9gR9pYfM5I9v8/wBK2/7FneFmCXEMLcIbhwpb3A6gVwGiaR4o03UYhbaZOZ88RqA27HXoeB9K9PgiYRRyal4Y1KKVhlyHbr3966MPgIRpuMtNROjTr+/JWn+P4mB/wix/5/o/+/lFdoLXT8DPhfUfx8yiuj6lT7v8P8hex85ffEZef8gu0+oriPiZ/rNI+j/zFFFbYn+Ez5uh8ZP4l/5Cq/8AYN/9nFU/CH/Hvd/9dv8A2Wiih/Ee7k/wv1/Q63Qv9fb/APXT+ldFrP8Ax/xfRP8A0IUUVX2T0K38RD5v9dJ/vH+dFFFUC2P/2Q==', datatype=rdflib.URIRef(ns.bsfs.BinaryBlob))),
- (rdflib.URIRef(pre_preview + '26f16643b2570ac5b2d1f8c373d492cb724aae2dd8d71a0b63647838ed651254_s50'), rdflib.URIRef(ns.bsp.asset), rdflib.Literal('/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/wAALCAAyACQBAREA/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/9oACAEBAAA/APdLq6eAgKoI25Oc+oHYe9Qfb5sr+6UZHUhuv5VYjnZyQSo9gpNTgP3YH6Lj+tPqCa2jmILrkgEVH/Z8HHy8DjGB/hUq26IMAkj0IH+FTUUUUUUUUUUUUUUUUUUUUUUUUUUV/9k=', datatype=rdflib.URIRef(ns.bsfs.BinaryBlob))),
- (rdflib.URIRef(pre_preview + '5d1235838c3d501204bb09c2de563d7e4a7fd17b7ec4ff302221c0e88c4741aa_s50'), rdflib.URIRef(ns.bsp.asset), rdflib.Literal('/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/wAALCAAyACQBAREA/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/9oACAEBAAA/APdLm5eBwFVTkd89c+1Qf2hMSAI15/3v8KtR3DSFgIiceh7/AMv1qcHIzjFLVO7tnncFduAMc+v5GoDZXJAw65A/vdT/AN81PDasjMXPBGAMgj8toqxHGIxgfyA/lUlFFFFFFFFFFFFFFFFFFFFFFFFFf//Z', datatype=rdflib.URIRef(ns.bsfs.BinaryBlob))),
- (rdflib.URIRef(pre_preview + '79cb8a7e6369361a4f4cb7ff729c1ed3fcf87204769623d6fbd6ebfae601e5c7_s50'), rdflib.URIRef(ns.bsp.asset), rdflib.Literal('/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/wAALCAAyACQBAREA/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/9oACAEBAAA/APdLq5eFgEQEYySQf6CoDqEo2/u1yevDf4VJHfZ3eZhNvojHvj0q4h3IDnOR1AxmnVXntEuDlyR8u3gA8fiDUR02I4G9uOei9eeenvTvsS5J82Tn6cfpUsMPkrgSOw9Gxx+lTUUUUUUUUUUUUUUUUUUUUUUUUUV//9k=', datatype=rdflib.URIRef(ns.bsfs.BinaryBlob))),
- (rdflib.URIRef(pre_preview + '7a975385a110c21fcd12e238fab9501550fa02f6328749068a3bffd65e291027_s50'), rdflib.URIRef(ns.bsp.asset), rdflib.Literal('/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/wAALCAAyACQBAREA/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/9oACAEBAAA/APdLq6eBgFUHjPIJ7+wqudQmGMxpyMk4bA6+30/OrSyzFvm8kDrjecgflVhSGGVIIPcUtV57RLjBZmBAxwB/UGov7NiGMMw25wQF45z6VKtrGuc7mz6n3zVjpRRRRRRRRRRRRRRRRRRRRRRRRRRX/9k=', datatype=rdflib.URIRef(ns.bsfs.BinaryBlob))),
- (rdflib.URIRef(pre_preview + '968b9aa178585bc8d1fca0e4e32b8cf30b3941eff72f34e320584aaae8fd23ac_s50'), rdflib.URIRef(ns.bsp.asset), rdflib.Literal('/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/wAALCAAyACQBAREA/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/9oACAEBAAA/APdLm5eFsIgPy55zyc47CoRfTkf6uPOOckjnn29qmS5dmbK52noq5OPzqwj7/wCFl/3hin1n36MzgqhbCkcKTz+ANUzA5Cjynx7IRjn/AHfT271d8gAEFGxzwCfX2WrMR2gIQfbg/wCAqaiiiiiiiiiiiiiiiiiiiiiiiiiv/9k=', datatype=rdflib.URIRef(ns.bsfs.BinaryBlob))),
- (rdflib.URIRef(pre_preview + '9827509a74a60dfceed11936f7f624e9c932f66c8c0d20d355d56f8c3c9b56b1_s50'), rdflib.URIRef(ns.bsp.asset), rdflib.Literal('/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/wAALCAAyACQBAREA/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/9oACAEBAAA/APdLq5eAgKoPyknIPb6ColvZywHlp79R+WRU3nT7iojHXqQR6VYUk9QR9adVK8t3mdSqggLjJxkHPuD/AJFVlsZ/l+RFIXGTtI6k9Npq3FbFdwYKAemAp/8AZR/WrKLtGMn9KdRRRRRRRRRRRRRRRRRRRRRRRRRX/9k=', datatype=rdflib.URIRef(ns.bsfs.BinaryBlob))),
- (rdflib.URIRef(pre_preview + '567049149769e1d02e6af6cfee3991f7cf0cbc935cbf6a566047f40155fb13a8_s50'), rdflib.URIRef(ns.bsp.asset), rdflib.Literal('/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/wAALCAAyACQBAREA/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/9oACAEBAAA/APdLm5eFwFVSCpPIPYj0HvVf+0ZiFxGnIychhj9KtQyTSNkiLZ7E5B/EVZorN1EZkXAJIQ4wM9x7GqYAAXCAgDHKnGMn0X/Oa0LeMJudcKx64iJz+OATVoOOh3E+oUipKayK33lB+opPKj/55r+VHlR8/Iv5U+iiiiiiiiiiiiiiiiiiiiiv/9k=', datatype=rdflib.URIRef(ns.bsfs.BinaryBlob))),
- (rdflib.URIRef(pre_preview + 'df2185d8927ccef65c92fc90b94e800b02791354d8dede9dd9aa0e2c2cb1e91e_s50'), rdflib.URIRef(ns.bsp.asset), rdflib.Literal('/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/wAALCAAyACQBAREA/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/9oACAEBAAA/APdLm5eGQBVU5XPIJ7j0FQfb5sgiNcH2b39vapkvGPDIucjoTjBOPSrKuHHGencEU+ql1am4IIYA7cDIB757g1CunFWByAAOCMAg5yD07VcCEN0P/fZNS0UUUUUUUUUUUUUUUUUUUUUUUUUV/9k=', datatype=rdflib.URIRef(ns.bsfs.BinaryBlob))),
- (rdflib.URIRef(pre_preview + 'a63c84e647138a2b68113474212f6aee542b3707171ff178551db3c296e59817_s50'), rdflib.URIRef(ns.bsp.asset), rdflib.Literal('/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/wAALCAAyACQBAREA/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/9oACAEBAAA/APdLq6eBgFUH5c5IPqPQVANQmJUeWvPXhvUj09qspcM2cAnHHCE/rmpUl3nGx1+oxUlVLq1M7KQQPlI5APXHqDUKacyMDvHTsBk9fb3q4kXl5IYkk5OQB/ICpaKKKKKKKKKKKKKKKKKKKKKKKKKK/9k=', datatype=rdflib.URIRef(ns.bsfs.BinaryBlob))),
- (rdflib.URIRef(pre_preview + 'a8b3245636074d5370283b690281abda8ffdff12ce8b1af77c8bc0a4c85be860_s50'), rdflib.URIRef(ns.bsp.asset), rdflib.Literal('/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/wAALCAAyACQBAREA/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/9oACAEBAAA/APdbm4eF1CqDkZOQT3HoKr/b5vl/dpkj/awDnHp06fzqZLiRmIPk47fMQf1FXKKikgilOZEDHGOaZ9itsg+SuQMA08QoowNwHoGP+NO8serf99Gn0UUUUUUUUUUUUUUUUUUUUUUUUV//2Q==', datatype=rdflib.URIRef(ns.bsfs.BinaryBlob))),
- (rdflib.URIRef(pre_preview + 'dbfd8ebc0557c4925e9ff8411629a74a15eca934a4c2a6bd3134dd81d2f95a36_s50'), rdflib.URIRef(ns.bsp.asset), rdflib.Literal('/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/wAALCAAyACQBAREA/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/9oACAEBAAA/APdbm5eFwqqDkZ5B9QOw96rHUZgoPlLkgno3b8Kel7IzspVePYgdcck1YilaTA3JnqQFPT86sVQvoXkYFUDEKRz7np0NVWtZcAiLkd8Dg/8AfPqO3rWhEk6thsbc9mz+mP61Zoooooooooooooooooooooooooor/9k=', datatype=rdflib.URIRef(ns.bsfs.BinaryBlob))),
+ (rdflib.URIRef(pre_preview + '2656e303d7218300326df73b64f312d8b37eb980358be27a38b5f63dae259be3_s50'), rdflib.URIRef(ns.bsp.asset), rdflib.Literal('/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCAAhADIDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDi9Ktb+O3khZTg/wAB7VSGnKkkhkAR85weteo3Vl9mvLtWjVWEJaN/9rsD7HkVwNza3kmsn7RYsDuzsdSVb/GvLo15W9rKNkVDmvzKN0dx4L1Sb+x2S7jZ7aM7BKF+XPoffkVdOpWDSSI9sGizk5HWuE8S69q0NnHptnB9ms7Nh8lr+6SSXALhsHJUcY7kitPTLi51nR0nMKpO6ZkCHABxngdq1xGKnSs1Kyvrc7qEMW2/Zrz/AKudnbXXhuaEiO3jjY9TtxVG8ht3mQwgOnaubuVmtbFV2gSjjn1q1prajJF+9dEQdMVjPHKtFxaXqc9fE1JXpzjr+J0Is7fA+VaKwmludx/0xevrRXLaH8xyfVZdjpNFsgsUlpryPkjyVuVJ6AnH8z/I1flS30m2ezvdt3bbd1teRL8yntu/xGfeua1zXtbs7dh5I8mRdhkD7mYEY5GOf51Jp+vW8Vnu1KT7FJKMmO5b5JcdwDxn1HFfR1KUZRd1v93zPoaFfD1J+5Kz+79DjfEV9Dc3E0hk5Zi5ZR1btx+NYNlrn9nllhkKgnPpnjr9Of1H0rrdc0bQtTvgsWbSRiwJjk2K+ADwrZ9RyOOa4/U/AWs21y0mmhL60dyI5IpVLduGGeCM/jXmPL201N3NK9SpfngrryOr0y+i1fT4lvZ9gR9pYfM5I9v8/wBK2/7FneFmCXEMLcIbhwpb3A6gVwGiaR4o03UYhbaZOZ88RqA27HXoeB9K9PgiYRRyal4Y1KKVhlyHbr3966MPgIRpuMtNROjTr+/JWn+P4mB/wix/5/o/+/lFdoLXT8DPhfUfx8yiuj6lT7v8P8hex85ffEZef8gu0+oriPiZ/rNI+j/zFFFbYn+Ez5uh8ZP4l/5Cq/8AYN/9nFU/CH/Hvd/9dv8A2Wiih/Ee7k/wv1/Q63Qv9fb/APXT+ldFrP8Ax/xfRP8A0IUUVX2T0K38RD5v9dJ/vH+dFFFUC2P/2Q==', datatype=rdflib.URIRef(ns.bsl.BinaryBlob))),
+ (rdflib.URIRef(pre_preview + '26f16643b2570ac5b2d1f8c373d492cb724aae2dd8d71a0b63647838ed651254_s50'), rdflib.URIRef(ns.bsp.asset), rdflib.Literal('/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/wAALCAAyACQBAREA/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/9oACAEBAAA/APdLq6eAgKoI25Oc+oHYe9Qfb5sr+6UZHUhuv5VYjnZyQSo9gpNTgP3YH6Lj+tPqCa2jmILrkgEVH/Z8HHy8DjGB/hUq26IMAkj0IH+FTUUUUUUUUUUUUUUUUUUUUUUUUUUV/9k=', datatype=rdflib.URIRef(ns.bsl.BinaryBlob))),
+ (rdflib.URIRef(pre_preview + '5d1235838c3d501204bb09c2de563d7e4a7fd17b7ec4ff302221c0e88c4741aa_s50'), rdflib.URIRef(ns.bsp.asset), rdflib.Literal('/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/wAALCAAyACQBAREA/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/9oACAEBAAA/APdLm5eBwFVTkd89c+1Qf2hMSAI15/3v8KtR3DSFgIiceh7/AMv1qcHIzjFLVO7tnncFduAMc+v5GoDZXJAw65A/vdT/AN81PDasjMXPBGAMgj8toqxHGIxgfyA/lUlFFFFFFFFFFFFFFFFFFFFFFFFFf//Z', datatype=rdflib.URIRef(ns.bsl.BinaryBlob))),
+ (rdflib.URIRef(pre_preview + '79cb8a7e6369361a4f4cb7ff729c1ed3fcf87204769623d6fbd6ebfae601e5c7_s50'), rdflib.URIRef(ns.bsp.asset), rdflib.Literal('/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/wAALCAAyACQBAREA/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/9oACAEBAAA/APdLq5eFgEQEYySQf6CoDqEo2/u1yevDf4VJHfZ3eZhNvojHvj0q4h3IDnOR1AxmnVXntEuDlyR8u3gA8fiDUR02I4G9uOei9eeenvTvsS5J82Tn6cfpUsMPkrgSOw9Gxx+lTUUUUUUUUUUUUUUUUUUUUUUUUUV//9k=', datatype=rdflib.URIRef(ns.bsl.BinaryBlob))),
+ (rdflib.URIRef(pre_preview + '7a975385a110c21fcd12e238fab9501550fa02f6328749068a3bffd65e291027_s50'), rdflib.URIRef(ns.bsp.asset), rdflib.Literal('/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/wAALCAAyACQBAREA/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/9oACAEBAAA/APdLq6eBgFUHjPIJ7+wqudQmGMxpyMk4bA6+30/OrSyzFvm8kDrjecgflVhSGGVIIPcUtV57RLjBZmBAxwB/UGov7NiGMMw25wQF45z6VKtrGuc7mz6n3zVjpRRRRRRRRRRRRRRRRRRRRRRRRRRX/9k=', datatype=rdflib.URIRef(ns.bsl.BinaryBlob))),
+ (rdflib.URIRef(pre_preview + '968b9aa178585bc8d1fca0e4e32b8cf30b3941eff72f34e320584aaae8fd23ac_s50'), rdflib.URIRef(ns.bsp.asset), rdflib.Literal('/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/wAALCAAyACQBAREA/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/9oACAEBAAA/APdLm5eFsIgPy55zyc47CoRfTkf6uPOOckjnn29qmS5dmbK52noq5OPzqwj7/wCFl/3hin1n36MzgqhbCkcKTz+ANUzA5Cjynx7IRjn/AHfT271d8gAEFGxzwCfX2WrMR2gIQfbg/wCAqaiiiiiiiiiiiiiiiiiiiiiiiiiv/9k=', datatype=rdflib.URIRef(ns.bsl.BinaryBlob))),
+ (rdflib.URIRef(pre_preview + '9827509a74a60dfceed11936f7f624e9c932f66c8c0d20d355d56f8c3c9b56b1_s50'), rdflib.URIRef(ns.bsp.asset), rdflib.Literal('/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/wAALCAAyACQBAREA/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/9oACAEBAAA/APdLq5eAgKoPyknIPb6ColvZywHlp79R+WRU3nT7iojHXqQR6VYUk9QR9adVK8t3mdSqggLjJxkHPuD/AJFVlsZ/l+RFIXGTtI6k9Npq3FbFdwYKAemAp/8AZR/WrKLtGMn9KdRRRRRRRRRRRRRRRRRRRRRRRRRX/9k=', datatype=rdflib.URIRef(ns.bsl.BinaryBlob))),
+ (rdflib.URIRef(pre_preview + '567049149769e1d02e6af6cfee3991f7cf0cbc935cbf6a566047f40155fb13a8_s50'), rdflib.URIRef(ns.bsp.asset), rdflib.Literal('/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/wAALCAAyACQBAREA/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/9oACAEBAAA/APdLm5eFwFVSCpPIPYj0HvVf+0ZiFxGnIychhj9KtQyTSNkiLZ7E5B/EVZorN1EZkXAJIQ4wM9x7GqYAAXCAgDHKnGMn0X/Oa0LeMJudcKx64iJz+OATVoOOh3E+oUipKayK33lB+opPKj/55r+VHlR8/Iv5U+iiiiiiiiiiiiiiiiiiiiiv/9k=', datatype=rdflib.URIRef(ns.bsl.BinaryBlob))),
+ (rdflib.URIRef(pre_preview + 'df2185d8927ccef65c92fc90b94e800b02791354d8dede9dd9aa0e2c2cb1e91e_s50'), rdflib.URIRef(ns.bsp.asset), rdflib.Literal('/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/wAALCAAyACQBAREA/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/9oACAEBAAA/APdLm5eGQBVU5XPIJ7j0FQfb5sgiNcH2b39vapkvGPDIucjoTjBOPSrKuHHGencEU+ql1am4IIYA7cDIB757g1CunFWByAAOCMAg5yD07VcCEN0P/fZNS0UUUUUUUUUUUUUUUUUUUUUUUUUV/9k=', datatype=rdflib.URIRef(ns.bsl.BinaryBlob))),
+ (rdflib.URIRef(pre_preview + 'a63c84e647138a2b68113474212f6aee542b3707171ff178551db3c296e59817_s50'), rdflib.URIRef(ns.bsp.asset), rdflib.Literal('/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/wAALCAAyACQBAREA/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/9oACAEBAAA/APdLq6eBgFUH5c5IPqPQVANQmJUeWvPXhvUj09qspcM2cAnHHCE/rmpUl3nGx1+oxUlVLq1M7KQQPlI5APXHqDUKacyMDvHTsBk9fb3q4kXl5IYkk5OQB/ICpaKKKKKKKKKKKKKKKKKKKKKKKKKK/9k=', datatype=rdflib.URIRef(ns.bsl.BinaryBlob))),
+ (rdflib.URIRef(pre_preview + 'a8b3245636074d5370283b690281abda8ffdff12ce8b1af77c8bc0a4c85be860_s50'), rdflib.URIRef(ns.bsp.asset), rdflib.Literal('/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/wAALCAAyACQBAREA/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/9oACAEBAAA/APdbm4eF1CqDkZOQT3HoKr/b5vl/dpkj/awDnHp06fzqZLiRmIPk47fMQf1FXKKikgilOZEDHGOaZ9itsg+SuQMA08QoowNwHoGP+NO8serf99Gn0UUUUUUUUUUUUUUUUUUUUUUUUV//2Q==', datatype=rdflib.URIRef(ns.bsl.BinaryBlob))),
+ (rdflib.URIRef(pre_preview + 'dbfd8ebc0557c4925e9ff8411629a74a15eca934a4c2a6bd3134dd81d2f95a36_s50'), rdflib.URIRef(ns.bsp.asset), rdflib.Literal('/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/wAALCAAyACQBAREA/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/9oACAEBAAA/APdbm5eFwqqDkZ5B9QOw96rHUZgoPlLkgno3b8Kel7IzspVePYgdcck1YilaTA3JnqQFPT86sVQvoXkYFUDEKRz7np0NVWtZcAiLkd8Dg/8AfPqO3rWhEk6thsbc9mz+mP61Zoooooooooooooooooooooooooor/9k=', datatype=rdflib.URIRef(ns.bsl.BinaryBlob))),
}))
# NOTE: we don't check ns.bsm.t_created since it depends on the execution time. Triples would look like this:
@@ -170,7 +189,7 @@ class TestIndex(unittest.TestCase):
# (rdflib.URIRef(pre_file + '80818b8ec2ee1919116dba9c8a7e0a4608313cf3b463cd88e9ed77a700dd92d3'), rdflib.URIRef(ns.bsm.t_created), rdflib.Literal('1670..........', datatype=rdflib.XSD.integer)),
# ...
# instead, we simply check if there's such a predicate for each file
- self.assertSetEqual({sub for sub, _ in bsfs._backend._graph.subject_objects(rdflib.URIRef(ns.bsm.t_created))}, {
+ self.assertSetEqual({sub for sub, _ in bsfs._backend._graph.subject_objects(rdflib.URIRef(ns.bsfs.Node().t_created))}, {
rdflib.URIRef(pre_file + '2f4109b40107cc50e0884755a1a961ed126887e49b8dbaf0e146b2e226aa6647'),
rdflib.URIRef(pre_file + '441f3d10c8ff489fe8e33e639606512f6c463151cc429de7e554b9af670c2ece'),
rdflib.URIRef(pre_file + '69b98ecf7aff3e95b09688ba93331678eb8397817111f674c9558e6dd8f5e871'),
@@ -201,6 +220,8 @@ class TestIndex(unittest.TestCase):
outbuf = io.StringIO()
with contextlib.redirect_stdout(outbuf):
bsfs = main([
+ '--config',
+ self.config_path,
'--print',
'-r',
'--host', 'http://example.com',
@@ -209,82 +230,70 @@ class TestIndex(unittest.TestCase):
os.path.join(os.path.dirname(__file__), 'testfile'),
])
self.assertTrue((set(outbuf.getvalue().split('\n')) - {''}).issuperset({
- f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#2f4109b40107cc50e0884755a1a961ed126887e49b8dbaf0e146b2e226aa6647) Predicate({ns.bse.author}) Me, myself, and I',
- f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#2f4109b40107cc50e0884755a1a961ed126887e49b8dbaf0e146b2e226aa6647) Predicate({ns.bse.filename}) alpha_second',
- f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#2f4109b40107cc50e0884755a1a961ed126887e49b8dbaf0e146b2e226aa6647) Predicate({ns.bse.filesize}) 696',
- f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#441f3d10c8ff489fe8e33e639606512f6c463151cc429de7e554b9af670c2ece) Predicate({ns.bse.author}) Me, myself, and I',
- f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#441f3d10c8ff489fe8e33e639606512f6c463151cc429de7e554b9af670c2ece) Predicate({ns.bse.filename}) omega_second',
- f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#441f3d10c8ff489fe8e33e639606512f6c463151cc429de7e554b9af670c2ece) Predicate({ns.bse.filesize}) 503',
- f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#69b98ecf7aff3e95b09688ba93331678eb8397817111f674c9558e6dd8f5e871) Predicate({ns.bse.author}) Me, myself, and I',
- f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#69b98ecf7aff3e95b09688ba93331678eb8397817111f674c9558e6dd8f5e871) Predicate({ns.bse.filename}) td_first',
- f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#69b98ecf7aff3e95b09688ba93331678eb8397817111f674c9558e6dd8f5e871) Predicate({ns.bse.filesize}) 911',
- f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#78f7eb7f0d8221cdb2cb26c978fa42a11f75eb87becc768f4474134cb1e06926) Predicate({ns.bse.author}) Me, myself, and I',
- f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#78f7eb7f0d8221cdb2cb26c978fa42a11f75eb87becc768f4474134cb1e06926) Predicate({ns.bse.filename}) testfile',
- f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#78f7eb7f0d8221cdb2cb26c978fa42a11f75eb87becc768f4474134cb1e06926) Predicate({ns.bse.filesize}) 885',
- f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#80818b8ec2ee1919116dba9c8a7e0a4608313cf3b463cd88e9ed77a700dd92d3) Predicate({ns.bse.author}) Me, myself, and I',
- f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#80818b8ec2ee1919116dba9c8a7e0a4608313cf3b463cd88e9ed77a700dd92d3) Predicate({ns.bse.filename}) bar_first',
- f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#80818b8ec2ee1919116dba9c8a7e0a4608313cf3b463cd88e9ed77a700dd92d3) Predicate({ns.bse.filesize}) 956',
- f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#976d2ea0e58488678cc7e435fbfadabfb6eb6cf50ad51862f38f73729ed11795) Predicate({ns.bse.author}) Me, myself, and I',
- f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#976d2ea0e58488678cc7e435fbfadabfb6eb6cf50ad51862f38f73729ed11795) Predicate({ns.bse.filename}) omega_first',
- f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#976d2ea0e58488678cc7e435fbfadabfb6eb6cf50ad51862f38f73729ed11795) Predicate({ns.bse.filesize}) 648',
- f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#997e2fbb7494a3818ec782d2bc87bf1cffafba6b9c0f658e4a6c18a723e944d3) Predicate({ns.bse.author}) Me, myself, and I',
- f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#997e2fbb7494a3818ec782d2bc87bf1cffafba6b9c0f658e4a6c18a723e944d3) Predicate({ns.bse.filename}) alpha_first',
- f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#997e2fbb7494a3818ec782d2bc87bf1cffafba6b9c0f658e4a6c18a723e944d3) Predicate({ns.bse.filesize}) 754',
- f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#a8af899ecdab60dfaea8ec7f934053624c80a1054539e163f2c7eaa986c2777d) Predicate({ns.bse.author}) Me, myself, and I',
- f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#a8af899ecdab60dfaea8ec7f934053624c80a1054539e163f2c7eaa986c2777d) Predicate({ns.bse.filename}) foo_second',
- f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#a8af899ecdab60dfaea8ec7f934053624c80a1054539e163f2c7eaa986c2777d) Predicate({ns.bse.filesize}) 585',
- f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#b8fd7fba818254166a6043195004138ebda6923e012442f819a2c49671136c70) Predicate({ns.bse.author}) Me, myself, and I',
- f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#b8fd7fba818254166a6043195004138ebda6923e012442f819a2c49671136c70) Predicate({ns.bse.filename}) bar_second',
- f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#b8fd7fba818254166a6043195004138ebda6923e012442f819a2c49671136c70) Predicate({ns.bse.filesize}) 636',
- f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#d43758ace82154a1cc10ca0dfef63cb20dd831f9c87edd6dc06539eefe67371d) Predicate({ns.bse.author}) Me, myself, and I',
- f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#d43758ace82154a1cc10ca0dfef63cb20dd831f9c87edd6dc06539eefe67371d) Predicate({ns.bse.filename}) foo_first',
- f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#d43758ace82154a1cc10ca0dfef63cb20dd831f9c87edd6dc06539eefe67371d) Predicate({ns.bse.filesize}) 546',
- f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#d803187cbf3676ae9d38126270a6152c60431589aa3bb3824baf8954e9c097f1) Predicate({ns.bse.author}) Me, myself, and I',
- f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#d803187cbf3676ae9d38126270a6152c60431589aa3bb3824baf8954e9c097f1) Predicate({ns.bse.filename}) td_second',
- f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#d803187cbf3676ae9d38126270a6152c60431589aa3bb3824baf8954e9c097f1) Predicate({ns.bse.filesize}) 703',
- f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#accb115d266ad60c53cd01a7f7130f245886ce8eaf69bc85319febc11d9fe089) Predicate({ns.bse.filesize}) 349264',
- f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#accb115d266ad60c53cd01a7f7130f245886ce8eaf69bc85319febc11d9fe089) Predicate({ns.bse.author}) Me, myself, and I',
- f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#accb115d266ad60c53cd01a7f7130f245886ce8eaf69bc85319febc11d9fe089) Predicate({ns.bse.filename}) testimage.jpg',
+ f'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/file#2f4109b40107cc50e0884755a1a961ed126887e49b8dbaf0e146b2e226aa6647) Predicate({ns.bse.author}) Me, myself, and I',
+ f'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/file#2f4109b40107cc50e0884755a1a961ed126887e49b8dbaf0e146b2e226aa6647) Predicate({ns.bse.filename}) alpha_second',
+ f'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/file#441f3d10c8ff489fe8e33e639606512f6c463151cc429de7e554b9af670c2ece) Predicate({ns.bse.author}) Me, myself, and I',
+ f'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/file#441f3d10c8ff489fe8e33e639606512f6c463151cc429de7e554b9af670c2ece) Predicate({ns.bse.filename}) omega_second',
+ f'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/file#69b98ecf7aff3e95b09688ba93331678eb8397817111f674c9558e6dd8f5e871) Predicate({ns.bse.author}) Me, myself, and I',
+ f'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/file#69b98ecf7aff3e95b09688ba93331678eb8397817111f674c9558e6dd8f5e871) Predicate({ns.bse.filename}) td_first',
+ f'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/file#78f7eb7f0d8221cdb2cb26c978fa42a11f75eb87becc768f4474134cb1e06926) Predicate({ns.bse.author}) Me, myself, and I',
+ f'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/file#78f7eb7f0d8221cdb2cb26c978fa42a11f75eb87becc768f4474134cb1e06926) Predicate({ns.bse.filename}) testfile',
+ f'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/file#80818b8ec2ee1919116dba9c8a7e0a4608313cf3b463cd88e9ed77a700dd92d3) Predicate({ns.bse.author}) Me, myself, and I',
+ f'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/file#80818b8ec2ee1919116dba9c8a7e0a4608313cf3b463cd88e9ed77a700dd92d3) Predicate({ns.bse.filename}) bar_first',
+ f'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/file#976d2ea0e58488678cc7e435fbfadabfb6eb6cf50ad51862f38f73729ed11795) Predicate({ns.bse.author}) Me, myself, and I',
+ f'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/file#976d2ea0e58488678cc7e435fbfadabfb6eb6cf50ad51862f38f73729ed11795) Predicate({ns.bse.filename}) omega_first',
+ f'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/file#997e2fbb7494a3818ec782d2bc87bf1cffafba6b9c0f658e4a6c18a723e944d3) Predicate({ns.bse.author}) Me, myself, and I',
+ f'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/file#997e2fbb7494a3818ec782d2bc87bf1cffafba6b9c0f658e4a6c18a723e944d3) Predicate({ns.bse.filename}) alpha_first',
+ f'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/file#a8af899ecdab60dfaea8ec7f934053624c80a1054539e163f2c7eaa986c2777d) Predicate({ns.bse.author}) Me, myself, and I',
+ f'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/file#a8af899ecdab60dfaea8ec7f934053624c80a1054539e163f2c7eaa986c2777d) Predicate({ns.bse.filename}) foo_second',
+ f'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/file#b8fd7fba818254166a6043195004138ebda6923e012442f819a2c49671136c70) Predicate({ns.bse.author}) Me, myself, and I',
+ f'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/file#b8fd7fba818254166a6043195004138ebda6923e012442f819a2c49671136c70) Predicate({ns.bse.filename}) bar_second',
+ f'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/file#d43758ace82154a1cc10ca0dfef63cb20dd831f9c87edd6dc06539eefe67371d) Predicate({ns.bse.author}) Me, myself, and I',
+ f'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/file#d43758ace82154a1cc10ca0dfef63cb20dd831f9c87edd6dc06539eefe67371d) Predicate({ns.bse.filename}) foo_first',
+ f'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/file#d803187cbf3676ae9d38126270a6152c60431589aa3bb3824baf8954e9c097f1) Predicate({ns.bse.author}) Me, myself, and I',
+ f'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/file#d803187cbf3676ae9d38126270a6152c60431589aa3bb3824baf8954e9c097f1) Predicate({ns.bse.filename}) td_second',
+ f'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/file#accb115d266ad60c53cd01a7f7130f245886ce8eaf69bc85319febc11d9fe089) Predicate({ns.bse.author}) Me, myself, and I',
+ f'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/file#accb115d266ad60c53cd01a7f7130f245886ce8eaf69bc85319febc11d9fe089) Predicate({ns.bse.filename}) testimage.jpg',
# features
- f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#accb115d266ad60c53cd01a7f7130f245886ce8eaf69bc85319febc11d9fe089) Predicate(http://bsfs.ai/schema/Entity/colors_spatial#0658f2234a054e1dd59a14462c89f7733e019160419c796356aa831498bd0a04) (91, 127, 121, 94, 138, 167, 163, 134, 190, 138, 170, 156, 121, 142, 159)',
+ f'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/file#accb115d266ad60c53cd01a7f7130f245886ce8eaf69bc85319febc11d9fe089) Predicate(https://schema.bsfs.io/ie/Node/Entity#colors_spatial_0658f2234a054e1dd59a14462c89f7733e019160419c796356aa831498bd0a04) (91, 127, 121, 94, 138, 167, 163, 134, 190, 138, 170, 156, 121, 142, 159)',
# links to previews
- f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#2f4109b40107cc50e0884755a1a961ed126887e49b8dbaf0e146b2e226aa6647) Predicate({ns.bse.preview}) Node(http://bsfs.ai/schema/Preview, http://example.com/me/preview#79cb8a7e6369361a4f4cb7ff729c1ed3fcf87204769623d6fbd6ebfae601e5c7_s50)',
- f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#441f3d10c8ff489fe8e33e639606512f6c463151cc429de7e554b9af670c2ece) Predicate({ns.bse.preview}) Node(http://bsfs.ai/schema/Preview, http://example.com/me/preview#a8b3245636074d5370283b690281abda8ffdff12ce8b1af77c8bc0a4c85be860_s50)',
- f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#69b98ecf7aff3e95b09688ba93331678eb8397817111f674c9558e6dd8f5e871) Predicate({ns.bse.preview}) Node(http://bsfs.ai/schema/Preview, http://example.com/me/preview#968b9aa178585bc8d1fca0e4e32b8cf30b3941eff72f34e320584aaae8fd23ac_s50)',
- f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#78f7eb7f0d8221cdb2cb26c978fa42a11f75eb87becc768f4474134cb1e06926) Predicate({ns.bse.preview}) Node(http://bsfs.ai/schema/Preview, http://example.com/me/preview#dbfd8ebc0557c4925e9ff8411629a74a15eca934a4c2a6bd3134dd81d2f95a36_s50)',
- f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#80818b8ec2ee1919116dba9c8a7e0a4608313cf3b463cd88e9ed77a700dd92d3) Predicate({ns.bse.preview}) Node(http://bsfs.ai/schema/Preview, http://example.com/me/preview#567049149769e1d02e6af6cfee3991f7cf0cbc935cbf6a566047f40155fb13a8_s50)',
- f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#976d2ea0e58488678cc7e435fbfadabfb6eb6cf50ad51862f38f73729ed11795) Predicate({ns.bse.preview}) Node(http://bsfs.ai/schema/Preview, http://example.com/me/preview#df2185d8927ccef65c92fc90b94e800b02791354d8dede9dd9aa0e2c2cb1e91e_s50)',
- f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#997e2fbb7494a3818ec782d2bc87bf1cffafba6b9c0f658e4a6c18a723e944d3) Predicate({ns.bse.preview}) Node(http://bsfs.ai/schema/Preview, http://example.com/me/preview#9827509a74a60dfceed11936f7f624e9c932f66c8c0d20d355d56f8c3c9b56b1_s50)',
- f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#a8af899ecdab60dfaea8ec7f934053624c80a1054539e163f2c7eaa986c2777d) Predicate({ns.bse.preview}) Node(http://bsfs.ai/schema/Preview, http://example.com/me/preview#7a975385a110c21fcd12e238fab9501550fa02f6328749068a3bffd65e291027_s50)',
- f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#accb115d266ad60c53cd01a7f7130f245886ce8eaf69bc85319febc11d9fe089) Predicate({ns.bse.preview}) Node(http://bsfs.ai/schema/Preview, http://example.com/me/preview#2656e303d7218300326df73b64f312d8b37eb980358be27a38b5f63dae259be3_s50)',
- f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#b8fd7fba818254166a6043195004138ebda6923e012442f819a2c49671136c70) Predicate({ns.bse.preview}) Node(http://bsfs.ai/schema/Preview, http://example.com/me/preview#a63c84e647138a2b68113474212f6aee542b3707171ff178551db3c296e59817_s50)',
- f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#d43758ace82154a1cc10ca0dfef63cb20dd831f9c87edd6dc06539eefe67371d) Predicate({ns.bse.preview}) Node(http://bsfs.ai/schema/Preview, http://example.com/me/preview#26f16643b2570ac5b2d1f8c373d492cb724aae2dd8d71a0b63647838ed651254_s50)',
- f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#d803187cbf3676ae9d38126270a6152c60431589aa3bb3824baf8954e9c097f1) Predicate({ns.bse.preview}) Node(http://bsfs.ai/schema/Preview, http://example.com/me/preview#5d1235838c3d501204bb09c2de563d7e4a7fd17b7ec4ff302221c0e88c4741aa_s50)',
+ f'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/file#2f4109b40107cc50e0884755a1a961ed126887e49b8dbaf0e146b2e226aa6647) Predicate({ns.bse.preview}) Node(https://schema.bsfs.io/ie/Node/Preview, http://example.com/me/preview#79cb8a7e6369361a4f4cb7ff729c1ed3fcf87204769623d6fbd6ebfae601e5c7_s50)',
+ f'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/file#441f3d10c8ff489fe8e33e639606512f6c463151cc429de7e554b9af670c2ece) Predicate({ns.bse.preview}) Node(https://schema.bsfs.io/ie/Node/Preview, http://example.com/me/preview#a8b3245636074d5370283b690281abda8ffdff12ce8b1af77c8bc0a4c85be860_s50)',
+ f'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/file#69b98ecf7aff3e95b09688ba93331678eb8397817111f674c9558e6dd8f5e871) Predicate({ns.bse.preview}) Node(https://schema.bsfs.io/ie/Node/Preview, http://example.com/me/preview#968b9aa178585bc8d1fca0e4e32b8cf30b3941eff72f34e320584aaae8fd23ac_s50)',
+ f'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/file#78f7eb7f0d8221cdb2cb26c978fa42a11f75eb87becc768f4474134cb1e06926) Predicate({ns.bse.preview}) Node(https://schema.bsfs.io/ie/Node/Preview, http://example.com/me/preview#dbfd8ebc0557c4925e9ff8411629a74a15eca934a4c2a6bd3134dd81d2f95a36_s50)',
+ f'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/file#80818b8ec2ee1919116dba9c8a7e0a4608313cf3b463cd88e9ed77a700dd92d3) Predicate({ns.bse.preview}) Node(https://schema.bsfs.io/ie/Node/Preview, http://example.com/me/preview#567049149769e1d02e6af6cfee3991f7cf0cbc935cbf6a566047f40155fb13a8_s50)',
+ f'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/file#976d2ea0e58488678cc7e435fbfadabfb6eb6cf50ad51862f38f73729ed11795) Predicate({ns.bse.preview}) Node(https://schema.bsfs.io/ie/Node/Preview, http://example.com/me/preview#df2185d8927ccef65c92fc90b94e800b02791354d8dede9dd9aa0e2c2cb1e91e_s50)',
+ f'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/file#997e2fbb7494a3818ec782d2bc87bf1cffafba6b9c0f658e4a6c18a723e944d3) Predicate({ns.bse.preview}) Node(https://schema.bsfs.io/ie/Node/Preview, http://example.com/me/preview#9827509a74a60dfceed11936f7f624e9c932f66c8c0d20d355d56f8c3c9b56b1_s50)',
+ f'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/file#a8af899ecdab60dfaea8ec7f934053624c80a1054539e163f2c7eaa986c2777d) Predicate({ns.bse.preview}) Node(https://schema.bsfs.io/ie/Node/Preview, http://example.com/me/preview#7a975385a110c21fcd12e238fab9501550fa02f6328749068a3bffd65e291027_s50)',
+ f'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/file#accb115d266ad60c53cd01a7f7130f245886ce8eaf69bc85319febc11d9fe089) Predicate({ns.bse.preview}) Node(https://schema.bsfs.io/ie/Node/Preview, http://example.com/me/preview#2656e303d7218300326df73b64f312d8b37eb980358be27a38b5f63dae259be3_s50)',
+ f'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/file#b8fd7fba818254166a6043195004138ebda6923e012442f819a2c49671136c70) Predicate({ns.bse.preview}) Node(https://schema.bsfs.io/ie/Node/Preview, http://example.com/me/preview#a63c84e647138a2b68113474212f6aee542b3707171ff178551db3c296e59817_s50)',
+ f'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/file#d43758ace82154a1cc10ca0dfef63cb20dd831f9c87edd6dc06539eefe67371d) Predicate({ns.bse.preview}) Node(https://schema.bsfs.io/ie/Node/Preview, http://example.com/me/preview#26f16643b2570ac5b2d1f8c373d492cb724aae2dd8d71a0b63647838ed651254_s50)',
+ f'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/file#d803187cbf3676ae9d38126270a6152c60431589aa3bb3824baf8954e9c097f1) Predicate({ns.bse.preview}) Node(https://schema.bsfs.io/ie/Node/Preview, http://example.com/me/preview#5d1235838c3d501204bb09c2de563d7e4a7fd17b7ec4ff302221c0e88c4741aa_s50)',
# preview dimensions
- f'Node(http://bsfs.ai/schema/Preview, http://example.com/me/preview#2656e303d7218300326df73b64f312d8b37eb980358be27a38b5f63dae259be3_s50) Predicate({ns.bsp.height}) 33',
- f'Node(http://bsfs.ai/schema/Preview, http://example.com/me/preview#2656e303d7218300326df73b64f312d8b37eb980358be27a38b5f63dae259be3_s50) Predicate({ns.bsp.width}) 50',
- f'Node(http://bsfs.ai/schema/Preview, http://example.com/me/preview#26f16643b2570ac5b2d1f8c373d492cb724aae2dd8d71a0b63647838ed651254_s50) Predicate({ns.bsp.height}) 50',
- f'Node(http://bsfs.ai/schema/Preview, http://example.com/me/preview#26f16643b2570ac5b2d1f8c373d492cb724aae2dd8d71a0b63647838ed651254_s50) Predicate({ns.bsp.width}) 36',
- f'Node(http://bsfs.ai/schema/Preview, http://example.com/me/preview#567049149769e1d02e6af6cfee3991f7cf0cbc935cbf6a566047f40155fb13a8_s50) Predicate({ns.bsp.height}) 50',
- f'Node(http://bsfs.ai/schema/Preview, http://example.com/me/preview#567049149769e1d02e6af6cfee3991f7cf0cbc935cbf6a566047f40155fb13a8_s50) Predicate({ns.bsp.width}) 36',
- f'Node(http://bsfs.ai/schema/Preview, http://example.com/me/preview#5d1235838c3d501204bb09c2de563d7e4a7fd17b7ec4ff302221c0e88c4741aa_s50) Predicate({ns.bsp.height}) 50',
- f'Node(http://bsfs.ai/schema/Preview, http://example.com/me/preview#5d1235838c3d501204bb09c2de563d7e4a7fd17b7ec4ff302221c0e88c4741aa_s50) Predicate({ns.bsp.width}) 36',
- f'Node(http://bsfs.ai/schema/Preview, http://example.com/me/preview#79cb8a7e6369361a4f4cb7ff729c1ed3fcf87204769623d6fbd6ebfae601e5c7_s50) Predicate({ns.bsp.height}) 50',
- f'Node(http://bsfs.ai/schema/Preview, http://example.com/me/preview#79cb8a7e6369361a4f4cb7ff729c1ed3fcf87204769623d6fbd6ebfae601e5c7_s50) Predicate({ns.bsp.width}) 36',
- f'Node(http://bsfs.ai/schema/Preview, http://example.com/me/preview#7a975385a110c21fcd12e238fab9501550fa02f6328749068a3bffd65e291027_s50) Predicate({ns.bsp.height}) 50',
- f'Node(http://bsfs.ai/schema/Preview, http://example.com/me/preview#7a975385a110c21fcd12e238fab9501550fa02f6328749068a3bffd65e291027_s50) Predicate({ns.bsp.width}) 36',
- f'Node(http://bsfs.ai/schema/Preview, http://example.com/me/preview#968b9aa178585bc8d1fca0e4e32b8cf30b3941eff72f34e320584aaae8fd23ac_s50) Predicate({ns.bsp.height}) 50',
- f'Node(http://bsfs.ai/schema/Preview, http://example.com/me/preview#968b9aa178585bc8d1fca0e4e32b8cf30b3941eff72f34e320584aaae8fd23ac_s50) Predicate({ns.bsp.width}) 36',
- f'Node(http://bsfs.ai/schema/Preview, http://example.com/me/preview#9827509a74a60dfceed11936f7f624e9c932f66c8c0d20d355d56f8c3c9b56b1_s50) Predicate({ns.bsp.height}) 50',
- f'Node(http://bsfs.ai/schema/Preview, http://example.com/me/preview#9827509a74a60dfceed11936f7f624e9c932f66c8c0d20d355d56f8c3c9b56b1_s50) Predicate({ns.bsp.width}) 36',
- f'Node(http://bsfs.ai/schema/Preview, http://example.com/me/preview#a63c84e647138a2b68113474212f6aee542b3707171ff178551db3c296e59817_s50) Predicate({ns.bsp.height}) 50',
- f'Node(http://bsfs.ai/schema/Preview, http://example.com/me/preview#a63c84e647138a2b68113474212f6aee542b3707171ff178551db3c296e59817_s50) Predicate({ns.bsp.width}) 36',
- f'Node(http://bsfs.ai/schema/Preview, http://example.com/me/preview#a8b3245636074d5370283b690281abda8ffdff12ce8b1af77c8bc0a4c85be860_s50) Predicate({ns.bsp.height}) 50',
- f'Node(http://bsfs.ai/schema/Preview, http://example.com/me/preview#a8b3245636074d5370283b690281abda8ffdff12ce8b1af77c8bc0a4c85be860_s50) Predicate({ns.bsp.width}) 36',
- f'Node(http://bsfs.ai/schema/Preview, http://example.com/me/preview#dbfd8ebc0557c4925e9ff8411629a74a15eca934a4c2a6bd3134dd81d2f95a36_s50) Predicate({ns.bsp.height}) 50',
- f'Node(http://bsfs.ai/schema/Preview, http://example.com/me/preview#dbfd8ebc0557c4925e9ff8411629a74a15eca934a4c2a6bd3134dd81d2f95a36_s50) Predicate({ns.bsp.width}) 36',
- f'Node(http://bsfs.ai/schema/Preview, http://example.com/me/preview#df2185d8927ccef65c92fc90b94e800b02791354d8dede9dd9aa0e2c2cb1e91e_s50) Predicate({ns.bsp.height}) 50',
- f'Node(http://bsfs.ai/schema/Preview, http://example.com/me/preview#df2185d8927ccef65c92fc90b94e800b02791354d8dede9dd9aa0e2c2cb1e91e_s50) Predicate({ns.bsp.width}) 36',
+ f'Node(https://schema.bsfs.io/ie/Node/Preview, http://example.com/me/preview#2656e303d7218300326df73b64f312d8b37eb980358be27a38b5f63dae259be3_s50) Predicate({ns.bsp.height}) 33',
+ f'Node(https://schema.bsfs.io/ie/Node/Preview, http://example.com/me/preview#2656e303d7218300326df73b64f312d8b37eb980358be27a38b5f63dae259be3_s50) Predicate({ns.bsp.width}) 50',
+ f'Node(https://schema.bsfs.io/ie/Node/Preview, http://example.com/me/preview#26f16643b2570ac5b2d1f8c373d492cb724aae2dd8d71a0b63647838ed651254_s50) Predicate({ns.bsp.height}) 50',
+ f'Node(https://schema.bsfs.io/ie/Node/Preview, http://example.com/me/preview#26f16643b2570ac5b2d1f8c373d492cb724aae2dd8d71a0b63647838ed651254_s50) Predicate({ns.bsp.width}) 36',
+ f'Node(https://schema.bsfs.io/ie/Node/Preview, http://example.com/me/preview#567049149769e1d02e6af6cfee3991f7cf0cbc935cbf6a566047f40155fb13a8_s50) Predicate({ns.bsp.height}) 50',
+ f'Node(https://schema.bsfs.io/ie/Node/Preview, http://example.com/me/preview#567049149769e1d02e6af6cfee3991f7cf0cbc935cbf6a566047f40155fb13a8_s50) Predicate({ns.bsp.width}) 36',
+ f'Node(https://schema.bsfs.io/ie/Node/Preview, http://example.com/me/preview#5d1235838c3d501204bb09c2de563d7e4a7fd17b7ec4ff302221c0e88c4741aa_s50) Predicate({ns.bsp.height}) 50',
+ f'Node(https://schema.bsfs.io/ie/Node/Preview, http://example.com/me/preview#5d1235838c3d501204bb09c2de563d7e4a7fd17b7ec4ff302221c0e88c4741aa_s50) Predicate({ns.bsp.width}) 36',
+ f'Node(https://schema.bsfs.io/ie/Node/Preview, http://example.com/me/preview#79cb8a7e6369361a4f4cb7ff729c1ed3fcf87204769623d6fbd6ebfae601e5c7_s50) Predicate({ns.bsp.height}) 50',
+ f'Node(https://schema.bsfs.io/ie/Node/Preview, http://example.com/me/preview#79cb8a7e6369361a4f4cb7ff729c1ed3fcf87204769623d6fbd6ebfae601e5c7_s50) Predicate({ns.bsp.width}) 36',
+ f'Node(https://schema.bsfs.io/ie/Node/Preview, http://example.com/me/preview#7a975385a110c21fcd12e238fab9501550fa02f6328749068a3bffd65e291027_s50) Predicate({ns.bsp.height}) 50',
+ f'Node(https://schema.bsfs.io/ie/Node/Preview, http://example.com/me/preview#7a975385a110c21fcd12e238fab9501550fa02f6328749068a3bffd65e291027_s50) Predicate({ns.bsp.width}) 36',
+ f'Node(https://schema.bsfs.io/ie/Node/Preview, http://example.com/me/preview#968b9aa178585bc8d1fca0e4e32b8cf30b3941eff72f34e320584aaae8fd23ac_s50) Predicate({ns.bsp.height}) 50',
+ f'Node(https://schema.bsfs.io/ie/Node/Preview, http://example.com/me/preview#968b9aa178585bc8d1fca0e4e32b8cf30b3941eff72f34e320584aaae8fd23ac_s50) Predicate({ns.bsp.width}) 36',
+ f'Node(https://schema.bsfs.io/ie/Node/Preview, http://example.com/me/preview#9827509a74a60dfceed11936f7f624e9c932f66c8c0d20d355d56f8c3c9b56b1_s50) Predicate({ns.bsp.height}) 50',
+ f'Node(https://schema.bsfs.io/ie/Node/Preview, http://example.com/me/preview#9827509a74a60dfceed11936f7f624e9c932f66c8c0d20d355d56f8c3c9b56b1_s50) Predicate({ns.bsp.width}) 36',
+ f'Node(https://schema.bsfs.io/ie/Node/Preview, http://example.com/me/preview#a63c84e647138a2b68113474212f6aee542b3707171ff178551db3c296e59817_s50) Predicate({ns.bsp.height}) 50',
+ f'Node(https://schema.bsfs.io/ie/Node/Preview, http://example.com/me/preview#a63c84e647138a2b68113474212f6aee542b3707171ff178551db3c296e59817_s50) Predicate({ns.bsp.width}) 36',
+ f'Node(https://schema.bsfs.io/ie/Node/Preview, http://example.com/me/preview#a8b3245636074d5370283b690281abda8ffdff12ce8b1af77c8bc0a4c85be860_s50) Predicate({ns.bsp.height}) 50',
+ f'Node(https://schema.bsfs.io/ie/Node/Preview, http://example.com/me/preview#a8b3245636074d5370283b690281abda8ffdff12ce8b1af77c8bc0a4c85be860_s50) Predicate({ns.bsp.width}) 36',
+ f'Node(https://schema.bsfs.io/ie/Node/Preview, http://example.com/me/preview#dbfd8ebc0557c4925e9ff8411629a74a15eca934a4c2a6bd3134dd81d2f95a36_s50) Predicate({ns.bsp.height}) 50',
+ f'Node(https://schema.bsfs.io/ie/Node/Preview, http://example.com/me/preview#dbfd8ebc0557c4925e9ff8411629a74a15eca934a4c2a6bd3134dd81d2f95a36_s50) Predicate({ns.bsp.width}) 36',
+ f'Node(https://schema.bsfs.io/ie/Node/Preview, http://example.com/me/preview#df2185d8927ccef65c92fc90b94e800b02791354d8dede9dd9aa0e2c2cb1e91e_s50) Predicate({ns.bsp.height}) 50',
+ f'Node(https://schema.bsfs.io/ie/Node/Preview, http://example.com/me/preview#df2185d8927ccef65c92fc90b94e800b02791354d8dede9dd9aa0e2c2cb1e91e_s50) Predicate({ns.bsp.width}) 36',
# assets
# ... (not checked)
}))
diff --git a/test/apps/test_info.py b/test/apps/test_info.py
index 725fb65..ffcaecf 100644
--- a/test/apps/test_info.py
+++ b/test/apps/test_info.py
@@ -1,15 +1,15 @@
-"""
-Part of the bsie test suite.
-A copy of the license is provided with the project.
-Author: Matthias Baumgartner, 2022
-"""
# standard imports
import argparse
import contextlib
import io
+import os
+import tempfile
import unittest
+# external imports
+import yaml
+
# bsie imports
from bsie.utils import bsfs
@@ -20,41 +20,72 @@ from bsie.apps.info import main
## code ##
class TestIndex(unittest.TestCase):
+ def setUp(self):
+ config = {
+ 'ReaderBuilder': {},
+ 'ExtractorBuilder': [
+ {'bsie.extractor.preview.Preview': {
+ 'max_sides': [50],
+ }},
+ {'bsie.extractor.generic.path.Path': {}},
+ {'bsie.extractor.generic.constant.Constant': {
+ 'schema': '''
+ bse:author rdfs:subClassOf bsfs:Predicate ;
+ rdfs:domain bsn:Entity ;
+ rdfs:range xsd:string ;
+ bsfs:unique "true"^^xsd:boolean .
+ ''',
+ 'tuples': [['https://schema.bsfs.io/ie/Node/Entity#author', 'Me, myself, and I']],
+ }},
+ {'bsie.extractor.image.colors_spatial.ColorsSpatial': {
+ 'width': 2,
+ 'height': 2,
+ 'exp': 2,
+ }},
+ ]
+ }
+ # create config file
+ _, self.config_path = tempfile.mkstemp(prefix='bsie-test-', suffix='.yaml')
+ with open(self.config_path, 'wt') as cfile:
+ yaml.dump(config, cfile)
+
+ def tearDown(self):
+ if os.path.exists(self.config_path):
+ os.unlink(self.config_path)
+
def test_predicates(self):
outbuf = io.StringIO()
with contextlib.redirect_stdout(outbuf):
# show predicates infos
- main(['predicates'])
+ main(['--config', self.config_path, 'predicates'])
# verify output
self.assertSetEqual({pred for pred in outbuf.getvalue().split('\n') if pred != ''}, {
- 'http://bsfs.ai/schema/Entity#author',
- 'http://bsfs.ai/schema/Predicate',
- 'http://bsfs.ai/schema/Entity#filename',
- 'http://bsfs.ai/schema/Entity#filesize',
- 'http://bsfs.ai/schema/Entity/colors_spatial#0658f2234a054e1dd59a14462c89f7733e019160419c796356aa831498bd0a04',
- 'http://bsfs.ai/schema/Entity#preview',
- 'http://bsfs.ai/schema/Preview#width',
- 'http://bsfs.ai/schema/Preview#height',
- 'http://bsfs.ai/schema/Preview#asset',
+ 'https://schema.bsfs.io/ie/Node/Entity#author',
+ 'https://schema.bsfs.io/core/Predicate',
+ 'https://schema.bsfs.io/ie/Node/Entity#filename',
+ 'https://schema.bsfs.io/ie/Node/Entity#colors_spatial_0658f2234a054e1dd59a14462c89f7733e019160419c796356aa831498bd0a04',
+ 'https://schema.bsfs.io/ie/Node/Entity#preview',
+ 'https://schema.bsfs.io/ie/Node/Preview#width',
+ 'https://schema.bsfs.io/ie/Node/Preview#height',
+ 'https://schema.bsfs.io/ie/Node/Preview#asset',
})
def test_schema(self):
outbuf = io.StringIO()
with contextlib.redirect_stdout(outbuf):
# show schema infos
- main(['schema'])
+ main(['--config', self.config_path, 'schema'])
# verify output
schema = bsfs.schema.from_string(outbuf.getvalue())
self.assertSetEqual({pred.uri for pred in schema.predicates()}, {
- 'http://bsfs.ai/schema/Entity#author',
- 'http://bsfs.ai/schema/Predicate',
- 'http://bsfs.ai/schema/Entity#filename',
- 'http://bsfs.ai/schema/Entity#filesize',
- 'http://bsfs.ai/schema/Entity/colors_spatial#0658f2234a054e1dd59a14462c89f7733e019160419c796356aa831498bd0a04',
- 'http://bsfs.ai/schema/Entity#preview',
- 'http://bsfs.ai/schema/Preview#width',
- 'http://bsfs.ai/schema/Preview#height',
- 'http://bsfs.ai/schema/Preview#asset',
+ 'https://schema.bsfs.io/ie/Node/Entity#author',
+ 'https://schema.bsfs.io/core/Predicate',
+ 'https://schema.bsfs.io/ie/Node/Entity#filename',
+ 'https://schema.bsfs.io/ie/Node/Entity#colors_spatial_0658f2234a054e1dd59a14462c89f7733e019160419c796356aa831498bd0a04',
+ 'https://schema.bsfs.io/ie/Node/Entity#preview',
+ 'https://schema.bsfs.io/ie/Node/Preview#width',
+ 'https://schema.bsfs.io/ie/Node/Preview#height',
+ 'https://schema.bsfs.io/ie/Node/Preview#asset',
})
def test_invalid(self):
diff --git a/test/apps/test_loader.py b/test/apps/test_loader.py
new file mode 100644
index 0000000..4670266
--- /dev/null
+++ b/test/apps/test_loader.py
@@ -0,0 +1,83 @@
+
+# standard imports
+import os
+import tempfile
+import unittest
+
+# external imports
+import yaml
+
+# objects to test
+from bsie.apps._loader import load_pipeline
+
+
+## code ##
+
+class TestLoader(unittest.TestCase):
+ def test_load_pipeline(self):
+ # config file can be empty
+ config = {
+ 'ReaderBuilder': {},
+ 'ExtractorBuilder': []
+ }
+ # create config file
+ _, path = tempfile.mkstemp(prefix='bsie-test-', suffix='.yaml')
+ with open(path, 'wt') as cfile:
+ yaml.dump(config, cfile)
+ # pipeline contains only default predicates
+ pipeline = load_pipeline(path)
+ self.assertSetEqual({pred.uri for pred in pipeline.schema.predicates()}, {
+ 'https://schema.bsfs.io/core/Predicate',
+ })
+
+ # pipeline is built according to configured extractors
+ config = {
+ 'ReaderBuilder': {},
+ 'ExtractorBuilder': [
+ {'bsie.extractor.preview.Preview': {
+ 'max_sides': [50],
+ }},
+ {'bsie.extractor.generic.path.Path': {}},
+ {'bsie.extractor.generic.constant.Constant': {
+ 'schema': '''
+ bse:author rdfs:subClassOf bsfs:Predicate ;
+ rdfs:domain bsn:Entity ;
+ rdfs:range xsd:string ;
+ bsfs:unique "true"^^xsd:boolean .
+ ''',
+ 'tuples': [['https://schema.bsfs.io/ie/Node/Entity#author', 'Me, myself, and I']],
+ }},
+ {'bsie.extractor.image.colors_spatial.ColorsSpatial': {
+ 'width': 2,
+ 'height': 2,
+ 'exp': 2,
+ }},
+ ]
+ }
+ # create config file
+ _, path = tempfile.mkstemp(prefix='bsie-test-', suffix='.yaml')
+ with open(path, 'wt') as cfile:
+ yaml.dump(config, cfile)
+ # pipeline contains all defined predicates
+ pipeline = load_pipeline(path)
+ self.assertSetEqual({pred.uri for pred in pipeline.schema.predicates()}, {
+ 'https://schema.bsfs.io/ie/Node/Entity#author',
+ 'https://schema.bsfs.io/core/Predicate',
+ 'https://schema.bsfs.io/ie/Node/Entity#filename',
+ 'https://schema.bsfs.io/ie/Node/Entity#colors_spatial_0658f2234a054e1dd59a14462c89f7733e019160419c796356aa831498bd0a04',
+ 'https://schema.bsfs.io/ie/Node/Entity#preview',
+ 'https://schema.bsfs.io/ie/Node/Preview#width',
+ 'https://schema.bsfs.io/ie/Node/Preview#height',
+ 'https://schema.bsfs.io/ie/Node/Preview#asset',
+ })
+
+ # config file must exist
+ self.assertRaises(OSError, load_pipeline, 'invalid.yaml')
+
+
+## main ##
+
+if __name__ == '__main__':
+ unittest.main()
+
+## EOF ##
diff --git a/test/apps/test_main.py b/test/apps/test_main.py
new file mode 100644
index 0000000..4fa094b
--- /dev/null
+++ b/test/apps/test_main.py
@@ -0,0 +1,57 @@
+
+# standard imports
+import contextlib
+import io
+import json
+import os
+import tempfile
+import unittest
+import yaml
+
+# objects to test
+from bsie.apps import main
+
+
+## code ##
+
+class TestMain(unittest.TestCase):
+ def setUp(self):
+ config = {
+ 'ReaderBuilder': {},
+ 'ExtractorBuilder': [
+ {'bsie.extractor.generic.stat.Stat': {}},
+ {'bsie.extractor.generic.path.Path': {}},
+ ]
+ }
+ # create config file
+ _, self.config_path = tempfile.mkstemp(prefix='bsie-test-', suffix='.yaml')
+ with open(self.config_path, 'wt') as cfile:
+ yaml.dump(config, cfile)
+
+ def tearDown(self):
+ if os.path.exists(self.config_path):
+ os.unlink(self.config_path)
+
+ def test_main(self):
+ # must at least pass an app
+ with contextlib.redirect_stderr(io.StringIO()):
+ self.assertRaises(SystemExit, main, [])
+ # app takes over
+ with contextlib.redirect_stderr(io.StringIO()):
+ self.assertRaises(SystemExit, main, ['info'])
+ outbuf = io.StringIO()
+ with contextlib.redirect_stdout(outbuf):
+ main(['info', '--config', self.config_path, 'predicates'])
+ self.assertEqual(set(outbuf.getvalue().strip().split('\n')), {
+ 'https://schema.bsfs.io/ie/Node/Entity#filename',
+ 'https://schema.bsfs.io/ie/Node/Entity#filesize',
+ 'https://schema.bsfs.io/core/Predicate',
+ })
+
+
+## main ##
+
+if __name__ == '__main__':
+ unittest.main()
+
+## EOF ##
diff --git a/test/extractor/generic/test_constant.py b/test/extractor/generic/test_constant.py
index bde3805..77ee02b 100644
--- a/test/extractor/generic/test_constant.py
+++ b/test/extractor/generic/test_constant.py
@@ -1,9 +1,4 @@
-"""
-Part of the bsie test suite.
-A copy of the license is provided with the project.
-Author: Matthias Baumgartner, 2022
-"""
# standard imports
import unittest
@@ -20,11 +15,11 @@ class TestConstant(unittest.TestCase):
def test_extract(self):
schema = '''
bse:author rdfs:subClassOf bsfs:Predicate ;
- rdfs:domain bsfs:Entity ;
+ rdfs:domain bsn:Entity ;
rdfs:range xsd:string ;
bsfs:unique "true"^^xsd:boolean .
bse:comment rdfs:subClassOf bsfs:Predicate ;
- rdfs:domain bsfs:Entity ;
+ rdfs:domain bsn:Entity ;
rdfs:range xsd:string ;
bsfs:unique "false"^^xsd:boolean .
'''
@@ -33,10 +28,10 @@ class TestConstant(unittest.TestCase):
(ns.bse.comment, 'the quick brown fox jumps over the lazy dog.'),
]
ext = Constant(schema, tuples)
- node = _node.Node(ns.bsfs.Entity, '') # Blank node
+ node = _node.Node(ns.bsn.Entity, '') # Blank node
p_author = ext.schema.predicate(ns.bse.author)
p_comment = ext.schema.predicate(ns.bse.comment)
- entity = ext.schema.node(ns.bsfs.Node).child(ns.bsfs.Entity)
+ entity = ext.schema.node(ns.bsfs.Node).child(ns.bsn.Entity)
string = ext.schema.literal(ns.bsfs.Literal).child(ns.xsd.string)
# baseline
self.assertSetEqual(set(ext.extract(node, None, (p_author, p_comment))),
@@ -55,11 +50,11 @@ class TestConstant(unittest.TestCase):
# schema compliance
schema = '''
bse:author rdfs:subClassOf bsfs:Predicate ;
- rdfs:domain bsfs:Entity ;
+ rdfs:domain bsn:Entity ;
rdfs:range xsd:string ;
bsfs:unique "true"^^xsd:boolean .
bse:comment rdfs:subClassOf bsfs:Predicate ;
- rdfs:domain bsfs:Entity ;
+ rdfs:domain bsn:Entity ;
rdfs:range xsd:string ;
bsfs:unique "false"^^xsd:boolean .
'''
@@ -80,13 +75,13 @@ class TestConstant(unittest.TestCase):
def test_eq(self):
schema_a = '''
bse:author rdfs:subClassOf bsfs:Predicate ;
- rdfs:domain bsfs:Entity ;
+ rdfs:domain bsn:Entity ;
rdfs:range xsd:string ;
bsfs:unique "true"^^xsd:boolean .
'''
schema_b = '''
bse:comment rdfs:subClassOf bsfs:Predicate ;
- rdfs:domain bsfs:Entity ;
+ rdfs:domain bsn:Entity ;
rdfs:range xsd:string ;
bsfs:unique "false"^^xsd:boolean .
'''
diff --git a/test/extractor/generic/test_path.py b/test/extractor/generic/test_path.py
index ae68686..0beb37e 100644
--- a/test/extractor/generic/test_path.py
+++ b/test/extractor/generic/test_path.py
@@ -1,9 +1,4 @@
-"""
-Part of the bsie test suite.
-A copy of the license is provided with the project.
-Author: Matthias Baumgartner, 2022
-"""
# standard imports
import unittest
@@ -31,17 +26,17 @@ class TestPath(unittest.TestCase):
self.assertEqual(Path().schema,
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 ;
- bsfs:unique "false"^^xsd:boolean .
+ bsfs:unique "true"^^xsd:boolean .
'''))
def test_extract(self):
ext = Path()
- node = _node.Node(ns.bsfs.File, '') # Blank node
+ node = _node.Node(ns.bsn.Entity, '') # Blank node
content = '/tmp/foo/bar'
p_filename = ext.schema.predicate(ns.bse.filename)
- entity = ext.schema.node(ns.bsfs.Node).child(ns.bsfs.Entity)
+ entity = ext.schema.node(ns.bsfs.Node).child(ns.bsn.Entity)
string = ext.schema.literal(ns.bsfs.Literal).child(ns.xsd.string)
# baseline
diff --git a/test/extractor/generic/test_stat.py b/test/extractor/generic/test_stat.py
index e5562d1..0e83e24 100644
--- a/test/extractor/generic/test_stat.py
+++ b/test/extractor/generic/test_stat.py
@@ -1,9 +1,4 @@
-"""
-Part of the bsie test suite.
-A copy of the license is provided with the project.
-Author: Matthias Baumgartner, 2022
-"""
# standard imports
import os
import unittest
@@ -32,17 +27,17 @@ class TestStat(unittest.TestCase):
self.assertEqual(Stat().schema,
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 ;
- bsfs:unique "false"^^xsd:boolean .
+ bsfs:unique "true"^^xsd:boolean .
'''))
def test_extract(self):
ext = Stat()
- node = _node.Node(ns.bsfs.File, '') # Blank node
+ node = _node.Node(ns.bsn.Entity, '') # Blank node
content = os.stat(__file__)
p_filesize = ext.schema.predicate(ns.bse.filesize)
- entity = ext.schema.node(ns.bsfs.Node).child(ns.bsfs.Entity)
+ entity = ext.schema.node(ns.bsfs.Node).child(ns.bsn.Entity)
string = ext.schema.literal(ns.bsfs.Literal).child(ns.xsd.string)
# baseline
diff --git a/test/extractor/image/test_colors_spatial.py b/test/extractor/image/test_colors_spatial.py
index ba551f3..902ab6d 100644
--- a/test/extractor/image/test_colors_spatial.py
+++ b/test/extractor/image/test_colors_spatial.py
@@ -1,9 +1,4 @@
-"""
-Part of the bsie test suite.
-A copy of the license is provided with the project.
-Author: Matthias Baumgartner, 2022
-"""
# standard imports
import os
import unittest
@@ -24,8 +19,8 @@ from bsie.extractor.image.colors_spatial import ColorsSpatial
class TestColorsSpatial(unittest.TestCase):
def setUp(self):
# content id with default constructors (width=32, height=32, exp=4)
- self.instance_prefix = 'http://ie.bsfs.ai/schema/Feature/ColorsSpatial'
- self.predicate_prefix = 'http://bsfs.ai/schema/Entity/colors_spatial'
+ self.instance_prefix = 'https://schema.bsfs.io/ie/Literal/Array/Feature/ColorsSpatial'
+ self.predicate_prefix = 'https://schema.bsfs.io/ie/Node/Entity#colors_spatial_'
self.uuid = 'adee8d6c43687021e1c5bffe56bcfe727f1638d792744137181304ef889dac2a'
def test_essentials(self):
@@ -55,7 +50,7 @@ class TestColorsSpatial(unittest.TestCase):
def test_schema(self):
schema = bsfs.schema.from_string(base.SCHEMA_PREAMBLE + f'''
- <{self.instance_prefix}> rdfs:subClassOf bsfs:Feature ;
+ <{self.instance_prefix}> rdfs:subClassOf bsa:Feature ;
# annotations
rdfs:label "Spatially dominant colors"^^xsd:string ;
schema:description "Domiant colors of subregions in an image."^^xsd:string ;
@@ -68,8 +63,8 @@ class TestColorsSpatial(unittest.TestCase):
<{self.instance_prefix}/args#height> "32"^^xsd:integer ;
<{self.instance_prefix}/args#exp> "4"^^xsd:float .
- <{self.predicate_prefix}#{self.uuid}> rdfs:subClassOf bsfs:Predicate ;
- rdfs:domain bsfs:File ;
+ <{self.predicate_prefix}{self.uuid}> rdfs:subClassOf bsfs:Predicate ;
+ rdfs:domain bsn:Entity ;
rdfs:range <{self.instance_prefix}#{self.uuid}> ;
bsfs:unique "true"^^xsd:boolean .
''')
@@ -78,7 +73,7 @@ class TestColorsSpatial(unittest.TestCase):
def test_extract(self):
ext = ColorsSpatial(2,2,2)
img = PIL.Image.open(os.path.join(os.path.dirname(__file__), 'testimage.jpg'))
- node = _node.Node(ns.bsfs.Entity, bsfs.URI('http://example.com/entity#1234'))
+ node = _node.Node(ns.bsn.Entity, bsfs.URI('http://example.com/entity#1234'))
principals = set(ext.principals)
self.assertEqual(len(principals), 1)
# valid invocation yields feature
diff --git a/test/extractor/image/test_photometrics.py b/test/extractor/image/test_photometrics.py
new file mode 100644
index 0000000..fb219e2
--- /dev/null
+++ b/test/extractor/image/test_photometrics.py
@@ -0,0 +1,143 @@
+
+# standard imports
+import unittest
+
+# bsie imports
+from bsie.extractor import base
+from bsie.utils import bsfs, node as _node, ns
+
+# objects to test
+from bsie.extractor.image.photometrics import Exif, _gps_to_dec
+
+
+## code ##
+
+class TestExif(unittest.TestCase):
+
+ def test_gps_to_dec(self):
+ # deg+min+sec format
+ self.assertAlmostEqual(_gps_to_dec('29/1 58/1 45/1'.split()), 29.979167, 6)
+ self.assertAlmostEqual(_gps_to_dec('31 08 03'.split()), 31.134167, 6)
+ self.assertAlmostEqual(_gps_to_dec('20 40 586/10'.split()), 20.682944, 6)
+ self.assertAlmostEqual(_gps_to_dec('88/1 34 68/10'.split()), 88.568556, 6)
+ # deg+min format
+ self.assertAlmostEqual(_gps_to_dec('13 472167/10000 0/1 '.split()), 13.786945, 6)
+ self.assertAlmostEqual(_gps_to_dec('104/1 3215/100 0/1'.split()), 104.535833, 6)
+
+ def test_eq(self):
+ # identical instances are equal
+ self.assertEqual(Exif(), Exif())
+ self.assertEqual(hash(Exif()), hash(Exif()))
+ # comparison respects type
+ class Foo(): pass
+ self.assertNotEqual(Exif(), Foo())
+ self.assertNotEqual(hash(Exif()), hash(Foo()))
+ self.assertNotEqual(Exif(), 1234)
+ self.assertNotEqual(hash(Exif()), hash(1234))
+ self.assertNotEqual(Exif(), None)
+ self.assertNotEqual(hash(Exif()), hash(None))
+
+ def test_schema(self):
+ self.assertSetEqual({pred.uri for pred in Exif().schema.predicates()}, {
+ ns.bsfs.Predicate,
+ ns.bse.exposure,
+ ns.bse.aperture,
+ ns.bse.iso,
+ ns.bse.focal_length,
+ ns.bse.width,
+ ns.bse.height,
+ ns.bse.orientation,
+ ns.bse.orientation_label,
+ ns.bse.altitude,
+ ns.bse.latitude,
+ ns.bse.longitude,
+ })
+
+ def test_extract(self):
+ ext = Exif()
+ node = _node.Node(ns.bsfs.File, '') # Blank node
+ content = {
+ 'Exif.Photo.ExposureTime': '10/600',
+ 'Exif.Photo.FNumber': '48/10',
+ 'Exif.Photo.ISOSpeedRatings': '400',
+ 'Exif.Photo.FocalLength': '460/10',
+ 'Exif.Photo.PixelXDimension': '4288',
+ 'Exif.Photo.PixelYDimension': '2848',
+ 'Exif.Image.Orientation': '1',
+ 'Exif.GPSInfo.GPSAltitude': '431/1',
+ 'Exif.GPSInfo.GPSLatitude': '46/1 11397/625 0/1',
+ 'Exif.GPSInfo.GPSLongitude': '7/1 131250/2500 0/1',
+ }
+
+ # invalid principals are ignored
+ self.assertSetEqual(set(ext.extract(node, content, {ns.bse.filename})), set())
+ # extract finds all relevant information
+ self.assertSetEqual(set(ext.extract(node, content, {ext.schema.predicate(ns.bse.exposure)})),
+ {(node, ext.schema.predicate(ns.bse.exposure), 60.0)})
+ self.assertSetEqual(set(ext.extract(node, content, {ext.schema.predicate(ns.bse.aperture)})),
+ {(node, ext.schema.predicate(ns.bse.aperture), 4.8)})
+ self.assertSetEqual(set(ext.extract(node, content, {ext.schema.predicate(ns.bse.iso)})),
+ {(node, ext.schema.predicate(ns.bse.iso), 400)})
+ self.assertSetEqual(set(ext.extract(node, content, {ext.schema.predicate(ns.bse.focal_length)})),
+ {(node, ext.schema.predicate(ns.bse.focal_length), 46.0)})
+ self.assertSetEqual(set(ext.extract(node, content, {ext.schema.predicate(ns.bse.width)})),
+ {(node, ext.schema.predicate(ns.bse.width), 4288)})
+ self.assertSetEqual(set(ext.extract(node, content, {ext.schema.predicate(ns.bse.height)})),
+ {(node, ext.schema.predicate(ns.bse.height), 2848)})
+ self.assertSetEqual(set(ext.extract(node, content, {ext.schema.predicate(ns.bse.orientation)})),
+ {(node, ext.schema.predicate(ns.bse.orientation), 1)})
+ self.assertSetEqual(set(ext.extract(node, content, {ext.schema.predicate(ns.bse.orientation_label)})),
+ {(node, ext.schema.predicate(ns.bse.orientation_label), 'landscape')})
+ self.assertSetEqual(set(ext.extract(node, content, {ext.schema.predicate(ns.bse.altitude)})),
+ {(node, ext.schema.predicate(ns.bse.altitude), 431.0)})
+ self.assertSetEqual(set(ext.extract(node, content, {ext.schema.predicate(ns.bse.latitude)})),
+ {(node, ext.schema.predicate(ns.bse.latitude), 46.30392)})
+ self.assertSetEqual(set(ext.extract(node, content, {ext.schema.predicate(ns.bse.longitude)})),
+ {(node, ext.schema.predicate(ns.bse.longitude), 7.875)})
+
+ # check orientation label
+ self.assertSetEqual(set(ext.extract(
+ node, {
+ 'Exif.Photo.PixelXDimension': '4288',
+ 'Exif.Photo.PixelYDimension': '2848',
+ 'Exif.Image.Orientation': '5',
+ },
+ {ext.schema.predicate(ns.bse.orientation_label)})),
+ {(node, ext.schema.predicate(ns.bse.orientation_label), 'portrait')})
+
+ # can pass multiple principals
+ self.assertSetEqual(set(ext.extract(node, content, {
+ ext.schema.predicate(ns.bse.exposure),
+ ext.schema.predicate(ns.bse.iso),
+ ext.schema.predicate(ns.bse.focal_length),
+ })), {
+ (node, ext.schema.predicate(ns.bse.exposure), 60.0),
+ (node, ext.schema.predicate(ns.bse.iso), 400),
+ (node, ext.schema.predicate(ns.bse.focal_length), 46.0),
+ })
+
+ # principals w/o content are ignored
+ self.assertSetEqual(set(ext.extract(
+ node,
+ content={'Exif.Photo.ExposureTime': '10/600'},
+ principals={
+ ext.schema.predicate(ns.bse.exposure),
+ ext.schema.predicate(ns.bse.iso),
+ ext.schema.predicate(ns.bse.focal_length),
+ })
+ ), {
+ (node, ext.schema.predicate(ns.bse.exposure), 60.0),
+ })
+
+ # empty content is acceptable
+ self.assertSetEqual(set(ext.extract(node, {}, set(ext.principals))), set())
+ # no principals is acceptable
+ self.assertSetEqual(set(ext.extract(node, content, set())), set())
+
+
+## main ##
+
+if __name__ == '__main__':
+ unittest.main()
+
+## EOF ##
diff --git a/test/extractor/test_base.py b/test/extractor/test_base.py
index acfaf58..81865e1 100644
--- a/test/extractor/test_base.py
+++ b/test/extractor/test_base.py
@@ -1,9 +1,4 @@
-"""
-Part of the bsie test suite.
-A copy of the license is provided with the project.
-Author: Matthias Baumgartner, 2022
-"""
# standard imports
import unittest
@@ -20,11 +15,11 @@ class StubExtractor(base.Extractor):
def __init__(self):
super().__init__(bsfs.schema.from_string(base.SCHEMA_PREAMBLE + '''
bse:author rdfs:subClassOf bsfs:Predicate ;
- rdfs:domain bsfs:Entity ;
+ rdfs:domain bsn:Entity ;
rdfs:range xsd:string ;
bsfs:unique "false"^^xsd:boolean .
bse:comment rdfs:subClassOf bsfs:Predicate ;
- rdfs:domain bsfs:Entity ;
+ rdfs:domain bsn:Entity ;
rdfs:range xsd:string ;
bsfs:unique "false"^^xsd:boolean .
'''))
@@ -53,8 +48,8 @@ class TestExtractor(unittest.TestCase):
def test_principals(self):
schema = bsfs.schema.Schema()
- entity = schema.node(ns.bsfs.Node).child(ns.bsfs.Entity)
- string = schema.literal(ns.bsfs.Literal).child(bsfs.URI('http://www.w3.org/2001/XMLSchema#string'))
+ entity = schema.node(ns.bsfs.Node).child(ns.bsn.Entity)
+ string = schema.literal(ns.bsfs.Literal).child(ns.xsd.string)
p_author = schema.predicate(ns.bsfs.Predicate).child(ns.bse.author, domain=entity, range=string)
p_comment = schema.predicate(ns.bsfs.Predicate).child(ns.bse.comment, domain=entity, range=string)
ext = StubExtractor()
diff --git a/test/extractor/test_builder.py b/test/extractor/test_builder.py
index 039ea53..fbb0895 100644
--- a/test/extractor/test_builder.py
+++ b/test/extractor/test_builder.py
@@ -1,9 +1,4 @@
-"""
-Part of the bsie test suite.
-A copy of the license is provided with the project.
-Author: Matthias Baumgartner, 2022
-"""
# standard imports
import unittest
@@ -51,33 +46,33 @@ class TestExtractorBuilder(unittest.TestCase):
{'bsie.extractor.generic.constant.Constant': {
'schema': '''
bse:author rdfs:subClassOf bsfs:Predicate ;
- rdfs:domain bsfs:Entity ;
+ rdfs:domain bsn:Entity ;
rdfs:range xsd:string ;
bsfs:unique "true"^^xsd:boolean .
bse:rating rdfs:subClassOf bsfs:Predicate ;
- rdfs:domain bsfs:Entity ;
+ rdfs:domain bsn:Entity ;
rdfs:range xsd:integer ;
bsfs:unique "true"^^xsd:boolean .
''',
'tuples': [
- ('http://bsfs.ai/schema/Entity#author', 'Me, myself, and I'),
- ('http://bsfs.ai/schema/Entity#rating', 123),
+ ('https://schema.bsfs.io/ie/Node/Entity#author', 'Me, myself, and I'),
+ ('https://schema.bsfs.io/ie/Node/Entity#rating', 123),
],
}}])
obj = builder.build(0)
import bsie.extractor.generic.constant
self.assertEqual(obj, bsie.extractor.generic.constant.Constant('''
bse:author rdfs:subClassOf bsfs:Predicate ;
- rdfs:domain bsfs:Entity ;
+ rdfs:domain bsn:Entity ;
rdfs:range xsd:string ;
bsfs:unique "true"^^xsd:boolean .
bse:rating rdfs:subClassOf bsfs:Predicate ;
- rdfs:domain bsfs:Entity ;
+ rdfs:domain bsn:Entity ;
rdfs:range xsd:integer ;
bsfs:unique "true"^^xsd:boolean .
''', [
- ('http://bsfs.ai/schema/Entity#author', 'Me, myself, and I'),
- ('http://bsfs.ai/schema/Entity#rating', 123),
+ ('https://schema.bsfs.io/ie/Node/Entity#author', 'Me, myself, and I'),
+ ('https://schema.bsfs.io/ie/Node/Entity#rating', 123),
]))
# building with invalid args
diff --git a/test/extractor/test_preview.py b/test/extractor/test_preview.py
index 10d2a7f..6526783 100644
--- a/test/extractor/test_preview.py
+++ b/test/extractor/test_preview.py
@@ -1,9 +1,4 @@
-"""
-Part of the bsie test suite.
-A copy of the license is provided with the project.
-Author: Matthias Baumgartner, 2022
-"""
# standard imports
import io
import os
@@ -45,28 +40,28 @@ class TestPreview(unittest.TestCase):
def test_schema(self):
self.assertEqual(Preview([1,2,3]).schema,
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 .
+ <https://schema.bsfs.io/ie/Literal/BinaryBlob/JPEG> 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 <https://schema.bsfs.io/ie/Literal/BinaryBlob/JPEG> ;
bsfs:unique "true"^^xsd:boolean .
'''))
@@ -74,7 +69,7 @@ class TestPreview(unittest.TestCase):
def test_extract(self):
# setup dependents
rdr = Reader()
- subject = _node.Node(ns.bsfs.File)
+ subject = _node.Node(ns.bsn.Entity)
path = os.path.join(os.path.dirname(__file__), 'testimage.jpg')
# setup extractor
@@ -88,7 +83,7 @@ class TestPreview(unittest.TestCase):
gen(10) # NOTE: consume some image to avoid resource error warning
# extract a preview
triples = set(ext.extract(subject, rdr(path), principals))
- thumbs = {node for node, _, _ in triples if node.node_type == ns.bsfs.Preview}
+ thumbs = {node for node, _, _ in triples if node.node_type == ns.bsn.Preview}
self.assertEqual(len(thumbs), 1)
thumb = list(thumbs)[0]
# test properties
@@ -112,7 +107,7 @@ class TestPreview(unittest.TestCase):
self.assertEqual(principals, {ext.schema.predicate(ns.bse.preview)})
# extract a preview
triples = set(ext.extract(subject, rdr(path), principals))
- thumbs = {node for node, _, _ in triples if node.node_type == ns.bsfs.Preview}
+ thumbs = {node for node, _, _ in triples if node.node_type == ns.bsn.Preview}
self.assertEqual(len(thumbs), 2)
self.assertSetEqual({10, 20}, {
value for _, pred, value in triples if pred == ext.schema.predicate(ns.bsp.width)})
diff --git a/test/lib/test_bsie.py b/test/lib/test_bsie.py
index ae23c4b..0c393cc 100644
--- a/test/lib/test_bsie.py
+++ b/test/lib/test_bsie.py
@@ -1,9 +1,4 @@
-"""
-Part of the bsie test suite.
-A copy of the license is provided with the project.
-Author: Matthias Baumgartner, 2022
-"""
# standard imports
import os
import unittest
@@ -30,17 +25,17 @@ class TestBSIE(unittest.TestCase):
{'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')],
+ tuples=[('https://schema.bsfs.io/ie/Node/Entity#author', 'Me, myself, and I')],
schema='''
bse:author rdfs:subClassOf bsfs:Predicate ;
- rdfs:domain bsfs:Entity ;
+ rdfs:domain bsn:Entity ;
rdfs:range xsd:string ;
bsfs:unique "true"^^xsd:boolean .
''',
)},
])
# build pipeline
- self.naming_policy = DefaultNamingPolicy(host='http://example.com/local', user='')
+ self.naming_policy = DefaultNamingPolicy(host='http://example.com/local', user='me')
pbuild = PipelineBuilder(rbuild, ebuild)
self.pipeline = pbuild.build()
@@ -54,17 +49,17 @@ class TestBSIE(unittest.TestCase):
})
self.assertEqual(lib.schema, bsfs.schema.from_string(SCHEMA_PREAMBLE + '''
bse:filename rdfs:subClassOf bsfs:Predicate ;
- rdfs:domain bsfs:File ;
+ rdfs:domain bsn:Entity ;
rdfs:range xsd:string ;
- bsfs:unique "false"^^xsd:boolean .
+ bsfs:unique "true"^^xsd:boolean .
bse:filesize rdfs:subClassOf bsfs:Predicate ;
- rdfs:domain bsfs:File ;
+ rdfs:domain bsn:Entity ;
rdfs:range xsd:integer;
- bsfs:unique "false"^^xsd:boolean .
+ bsfs:unique "true"^^xsd:boolean .
bse:author rdfs:subClassOf bsfs:Predicate ;
- rdfs:domain bsfs:Entity ;
+ rdfs:domain bsn:Entity ;
rdfs:range xsd:string ;
bsfs:unique "true"^^xsd:boolean .
'''))
@@ -81,12 +76,12 @@ class TestBSIE(unittest.TestCase):
})
self.assertEqual(lib.schema, bsfs.schema.from_string(SCHEMA_PREAMBLE + '''
bse:filesize rdfs:subClassOf bsfs:Predicate ;
- rdfs:domain bsfs:File ;
+ rdfs:domain bsn:Entity ;
rdfs:range xsd:integer;
- bsfs:unique "false"^^xsd:boolean .
+ bsfs:unique "true"^^xsd:boolean .
bse:author rdfs:subClassOf bsfs:Predicate ;
- rdfs:domain bsfs:Entity ;
+ rdfs:domain bsn:Entity ;
rdfs:range xsd:string ;
bsfs:unique "true"^^xsd:boolean .
'''))
@@ -99,17 +94,17 @@ class TestBSIE(unittest.TestCase):
})
self.assertEqual(lib.schema, bsfs.schema.from_string(SCHEMA_PREAMBLE + '''
bse:filename rdfs:subClassOf bsfs:Predicate ;
- rdfs:domain bsfs:File ;
+ rdfs:domain bsn:Entity ;
rdfs:range xsd:string ;
- bsfs:unique "false"^^xsd:boolean .
+ bsfs:unique "true"^^xsd:boolean .
bse:filesize rdfs:subClassOf bsfs:Predicate ;
- rdfs:domain bsfs:File ;
+ rdfs:domain bsn:Entity ;
rdfs:range xsd:integer;
- bsfs:unique "false"^^xsd:boolean .
+ bsfs:unique "true"^^xsd:boolean .
bse:author rdfs:subClassOf bsfs:Predicate ;
- rdfs:domain bsfs:Entity ;
+ rdfs:domain bsn:Entity ;
rdfs:range xsd:string ;
bsfs:unique "true"^^xsd:boolean .
@@ -126,7 +121,7 @@ class TestBSIE(unittest.TestCase):
})
self.assertEqual(lib.schema, bsfs.schema.from_string(SCHEMA_PREAMBLE + '''
bse:author rdfs:subClassOf bsfs:Predicate ;
- rdfs:domain bsfs:Entity ;
+ rdfs:domain bsn:Entity ;
rdfs:range xsd:string ;
bsfs:unique "true"^^xsd:boolean .
'''))
@@ -141,9 +136,9 @@ class TestBSIE(unittest.TestCase):
})
self.assertEqual(lib.schema, bsfs.schema.from_string(SCHEMA_PREAMBLE + '''
bse:filesize rdfs:subClassOf bsfs:Predicate ;
- rdfs:domain bsfs:File ;
+ rdfs:domain bsn:Entity ;
rdfs:range xsd:integer;
- bsfs:unique "false"^^xsd:boolean .
+ bsfs:unique "true"^^xsd:boolean .
'''))
@@ -157,7 +152,7 @@ class TestBSIE(unittest.TestCase):
ns.bse.author,
})
content_hash = 'a948904f2f0f479b8f8197694b30184b0d2ed1c1cd2a1ec0fb85d299a192a447'
- subject = node.Node(ns.bsfs.File, uri=f'http://example.com/local/file#{content_hash}')
+ subject = node.Node(ns.bsn.Entity, uri=f'http://example.com/local/me/file#{content_hash}')
testfile = os.path.join(os.path.dirname(__file__), 'testfile.t')
# from_file extracts all available triples
diff --git a/test/lib/test_builder.py b/test/lib/test_builder.py
index 48e932b..3ecb3d3 100644
--- a/test/lib/test_builder.py
+++ b/test/lib/test_builder.py
@@ -1,9 +1,4 @@
-"""
-Part of the bsie test suite.
-A copy of the license is provided with the project.
-Author: Matthias Baumgartner, 2022
-"""
# standard imports
import logging
import unittest
@@ -23,11 +18,11 @@ class TestPipelineBuilder(unittest.TestCase):
def test_build(self):
c_schema = '''
bse:author rdfs:subClassOf bsfs:Predicate ;
- rdfs:domain bsfs:Entity ;
+ rdfs:domain bsn:Entity ;
rdfs:range xsd:string ;
bsfs:unique "true"^^xsd:boolean .
'''
- c_tuples = [('http://bsfs.ai/schema/Entity#author', 'Me, myself, and I')]
+ c_tuples = [('https://schema.bsfs.io/ie/Node/Entity#author', 'Me, myself, and I')]
# prepare builders
rbuild = ReaderBuilder({})
ebuild = ExtractorBuilder([
diff --git a/test/lib/test_naming_policy.py b/test/lib/test_naming_policy.py
index 4861c84..c9b0cd2 100644
--- a/test/lib/test_naming_policy.py
+++ b/test/lib/test_naming_policy.py
@@ -1,9 +1,4 @@
-"""
-Part of the bsie test suite.
-A copy of the license is provided with the project.
-Author: Matthias Baumgartner, 2022
-"""
# standard imports
import unittest
@@ -26,55 +21,55 @@ class TestDefaultNamingPolicy(unittest.TestCase):
policy = DefaultNamingPolicy('http://example.com', 'me')
# handle_node doesn't modify existing uris
self.assertEqual(policy.handle_node(
- Node(ns.bsfs.Entity, uri='http://example.com/you/foo#bar')).uri,
+ Node(ns.bsn.Invalid, uri='http://example.com/you/foo#bar')).uri,
URI('http://example.com/you/foo#bar'))
# processes bsfs:File
self.assertEqual(policy.handle_node(
- Node(ns.bsfs.File, ucid='abc123cba')).uri,
+ Node(ns.bsn.Entity, ucid='abc123cba')).uri,
URI('http://example.com/me/file#abc123cba'))
# processes bsfs:Preview
self.assertEqual(policy.handle_node(
- Node(ns.bsfs.Preview, ucid='abc123cba', size=123)).uri,
+ Node(ns.bsn.Preview, ucid='abc123cba', size=123)).uri,
URI('http://example.com/me/preview#abc123cba_s123'))
# raises an exception on unknown types
self.assertRaises(errors.ProgrammingError, policy.handle_node,
- Node(ns.bsfs.Entity, ucid='abc123cba', size=123))
+ Node(ns.bsn.Invalid, ucid='abc123cba', size=123))
def test_name_file(self):
# setup
policy = DefaultNamingPolicy('http://example.com', 'me')
# name_file uses ucid
self.assertEqual(policy.name_file(
- Node(ns.bsfs.File, ucid='123abc321')).uri,
+ Node(ns.bsn.Entity, ucid='123abc321')).uri,
URI('http://example.com/me/file#123abc321'))
# name_file falls back to a random guid
self.assertTrue(policy.name_file(
- Node(ns.bsfs.File)).uri.startswith('http://example.com/me/file#'))
+ Node(ns.bsn.Entity)).uri.startswith('http://example.com/me/file#'))
def test_name_preview(self):
# setup
policy = DefaultNamingPolicy('http://example.com', 'me')
# name_preview uses ucid
self.assertEqual(policy.name_preview(
- Node(ns.bsfs.Preview, ucid='123abc321')).uri,
+ Node(ns.bsn.Preview, ucid='123abc321')).uri,
URI('http://example.com/me/preview#123abc321'))
self.assertEqual(policy.name_preview(
- Node(ns.bsfs.Preview, ucid='123abc321', size=400)).uri,
+ Node(ns.bsn.Preview, ucid='123abc321', size=400)).uri,
URI('http://example.com/me/preview#123abc321_s400'))
# name_preview uses source
self.assertEqual(policy.name_preview(
- Node(ns.bsfs.Preview, source=Node(ns.bsfs.File, ucid='123file321'))).uri,
+ Node(ns.bsn.Preview, source=Node(ns.bsn.Entity, ucid='123file321'))).uri,
URI('http://example.com/me/preview#123file321'))
self.assertEqual(policy.name_preview(
- Node(ns.bsfs.Preview, source=Node(ns.bsfs.File, ucid='123file321'), size=300)).uri,
+ Node(ns.bsn.Preview, source=Node(ns.bsn.Entity, ucid='123file321'), size=300)).uri,
URI('http://example.com/me/preview#123file321_s300'))
# name_preview falls back to a random guid
self.assertTrue(policy.name_preview(
- Node(ns.bsfs.Preview)).uri.startswith('http://example.com/me/preview#'))
+ Node(ns.bsn.Preview)).uri.startswith('http://example.com/me/preview#'))
self.assertTrue(policy.name_preview(
- Node(ns.bsfs.Preview, size=200)).uri.startswith('http://example.com/me/preview#'))
+ Node(ns.bsn.Preview, size=200)).uri.startswith('http://example.com/me/preview#'))
self.assertTrue(policy.name_preview(
- Node(ns.bsfs.Preview, size=200)).uri.endswith('_s200'))
+ Node(ns.bsn.Preview, size=200)).uri.endswith('_s200'))
class TestNamingPolicyIterator(unittest.TestCase):
@@ -99,16 +94,16 @@ class TestNamingPolicyIterator(unittest.TestCase):
# setup
policy = DefaultNamingPolicy('http://example.com', 'me')
triples = [
- (Node(ns.bsfs.File, ucid='foo'), 'predA', 'hello'),
- (Node(ns.bsfs.Preview, ucid='bar'), 'predB', 1234),
- (Node(ns.bsfs.Preview, ucid='hello'), 'predC', Node(ns.bsfs.File, ucid='world'))
+ (Node(ns.bsn.Entity, ucid='foo'), 'predA', 'hello'),
+ (Node(ns.bsn.Preview, ucid='bar'), 'predB', 1234),
+ (Node(ns.bsn.Preview, ucid='hello'), 'predC', Node(ns.bsn.Entity, ucid='world'))
]
# handles nodes, handles values, ignores predicate
self.assertListEqual(list(policy(triples)), [
- (Node(ns.bsfs.File, uri='http://example.com/me/file#foo'), 'predA', 'hello'),
- (Node(ns.bsfs.Preview, uri='http://example.com/me/preview#bar'), 'predB', 1234),
- (Node(ns.bsfs.Preview, uri='http://example.com/me/preview#hello'), 'predC',
- Node(ns.bsfs.File, uri='http://example.com/me/file#world')),
+ (Node(ns.bsn.Entity, uri='http://example.com/me/file#foo'), 'predA', 'hello'),
+ (Node(ns.bsn.Preview, uri='http://example.com/me/preview#bar'), 'predB', 1234),
+ (Node(ns.bsn.Preview, uri='http://example.com/me/preview#hello'), 'predC',
+ Node(ns.bsn.Entity, uri='http://example.com/me/file#world')),
])
diff --git a/test/lib/test_pipeline.py b/test/lib/test_pipeline.py
index 61fddd7..eb088a9 100644
--- a/test/lib/test_pipeline.py
+++ b/test/lib/test_pipeline.py
@@ -1,9 +1,4 @@
-"""
-Part of the bsie test suite.
-A copy of the license is provided with the project.
-Author: Matthias Baumgartner, 2022
-"""
# standard imports
import logging
import os
@@ -28,19 +23,19 @@ class TestPipeline(unittest.TestCase):
# constant A
csA = '''
bse:author rdfs:subClassOf bsfs:Predicate ;
- rdfs:domain bsfs:File ;
+ rdfs:domain bsn:Entity ;
rdfs:range xsd:string ;
bsfs:unique "true"^^xsd:boolean .
'''
- tupA = [('http://bsfs.ai/schema/Entity#author', 'Me, myself, and I')]
+ tupA = [('https://schema.bsfs.io/ie/Node/Entity#author', 'Me, myself, and I')]
# constant B
csB = '''
bse:rating rdfs:subClassOf bsfs:Predicate ;
- rdfs:domain bsfs:File ;
+ rdfs:domain bsn:Entity ;
rdfs:range xsd:integer ;
bsfs:unique "true"^^xsd:boolean .
'''
- tupB = [('http://bsfs.ai/schema/Entity#rating', 123)]
+ tupB = [('https://schema.bsfs.io/ie/Node/Entity#rating', 123)]
# extractors/readers
self.ext2rdr = {
bsie.extractor.generic.path.Path(): bsie.reader.path.Path(),
@@ -89,13 +84,13 @@ class TestPipeline(unittest.TestCase):
pipeline = Pipeline(self.ext2rdr)
# build objects for tests
content_hash = 'a948904f2f0f479b8f8197694b30184b0d2ed1c1cd2a1ec0fb85d299a192a447'
- subject = node.Node(ns.bsfs.File, ucid=content_hash)
+ subject = node.Node(ns.bsn.Entity, ucid=content_hash)
testfile = os.path.join(os.path.dirname(__file__), 'testfile.t')
p_filename = pipeline.schema.predicate(ns.bse.filename)
p_filesize = pipeline.schema.predicate(ns.bse.filesize)
p_author = pipeline.schema.predicate(ns.bse.author)
p_rating = pipeline.schema.predicate(ns.bse.rating)
- entity = pipeline.schema.node(ns.bsfs.File)
+ entity = pipeline.schema.node(ns.bsn.Entity)
p_invalid = pipeline.schema.predicate(ns.bsfs.Predicate).child(ns.bse.foo, range=entity)
# extract given predicates
diff --git a/test/reader/image/load_nef.py b/test/reader/image/load_nef.py
index 5ba0adc..02be470 100644
--- a/test/reader/image/load_nef.py
+++ b/test/reader/image/load_nef.py
@@ -1,9 +1,4 @@
-"""
-Part of the bsie test suite.
-A copy of the license is provided with the project.
-Author: Matthias Baumgartner, 2022
-"""
# standard imports
import os
diff --git a/test/reader/image/test_image.py b/test/reader/image/test_image.py
index 26f6a93..ee9b8f9 100644
--- a/test/reader/image/test_image.py
+++ b/test/reader/image/test_image.py
@@ -1,9 +1,4 @@
-"""
-Part of the bsie test suite.
-A copy of the license is provided with the project.
-Author: Matthias Baumgartner, 2022
-"""
# standard imports
import importlib
import os
diff --git a/test/reader/image/test_pillow.py b/test/reader/image/test_pillow.py
index 8abf5c1..2cff768 100644
--- a/test/reader/image/test_pillow.py
+++ b/test/reader/image/test_pillow.py
@@ -1,9 +1,4 @@
-"""
-Part of the bsie test suite.
-A copy of the license is provided with the project.
-Author: Matthias Baumgartner, 2022
-"""
# standard imports
import os
import unittest
diff --git a/test/reader/image/test_raw_image.py b/test/reader/image/test_raw_image.py
index ba21b5a..3b240d0 100644
--- a/test/reader/image/test_raw_image.py
+++ b/test/reader/image/test_raw_image.py
@@ -1,9 +1,4 @@
-"""
-Part of the bsie test suite.
-A copy of the license is provided with the project.
-Author: Matthias Baumgartner, 2022
-"""
# standard imports
import importlib
import os
@@ -37,10 +32,10 @@ class TestRawImage(unittest.TestCase):
#self.assertEqual(img.getdata().getpixel((0, 0)), (0, 0, 0))
img.close()
# raises exception when image cannot be read
+ self.assertRaises(errors.UnsupportedFileFormatError, rdr,
+ os.path.join(os.path.dirname(__file__), 'testimage.jpg'))
self.assertRaises(errors.ReaderError, rdr,
os.path.join(os.path.dirname(__file__), 'invalid.nef'))
- self.assertRaises(errors.ReaderError, rdr,
- os.path.join(os.path.dirname(__file__), 'testimage.jpg'))
diff --git a/test/reader/preview/load_nef.py b/test/reader/preview/load_nef.py
index 5ba0adc..02be470 100644
--- a/test/reader/preview/load_nef.py
+++ b/test/reader/preview/load_nef.py
@@ -1,9 +1,4 @@
-"""
-Part of the bsie test suite.
-A copy of the license is provided with the project.
-Author: Matthias Baumgartner, 2022
-"""
# standard imports
import os
diff --git a/test/reader/preview/test_pg.py b/test/reader/preview/test_pg.py
index e492cfa..30095c5 100644
--- a/test/reader/preview/test_pg.py
+++ b/test/reader/preview/test_pg.py
@@ -1,9 +1,4 @@
-"""
-Part of the bsie test suite.
-A copy of the license is provided with the project.
-Author: Matthias Baumgartner, 2022
-"""
# standard imports
from functools import partial
import os
@@ -57,6 +52,7 @@ class TestPreviewGeneratorReader(unittest.TestCase):
self.assertEqual(sum(img.getdata()), 20258)
# cleanup
img.close()
+ del rdr
# can define a cache dir
pg_dir = tempfile.mkdtemp(prefix='bsie-test')
diff --git a/test/reader/preview/test_pillow.py b/test/reader/preview/test_pillow.py
index ca38d89..20f08ec 100644
--- a/test/reader/preview/test_pillow.py
+++ b/test/reader/preview/test_pillow.py
@@ -1,9 +1,4 @@
-"""
-Part of the bsie test suite.
-A copy of the license is provided with the project.
-Author: Matthias Baumgartner, 2022
-"""
# standard imports
from functools import partial
import os
@@ -25,11 +20,15 @@ class TestPillowPreviewReader(unittest.TestCase):
def test_call(self):
rdr = PillowPreviewReader()
# raises exception when image cannot be read
- self.assertRaises(errors.ReaderError, rdr,
+ self.assertRaises(errors.UnsupportedFileFormatError, rdr,
os.path.join(os.path.dirname(__file__), 'invalid.jpg'))
+ # raises exception when image cannot be read
+ self.assertRaises(errors.ReaderError, rdr,
+ os.path.join(os.path.dirname(__file__), 'inexistent.jpg'))
# raises exception when image has invalid type
self.assertRaises(errors.UnsupportedFileFormatError, rdr,
os.path.join(os.path.dirname(__file__), 'invalid.foo'))
+
# proper file produces a generator
gen = rdr(os.path.join(os.path.dirname(__file__), 'testimage.jpg'))
self.assertIsInstance(gen, partial)
diff --git a/test/reader/preview/test_preview.py b/test/reader/preview/test_preview.py
index fde610f..e144877 100644
--- a/test/reader/preview/test_preview.py
+++ b/test/reader/preview/test_preview.py
@@ -1,9 +1,4 @@
-"""
-Part of the bsie test suite.
-A copy of the license is provided with the project.
-Author: Matthias Baumgartner, 2022
-"""
# standard imports
from functools import partial
import importlib
diff --git a/test/reader/preview/test_rawpy.py b/test/reader/preview/test_rawpy.py
index ed35f53..11a6f9b 100644
--- a/test/reader/preview/test_rawpy.py
+++ b/test/reader/preview/test_rawpy.py
@@ -1,9 +1,4 @@
-"""
-Part of the bsie test suite.
-A copy of the license is provided with the project.
-Author: Matthias Baumgartner, 2022
-"""
# standard imports
from functools import partial
import importlib
diff --git a/test/reader/preview/test_utils.py b/test/reader/preview/test_utils.py
index c10c38c..2b15bc6 100644
--- a/test/reader/preview/test_utils.py
+++ b/test/reader/preview/test_utils.py
@@ -1,9 +1,4 @@
-"""
-Part of the bsie test suite.
-A copy of the license is provided with the project.
-Author: Matthias Baumgartner, 2022
-"""
# standard imports
import os
import unittest
diff --git a/test/reader/test_base.py b/test/reader/test_base.py
index 41f4c29..5dd2855 100644
--- a/test/reader/test_base.py
+++ b/test/reader/test_base.py
@@ -1,9 +1,4 @@
-"""
-Part of the bsie test suite.
-A copy of the license is provided with the project.
-Author: Matthias Baumgartner, 2022
-"""
# standard imports
import unittest
diff --git a/test/reader/test_builder.py b/test/reader/test_builder.py
index 92e9edc..84e8e7a 100644
--- a/test/reader/test_builder.py
+++ b/test/reader/test_builder.py
@@ -1,9 +1,4 @@
-"""
-Part of the bsie test suite.
-A copy of the license is provided with the project.
-Author: Matthias Baumgartner, 2022
-"""
# standard imports
import unittest
diff --git a/test/reader/test_chain.py b/test/reader/test_chain.py
index 901faa1..665aabc 100644
--- a/test/reader/test_chain.py
+++ b/test/reader/test_chain.py
@@ -1,9 +1,4 @@
-"""
-Part of the bsie test suite.
-A copy of the license is provided with the project.
-Author: Matthias Baumgartner, 2022
-"""
# standard imports
import logging
import os
diff --git a/test/reader/test_exif.py b/test/reader/test_exif.py
new file mode 100644
index 0000000..de6e801
--- /dev/null
+++ b/test/reader/test_exif.py
@@ -0,0 +1,52 @@
+
+# standard imports
+import os
+import unittest
+
+# external imports
+import pyexiv2
+
+# bsie imports
+from bsie.utils import errors
+
+# objects to test
+from bsie.reader.exif import Exif
+
+
+## code ##
+
+class TestExif(unittest.TestCase):
+ def test_call(self):
+ rdr = Exif()
+ # discards non-image files
+ self.assertRaises(errors.UnsupportedFileFormatError, rdr,
+ os.path.join(os.path.dirname(__file__), 'invalid.doc'))
+ # raises on invalid image files
+ self.assertRaises(errors.UnsupportedFileFormatError, rdr,
+ os.path.join(os.path.dirname(__file__), 'invalid.jpg'))
+ # raises on invalid image files
+ pyexiv2.set_log_level(3) # suppress log message
+ self.assertRaises(errors.ReaderError, rdr,
+ os.path.join(os.path.dirname(__file__), 'testimage_exif_corrupted.jpg'))
+ # returns dict with exif info
+ self.assertDictEqual(rdr(os.path.join(os.path.dirname(__file__), 'testimage_exif.jpg')), {
+ 'Exif.Image.Artist': 'nobody',
+ 'Exif.Image.ExifTag': '110',
+ 'Exif.Image.ResolutionUnit': '2',
+ 'Exif.Image.XResolution': '300/1',
+ 'Exif.Image.YCbCrPositioning': '1',
+ 'Exif.Image.YResolution': '300/1',
+ 'Exif.Photo.ColorSpace': '65535',
+ 'Exif.Photo.ComponentsConfiguration': '1 2 3 0',
+ 'Exif.Photo.ExifVersion': '48 50 51 50',
+ 'Exif.Photo.FlashpixVersion': '48 49 48 48',
+ 'Exif.Photo.ISOSpeedRatings': '200',
+ })
+
+
+## main ##
+
+if __name__ == '__main__':
+ unittest.main()
+
+## EOF ##
diff --git a/test/reader/test_path.py b/test/reader/test_path.py
index 95e447f..f2eee06 100644
--- a/test/reader/test_path.py
+++ b/test/reader/test_path.py
@@ -1,9 +1,4 @@
-"""
-Part of the bsie test suite.
-A copy of the license is provided with the project.
-Author: Matthias Baumgartner, 2022
-"""
# standard imports
import unittest
diff --git a/test/reader/test_stat.py b/test/reader/test_stat.py
index fd9fdcd..f36b8b3 100644
--- a/test/reader/test_stat.py
+++ b/test/reader/test_stat.py
@@ -1,9 +1,4 @@
-"""
-Part of the bsie test suite.
-A copy of the license is provided with the project.
-Author: Matthias Baumgartner, 2022
-"""
# standard imports
import os
import unittest
diff --git a/test/reader/testimage_exif.jpg b/test/reader/testimage_exif.jpg
new file mode 100644
index 0000000..a774bc2
--- /dev/null
+++ b/test/reader/testimage_exif.jpg
Binary files differ
diff --git a/test/reader/testimage_exif_corrupted.jpg b/test/reader/testimage_exif_corrupted.jpg
new file mode 100644
index 0000000..e51a9dc
--- /dev/null
+++ b/test/reader/testimage_exif_corrupted.jpg
Binary files differ
diff --git a/test/utils/filematcher/test_matcher.py b/test/utils/filematcher/test_matcher.py
index c3cccee..88e96c2 100644
--- a/test/utils/filematcher/test_matcher.py
+++ b/test/utils/filematcher/test_matcher.py
@@ -1,9 +1,4 @@
-"""
-Part of the bsie test suite.
-A copy of the license is provided with the project.
-Author: Matthias Baumgartner, 2022
-"""
# standard imports
import os
import stat
diff --git a/test/utils/filematcher/test_parser.py b/test/utils/filematcher/test_parser.py
index c594747..536db00 100644
--- a/test/utils/filematcher/test_parser.py
+++ b/test/utils/filematcher/test_parser.py
@@ -1,9 +1,4 @@
-"""
-Part of the bsie test suite.
-A copy of the license is provided with the project.
-Author: Matthias Baumgartner, 2022
-"""
# standard imports
import unittest
diff --git a/test/utils/test_loading.py b/test/utils/test_loading.py
index 58ff166..b8773ab 100644
--- a/test/utils/test_loading.py
+++ b/test/utils/test_loading.py
@@ -1,9 +1,4 @@
-"""
-Part of the bsie test suite.
-A copy of the license is provided with the project.
-Author: Matthias Baumgartner, 2022
-"""
# standard imports
import unittest
diff --git a/test/utils/test_node.py b/test/utils/test_node.py
index 1dcd0ed..c0662a1 100644
--- a/test/utils/test_node.py
+++ b/test/utils/test_node.py
@@ -1,9 +1,4 @@
-"""
-Part of the bsie test suite.
-A copy of the license is provided with the project.
-Author: Matthias Baumgartner, 2022
-"""
# standard imports
import unittest
@@ -75,17 +70,17 @@ class TestNode(unittest.TestCase):
def test_str(self):
uri = bsfs.URI('http://example.com/me/entity#1234')
# basic string conversion
- node = Node(ns.bsfs.Entity, uri)
- self.assertEqual(str(node), 'Node(http://bsfs.ai/schema/Entity, http://example.com/me/entity#1234)')
- self.assertEqual(repr(node), 'Node(http://bsfs.ai/schema/Entity, http://example.com/me/entity#1234)')
+ node = Node(ns.bsn.Entity, uri)
+ self.assertEqual(str(node), 'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/entity#1234)')
+ self.assertEqual(repr(node), 'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/entity#1234)')
# string conversion respects node_type
- node = Node(ns.bsfs.Foo, uri)
- self.assertEqual(str(node), 'Node(http://bsfs.ai/schema/Foo, http://example.com/me/entity#1234)')
- self.assertEqual(repr(node), 'Node(http://bsfs.ai/schema/Foo, http://example.com/me/entity#1234)')
+ node = Node(ns.bsn.Foo, uri)
+ self.assertEqual(str(node), 'Node(https://schema.bsfs.io/ie/Node/Foo, http://example.com/me/entity#1234)')
+ self.assertEqual(repr(node), 'Node(https://schema.bsfs.io/ie/Node/Foo, http://example.com/me/entity#1234)')
# string conversion respects uri
- node = Node(ns.bsfs.Entity, bsfs.URI('http://example.com/me/entity#4321'))
- self.assertEqual(str(node), 'Node(http://bsfs.ai/schema/Entity, http://example.com/me/entity#4321)')
- self.assertEqual(repr(node), 'Node(http://bsfs.ai/schema/Entity, http://example.com/me/entity#4321)')
+ node = Node(ns.bsn.Entity, bsfs.URI('http://example.com/me/entity#4321'))
+ self.assertEqual(str(node), 'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/entity#4321)')
+ self.assertEqual(repr(node), 'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/entity#4321)')