Latest Threat Research:SANDWORM_MODE: Shai-Hulud-Style npm Worm Hijacks CI Workflows and Poisons AI Toolchains.Details
Socket
Book a DemoInstallSign in
Socket

funowl

Package Overview
Dependencies
Maintainers
3
Versions
17
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

funowl - npm Package Compare versions

Comparing version
0.1.12
to
0.1.13
+1
.gitattributes
tests/data/cr.ofn.txt eol=crlf
[console_scripts]
funowl = funowl.cli:evaluate_cli
import sys
from argparse import ArgumentParser
from typing import Optional, Union, List
from rdflib import Graph
from rdflib.plugin import plugins as rdflib_plugins
from rdflib.serializer import Serializer as rdflib_serializer
from rdflib.util import guess_format
from .converters.functional_converter import to_python
valid_formats = ["ttl"] + sorted(
[x.name for x in rdflib_plugins(None, rdflib_serializer) if "/" not in str(x.name)]
)
DEFAULT_FORMAT = "ttl"
def genargs(prog: Optional[str] = None) -> ArgumentParser:
"""
Create a command line parser
:return: parser
"""
parser = ArgumentParser(prog, description="Convert OWL Functional Syntax to RDF")
parser.add_argument("input", help="Input OWL functional syntax. Can be a file name or URL")
parser.add_argument("output", help="Output file. If omitted, output goes to stdout", nargs='?')
parser.add_argument("-f", "--format", help="Output RDF Format. If omitted, guess from output file suffix.\n"
" If guessing doesn't work, assume 'turtle'",
choices=valid_formats)
parser.add_argument("-np", "--noProgressBar", help="Don't output the progress indicators", action="store_true")
return parser
def evaluate_cli(argv: Optional[Union[str, List[str]]] = None, prog: Optional[str] = None) -> int:
if isinstance(argv, str):
argv = argv.split()
opts = genargs(prog).parse_args(argv if argv is not None else sys.argv[1:])
# Read the functional syntax ontology
ontology = to_python(opts.input, print_progress=bool(opts.output) and not opts.noProgressBar)
# Convert to RDF
g = Graph()
ontology.to_rdf(g)
# Emit as appropriate
if opts.output:
g.serialize(opts.output, format=opts.format or guess_format(opts.output) or DEFAULT_FORMAT)
else:
print(g.serialize(format=opts.format or DEFAULT_FORMAT))
return 0
if __name__ == '__main__':
evaluate_cli(sys.argv[1:])
Prefix(:=<http://www.w3.org/2002/07/owl#>)
Prefix(owl:=<http://www.w3.org/2002/07/owl#>)
Prefix(rdf:=<http://www.w3.org/1999/02/22-rdf-syntax-ns#>)
Prefix(xml:=<http://www.w3.org/XML/1998/namespace>)
Prefix(xsd:=<http://www.w3.org/2001/XMLSchema#>)
Prefix(rdfs:=<http://www.w3.org/2000/01/rdf-schema#>)
Ontology(<http://www.w3.org/2002/07/owl>
<http://www.w3.org/2002/07/owl>
Import(<http://www.w3.org/2000/01/rdf-schema>)
Annotation(<http://purl.org/dc/elements/1.1/title> "The OWL 2 Schema vocabulary (OWL 2)")
Annotation(rdfs:comment "
This ontology partially describes the built-in classes and
properties that together form the basis of the RDF/XML syntax of OWL 2.
The content of this ontology is based on Tables 6.1 and 6.2
in Section 6.4 of the OWL 2 RDF-Based Semantics specification,
available at http://www.w3.org/TR/owl2-rdf-based-semantics/.
Please note that those tables do not include the different annotations
(labels, comments and rdfs:isDefinedBy links) used in this file.
Also note that the descriptions provided in this ontology do not
provide a complete and correct formal description of either the syntax
or the semantics of the introduced terms (please see the OWL 2
recommendations for the complete and normative specifications).
Furthermore, the information provided by this ontology may be
misleading if not used with care. This ontology SHOULD NOT be imported
into OWL ontologies. Importing this file into an OWL 2 DL ontology
will cause it to become an OWL 2 Full ontology and may have other,
unexpected, consequences.
")
Annotation(rdfs:isDefinedBy <http://www.w3.org/TR/owl2-mapping-to-rdf/>)
Declaration(AnnotationProperty(<http://purl.org/dc/elements/1.1/title>))
)

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

usage: cli [-h]
[-f {ttl,hext,json-ld,longturtle,n3,nquads,nt,nt11,ntriples,pretty-xml,trig,trix,ttl,turtle,xml}]
[-np]
input [output]
Convert OWL Functional Syntax to RDF
positional arguments:
input Input OWL functional syntax. Can be a file name or URL
output Output file. If omitted, output goes to stdout
options:
-h, --help show this help message and exit
-f {ttl,hext,json-ld,longturtle,n3,nquads,nt,nt11,ntriples,pretty-xml,trig,trix,ttl,turtle,xml}, --format {ttl,hext,json-ld,longturtle,n3,nquads,nt,nt11,ntriples,pretty-xml,trig,trix,ttl,turtle,xml}
Output RDF Format. If omitted, guess from output file
suffix. If guessing doesn't work, assume 'turtle'
-np, --noProgressBar Don't output the progress indicators

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

import argparse
import os.path
import unittest
from contextlib import redirect_stdout
from io import StringIO
from typing import List
from funowl import cli
CWD = os.path.dirname(__file__)
TEST_DATA_DIR = os.path.join(CWD, 'data')
UPDATE_OUTPUT_FILES = False
CLI_NAME = 'cli'
# Override the annoying argparse insistence on doing a sys.exit after help printed
class HelpPrintedException(Exception):
pass
def exit(parser, status=0, message=None):
raise HelpPrintedException(message)
class CLITestCase(unittest.TestCase):
@staticmethod
def _file_or_text(inp: str) -> str:
if '\n' in inp:
return inp
with open(os.path.join(TEST_DATA_DIR, inp)) as f:
return f.read()
def _compare_output(self, expected, actual) -> bool:
e_str = self._file_or_text(expected)
a_str = self._file_or_text(actual)
if e_str == a_str:
return True
# If expected is in the form of a file name, update the output
if e_str != expected: # expected is a file name
print(f">>> File: {e_str} has changed")
if UPDATE_OUTPUT_FILES:
with open(os.path.join(TEST_DATA_DIR, expected), 'w') as f:
f.write(actual)
return False or not UPDATE_OUTPUT_FILES
def _generate_file(self, infilename: str, outfilename: str, addl_params: List[str] = None) -> None:
args = [os.path.join(TEST_DATA_DIR, infilename), os.path.join(TEST_DATA_DIR, outfilename)]
if addl_params:
args += addl_params
cli.evaluate_cli(args, CLI_NAME)
def test_cli_help(self):
""" Test help function """
orig_exit = argparse.ArgumentParser.exit
argparse.ArgumentParser.exit = exit
with self.assertRaises(HelpPrintedException):
out_txt = StringIO()
with redirect_stdout(out_txt):
cli.evaluate_cli("-h", CLI_NAME)
argparse.ArgumentParser.exit = orig_exit
if not self._compare_output('cli_help.txt', out_txt.getvalue()):
self.fail(msg="Help output has changed!")
def test_cli_conversion(self):
""" Test basic conversion """
self._generate_file('pizza.owl', 'pizza_out.ttl')
def test_auto_output_type(self):
""" Test that output file name suffixes are recognized """
# Should generate json-ld
self._generate_file('pizza.owl', 'pizza_out.jsonld')
# Should generate owl (explicit)
self._generate_file('pizza.owl', 'pizza_out2.jsonld', ["-f", "hext"])
# Not sure
self._generate_file('pizza.owl', 'pizza_out3.foo')
def test_cli_options(self):
""" Make sure that file name suffixes are recognized """
cli.evaluate_cli(
[os.path.join(TEST_DATA_DIR, 'basic.owl'), os.path.join(TEST_DATA_DIR, 'basic_out.n3')],
CLI_NAME)
# Dots shouldn't be printed if "-np" or output is to stdout
output = StringIO()
with redirect_stdout(output):
cli.evaluate_cli(
[os.path.join(TEST_DATA_DIR, 'pizza.owl'), os.path.join(TEST_DATA_DIR, 'pizza_out4.n3'), '-np'],
CLI_NAME)
cli.evaluate_cli(
[os.path.join(TEST_DATA_DIR, 'pizza.owl')],
CLI_NAME)
self.assertNotIn(".....", output.getvalue())
if __name__ == '__main__':
unittest.main()
import os
import unittest
from io import StringIO
from funowl.converters.functional_converter import to_python
from tests import datadir
class CRTestCase(unittest.TestCase):
""" Test issue_45 - error thrown if literals contain carriage returns """
def test_cr_issue(self):
owl = None
with open(os.path.join(datadir, 'cr.ofn.txt')) as f:
owl = to_python(f.read())
self.assertTrue(str(owl.ontology.annotations[1].value.v).startswith("\n This ontology partially"))
if __name__ == '__main__':
unittest.main()
import os
import unittest
from rdflib import Graph
from funowl.converters.functional_converter import to_python
from tests import datadir
class FunctionalToRDFTestCase(unittest.TestCase):
""" Demo of how one goes about converting functional syntax to RDF """
def test_fun_to_rdf(self):
# The functional syntax input can be a string, URL, file loc or open file
function_pizza = os.path.join(datadir, 'pizza.owl')
internal_pizza = to_python(function_pizza)
# Emit the internal representation as an rdflib graph
g = Graph()
internal_pizza.to_rdf(g)
# Serialize the rdflib graph in your favorite format
turtle_pizza = os.path.join(datadir, 'pizza_out.ttl')
g.serialize(turtle_pizza)
if __name__ == '__main__':
unittest.main()
import unittest
from dataclasses import dataclass
from typing import Tuple, Optional, List, Dict
import rdflib
import rdflib_shim
# Make sure the import above works
shimed = rdflib_shim.RDFLIB_SHIM
# Code to evaluate how we can use the rdflib namespace library to manage our namespace behavior. What we need in
# funowl is:
# 1) Assign multiple prefixes to the same URI including the default ('') prefix
# 2) Map a curie (well - strictly speaking, PNAME_LN as defined in
# https://www.w3.org/TR/2008/REC-rdf-sparql-query-20080115/#QSynIRI) to a corresponding URI using _any_
# prefix defined in the Prefixes section
# 3) Map a URI to a curie:
# a) Using the longest mapped URI possible and
# b) Using the most recent declared URI mapping in the case of duplicates
# 4) Validate and, when necessary escape URI syntax
# 5) Raise an exception when the same prefix is mapped to two different URIs
# 6) Raise an exception when the following prefixes (from table 2 in the functional spec) are declared
# rdf, rdfs, xsd, owl
#
# The closest we can get in rdflib 6.2.0 is
# 1) We NEVER want to use bind(..., replace=False, ...). Mangled namespaces are not good things.
# 2) We have to preserve ALL prefix/URI mappings, not just the latest
# 3) We have to reject any duplicate prefix declarations
# 2) RDFlib 6.2.0 treats namespaces as a unique dictionary -- you can never have more than one prefix. This is NOT
# the behavior we need to implement.
# 3) the namespace_with_bind_override_fix == False appears to replicate some sort of earlier bug that we don't care
# about.
EX = "http://example.org/ns1#"
EXNS = rdflib.Namespace(EX)
EXURI = rdflib.URIRef(EX)
EX2 = "http://example.org/ns2#"
EX2NS = rdflib.Namespace(EX2)
EX2URI = rdflib.URIRef(EX2)
PRINT_OUTPUT = False # Print tabular output
using_rdflib_v6 = rdflib.__version__ >= "6.2"
using_rdflib_v5 = rdflib.__version__.startswith("5.0.0")
ignore_prefixes = ['xml', 'rdf', 'rdfs', 'xsd', 'owl']
print(f"===== TESTING RDFLIB VERSION: {rdflib.__version__}")
@unittest.skipUnless(using_rdflib_v5 or using_rdflib_v6, "Tests skipped on unrecognized versions of rdflib")
class RDFLIBNamespaceBindingTestCase(unittest.TestCase):
"""
Until recently, we have been using the rdflib namespace manager to handle the functional declarations. The 6.x
release of rdflib, however, has linked the namespace management more tightly with the behavior expected in
the RDF world.
"""
@dataclass
class EvalResult:
patch: bool # rdflib.namespace._with_bind_override_fix
replace: bool
override: bool
result: List[Tuple[str, str]]
@staticmethod
def hdr() -> str:
""" Print a table header """
return "patch\treplace\toverride\tresult\n-----\t-------\t--------\t--------------"
def __str__(self):
""" Print the actual result """
result_str = ' '.join([f"({prefix}:, {ns})" for prefix, ns in self.result])
return f"{self.patch}\t{self.replace}\t{self.override}\t\t{result_str}"
@staticmethod
def print_output(hdr: str) -> None:
if PRINT_OUTPUT:
print(f"\n===== {hdr} =====")
print(RDFLIBNamespaceBindingTestCase.EvalResult.hdr())
@staticmethod
def graph_bindings_dict(g: rdflib.Graph) -> Dict[str, str]:
""" Return non-iggnored graph namespaces as a dictionary """
return {prefix: str(uri) for prefix, uri in g.namespaces() if prefix not in ignore_prefixes}
@staticmethod
def graph_bindings_tuples(g: rdflib.Graph) -> List[Tuple[str, str]]:
""" Return non-ignored graph namespaces as tuples """
return [(prefix, uri) for prefix, uri in g.namespaces() if prefix not in ignore_prefixes]
@staticmethod
def eval_options(bindings: List[Tuple[Optional[str], str]]) -> List[EvalResult]:
""" Evaluate how _bindings_ are interpreted using the _replace_, _override_ and _patch_ variables """
rval = []
for patch in (True, False):
for replace in (True, False):
for override in (True, False):
rdflib.namespace._with_bind_override_fix = patch
g = rdflib.Graph()
for prefix, ns in bindings:
g.bind(prefix, ns, override=override, replace=replace)
rval.append(
RDFLIBNamespaceBindingTestCase.EvalResult(
patch, replace, override, RDFLIBNamespaceBindingTestCase.graph_bindings_tuples(g)))
return rval
def run_test(self, hdr: str, bindings: List[Tuple[Optional[str], str]]) -> List[EvalResult]:
""" Run a particular binding test and return the result """
self.print_output(hdr)
rslt = self.eval_options(bindings)
if PRINT_OUTPUT:
for opt in self.eval_options(bindings):
print(str(opt))
return rslt
def test_decl_default(self):
""" Test a namespace followed by a default for the same URI """
rslt = self.run_test("EX: ns1, : ns1", [('EX', EX), (None, EX)])
for er in rslt:
# We should have two declarations
if er.override:
self.assertEqual(2, len(er.result))
self.assertEqual({('EX', EXURI), ('', EXURI)}, set(er.result))
def test_decl_default_rev(self):
""" Test a default followed by a namespace for the same URI """
rslt = self.run_test(": ns1, EX: ns1", [(None, EXURI), ('EX', EXURI)])
for er in rslt:
# We should have two declarations
if er.override:
self.assertEqual(2, len(er.result))
self.assertEqual({('EX', EXURI), ('', EXURI)}, set(er.result))
def test_two_namespaces(self):
""" Test two prefixes with the same URI """
rslt = self.run_test("EXA: ns1, EXB: ns1", [('EXA', EXURI), ('EXB', EXURI)])
for er in rslt:
# We should have two declarations
if er.override:
self.assertEqual(2, len(er.result))
self.assertEqual({('EXA', EXURI), ('EXB', EXURI)}, set(er.result))
def test_two_diff_namespaces(self):
""" Test the same prefix with two different URIs
rdlib 6.2.0 -- if _replace_ and _override_ use last namespace
if _replace_ and not _override_ and _patch_ use first namespace
if _replace_ and not _override_ and not _patch_ use last namespace
if not _replace_ mangle second namespace (NEVER desirable)
"""
rslt = self.run_test("EXA: ns1, EXA: ns2", [('EXA', EX), ('EXA', EX2)])
for er in rslt:
# We should have two declarations
if er.replace:
self.assertEqual(1, len(er.result))
self.assertEqual({('EXA', EX2URI)}, set(er.result))
def test_two_defaults(self):
"""
Test two default declarations for the same URI
rdlib 6.2.0 -- if _replace_ and _override_ use last namespace
-- if _replace_ and not _override_ use first namespace
-- if not _replace_ last namespace prefix is "default1" (NEVER desirable)
"""
rslt = self.run_test(": ns1, : ns2", [(None, EX), (None, EX2)])
for evalresult in rslt:
# We should have two declarations
if evalresult.replace:
self.assertEqual(1, len(evalresult.result))
self.assertEqual({('', EX2URI)}, set(evalresult.result))
def test_three_turtle_namespaces(self):
""" Examine how rdflib handles two namespaces and a default w/ same URI """
turtle = """@prefix : <http://example.org/ns1#> .
@prefix NSA: <http://example.org/ns1#> .
@prefix NSB: <http://example.org/ns1#> .
NSA:foo NSB:bar :fee ."""
# The n3 (turtle) parser maintains its own namespace system to map the above code to the correct URI's
g = rdflib.Graph()
g.parse(data=turtle, format="turtle")
output_ttl = g.serialize(format="turtle")
# V6 returns a string, V5 returns a bytearray. This is NOT backwards compatible
# rdflib_shim takes care of this issue
# In both versions, only the last version is preserved on output
self.assertEqual("""@prefix NSB: <http://example.org/ns1#> .
NSB:foo NSB:bar NSB:fee .""", output_ttl.strip())
nsdict = self.graph_bindings_dict(g)
# NSB exists in both versions
self.assertIn("NSB", nsdict)
# But NSA and default is only available in v5
if using_rdflib_v5:
self.assertIn("NSA", nsdict)
self.assertIn("", nsdict)
self.assertEqual({'': 'http://example.org/ns1#',
'NSA': 'http://example.org/ns1#',
'NSB': 'http://example.org/ns1#'}, nsdict)
elif using_rdflib_v6:
self.assertNotIn("NSA", nsdict)
self.assertNotIn("", nsdict)
self.assertEqual({'NSB': 'http://example.org/ns1#'}, nsdict)
# All the above are expected to fail in v6 and pass in v5
test_decl_default.__unittest_expecting_failure__ = using_rdflib_v6
test_decl_default_rev.__unittest_expecting_failure__ = using_rdflib_v6
test_two_defaults.__unittest_expecting_failure__ = using_rdflib_v6
test_two_diff_namespaces.__unittest_expecting_failure__ = using_rdflib_v6
test_two_namespaces.__unittest_expecting_failure__ = using_rdflib_v6
@unittest.skipUnless(using_rdflib_v6, "expand_curie is only a v6 function")
def test_rdflib_v6_expand_curie(self):
""" Evaluate v6 (only) curie expansion function """
turtle = """@prefix : <http://example.org/ns1#> .
@prefix NSA: <http://example.org/ns1#> .
@prefix NSB: <http://example.org/ns1#> .
NSA:foo NSB:bar :fee ."""
# The n3 (turtle) parser maintains its own namespace system to map the above code to the correct URI's
g = rdflib.Graph()
g.parse(data=turtle, format="turtle")
# The good news is that v6 has an _expand_curie_ function:
self.assertEqual("http://example.org/ns1#test1", str(g.namespace_manager.expand_curie("NSB:test1")))
# The bad news, however, is 1) It won't work against all curies
with self.assertRaises(ValueError) as e:
self.assertEqual("http://example.org/ns1#test1", str(g.namespace_manager.expand_curie("NSA:test1")))
self.assertIn('Prefix "NSA" not bound to any namespace', str(e))
# and 2) it doesn't recognize the default namespace, period
with self.assertRaises(ValueError) as e:
self.assertEqual("http://example.org/ns1#test1", str(g.namespace_manager.expand_curie(":test1")))
self.assertIn('Malformed curie argument', str(e))
# Even if we explicitly add it
g.bind("", "http://example.org/ns1#", override=True, replace=True)
self.assertIn("", {prefix: ns for prefix, ns in g.namespaces()})
with self.assertRaises(ValueError) as e:
self.assertEqual("http://example.org/ns1#test1", str(g.namespace_manager.expand_curie(":test1")))
self.assertIn('Malformed curie argument', str(e), "expand_curie simply doesn't recognize defaults")
def test_rdflib_heisenberg(self):
""" In which we demonstrate that the act of observing namespaces changes them """
# If we wait until the end to print the bindings, the default namespace goes away
g = rdflib.Graph()
g.bind('', EX)
g.bind('NSA', EX)
g.add((EXNS.s1, EXNS.p1, EXNS.o1))
g.add((EXNS.s2, EXNS.p2, EXNS.o2))
self.assertEqual("""@prefix NSA: <http://example.org/ns1#> .
NSA:s1 NSA:p1 NSA:o1 .
NSA:s2 NSA:p2 NSA:o2 .""", g.serialize(format="turtle").strip())
# If we print the bindings in the middle, both namespaces remain
g = rdflib.Graph()
g.bind('', EX)
g.add((EXNS.s1, EXNS.p1, EXNS.o1))
g.serialize(format="turtle")
g.bind('NSA', EX)
g.add((EXNS.s2, EXNS.p2, EXNS.o2))
self.assertEqual("""@prefix : <http://example.org/ns1#> .
@prefix NSA: <http://example.org/ns1#> .
:s1 :p1 :o1 .
NSA:s2 NSA:p2 NSA:o2 .""", g.serialize(format="turtle").strip())
if __name__ == '__main__':
unittest.main()
import unittest
from rdflib import Graph, URIRef
class RDFLIBCacheBugTestCase(unittest.TestCase):
def test_cache_bug(self):
g = Graph()
# Prime the cache w/ myns
g.parse(data="""
@prefix MYNS: <http://funkyurl.org/> .
MYNS:Foo a MYNS:Bar .""", format="turtle")
g.serialize(format="turtle")
# Remove MYNS
g.bind('YOURNS', 'http://funkyurl.org/')
# Re-add MYNS with a different URL
g.bind('MYNS', 'http://gotcha.org/', replace=True)
g.add((URIRef('http://funkyurl.org/SAM'), URIRef('http://funkyurl.org/SAM'), URIRef('http://funkyurl.org/SAM')))
self.assertEqual("""@prefix MYNS: <http://funkyurl.org/> .
@prefix YOURNS: <http://funkyurl.org/> .
MYNS:Foo a MYNS:Bar .
YOURNS:SAM YOURNS:SAM YOURNS:SAM .""", g.serialize(format="turtle").decode().strip())
if __name__ == '__main__':
unittest.main()
import re
from typing import Tuple, Set, Optional
from unittest import TestCase
from rdflib import RDFS
prefixes_re = re.compile(r"^(?:\s*Prefix\( (.*?) \))", flags=re.MULTILINE)
ontology_re = re.compile(r"Ontology\((.*)\)\s*$", flags=re.MULTILINE+re.DOTALL)
def _parse_output(t: str) -> Tuple[Set[str], str]:
""" Convert a functional syntax output into a list of prefixes and the ontology definition"""
prefixes = set()
m = None
for m in prefixes_re.finditer(t):
prefixes.add(m.group(1))
lastcol = m.regs[0][1] if m is not None else 0
ontology = ontology_re.findall(t[lastcol:])
return prefixes, ontology[0] if len(ontology) else ""
def compare_functional_output(expected: str, actual: str, caller: TestCase, msg: Optional[str]) -> None:
""" Compare expected functional syntax to actual functional syntax taking random order of prefixes into account """
expected_prefixes, expected_ontology = _parse_output(expected)
actual_prefixes, actual_ontology = _parse_output(actual)
if actual_prefixes != expected_prefixes:
in_actual_only = sorted(list(actual_prefixes - expected_prefixes))
in_expected_only = sorted(list(expected_prefixes - actual_prefixes))
if in_actual_only:
in_actual_list = "\n\t\t".join(sorted(in_actual_only))
expanded_msg = f"""\n\tUnexpected prefixes:\n\t\t{in_actual_list}\n\t"""
else:
expanded_msg = ""
if in_expected_only:
# If the only issue is an extra RDFS, let it slide. Older rdflibs put it in unasked
if not in_actual_only and len(in_expected_only) == 1 and str(RDFS) in in_expected_only[0]:
pass
else:
in_expected_list = "\n\t\t".join(sorted(in_expected_only))
expanded_msg += ("\n\t" if expanded_msg else "") + f"""Missing prefixes:\n\t\t{in_expected_list}"""
if expanded_msg:
caller.fail(expanded_msg + (msg if msg else ""))
caller.assertEqual(expected_ontology, actual_ontology, msg)
if __name__ == '__main__':
inside = """A bunch o
Inside
stuff
Including a "deeply 'embedded Prefix( foo = bar )` as well as a paren and an inner ) Ontology( NOT HERE!!! )
"""
test = f"""Prefix( xml: = <http://www.w3.org/XML/1998/namespace> )
Prefix( rdf: = <http://www.w3.org/1999/02/22-rdf-syntax-ns#> )
Prefix( rdfs: = <http://www.w3.org/2000/01/rdf-schema#> )
Prefix( xsd: = <http://www.w3.org/2001/XMLSchema#> )
Prefix( owl: = <http://www.w3.org/2002/07/owl#> )
Ontology({inside} )"""
test2 = """ Prefix( xml: = <http://example.org/xml2#> )
Prefix( rdf: = <http://www.w3.org/1999/02/22-rdf-syntax-ns#> )
Prefix( rdfs: = <http://www.w3.org/2000/01/rdf-schema#> )
Prefix( xsd: = <http://www.w3.org/2001/XMLSchema#> )
Prefix( owl: = <http://www.w3.org/2002/07/owl#> )
Prefix( : = <http://www.w3.org/2002/07/owl#> )"""
test2_prefixes = {'xsd: = <http://www.w3.org/2001/XMLSchema#>',
'owl: = <http://www.w3.org/2002/07/owl#>',
'rdfs: = <http://www.w3.org/2000/01/rdf-schema#>',
': = <http://www.w3.org/2002/07/owl#>',
'xml: = <http://example.org/xml2#>',
'rdf: = <http://www.w3.org/1999/02/22-rdf-syntax-ns#>'}
class QuickTest(TestCase):
def test_comparator(self):
compare_functional_output(test, test, self, "Testing utility failed")
def test_parser(self):
self.assertEqual(_parse_output(test2), (test2_prefixes, ""))
compare_functional_output(test2, test2, self, "Testing utility failed 2")
qt = QuickTest()
qt.test_comparator()
qt.test_parser()
print("compare_functional_output passes")
+3
-3

@@ -8,2 +8,3 @@ name: Build

update-requirements:
if: False
runs-on: ubuntu-latest

@@ -14,3 +15,3 @@ steps:

with:
python-version: 3.8
python-version: 3.11
- uses: dschep/install-pipenv-action@v1

@@ -34,3 +35,2 @@ - name: Update requirements

test:
needs: update-requirements
name: Run TOX tests

@@ -40,3 +40,3 @@ runs-on: ubuntu-latest

matrix:
python-version: [ 3.8, 3.9, "3.10" ]
python-version: [ 3.8, 3.9, "3.10", "3.11" ]

@@ -43,0 +43,0 @@ steps:

@@ -1,1 +0,1 @@

Harold Solbrig <solbrig@jhu.edu>
Harold Solbrig <github@solbrigs.us>

@@ -1,1 +0,1 @@

{"git_version": "4086331", "is_release": false}
{"git_version": "d146cfd", "is_release": false}
Metadata-Version: 1.2
Name: funowl
Version: 0.1.12
Version: 0.1.13
Summary: Python rendering of the OWL Functional syntax

@@ -5,0 +5,0 @@ Home-page: http://biolink.github.io/hsolbrig

bcp47
jsonasobj
pyjsg>=0.11.6
rdflib-shim
rdflib>=5.0.0
rdflib==6.2.0
rfc3987

@@ -94,2 +94,4 @@ import logging

class FunOwlBase(FunOwlRoot, metaclass=FunOwlBaseMeta):
pass
def _subjects(self, g: Graph) -> List[SUBJ]:
# This should never get called. If it does, FunOwlRoot will raise a notimplemented error.
return super()._subjects(g)

@@ -273,3 +273,4 @@ import logging

def fparse(inp: bytes, start: int, consumer: Callable[[FunOwlBase], None]) -> int:
def fparse(inp: bytes, start: int, consumer: Callable[[FunOwlBase], None], print_progress: bool = True) -> int:
"""

@@ -280,2 +281,3 @@ Functional parser - work through inp pulling complete functions out and processing them.

:param consumer: OWLFunc entry consumer
:param print_progress: Print conversion progress indicator on command line
:return: final position

@@ -303,3 +305,3 @@ """

start = skip_comments(inp, start)
start = fparse(inp, start, lambda f: o.add_arg(f))
start = fparse(inp, start, lambda f: o.add_arg(f, print_progress=print_progress))
consumer(o)

@@ -341,6 +343,7 @@ start = skip_comments(inp, start)

def to_python(defn: Union[str, bytes, IO]) -> Optional[OntologyDocument]:
def to_python(defn: Union[str, bytes, IO], print_progress: bool = True) -> Optional[OntologyDocument]:
"""
Convert the functional syntax in defn to a Python representation
:param defn: The ontology definition
:param print_progress: Print progress indicator on command line
:return: Ontology Document

@@ -357,3 +360,3 @@ """

ontology_doc = OntologyDocument()
fparse(to_bytes_array(defn), 0, consumer)
fparse(to_bytes_array(defn), 0, consumer, print_progress=print_progress)
return ontology_doc

@@ -134,2 +134,12 @@ """

prefix, name = self.split(':', 1)
return URIRef(g.namespace_manager.store.namespace(prefix or "") + name)
namespace = g.namespace_manager.store.namespace(prefix or "")
if namespace:
return URIRef(namespace + name)
# RDFLIB 6.2.0 and beyond only allow one namespace, meaning that our NS may no longer be there.
# We now keep track of the original declarations to see whether we can find it in a pinch
from funowl import IRI
rval = IRI.prefix_declarations.as_uri(prefix, name) if IRI.prefix_declarations else None
if not rval:
raise ValueError(f"Unrecognized prefix: {prefix}")
return rval
""" IRI := fullIRI | abbreviatedIRI """
import logging
from dataclasses import dataclass, Field
from typing import Union, ClassVar, Optional, Type, List
from dataclasses import dataclass
from typing import Union, ClassVar, Optional, List

@@ -12,2 +12,3 @@ from rdflib import URIRef, Namespace, Graph, RDF, OWL, XSD, RDFS

from funowl.general_definitions import FullIRI, AbbreviatedIRI
from funowl.prefix_declarations import PrefixDeclarations
from funowl.writers.FunctionalWriter import FunctionalWriter

@@ -20,3 +21,5 @@

v: Union[AbbreviatedIRI, FullIRI, URIRef, str] = exclude([URIRef, str])
rdf_type: ClassVar[URIRef] = None
prefix_declarations: ClassVar[PrefixDeclarations] = None # Link to prefixes section, if declared

@@ -27,17 +30,12 @@ # def __post_init__(self):

def full_uri(self, g: Graph) -> Optional[URIRef]:
if isinstance(self.v, URIRef):
return self.v
if isinstance(self.v, AbbreviatedIRI):
# TODO: find the code in rdflib that does this
ns, local = self.v.split(':', 1)
for ns1, uri in g.namespaces():
if ns == ns1:
return(Namespace(uri)[local])
logging.warning(f"IRI: {self.v} - {ns} not a valid prefix")
return None
if isinstance(self.v, FullIRI):
if not isinstance(self.v, AbbreviatedIRI):
return URIRef(self.v)
prefix, lname = str(self).split(':', 1)
if self.prefix_declarations and prefix in self.prefix_declarations:
return self.prefix_declarations[prefix] + lname
return self.v.to_rdf(g)
def to_functional(self, w: FunctionalWriter) -> FunctionalWriter:
fulluri = self.full_uri(w.g)
""" Emit an abbreviated URI if possible, otherwise a full one """
fulluri = None if isinstance(self.v, AbbreviatedIRI) else self.full_uri(w.g)
return w + (fulluri.n3(w.g.namespace_manager) if fulluri else self.v)

@@ -44,0 +42,0 @@

@@ -24,2 +24,3 @@ """

class AnonymousIndividual(NodeID):

@@ -26,0 +27,0 @@ def to_rdf(self, g: Graph, emit_type_arc: bool = False) -> BNode:

@@ -35,3 +35,3 @@ """

from funowl.objectproperty_expressions import ObjectPropertyExpression
from funowl.prefix_declarations import Prefix
from funowl.prefix_declarations import Prefix, PrefixDeclarations
from funowl.terminals.TypingHelper import isinstance_, proc_forwards

@@ -46,2 +46,3 @@ from funowl.writers.FunctionalWriter import FunctionalWriter

@dataclass

@@ -57,3 +58,3 @@ class Import(FunOwlBase):

def to_rdf(self, _: Graph) -> Optional[NODE]:
def to_rdf(self, _: Graph, emit_type_arc: Optional[bool] = False) -> Optional[NODE]:
return URIRef(str(self.ontology_iri()))

@@ -97,16 +98,17 @@

def add_arg(self, arg: [IRI.types(), Import, Axiom, Annotation]):
def add_arg(self, arg: [IRI.types(), Import, Axiom, Annotation], print_progress: bool = True):
if isinstance_(arg, Axiom):
self.axioms.append(arg)
self._naxioms += 1
if not self._naxioms % 100000:
print(self._naxioms)
elif not self._naxioms % 10000:
print(self._naxioms)
elif not self._naxioms % 1000:
print('k', end='')
sys.stdout.flush()
elif not self._naxioms % 100:
print('.', end='')
sys.stdout.flush()
if print_progress:
self._naxioms += 1
if not self._naxioms % 100000:
print(self._naxioms)
elif not self._naxioms % 10000:
print(self._naxioms)
elif not self._naxioms % 1000:
print('k', end='')
sys.stdout.flush()
elif not self._naxioms % 100:
print('.', end='')
sys.stdout.flush()
elif isinstance(arg, IRI):

@@ -140,5 +142,5 @@ if not self.iri:

if not issubclass(type(sub), Class) and isinstance(sub, Class):
sub = Class(sub)
pass
if not issubclass(type(sup), Class) and isinstance(sup, Class):
sup = Class(sup)
pass
self.axioms.append(SubClassOf(sub, sup))

@@ -191,3 +193,3 @@ return self

for individual in individuals:
self.axioms.append(NamedIndividual(individual))
self.axioms.append(Declaration(NamedIndividual(individual)))
return self

@@ -256,7 +258,8 @@

"""
prefixDeclarations: List[Prefix] = empty_list_wrapper(Prefix)
prefixDeclarations: PrefixDeclarations = None
ontology: Ontology = None
def __init__(self, default_prefix: FullIRI = None, ontology: Optional[Ontology] = None, **prefixes: FullIRI):
self.prefixDeclarations = []
def __init__(self, default_prefix: Union[FullIRI, Namespace, str] = None, ontology: Optional[Ontology] = None,
**prefixes: Union[FullIRI, Namespace, str]):
self.prefixDeclarations = PrefixDeclarations()
self.ontology = ontology if ontology is not None else Ontology()

@@ -285,3 +288,3 @@ if default_prefix:

if isinstance(item, PrefixName):
for p in self.prefixDeclarations:
for p in self.prefixDeclarations.as_prefixes():
if p.prefixName == item:

@@ -295,4 +298,17 @@ return p.fullIRI

def add_namespaces(self, g: Graph, add_funowl_namespace: bool = False) -> Graph:
for prefix in self.prefixDeclarations:
g.namespace_manager.bind(str(prefix.prefixName or ''), str(prefix.fullIRI), True, True)
"""
Transfer the namespace declarations included in the prefixDeclarations section into the rdflib Graph.
Note: rdflib 6.2.0 and up only associates ONE prefix with every unique URI. Adding a second prefix will
delete the first, which can pose real issues for code like this. You have to use the prefixDeclarations
package to transform AbbreviatedIRI's into URI's, as they might disappear in rdflib. When going from IRIs
back to Abbreviated IRIs, we use the _last_prefix declared with one exception: the default prefix is always
preferred over a named prefix.
:param g: rdflib graph to transfer to
:param add_funowl_namespace: True means add our own namespace in
:return: g with namespaces added.
"""
for prefix in self.prefixDeclarations.as_prefixes():
g.namespace_manager.bind(str(prefix.prefixName or ''), str(prefix.fullIRI), override=True, replace=False)
if add_funowl_namespace:

@@ -304,5 +320,6 @@ g.namespace_manager.bind(FUNOWL_NAMESPACE, FUNOWL_URI)

""" Return a FunctionalWriter instance with the representation of the OntologyDocument in functional syntax """
IRI.prefix_declarations = self.prefixDeclarations
w = w or FunctionalWriter()
self.add_namespaces(w.g)
return w.iter([Prefix(ns, uri) for ns, uri in w.g.namespaces()], indent=False).hardbr() + \
return w.iter(self.prefixDeclarations.as_prefixes(), indent=False).hardbr() + \
(self.ontology or Ontology())

@@ -312,2 +329,3 @@

""" Convert the ontology document into RDF representation """
IRI.prefix_declarations = self.prefixDeclarations
self.add_namespaces(g, add_funowl_namespace=emit_functional_definitions)

@@ -314,0 +332,0 @@ return self.ontology.to_rdf(g, emit_type_arc, emit_functional_definitions)

from dataclasses import dataclass
from typing import Optional, List, Union
from typing import Optional, Union, Iterable, Dict
from rdflib import Graph
from rdflib.namespace import NamespaceManager, OWL
from rdflib import Graph, RDF, RDFS, XSD, OWL, Namespace
from rdflib.namespace import NamespaceManager
from rdflib.term import URIRef
from funowl.base.cast_function import exclude
from funowl.base.fun_owl_base import FunOwlBase

@@ -13,7 +12,10 @@ from funowl.general_definitions import PrefixName, FullIRI

PREFIX_NAME_TYPE = Optional[Union[PrefixName, str]]
FULL_IRI_TYPE = Union[FullIRI, Namespace, URIRef, str]
@dataclass
class Prefix(FunOwlBase):
prefixName: Optional[Union[PrefixName, str]]
fullIRI: FullIRI
prefixName: PREFIX_NAME_TYPE # Always recorded as PrefixName
fullIRI: FULL_IRI_TYPE # Always recorded as FullURI

@@ -23,3 +25,8 @@ def __post_init__(self):

self.prefixName = PrefixName(self.prefixName)
if not isinstance(self.fullIRI, FullIRI):
self.fullIRI = FullIRI(self.fullIRI)
def __hash__(self):
return hash(self.prefixName)
def to_functional(self, w: FunctionalWriter) -> FunctionalWriter:

@@ -30,12 +37,36 @@ return w.func(self, lambda: w.concat((self.prefixName or '') + ':', '=',

# Table 2. Declarations of the Standard Prefix Names
# Prefix name Prefix IRI
# rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
# rdfs: <http://www.w3.org/2000/01/rdf-schema#>
# xsd: <http://www.w3.org/2001/XMLSchema#>
# owl: <http://www.w3.org/2002/07/owl#>
RDF_PREFIX = Prefix('rdf', str(RDF))
RDFS_PREFIX = Prefix('rdfs', str(RDFS))
XSD_PREFIX = Prefix('xsd', str(XSD))
OWL_PREFIX = Prefix('owl', str(OWL))
# DEFAULT_PREFIX = Prefix(None, str(OWL))
PREFIX_PRESETS = {RDF_PREFIX, RDFS_PREFIX, XSD_PREFIX, OWL_PREFIX}
class PrefixDeclarations(NamespaceManager):
def __init__(self, g: Optional[Graph] = None) -> None:
self._init = True
super().__init__(g if g is not None else Graph())
self.bind('owl', OWL)
self._prefixMap: Dict[str, Prefix] = dict()
super().__init__(g or Graph())
for prefix in PREFIX_PRESETS:
self.bind(prefix.prefixName, prefix.fullIRI)
self._init = False
def as_prefixes(self) -> List[Prefix]:
def __contains__(self, item: Union[Prefix, str]) -> bool:
return str(item) in self._prefixMap
def __getitem__(self, item: Union[Prefix, str]) -> URIRef:
entry = self._prefixMap.get(str(item))
return URIRef(entry.fullIRI)
def as_prefixes(self) -> Iterable[Prefix]:
""" Return the contents of the manager as a list of Prefixes """
return [Prefix(ns if ns else None, uri) for (ns, uri) in self.namespaces()]
return self._prefixMap.values()

@@ -46,3 +77,3 @@ def __setattr__(self, key, value):

else:
self.append(Prefix(key, value))
self.bind(key, value)

@@ -52,7 +83,21 @@ def append(self, decl: Prefix) -> None:

def bind(self, prefix, namespace, override=True, replace=True):
""" Bind with override and replace defaults changed """
super().bind(str(prefix) if prefix is not None else None, str(namespace), override, replace)
def as_uri(self, prefix: Union[Prefix, str], namespace: str) -> Optional[URIRef]:
"""
Map prefix/namespace into a URI
:param prefix:
:param namespace:
:return:
"""
prefix = str(prefix) if prefix else '' # Guard against None creeping in
if prefix in self._prefixMap:
return URIRef(self._prefixMap[prefix].fullIRI + namespace)
return None
def bind(self, prefix: PREFIX_NAME_TYPE, namespace: FULL_IRI_TYPE, _=True, __=True):
""" Bind w/ defaults overriden """
prefix = str(prefix) if prefix else ''
self._prefixMap[prefix] = Prefix(prefix, str(namespace))
super().bind(prefix, str(namespace), override=True, replace=True)
def to_functional(self, w: FunctionalWriter) -> FunctionalWriter:
return w.iter(self.as_prefixes(), indent=False)

@@ -1,2 +0,2 @@

from typing import List, Optional, Callable, Union, Any
from typing import List, Optional, Callable, Union, Any, Iterable

@@ -143,3 +143,3 @@ from rdflib import Graph, OWL, URIRef

Generate a functional method in the form of "func( ... )"
:param func_name: Function name or object. If object, the class name is used

@@ -160,3 +160,3 @@ :param contents: Invoked to generate function contents

def iter(self, *objs: List[Any], f: Optional[Callable[[Any], "FunctionalWriter"]] = None, indent: bool=True) \
def iter(self, *objs: Iterable[Any], f: Optional[Callable[[Any], "FunctionalWriter"]] = None, indent: bool = True) \
-> "FunctionalWriter":

@@ -186,3 +186,3 @@ """

def opt(self, v: Optional[Any], sep: str = ' ') -> "FunctionalWriter":
""" Emit v if it exists
""" Emit v if it exists
:param v: Optional item to emit

@@ -189,0 +189,0 @@ :param sep: separator

@@ -10,3 +10,3 @@ [[source]]

[packages]
rdflib = ">=5.0.0"
rdflib = "==6.2.0"
rdflib-shim = "*"

@@ -16,1 +16,2 @@ pyjsg = ">=0.11.6"

bcp47 = "*"
jsonasobj = "*"
Metadata-Version: 1.2
Name: funowl
Version: 0.1.12
Version: 0.1.13
Summary: Python rendering of the OWL Functional syntax

@@ -5,0 +5,0 @@ Home-page: http://biolink.github.io/hsolbrig

+100
-0

@@ -124,3 +124,103 @@ ![Owl in a bucket](images/owlinbucket.jpg)

```
## Transforming Functional Syntax to RDF
See: [test_issue_57.py](tests/test_issues/test_issue_57.py) for full example
```python
from rdflib import Graph
from funowl.converters.functional_converter import to_python
# The functional syntax input can be a string, URL, file loc or open file
function_pizza = "https://github.com/Harold-Solbrig/funowl/blob/main/tests/data/pizza.owl"
internal_pizza = to_python(function_pizza)
# Emit the internal representation as an rdflib graph
g = Graph()
internal_pizza.to_rdf(g)
# Serialize the rdflib graph in your favorite format
print(g.serialize(format="ttl"))
```
## Command Line Interface
`funowl` can be installed with either `pip` or `pipenv`.
```shell
> funowl -h
usage: funowl [-h]
[-f {ttl,hext,json-ld,longturtle,n3,nquads,nt,nt11,ntriples,pretty-xml,trig,trix,ttl,turtle,xml}]
[-np]
input [output]
Convert OWL Functional Syntax to RDF
positional arguments:
input Input OWL functional syntax. Can be a file name or URL
output Output file. If omitted, output goes to stdout
options:
-h, --help show this help message and exit
-f {ttl,hext,json-ld,longturtle,n3,nquads,nt,nt11,ntriples,pretty-xml,trig,trix,ttl,turtle,xml}, --format {ttl,hext,json-ld,longturtle,n3,nquads,nt,nt11,ntriples,pretty-xml,trig,trix,ttl,turtle,xml}
Output RDF Format. If omitted, guess from output file
suffix. If guessing doesn't work, assume 'turtle'
-np, --noProgressBar Don't output the progress indicators
```
To convert an OWL functional representation of the pizza ontology to RDF:
```shell
> funowl https://raw.githubusercontent.com/Harold-Solbrig/funowl/main/tests/data/pizza.owl
@prefix dc: <http://purl.org/dc/elements/1.1/> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix pizza: <http://www.co-ode.org/ontologies/pizza/pizza.owl#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix skos: <http://www.w3.org/2004/02/skos/core#> .
@prefix terms: <http://purl.org/dc/terms/> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
dc:description a owl:AnnotationProperty .
dc:title a owl:AnnotationProperty .
terms:contributor a owl:AnnotationProperty .
terms:license a owl:AnnotationProperty .
terms:provenance a owl:AnnotationProperty .
<http://www.co-ode.org/ontologies/pizza> a owl:Ontology ;
rdfs:label "pizza"^^xsd:string ;
dc:description """An ontology about pizzas and their toppings.
...
```
To convert the same ontology into XML, either:
`funowl https://raw.githubusercontent.com/Harold-Solbrig/funowl/main/tests/data/pizza.owl -f xml > pizza.xml`
or
`funowl https://raw.githubusercontent.com/Harold-Solbrig/funowl/main/tests/data/pizza.owl pizza.xml`
```shell
> cat pizza.xml
<?xml version="1.0" encoding="utf-8"?>
<rdf:RDF
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:owl="http://www.w3.org/2002/07/owl#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
xmlns:skos="http://www.w3.org/2004/02/skos/core#"
xmlns:terms="http://purl.org/dc/terms/"
>
<rdf:Description rdf:nodeID="Nd1a614092c234a3b90971238bb6550e8">
<rdf:type rdf:resource="http://www.w3.org/2002/07/owl#Restriction"/>
<owl:onProperty rdf:resource="http://www.co-ode.org/ontologies/pizza/pizza.owl#hasTopping"/>
<owl:someValuesFrom rdf:resource="http://www.co-ode.org/ontologies/pizza/pizza.owl#TomatoTopping"/>
</rdf:Description>
...
</rdf:RDF>
```
## Other packages
While we would be happy to be corrected, to the best of our knowledge there is to be minimal support for OWL in python.

@@ -127,0 +227,0 @@ * [OwlReady2](https://owlready2.readthedocs.io/en/latest/) appears to be the closest thing to what we are

@@ -14,5 +14,6 @@ ################################################################################

bcp47
jsonasobj
pyjsg>=0.11.6
rdflib-shim
rdflib>=5.0.0
rdflib==6.2.0
rfc3987

@@ -31,2 +31,6 @@ [metadata]

[entry_points]
console_scripts =
funowl = funowl.cli:evaluate_cli
[egg_info]

@@ -33,0 +37,0 @@ tag_build =

@@ -13,2 +13,3 @@ #!/usr/bin/env python

pbr=True,
py_modules=['funowl']
)

@@ -28,11 +28,11 @@ import unittest

doc = OntologyDocument()
self.assertEqual(expected([]), str(doc.to_functional().getvalue()))
self.assertEqualOntology(expected([]), str(doc.to_functional().getvalue()))
doc.ontology.iri = "http://snomed.info/sct/"
self.assertEqual(expected(['<http://snomed.info/sct/>']), str(doc.to_functional().getvalue()))
self.assertEqualOntology(expected(['<http://snomed.info/sct/>']), str(doc.to_functional().getvalue()))
doc.ontology.version = "http://snomed.info/sct/version/201802017"
self.assertEqual(expected(['<http://snomed.info/sct/> <http://snomed.info/sct/version/201802017>']),
self.assertEqualOntology(expected(['<http://snomed.info/sct/> <http://snomed.info/sct/version/201802017>']),
doc.to_functional().getvalue())
doc.prefixes(RDFS, owl=OWL, rdf=RDF)
self.assertEqual('''Prefix( xml: = <http://www.w3.org/XML/1998/namespace> )
self.assertEqualOntology('''Prefix( xml: = <http://www.w3.org/XML/1998/namespace> )
Prefix( rdf: = <http://www.w3.org/1999/02/22-rdf-syntax-ns#> )

@@ -48,3 +48,3 @@ Prefix( rdfs: = <http://www.w3.org/2000/01/rdf-schema#> )

doc.ontology.annotations.append(Annotation(RDFS.label, "foo"))
self.assertEqual('''Prefix( xml: = <http://www.w3.org/XML/1998/namespace> )
self.assertEqualOntology('''Prefix( xml: = <http://www.w3.org/XML/1998/namespace> )
Prefix( rdf: = <http://www.w3.org/1999/02/22-rdf-syntax-ns#> )

@@ -51,0 +51,0 @@ Prefix( rdfs: = <http://www.w3.org/2000/01/rdf-schema#> )

@@ -27,3 +27,3 @@ import unittest

doc = OntologyDocument(A, ex=EX)
self.assertEqual("""Prefix( xml: = <http://www.w3.org/XML/1998/namespace> )
self.assertEqualOntology("""Prefix( xml: = <http://www.w3.org/XML/1998/namespace> )
Prefix( rdf: = <http://www.w3.org/1999/02/22-rdf-syntax-ns#> )

@@ -46,3 +46,3 @@ Prefix( rdfs: = <http://www.w3.org/2000/01/rdf-schema#> )

od.ontology.subClassOf(EX.Child, OWL.Thing)
self.assertEqual("""Prefix( xml: = <http://www.w3.org/XML/1998/namespace> )
self.assertEqualOntology("""Prefix( xml: = <http://www.w3.org/XML/1998/namespace> )
Prefix( rdf: = <http://www.w3.org/1999/02/22-rdf-syntax-ns#> )

@@ -49,0 +49,0 @@ Prefix( rdfs: = <http://www.w3.org/2000/01/rdf-schema#> )

@@ -12,7 +12,7 @@ import unittest

def test_prefix(self):
self.assertEqual('Prefix( rdf: = <http://www.w3.org/1999/02/22-rdf-syntax-ns#> )',
self.assertEqualOntology('Prefix( rdf: = <http://www.w3.org/1999/02/22-rdf-syntax-ns#> )',
str(Prefix('rdf', RDF).to_functional(self.w)))
self.assertEqual('Prefix( ex: = <http://www.example.org/test/> )',
self.assertEqualOntology('Prefix( ex: = <http://www.example.org/test/> )',
str(Prefix('ex', "http://www.example.org/test/").to_functional(self.w.reset())))
self.assertEqual('Prefix( : = <http://example.org/mt/> )',
self.assertEqualOntology('Prefix( : = <http://example.org/mt/> )',
str(Prefix(None, URIRef("http://example.org/mt/")).to_functional(self.w.reset())))

@@ -32,3 +32,3 @@ with self.assertRaises(TypeError):

pds.bind(None, RDFS.label)
self.assertEqual('''Prefix( xml: = <http://www.w3.org/XML/1998/namespace> )
self.assertEqualOntology('''Prefix( xml: = <http://www.w3.org/XML/1998/namespace> )
Prefix( rdf: = <http://www.w3.org/1999/02/22-rdf-syntax-ns#> )

@@ -44,3 +44,3 @@ Prefix( rdfs: = <http://www.w3.org/2000/01/rdf-schema#> )

pds = PrefixDeclarations()
self.assertEqual("""Prefix( xml: = <http://www.w3.org/XML/1998/namespace> )
self.assertEqualOntology("""Prefix( xml: = <http://www.w3.org/XML/1998/namespace> )
Prefix( rdf: = <http://www.w3.org/1999/02/22-rdf-syntax-ns#> )

@@ -52,3 +52,3 @@ Prefix( rdfs: = <http://www.w3.org/2000/01/rdf-schema#> )

pds.bind(None, "http://www.w3.org/2002/07/owl#")
self.assertEqual(""" Prefix( xml: = <http://example.org/xml2#> )
self.assertEqualOntology(""" Prefix( xml: = <http://example.org/xml2#> )
Prefix( rdf: = <http://www.w3.org/1999/02/22-rdf-syntax-ns#> )

@@ -61,3 +61,3 @@ Prefix( rdfs: = <http://www.w3.org/2000/01/rdf-schema#> )

pds.foaf = "http://foaf.org/"
self.assertEqual('''Prefix( xml: = <http://example.org/xml2#> )
self.assertEqualOntology('''Prefix( xml: = <http://example.org/xml2#> )
Prefix( rdf: = <http://www.w3.org/1999/02/22-rdf-syntax-ns#> )

@@ -64,0 +64,0 @@ Prefix( rdfs: = <http://www.w3.org/2000/01/rdf-schema#> )

@@ -9,2 +9,3 @@ import os

from tests import datadir, PREFIXES_BROKEN_MESSAGE, RDFLIB_PREFIXES_ARE_BROKEN
from tests.utils.base import TestBase

@@ -15,3 +16,3 @@ pizza = os.path.join(datadir, 'pizza.owl')

class FunctionalConverterTestCase(unittest.TestCase):
class FunctionalConverterTestCase(TestBase):
def verify(self, loc: Any) -> None:

@@ -27,3 +28,3 @@ self.maxDiff = None

else:
self.assertEqual(expected, str(doc.to_functional()))
self.assertEqualOntology(expected, str(doc.to_functional()))
else:

@@ -30,0 +31,0 @@ with open(pizza_fun, 'w') as f:

@@ -9,2 +9,3 @@ import unittest

from tests import RDFLIB_PREFIXES_ARE_BROKEN, PREFIXES_BROKEN_MESSAGE
from tests.utils.base import TestBase

@@ -21,3 +22,3 @@ text = """

class DeclarationTestCase(unittest.TestCase):
class DeclarationTestCase(TestBase):
def test_base_declaration(self):

@@ -33,3 +34,3 @@ decl = Declaration( Class( PIZZA.American))

actual = str(parsed.to_functional())
self.assertEqual("""Prefix( xml: = <http://www.w3.org/XML/1998/namespace> )
self.assertEqualOntology("""Prefix( xml: = <http://www.w3.org/XML/1998/namespace> )
Prefix( rdf: = <http://www.w3.org/1999/02/22-rdf-syntax-ns#> )

@@ -36,0 +37,0 @@ Prefix( rdfs: = <http://www.w3.org/2000/01/rdf-schema#> )

@@ -7,5 +7,6 @@ import unittest

from tests import RDFLIB_PREFIXES_ARE_BROKEN, PREFIXES_BROKEN_MESSAGE
from tests.utils.base import TestBase
class Issue2TestCase(unittest.TestCase):
class Issue2TestCase(TestBase):
@unittest.skipIf(RDFLIB_PREFIXES_ARE_BROKEN, PREFIXES_BROKEN_MESSAGE)

@@ -19,3 +20,3 @@ def test_cyclic_issue(self):

o.declarations(DataProperty(RELA['#hasLowerBound']))
self.assertEqual("""Prefix( xml: = <http://www.w3.org/XML/1998/namespace> )
self.assertEqualOntology("""Prefix( xml: = <http://www.w3.org/XML/1998/namespace> )
Prefix( rdf: = <http://www.w3.org/1999/02/22-rdf-syntax-ns#> )

@@ -38,3 +39,3 @@ Prefix( rdfs: = <http://www.w3.org/2000/01/rdf-schema#> )

o.axioms.append(ClassAssertion(URIRef("Interval"), REPR['#NormalizedRange']))
self.assertEqual("""Prefix( xml: = <http://www.w3.org/XML/1998/namespace> )
self.assertEqualOntology("""Prefix( xml: = <http://www.w3.org/XML/1998/namespace> )
Prefix( rdf: = <http://www.w3.org/1999/02/22-rdf-syntax-ns#> )

@@ -41,0 +42,0 @@ Prefix( rdfs: = <http://www.w3.org/2000/01/rdf-schema#> )

import logging
import unittest
from typing import Optional

@@ -8,2 +9,3 @@ from rdflib import Namespace

from tests import LOGLEVEL
from tests.utils.functional_comparator import compare_functional_output

@@ -25,1 +27,5 @@ logging.basicConfig(level=LOGLEVEL)

self.wa.reset()
def assertEqualOntology(self, expected: str, actual: str, msg:Optional[str] = None):
compare_functional_output(expected, actual, self, msg)

@@ -6,2 +6,3 @@ [tox]

py310
py311

@@ -8,0 +9,0 @@ [testenv]

{
"_meta": {
"hash": {
"sha256": "c8f2218262cd18a9584b6bfe4dfe8f417789a79d5ab4e45bd5ec3dc898cf034c"
},
"pipfile-spec": 6,
"requires": {},
"sources": [
{
"name": "pypi",
"url": "https://pypi.org/simple",
"verify_ssl": true
}
]
},
"default": {
"antlr4-python3-runtime": {
"hashes": [
"sha256:f224469b4168294902bb1efa80a8bf7855f24c99aef99cbefc1bcd3cce77881b"
],
"version": "==4.9.3"
},
"bcp47": {
"hashes": [
"sha256:309d3bbaef8d6c9ac59d37ba2167cc6620b4e7467ec8f1e09641b659bb1c0c6d",
"sha256:4878d2f3e697ef39ef3891a147280705e4377d5a8d7eb0702129b8d4a3718702"
],
"index": "pypi",
"version": "==0.0.4"
},
"isodate": {
"hashes": [
"sha256:0751eece944162659049d35f4f549ed815792b38793f07cf73381c1c87cbed96",
"sha256:48c5881de7e8b0a0d648cb024c8062dc84e7b840ed81e864c7614fd3c127bde9"
],
"version": "==0.6.1"
},
"jsonasobj": {
"hashes": [
"sha256:b9e329dc1ceaae7cf5d5b214684a0b100e0dad0be6d5bbabac281ec35ddeca65",
"sha256:d52e0544a54a08f6ea3f77fa3387271e3648655e0eace2f21e825c26370e44a2"
],
"version": "==1.3.1"
},
"pyjsg": {
"hashes": [
"sha256:10af60ff42219be7e85bf7f11c19b648715b0b29eb2ddbd269e87069a7c3f26d",
"sha256:4bd6e3ff2833fa2b395bbe803a2d72a5f0bab5b7285bccd0da1a1bc0aee88bfa"
],
"index": "pypi",
"version": "==0.11.10"
},
"pyparsing": {
"hashes": [
"sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb",
"sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc"
],
"markers": "python_full_version >= '3.6.8'",
"version": "==3.0.9"
},
"rdflib": {
"hashes": [
"sha256:8dbfa0af2990b98471dacbc936d6494c997ede92fd8ed693fb84ee700ef6f754",
"sha256:fc81cef513cd552d471f2926141396b633207109d0154c8e77926222c70367fe"
],
"index": "pypi",
"version": "==6.1.1"
},
"rdflib-jsonld": {
"hashes": [
"sha256:bcf84317e947a661bae0a3f2aee1eced697075fc4ac4db6065a3340ea0f10fc2",
"sha256:eda5a42a2e09f80d4da78e32b5c684bccdf275368f1541e6b7bcddfb1382a0e0"
],
"version": "==0.6.1"
},
"rdflib-shim": {
"hashes": [
"sha256:7a853e7750ef1e9bf4e35dea27d54e02d4ed087de5a9e0c329c4a6d82d647081",
"sha256:d955d11e2986aab42b6830ca56ac6bc9c893abd1d049a161c6de2f1b99d4fc0d"
],
"index": "pypi",
"version": "==1.0.3"
},
"rfc3987": {
"hashes": [
"sha256:10702b1e51e5658843460b189b185c0366d2cf4cff716f13111b0ea9fd2dce53",
"sha256:d3c4d257a560d544e9826b38bc81db676890c79ab9d7ac92b39c7a253d5ca733"
],
"index": "pypi",
"version": "==1.3.8"
},
"setuptools": {
"hashes": [
"sha256:5a844ad6e190dccc67d6d7411d119c5152ce01f7c76be4d8a1eaa314501bba77",
"sha256:bf8a748ac98b09d32c9a64a995a6b25921c96cc5743c1efa82763ba80ff54e91"
],
"markers": "python_version >= '3.7'",
"version": "==62.4.0"
},
"six": {
"hashes": [
"sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926",
"sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==1.16.0"
}
},
"develop": {
"certifi": {
"hashes": [
"sha256:84c85a9078b11105f04f3036a9482ae10e4621616db313fe045dd24743a0820d",
"sha256:fe86415d55e84719d75f8b69414f6438ac3547d2078ab91b67e779ef69378412"
],
"markers": "python_version >= '3.6'",
"version": "==2022.6.15"
},
"charset-normalizer": {
"hashes": [
"sha256:2857e29ff0d34db842cd7ca3230549d1a697f96ee6d3fb071cfa6c7393832597",
"sha256:6881edbebdb17b39b4eaaa821b438bf6eddffb4468cf344f09f89def34a8b1df"
],
"markers": "python_full_version >= '3.5.0'",
"version": "==2.0.12"
},
"idna": {
"hashes": [
"sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff",
"sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d"
],
"markers": "python_full_version >= '3.5.0'",
"version": "==3.3"
},
"requests": {
"hashes": [
"sha256:bc7861137fbce630f17b03d3ad02ad0bf978c844f3536d0edda6499dafce2b6f",
"sha256:d568723a7ebd25875d8d1eaf5dfa068cd2fc8194b2e483d7b1f7c81918dbec6b"
],
"index": "pypi",
"version": "==2.28.0"
},
"urllib3": {
"hashes": [
"sha256:44ece4d53fb1706f667c9bd1c648f5469a2ec925fcf3a776667042d645472c14",
"sha256:aabaf16477806a5e1dd19aa41f8c2b7950dd3c746362d7e3223dbe6de6ac448e"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'",
"version": "==1.26.9"
}
}
}

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display