Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update requirements #216

Merged
merged 11 commits into from
Sep 22, 2021
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,6 @@ Install with
See [docs/docker-instructions.md](#docs/docker-instructions.md)
for how to build a docker image.


Known issues
------------

Expand All @@ -150,13 +149,13 @@ Known issues
master](https://github.com/RDFLib/rdflib) if you need to serialise
to turtle.


Attributions and credits
------------------------
EMMOntoPy is maintained by [EMMC-ASBL](https://emmc.eu/). So far it has mainly been developed by
[SINTEF](https://www.sintef.no/).

### Contributing projects

- [EMMC-CSA](https://emmc.info/about-emmc-csa/);
Grant Agreement No: 723867
<img src="https://i2.wp.com/emmc.info/wp-content/uploads/2018/10/emmc_logo-low.jpg?fit=1701%2C1701&ssl=1" height="50">
Expand Down
116 changes: 116 additions & 0 deletions ontopy/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import datetime
import tempfile
import types
from typing import TYPE_CHECKING
import urllib.request
import xml.etree.ElementTree as ET

Expand All @@ -15,6 +16,11 @@
import owlready2


if TYPE_CHECKING:
from packaging.version import Version, LegacyVersion
from typing import Union


# Format mappings: file extension -> rdflib format name
FMAP = {
'n3': 'ntriples',
Expand All @@ -28,6 +34,15 @@
OWLREADY2_FORMATS = 'rdfxml', 'owl', 'xml', 'ntriples'


class IncompatibleVersion(Exception):
"""An installed dependency version is incompatible with a functionality of
this package."""


class UnknownVersion(Exception):
"""Cannot retrieve version from a package."""


def isinteractive():
"""Returns true if we are running from an interactive interpreater,
false otherwise."""
Expand Down Expand Up @@ -324,13 +339,71 @@ def write_catalog(mappings, output='catalog-v001.xml'):
f.write('\n'.join(s) + '\n')


def _validate_installed_version(
package: str, min_version: "Union[str, Version, LegacyVersion]"
) -> bool:
"""Validate an installed package.

Examine whether a minimum version is installed in the used Python
interpreter for a specific package.

Parameters:
package: The package to be investigated as a string, e.g., `"rdflib"`.
min_version: The minimum version expected to be installed.

Raises:
UnknownVersion: If the supplied package does not have a `__version__`
attribute.

Returns:
Whether or not the installed version is equal to or greater than the
`min_version`.

"""
import importlib
from packaging.version import (
parse as parse_version, LegacyVersion, Version
)

if isinstance(min_version, str):
min_version = parse_version(min_version)
elif isinstance(min_version, (LegacyVersion, Version)):
# We have the format we want
pass
else:
raise TypeError(
"min_version should be either a str, LegacyVersion or Version. "
"The latter classes being from the packaging.version module."
)

installed_package = importlib.import_module(
name=".", package=package
)
installed_package_version = getattr(installed_package, "__version__", None)
if not installed_package_version:
raise UnknownVersion(
f"Cannot retrieve version information from package {package!r}."
)

return parse_version(installed_package_version) >= min_version


def convert_imported(input, output, input_format=None, output_format='xml',
url_from_catalog=None, catalog_file='catalog-v001.xml'):
"""Convert imported ontologies.

Store the output in a directory structure matching the source
files. This require catalog file(s) to be present.

Warning:
To convert to Turtle (`.ttl`) format, you must have installed
`rdflib>=6.0.0`. See [Known issues](../README.md#Known-issues) in the
README for more information.

Raises:
IncompatibleVersion: If `rdflib<6.0.0` and the desired output format is
Turtle.

Args:
input: input ontology file name
output: output ontology file path. The directory part of `output`
Expand Down Expand Up @@ -395,6 +468,20 @@ def recur(graph, outext):

# Write output files
fmt = input_format if input_format else guess_format(input, fmap=FMAP)

if (
not _validate_installed_version(package="rdflib", min_version="6.0.0")
and (output_format == FMAP.get("ttl", "") or outext == "ttl")
):
from rdflib import __version__ as __rdflib_version__

raise IncompatibleVersion(
"To correctly convert to Turtle format, rdflib must be version "
"6.0.0 or greater, however, the detected rdflib version used "
f"by your Python interpreter is {__rdflib_version__!r}. For "
"more information see the 'Known issues' section of the README."
)

g = Graph()
g.parse(input, format=fmt)
g.serialize(destination=output, format=output_format)
Expand All @@ -410,6 +497,16 @@ def squash_imported(input, output, input_format=None, output_format='xml',
only be used if it exists in the same directory as the input file.

The the squash rdflib graph is returned.

Warning:
To convert to Turtle (`.ttl`) format, you must have installed
`rdflib>=6.0.0`. See [Known issues](../README.md#Known-issues) in the
README for more information.

Raises:
IncompatibleVersion: If `rdflib<6.0.0` and the desired output format is
Turtle.

"""
inroot = os.path.dirname(os.path.abspath(input))

Expand Down Expand Up @@ -440,6 +537,25 @@ def recur(g):
graph.parse(input, format=input_format)
recur(graph)
if output:
if (
not _validate_installed_version(
package="rdflib", min_version="6.0.0"
)
and (
output_format == FMAP.get("ttl", "")
or os.path.splitext(output)[1] == "ttl"
)
):
from rdflib import __version__ as __rdflib_version__

raise IncompatibleVersion(
"To correctly convert to Turtle format, rdflib must be version"
" 6.0.0 or greater, however, the detected rdflib version used "
f"by your Python interpreter is {__rdflib_version__!r}. For "
"more information see the 'Known issues' section of the "
"README."
)

graph.serialize(destination=output, format=output_format)
return graph

Expand Down
18 changes: 9 additions & 9 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
Cython>=0.29.21
Owlready2>=0.28,!=0.32,!=0.34
graphviz>=0.16
PyYAML>=5.4.1
blessings>=1.7
Pygments>=2.7.4
rdflib~=4.2.1
semver>=2.8.1
pydot>=1.4.1
Cython>=0.29.21,<0.30
Owlready2>=0.28,<0.35,!=0.32,!=0.34
graphviz>=0.16,<0.17
PyYAML>=5.4.1,<6
blessings>=1.7,<2
Pygments>=2.7.4,<3
rdflib>=4.2.1,<7
semver>=2.8.1,<3
pydot>=1.4.1,<2
75 changes: 52 additions & 23 deletions tools/ontoconvert
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,18 @@
"""Converts file format of input ontology and write it to output file(s).
"""
import argparse
import os
import sys

from rdflib.util import Graph, guess_format

from ontopy.utils import convert_imported, squash_imported
from ontopy.utils import (
convert_imported,
FMAP,
IncompatibleVersion,
squash_imported,
_validate_installed_version,
)
from ontopy.factpluspluswrapper.factppgraph import FaCTPPGraph


Expand Down Expand Up @@ -64,28 +72,49 @@ def main():
output_format = 'xml'

# Perform conversion
if args.recursive:
convert_imported(args.input, args.output,
input_format=input_format,
output_format=output_format,
url_from_catalog=args.url_from_catalog)
elif args.inferred:
g = squash_imported(args.input, None,
input_format=input_format)
fg = FaCTPPGraph(g)
if args.base_iri:
fg.base_iri = args.base_iri
g2 = fg.inferred_graph()
g2.serialize(destination=args.output, format=output_format)
elif args.squash:
squash_imported(args.input, args.output,
input_format=input_format,
output_format=output_format,
url_from_catalog=args.url_from_catalog)
else:
g = Graph()
g.parse(args.input, format=input_format)
g.serialize(destination=args.output, format=output_format)
try:
if args.recursive:
convert_imported(args.input, args.output,
input_format=input_format,
output_format=output_format,
url_from_catalog=args.url_from_catalog)
elif args.inferred:
g = squash_imported(args.input, None,
input_format=input_format)
fg = FaCTPPGraph(g)
if args.base_iri:
fg.base_iri = args.base_iri
g2 = fg.inferred_graph()
g2.serialize(destination=args.output, format=output_format)
elif args.squash:
squash_imported(args.input, args.output,
input_format=input_format,
output_format=output_format,
url_from_catalog=args.url_from_catalog)
else:
if (
not _validate_installed_version(
package="rdflib", min_version="6.0.0"
)
and (
output_format == FMAP.get("ttl", "")
or os.path.splitext(args.output)[1] == "ttl"
)
):
from rdflib import __version__ as __rdflib_version__

raise IncompatibleVersion(
"To correctly convert to Turtle format, rdflib must be version"
" 6.0.0 or greater, however, the detected rdflib version used "
f"by your Python interpreter is {__rdflib_version__!r}. For "
"more information see the 'Known issues' section of the README."
)

g = Graph()
g.parse(args.input, format=input_format)
g.serialize(destination=args.output, format=output_format)
except IncompatibleVersion as exc:
sys.exit(f"\033[91mERROR\033[0m: {exc}")


if __name__ == '__main__':
Expand Down