diff options
author | Nicholas Car <nicholas.car@surroundaustralia.com> | 2021-05-17 09:48:03 +1000 |
---|---|---|
committer | Nicholas Car <nicholas.car@surroundaustralia.com> | 2021-05-17 09:48:03 +1000 |
commit | 88a353649c92da6903ea53b7396d9c1365c1b1ee (patch) | |
tree | 68cfef44d34a53d99e020bf3f8b5b8e342c8fc02 | |
parent | bb03d810ffd0504c86476f3fd5f9ee31026376f9 (diff) | |
parent | a9aaef18c86f4bb645ee791a50c805bf0d9cecd0 (diff) | |
download | rdflib-88a353649c92da6903ea53b7396d9c1365c1b1ee.tar.gz |
Merge branch 'master' into docco_clean
-rw-r--r-- | .github/dependabot.yml | 12 | ||||
-rw-r--r-- | docs/sphinx-requirements.txt | 2 | ||||
-rw-r--r-- | rdflib/graph.py | 16 | ||||
-rw-r--r-- | rdflib/plugins/sparql/results/txtresults.py | 2 | ||||
-rw-r--r-- | rdflib/plugins/stores/sparqlstore.py | 2 | ||||
-rw-r--r-- | rdflib/term.py | 7 | ||||
-rw-r--r-- | setup.py | 2 | ||||
-rw-r--r-- | test/test_b64_binary.py | 29 | ||||
-rw-r--r-- | test/test_graph.py | 41 | ||||
-rw-r--r-- | test/test_sparql.py | 39 | ||||
-rw-r--r-- | test/test_sparqlstore.py | 13 |
11 files changed, 150 insertions, 15 deletions
diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..62f2d35d --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,12 @@ +version: 2 +updates: +- package-ecosystem: pip + directory: "/" + schedule: + interval: weekly + open-pull-requests-limit: 10 + ignore: + - dependency-name: sphinx + versions: + - 3.4.3 + - 3.5.2 diff --git a/docs/sphinx-requirements.txt b/docs/sphinx-requirements.txt index 403eec52..48ba7549 100644 --- a/docs/sphinx-requirements.txt +++ b/docs/sphinx-requirements.txt @@ -1,3 +1,3 @@ -sphinx==3.5.4 +sphinx==4.0.1 sphinxcontrib-apidoc git+https://github.com/gniezen/n3pygments.git diff --git a/rdflib/graph.py b/rdflib/graph.py index 9d4431bc..d2a5e872 100644 --- a/rdflib/graph.py +++ b/rdflib/graph.py @@ -879,11 +879,11 @@ class Graph(Node): for rt_2 in self.transitiveClosure(func, rt, seen): yield rt_2 - def transitive_objects(self, subject, property, remember=None): - """Transitively generate objects for the ``property`` relationship + def transitive_objects(self, subject, predicate, remember=None): + """Transitively generate objects for the ``predicate`` relationship Generated objects belong to the depth first transitive closure of the - ``property`` relationship starting at ``subject``. + ``predicate`` relationship starting at ``subject``. """ if remember is None: remember = {} @@ -891,15 +891,15 @@ class Graph(Node): return remember[subject] = 1 yield subject - for object in self.objects(subject, property): - for o in self.transitive_objects(object, property, remember): + for object in self.objects(subject, predicate): + for o in self.transitive_objects(object, predicate, remember): yield o def transitive_subjects(self, predicate, object, remember=None): - """Transitively generate objects for the ``property`` relationship + """Transitively generate subjects for the ``predicate`` relationship - Generated objects belong to the depth first transitive closure of the - ``property`` relationship starting at ``subject``. + Generated subjects belong to the depth first transitive closure of the + ``predicate`` relationship starting at ``object``. """ if remember is None: remember = {} diff --git a/rdflib/plugins/sparql/results/txtresults.py b/rdflib/plugins/sparql/results/txtresults.py index 426dd9a1..baa5316b 100644 --- a/rdflib/plugins/sparql/results/txtresults.py +++ b/rdflib/plugins/sparql/results/txtresults.py @@ -43,7 +43,7 @@ class TXTResultSerializer(ResultSerializer): return "(no results)\n" else: - keys = sorted(self.result.vars) + keys = self.result.vars maxlen = [0] * len(keys) b = [ [_termString(r[k], namespace_manager) for k in keys] diff --git a/rdflib/plugins/stores/sparqlstore.py b/rdflib/plugins/stores/sparqlstore.py index e021e5df..26436f20 100644 --- a/rdflib/plugins/stores/sparqlstore.py +++ b/rdflib/plugins/stores/sparqlstore.py @@ -167,7 +167,7 @@ class SPARQLStore(SPARQLConnector, Store): self.debug = DEBUG assert isinstance(query, str) - if initNs is not None: + if initNs is not None and len(initNs) > 0: query = self._inject_prefixes(query, initNs) if initBindings: diff --git a/rdflib/term.py b/rdflib/term.py index 3a822158..0f627e69 100644 --- a/rdflib/term.py +++ b/rdflib/term.py @@ -38,7 +38,6 @@ import logging import warnings import math -import base64 import xml.dom.minidom from datetime import date, time, datetime, timedelta @@ -53,6 +52,7 @@ from isodate import ( parse_duration, duration_isoformat, ) +from base64 import b64decode, b64encode from binascii import hexlify, unhexlify import rdflib @@ -1435,6 +1435,7 @@ _XSD_DAYTIMEDURATION = URIRef(_XSD_PFX + "dayTimeDuration") _XSD_YEARMONTHDURATION = URIRef(_XSD_PFX + "yearMonthDuration") _OWL_RATIONAL = URIRef("http://www.w3.org/2002/07/owl#rational") +_XSD_B64BINARY = URIRef(_XSD_PFX + "base64Binary") _XSD_HEXBINARY = URIRef(_XSD_PFX + "hexBinary") # TODO: gYearMonth, gYear, gMonthDay, gDay, gMonth @@ -1559,6 +1560,8 @@ _GenericPythonToXSDRules = [ _SpecificPythonToXSDRules = [ ((str, _XSD_HEXBINARY), hexlify), ((bytes, _XSD_HEXBINARY), hexlify), + ((str, _XSD_B64BINARY), b64encode), + ((bytes, _XSD_B64BINARY), b64encode), ] XSDToPython = { @@ -1593,7 +1596,7 @@ XSDToPython = { URIRef(_XSD_PFX + "unsignedByte"): int, URIRef(_XSD_PFX + "float"): float, URIRef(_XSD_PFX + "double"): float, - URIRef(_XSD_PFX + "base64Binary"): lambda s: base64.b64decode(s), + URIRef(_XSD_PFX + "base64Binary"): b64decode, URIRef(_XSD_PFX + "anyURI"): None, _RDF_XMLLITERAL: _parseXML, _RDF_HTMLLITERAL: _parseHTML, @@ -16,7 +16,7 @@ kwargs["test_suite"] = "nose.collector" kwargs["extras_require"] = { "html": ["html5lib"], "tests": kwargs["tests_require"], - "docs": ["sphinx < 4", "sphinxcontrib-apidoc"], + "docs": ["sphinx < 5", "sphinxcontrib-apidoc"], } diff --git a/test/test_b64_binary.py b/test/test_b64_binary.py new file mode 100644 index 00000000..b512f29d --- /dev/null +++ b/test/test_b64_binary.py @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- + +import unittest +import base64 +from rdflib import Literal, XSD + + +class B64BinaryTestCase(unittest.TestCase): + + def test_unicode(self): + str1 = "Test utf-8 string éàë" + # u b64string + b64_str1 = base64.b64encode(str1.encode("utf-8")).decode() + l1 = Literal(b64_str1, datatype=XSD.base64Binary) + b_str1 = l1.toPython() + self.assertEqual(b_str1.decode("utf-8"), str1) + self.assertEqual(str(l1), b64_str1) + + # b b64string + b64_str1b = base64.b64encode(str1.encode("utf-8")) + l1b = Literal(b64_str1b, datatype=XSD.base64Binary) + b_str1b = l1b.toPython() + self.assertEqual(b_str1, b_str1b) + self.assertEqual(b_str1b.decode("utf-8"), str1) + self.assertEqual(str(l1b), b64_str1) + + +if __name__ == "__main__": + unittest.main() diff --git a/test/test_graph.py b/test/test_graph.py index 93a81df3..9f6d5d9b 100644 --- a/test/test_graph.py +++ b/test/test_graph.py @@ -319,6 +319,47 @@ class GraphTestCase(unittest.TestCase): # this endpoint is currently not available, ignore this test. pass + def testTransitive(self): + person = URIRef("ex:person") + dad = URIRef("ex:dad") + mom = URIRef("ex:mom") + mom_of_dad = URIRef("ex:mom_o_dad") + mom_of_mom = URIRef("ex:mom_o_mom") + dad_of_dad = URIRef("ex:dad_o_dad") + dad_of_mom = URIRef("ex:dad_o_mom") + + parent = URIRef("ex:parent") + + g = Graph() + g.add((person, parent, dad)) + g.add((person, parent, mom)) + g.add((dad, parent, mom_of_dad)) + g.add((dad, parent, dad_of_dad)) + g.add((mom, parent, mom_of_mom)) + g.add((mom, parent, dad_of_mom)) + + # transitive parents of person + self.assertEqual( + set(g.transitive_objects(subject=person, predicate=parent)), + {person, dad, mom_of_dad, dad_of_dad, mom, mom_of_mom, dad_of_mom}, + ) + # transitive parents of dad + self.assertEqual( + set(g.transitive_objects(dad, parent)), {dad, mom_of_dad, dad_of_dad} + ) + # transitive parents of dad_of_dad + self.assertEqual(set(g.transitive_objects(dad_of_dad, parent)), {dad_of_dad}) + + # transitive children (inverse of parents) of mom_of_mom + self.assertEqual( + set(g.transitive_subjects(predicate=parent, object=mom_of_mom)), + {mom_of_mom, mom, person}, + ) + # transitive children (inverse of parents) of mom + self.assertEqual(set(g.transitive_subjects(parent, mom)), {mom, person}) + # transitive children (inverse of parents) of person + self.assertEqual(set(g.transitive_subjects(parent, person)), {person}) + # dynamically create classes for each registered Store diff --git a/test/test_sparql.py b/test/test_sparql.py index fa548146..6454e7ef 100644 --- a/test/test_sparql.py +++ b/test/test_sparql.py @@ -1,8 +1,8 @@ from rdflib.plugins.sparql import sparql, prepareQuery from rdflib import Graph, URIRef, Literal, BNode, ConjunctiveGraph from rdflib.namespace import Namespace, RDF, RDFS -from rdflib.plugins.sparql import prepareQuery from rdflib.compare import isomorphic +from rdflib.term import Variable from nose.tools import eq_ @@ -163,6 +163,43 @@ def test_named_filter_graph_query(): initNs={'ex': ex})) == [(Literal('Susan'),)] +def test_txtresult(): + data = f"""\ + @prefix rdfs: <{str(RDFS)}> . + rdfs:Class a rdfs:Class ; + rdfs:isDefinedBy <http://www.w3.org/2000/01/rdf-schema#> ; + rdfs:label "Class" ; + rdfs:comment "The class of classes." ; + rdfs:subClassOf rdfs:Resource . + """ + graph = Graph() + graph.parse(data=data, format="turtle") + result = graph.query( + """\ + SELECT ?class ?superClass ?label ?comment WHERE { + ?class rdf:type rdfs:Class. + ?class rdfs:label ?label. + ?class rdfs:comment ?comment. + ?class rdfs:subClassOf ?superClass. + } + """ + ) + vars = [ + Variable("class"), + Variable("superClass"), + Variable("label"), + Variable("comment"), + ] + assert result.type == "SELECT" + assert len(result) == 1 + assert result.vars == vars + txtresult = result.serialize(format="txt") + lines = txtresult.decode().splitlines() + assert len(lines) == 3 + vars_check = [Variable(var.strip()) for var in lines[0].split("|")] + assert vars_check == vars + + if __name__ == "__main__": import nose diff --git a/test/test_sparqlstore.py b/test/test_sparqlstore.py index 8154b10c..8d720de3 100644 --- a/test/test_sparqlstore.py +++ b/test/test_sparqlstore.py @@ -67,6 +67,19 @@ class SPARQLStoreDBPediaTestCase(unittest.TestCase): for i in res: assert type(i[0]) == Literal, i[0].n3() + def test_query_with_added_rdf_prolog(self): + prologue = """\ + PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> + PREFIX xyzzy: <http://www.w3.org/2004/02/skos/core#> + """ + query = """\ + SELECT ?label WHERE + { ?s a xyzzy:Concept ; xyzzy:prefLabel ?label . } LIMIT 10 + """ + res = helper.query_with_retry(self.graph, prologue + query) + for i in res: + assert type(i[0]) == Literal, i[0].n3() + def test_counting_graph_and_store_queries(self): query = """ SELECT ?s |