diff options
author | Nicholas Car <nicholas.car@surroundaustralia.com> | 2020-12-27 21:24:08 +1000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-12-27 21:24:08 +1000 |
commit | 0f191aede2e9a12d00fad737c8a56062c50952a0 (patch) | |
tree | d674e48e51f7eddeafa8fa0b47f254007f57148b | |
parent | 63b756f2e4ab8f570103debc88b3dcbbaae577f6 (diff) | |
parent | 009dc24f413fb6136e0ffbb78c4963749f8999bb (diff) | |
download | rdflib-0f191aede2e9a12d00fad737c8a56062c50952a0.tar.gz |
Merge branch 'master' into sparql-timezone
39 files changed, 267 insertions, 155 deletions
diff --git a/.travis.yml b/.travis.yml index 33536b1a..c8cf3a5d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,8 @@ # http://travis-ci.org/#!/RDFLib/rdflib +os: linux +arch: + - amd64 + - ppc64le language: python branches: only: @@ -101,7 +101,7 @@ g.bind("xsd", XSD) ``` This will allow the n-triples triple above to be serialised like this: ```python -print(g.serialize(format="turtle").decode("utf-8")) +print(g.serialize(format="turtle")) ``` With these results: diff --git a/docs/conf.py b/docs/conf.py index b6f457f1..67a0f592 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -102,7 +102,7 @@ version = re.sub("[0-9]+\\.[0-9]\\..*", "\1", release) exclude_trees = ["_build", "draft"] # The reST default role (used for this markup: `text`) to use for all documents. -default_role = 'py:obj' +default_role = "py:obj" # If true, '()' will be appended to :func: etc. cross-reference text. add_function_parentheses = True diff --git a/docs/intro_to_creating_rdf.rst b/docs/intro_to_creating_rdf.rst index 5d58945b..238eafba 100644 --- a/docs/intro_to_creating_rdf.rst +++ b/docs/intro_to_creating_rdf.rst @@ -12,7 +12,7 @@ represented by the classes :class:`~rdflib.term.URIRef`, :class:`~rdflib.term.BN ``URIRefs`` and ``BNodes`` can both be thought of as resources, such a person, a company, a website, etc. * A ``BNode`` is a node where the exact URI is not known. -* A ``URIRef`` is a node where the exact URI is knonw. ``URIRef``\s are also used to represent the properties/predicates in the RDF graph. +* A ``URIRef`` is a node where the exact URI is known. ``URIRef``\s are also used to represent the properties/predicates in the RDF graph. * ``Literals`` represent attribute values, such as a name, a date, a number, etc. The most common literal values are XML data types, e.g. string, int... diff --git a/docs/sphinx-requirements.txt b/docs/sphinx-requirements.txt index 175ef14e..4d7b2b16 100644 --- a/docs/sphinx-requirements.txt +++ b/docs/sphinx-requirements.txt @@ -1,3 +1,3 @@ -sphinx==3.2.1 +sphinx==3.4.0 sphinxcontrib-apidoc git+https://github.com/gniezen/n3pygments.git diff --git a/rdflib/container.py b/rdflib/container.py index 5960d0a7..3001ba46 100644 --- a/rdflib/container.py +++ b/rdflib/container.py @@ -14,7 +14,7 @@ class Container(object): >>> from rdflib import Graph, BNode, Literal, Bag
>>> g = Graph()
>>> b = Bag(g, BNode(), [Literal("One"), Literal("Two"), Literal("Three")])
- >>> print(g.serialize(format="turtle").decode())
+ >>> print(g.serialize(format="turtle"))
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
<BLANKLINE>
[] a rdf:Bag ;
@@ -30,7 +30,7 @@ class Container(object): >>> # add a new item
>>> b.append(Literal("Hello"))
- >>> print(g.serialize(format="turtle").decode())
+ >>> print(g.serialize(format="turtle"))
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
<BLANKLINE>
[] a rdf:Bag ;
diff --git a/rdflib/graph.py b/rdflib/graph.py index e0d5f854..cbaf8f2d 100644 --- a/rdflib/graph.py +++ b/rdflib/graph.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Optional, Union import logging from warnings import warn import random @@ -957,12 +957,17 @@ class Graph(Node): return self.namespace_manager.absolutize(uri, defrag) def serialize( - self, destination=None, format="xml", base=None, encoding=None, **args - ) -> Optional[bytes]: + self, destination=None, format="turtle", base=None, encoding=None, **args + ) -> Optional[Union[bytes, str]]: """Serialize the Graph to destination If destination is None serialize method returns the serialization as - bytes. Format defaults to xml (AKA rdf/xml). + bytes or string. + + If encoding is None and destination is None, returns a string + If encoding is set, and Destination is None, returns bytes + + Format defaults to turtle. Format support can be extended with plugins, but "xml", "n3", "turtle", "nt", "pretty-xml", "trix", "trig" and "nquads" are built in. @@ -975,8 +980,12 @@ class Graph(Node): serializer = plugin.get(format, Serializer)(self) if destination is None: stream = BytesIO() - serializer.serialize(stream, base=base, encoding=encoding, **args) - return stream.getvalue() + if encoding is None: + serializer.serialize(stream, base=base, encoding="utf-8", **args) + return stream.getvalue().decode("utf-8") + else: + serializer.serialize(stream, base=base, encoding=encoding, **args) + return stream.getvalue() if hasattr(destination, "write"): stream = destination serializer.serialize(stream, base=base, encoding=encoding, **args) @@ -999,6 +1008,13 @@ class Graph(Node): shutil.copy(name, dest) os.remove(name) + def print(self, format="turtle", encoding="utf-8", out=None): + print( + self.serialize(None, format=format, encoding=encoding).decode(encoding), + file=out, + flush=True, + ) + def parse( self, source=None, @@ -1130,13 +1146,13 @@ class Graph(Node): def query( self, query_object, - processor="sparql", - result="sparql", + processor: str = "sparql", + result: str = "sparql", initNs=None, initBindings=None, - use_store_provided=True, + use_store_provided: bool = True, **kwargs - ): + ) -> query.Result: """ Query this graph. @@ -1147,7 +1163,7 @@ class Graph(Node): if none are given, the namespaces from the graph's namespace manager are used. - :returntype: rdflib.query.QueryResult + :returntype: rdflib.query.Result """ diff --git a/rdflib/plugins/sparql/evaluate.py b/rdflib/plugins/sparql/evaluate.py index 496bc872..f5fd86ed 100644 --- a/rdflib/plugins/sparql/evaluate.py +++ b/rdflib/plugins/sparql/evaluate.py @@ -187,6 +187,7 @@ def evalGraph(ctx, part): ctx = ctx.clone() graph = ctx[part.term] + prev_graph = ctx.graph if graph is None: for graph in ctx.dataset.contexts(): @@ -199,11 +200,13 @@ def evalGraph(ctx, part): c = c.push() graphSolution = [{part.term: graph.identifier}] for x in _join(evalPart(c, part.p), graphSolution): + x.ctx.graph = prev_graph yield x else: c = ctx.pushGraph(ctx.dataset.get_context(graph)) for x in evalPart(c, part.p): + x.ctx.graph = prev_graph yield x diff --git a/rdflib/plugins/sparql/operators.py b/rdflib/plugins/sparql/operators.py index 228b0c28..126efdd9 100644 --- a/rdflib/plugins/sparql/operators.py +++ b/rdflib/plugins/sparql/operators.py @@ -1119,6 +1119,8 @@ def calculateFinalDateTime(obj1, dt1, obj2, dt2, operation): def EBV(rt): """ + Effective Boolean Value (EBV) + * If the argument is a typed literal with a datatype of xsd:boolean, the EBV is the value of that argument. * If the argument is a plain literal or a typed literal with a diff --git a/rdflib/plugins/sparql/parserutils.py b/rdflib/plugins/sparql/parserutils.py index c30e10d6..3e90887b 100644 --- a/rdflib/plugins/sparql/parserutils.py +++ b/rdflib/plugins/sparql/parserutils.py @@ -173,7 +173,7 @@ class CompValue(OrderedDict): def __getattr__(self, a): # Hack hack: OrderedDict relies on this if a in ("_OrderedDict__root", "_OrderedDict__end"): - raise AttributeError + raise AttributeError() try: return self[a] except KeyError: diff --git a/rdflib/plugins/sparql/sparql.py b/rdflib/plugins/sparql/sparql.py index 43aee3ed..b75b8054 100644 --- a/rdflib/plugins/sparql/sparql.py +++ b/rdflib/plugins/sparql/sparql.py @@ -164,7 +164,7 @@ class FrozenBindings(FrozenDict): if not isinstance(key, Node): key = Variable(key) - if not type(key) in (BNode, Variable): + if not isinstance(key, (BNode, Variable)): return key if key not in self._d: @@ -177,22 +177,20 @@ class FrozenBindings(FrozenDict): def merge(self, other): res = FrozenBindings(self.ctx, itertools.chain(self.items(), other.items())) - return res - def _now(self): + @property + def now(self): return self.ctx.now - def _bnodes(self): + @property + def bnodes(self): return self.ctx.bnodes - def _prologue(self): + @property + def prologue(self): return self.ctx.prologue - prologue = property(_prologue) - bnodes = property(_bnodes) - now = property(_now) - def forget(self, before, _except=None): """ return a frozen dict only of bindings made in self @@ -265,7 +263,9 @@ class QueryContext(object): r.bnodes = self.bnodes return r - def _get_dataset(self): + @property + def dataset(self): + """"current dataset""" if self._dataset is None: raise Exception( "You performed a query operation requiring " @@ -274,8 +274,6 @@ class QueryContext(object): ) return self._dataset - dataset = property(_get_dataset, doc="current dataset") - def load(self, source, default=False, **kwargs): def _load(graph, source): try: @@ -311,7 +309,7 @@ class QueryContext(object): def __getitem__(self, key): # in SPARQL BNodes are just labels - if not type(key) in (BNode, Variable): + if not isinstance(key, (BNode, Variable)): return key try: return self.bindings[key] @@ -353,11 +351,6 @@ class QueryContext(object): def clean(self): return self.clone([]) - # def pop(self): - # self.bindings = self.bindings.outer - # if self.bindings is None: - # raise Exception("We've bottomed out of the bindings stack!") - def thaw(self, frozenbindings): """ Create a new read/write query context from the given solution @@ -367,8 +360,7 @@ class QueryContext(object): return c -class Prologue(object): - +class Prologue: """ A class for holding prefixing bindings and base URI information """ @@ -407,7 +399,7 @@ class Prologue(object): return iri -class Query(object): +class Query: """ A parsed and translated query """ diff --git a/rdflib/plugins/stores/sleepycat.py b/rdflib/plugins/stores/sleepycat.py index 7729969e..b6b90470 100644 --- a/rdflib/plugins/stores/sleepycat.py +++ b/rdflib/plugins/stores/sleepycat.py @@ -12,16 +12,11 @@ def bb(u): try: - from bsddb import db + from bsddb3 import db has_bsddb = True except ImportError: - try: - from bsddb3 import db - - has_bsddb = True - except ImportError: - has_bsddb = False + has_bsddb = False if has_bsddb: diff --git a/rdflib/plugins/stores/sparqlconnector.py b/rdflib/plugins/stores/sparqlconnector.py index 13571caa..ffd8b30a 100644 --- a/rdflib/plugins/stores/sparqlconnector.py +++ b/rdflib/plugins/stores/sparqlconnector.py @@ -66,8 +66,8 @@ class SPARQLConnector(object): @method.setter def method(self, method): - if method not in ("GET", "POST"): - raise SPARQLConnectorException('Method must be "GET" or "POST"') + if method not in ("GET", "POST", "POST_FORM"): + raise SPARQLConnectorException('Method must be "GET", "POST", or "POST_FORM"') self._method = method @@ -75,7 +75,7 @@ class SPARQLConnector(object): if not self.query_endpoint: raise SPARQLConnectorException("Query endpoint not set!") - params = {"query": query} + params = {} # this test ensures we don't have a useless (BNode) default graph URI, which calls to Graph().query() will add if default_graph is not None and type(default_graph) != BNode: params["default-graph-uri"] = default_graph @@ -91,6 +91,7 @@ class SPARQLConnector(object): args["headers"].update(headers) if self.method == "GET": + params["query"] = query args["params"].update(params) qsa = "?" + urlencode(args["params"]) try: @@ -99,8 +100,16 @@ class SPARQLConnector(object): raise ValueError("You did something wrong formulating either the URI or your SPARQL query") elif self.method == "POST": args["headers"].update({"Content-Type": "application/sparql-query"}) + qsa = "?" + urlencode(params) + try: + res = urlopen(Request(self.query_endpoint + qsa, data=query.encode(), headers=args["headers"])) + except HTTPError as e: + return e.code, str(e), None + elif self.method == "POST_FORM": + params["query"] = query + args["params"].update(params) try: - res = urlopen(Request(self.query_endpoint, data=query.encode(), headers=args["headers"])) + res = urlopen(Request(self.query_endpoint, data=urlencode(args["params"]).encode(), headers=args["headers"])) except HTTPError as e: return e.code, str(e), None else: diff --git a/rdflib/plugins/stores/sparqlstore.py b/rdflib/plugins/stores/sparqlstore.py index a5bc3716..e021e5df 100644 --- a/rdflib/plugins/stores/sparqlstore.py +++ b/rdflib/plugins/stores/sparqlstore.py @@ -101,8 +101,6 @@ class SPARQLStore(SPARQLConnector, Store): auth=None, **sparqlconnector_kwargs ): - """ - """ super(SPARQLStore, self).__init__( query_endpoint=query_endpoint, returnFormat=returnFormat, auth=auth, **sparqlconnector_kwargs ) @@ -374,7 +372,7 @@ class SPARQLStore(SPARQLConnector, Store): raise TypeError("The SPARQL store is read only") def _is_contextual(self, graph): - """ Returns `True` if the "GRAPH" keyword must appear + """Returns `True` if the "GRAPH" keyword must appear in the final SPARQL query sent to the endpoint. """ if (not self.context_aware) or (graph is None): diff --git a/rdflib/query.py b/rdflib/query.py index ae23e3b3..c67f15ea 100644 --- a/rdflib/query.py +++ b/rdflib/query.py @@ -4,6 +4,7 @@ import shutil import tempfile import warnings import types +from typing import Optional from io import BytesIO @@ -205,8 +206,29 @@ class Result(object): return parser.parse(source, content_type=content_type, **kwargs) - def serialize(self, destination=None, encoding="utf-8", format="xml", **args): - + def serialize( + self, + destination: Optional[str] = None, + encoding: str = "utf-8", + format: str = "xml", + **args, + ) -> Optional[bytes]: + """ + Serialize the query result. + + The :code:`format` argument determines the Serializer class to use. + + - csv: :class:`~rdflib.plugins.sparql.results.csvresults.CSVResultSerializer` + - json: :class:`~rdflib.plugins.sparql.results.jsonresults.JSONResultSerializer` + - txt: :class:`~rdflib.plugins.sparql.results.txtresults.TXTResultSerializer` + - xml: :class:`~rdflib.plugins.sparql.results.xmlresults.XMLResultSerializer` + + :param destination: Path of file output. + :param encoding: Encoding of output. + :param format: One of ['csv', 'json', 'txt', xml'] + :param args: + :return: bytes + """ if self.type in ("CONSTRUCT", "DESCRIBE"): return self.graph.serialize( destination, encoding=encoding, format=format, **args diff --git a/rdflib/resource.py b/rdflib/resource.py index f9063754..bc1e07b0 100644 --- a/rdflib/resource.py +++ b/rdflib/resource.py @@ -1,6 +1,4 @@ -# -*- coding: utf-8 -*- - -__doc__ = """ +""" The :class:`~rdflib.resource.Resource` class wraps a :class:`~rdflib.graph.Graph` and a resource reference (i.e. a :class:`rdflib.term.URIRef` or diff --git a/rdflib/tools/rdf2dot.py b/rdflib/tools/rdf2dot.py index 37c8f784..1e202d40 100644 --- a/rdflib/tools/rdf2dot.py +++ b/rdflib/tools/rdf2dot.py @@ -153,7 +153,7 @@ def rdf2dot(g, stream, opts={}): + "<font point-size='10' color='#6666ff'>%s</font></td>" + "</tr>%s</table> > ] \n" ) - stream.write(opstr % (n, NODECOLOR, label(u, g), u, u, "".join(f))) + stream.write(opstr % (n, NODECOLOR, html.escape(label(u, g)), u, html.escape(u), "".join(f))) stream.write("}\n") diff --git a/test/helper.py b/test/helper.py new file mode 100644 index 00000000..240d90c7 --- /dev/null +++ b/test/helper.py @@ -0,0 +1,51 @@ +import time +import urllib.error + +import rdflib +import rdflib.query + + +MAX_RETRY = 10 +BACKOFF_FACTOR = 1.5 +def query_with_retry(graph: rdflib.Graph, query: str, **kwargs) -> rdflib.query.Result: + """Query graph an retry on failure, returns preloaded result + + The tests run against outside network targets which results + in flaky tests. Therefor retries are needed to increase stability. + + There are two main categories why these might fail: + + * Resource shortage on the server running the tests (e.g. out of ports) + * Issues outside the server (network, target server, etc) + + As fast feedback is important the retry should be done quickly. + Therefor the first retry is done after 100ms. But if the issue is + outside the server running the tests it we need to be good + citizenship of the internet and not hit servers of others at + a constant rate. (Also it might get us banned) + + Therefor this function implements a backoff mechanism. + + When adjusting the parameters please keep in mind that several + tests might run on the same machine at the same time + on our CI, and we really don't want to hit any rate limiting. + + The maximum time the function waits is: + + >>> sum((BACKOFF_FACTOR ** backoff) / 10 for backoff in range(MAX_RETRY)) + 11.3330078125 + """ + backoff = 0 + for i in range(MAX_RETRY): + try: + result = graph.query(query, **kwargs) + result.bindings # access bindings to ensure no lazy loading + return result + except urllib.error.URLError as e: + if i == MAX_RETRY -1: + raise e + + backoff_s = (BACKOFF_FACTOR ** backoff) / 10 + print(f"Network error {e} during query, waiting for {backoff_s:.2f}s and retrying") + time.sleep(backoff_s) + backoff += 1 diff --git a/test/test_finalnewline.py b/test/test_finalnewline.py index c78ac247..9b465b24 100644 --- a/test/test_finalnewline.py +++ b/test/test_finalnewline.py @@ -19,9 +19,9 @@ def testFinalNewline(): failed = set() for p in rdflib.plugin.plugins(None, rdflib.plugin.Serializer): - v = graph.serialize(format=p.name) + v = graph.serialize(format=p.name, encoding="latin-1") lines = v.split("\n".encode("latin-1")) - if "\n".encode("latin-1") not in v or (lines[-1] != "".encode("latin-1")): + if b"\n" not in v or (lines[-1] != b""): failed.add(p.name) assert len(failed) == 0, "No final newline for formats: '%s'" % failed diff --git a/test/test_issue1003.py b/test/test_issue1003.py index d59caf3d..752bb536 100644 --- a/test/test_issue1003.py +++ b/test/test_issue1003.py @@ -34,14 +34,14 @@ g.bind("skos", SKOS) g1 = Graph() g1 += g # @base should not be in output -assert "@base" not in g.serialize(format="turtle").decode("utf-8") +assert "@base" not in g.serialize(format="turtle") # 2. base one set for graph, no base set for serialization g2 = Graph(base=base_one) g2 += g # @base should be in output, from Graph (one) -assert "@base <http://one.org/> ." in g2.serialize(format="turtle").decode("utf-8") +assert "@base <http://one.org/> ." in g2.serialize(format="turtle") # 3. no base set for graph, base two set for serialization @@ -50,7 +50,7 @@ g3 += g # @base should be in output, from serialization (two) assert "@base <http://two.org/> ." in g3.serialize( format="turtle", base=base_two -).decode("utf-8") +) # 4. base one set for graph, base two set for serialization, Graph one overrides @@ -59,11 +59,11 @@ g4 += g # @base should be in output, from graph (one) assert "@base <http://two.org/> ." in g4.serialize( format="turtle", base=base_two -).decode("utf-8") +) # just checking that the serialization setting (two) hasn't snuck through assert "@base <http://one.org/> ." not in g4.serialize( format="turtle", base=base_two -).decode("utf-8") +) # 5. multiple serialization side effect checking @@ -72,11 +72,11 @@ g5 += g # @base should be in output, from serialization (two) assert "@base <http://two.org/> ." in g5.serialize( format="turtle", base=base_two -).decode("utf-8") +) # checking for side affects - no base now set for this serialization # @base should not be in output -assert "@base" not in g5.serialize(format="turtle").decode("utf-8") +assert "@base" not in g5.serialize(format="turtle") # 6. checking results for RDF/XML @@ -84,30 +84,22 @@ g6 = Graph() g6 += g g6.bind("dct", DCTERMS) g6.bind("skos", SKOS) -assert "@xml:base" not in g6.serialize(format="xml").decode("utf-8") -assert 'xml:base="http://one.org/"' in g6.serialize(format="xml", base=base_one).decode( - "utf-8" -) +assert "@xml:base" not in g6.serialize(format="xml") +assert 'xml:base="http://one.org/"' in g6.serialize(format="xml", base=base_one) g6.base = base_two -assert 'xml:base="http://two.org/"' in g6.serialize(format="xml").decode("utf-8") -assert 'xml:base="http://one.org/"' in g6.serialize(format="xml", base=base_one).decode( - "utf-8" -) +assert 'xml:base="http://two.org/"' in g6.serialize(format="xml") +assert 'xml:base="http://one.org/"' in g6.serialize(format="xml", base=base_one) # 7. checking results for N3 g7 = Graph() g7 += g g7.bind("dct", DCTERMS) g7.bind("skos", SKOS) -assert "@xml:base" not in g7.serialize(format="xml").decode("utf-8") -assert "@base <http://one.org/> ." in g7.serialize(format="n3", base=base_one).decode( - "utf-8" -) +assert "@xml:base" not in g7.serialize(format="xml") +assert "@base <http://one.org/> ." in g7.serialize(format="n3", base=base_one) g7.base = base_two -assert "@base <http://two.org/> ." in g7.serialize(format="n3").decode("utf-8") -assert "@base <http://one.org/> ." in g7.serialize(format="n3", base=base_one).decode( - "utf-8" -) +assert "@base <http://two.org/> ." in g7.serialize(format="n3") +assert "@base <http://one.org/> ." in g7.serialize(format="n3", base=base_one) # 8. checking results for TriX & TriG # TriX can specify a base per graph but setting a base for the whole @@ -122,12 +114,12 @@ g9 += g g9.base = base_two ds1.base = base_three -trix = ds1.serialize(format="trix", base=Namespace("http://two.org/")).decode("utf-8") +trix = ds1.serialize(format="trix", base=Namespace("http://two.org/")) assert '<graph xml:base="http://one.org/">' in trix assert '<graph xml:base="http://two.org/">' in trix assert '<TriX xml:base="http://two.org/"' in trix -trig = ds1.serialize(format="trig", base=Namespace("http://two.org/")).decode("utf-8") +trig = ds1.serialize(format="trig", base=Namespace("http://two.org/")) assert "@base <http://one.org/> ." not in trig assert "@base <http://three.org/> ." not in trig assert "@base <http://two.org/> ." in trig diff --git a/test/test_issue1043.py b/test/test_issue1043.py index db202d77..03def8c4 100644 --- a/test/test_issue1043.py +++ b/test/test_issue1043.py @@ -23,7 +23,7 @@ class TestIssue1043(unittest.TestCase): g.bind('rdfs', RDFS)
n = Namespace("http://example.org/")
g.add((n.number, RDFS.label, Literal(0.00000004, datatype=XSD.decimal)))
- print(g.serialize(format="turtle").decode("utf-8"))
+ g.print()
sys.stdout = sys.__stdout__
self.assertEqual(capturedOutput.getvalue(), expected)
diff --git a/test/test_issue161.py b/test/test_issue161.py index fa7529dc..5375742c 100644 --- a/test/test_issue161.py +++ b/test/test_issue161.py @@ -25,6 +25,6 @@ class EntityTest(TestCase): g = ConjunctiveGraph() g.parse(data=turtle, format="turtle") # Shouldn't have got to here - s = g.serialize(format="turtle") + s = g.serialize(format="turtle", encoding='latin-1') - self.assertTrue("@prefix _9".encode("latin-1") not in s) + self.assertTrue(b"@prefix _9" not in s) diff --git a/test/test_issue248.py b/test/test_issue248.py index 528e81a2..5efd44b0 100644 --- a/test/test_issue248.py +++ b/test/test_issue248.py @@ -74,7 +74,7 @@ class TestSerialization(unittest.TestCase): graph.add((concept, rdflib.RDF.type, SKOS["Concept"])) graph.add((concept, SKOS["prefLabel"], rdflib.Literal("Scrapbooks"))) graph.add((concept, DC["LCC"], rdflib.Literal("AC999.0999 - AC999999.Z9999"))) - sg = graph.serialize(format="n3", base=LCCO).decode("utf8") + sg = graph.serialize(format="n3", base=LCCO) # See issue 248 # Actual test should be the inverse of the below ... self.assertTrue("<1> a skos:Concept ;" in sg, sg) diff --git a/test/test_issue801.py b/test/test_issue801.py index ae27f346..69573352 100644 --- a/test/test_issue801.py +++ b/test/test_issue801.py @@ -12,7 +12,7 @@ class TestIssue801(unittest.TestCase): g.bind('', example) node = BNode() g.add((node, example['first%20name'], Literal('John'))) - self.assertEqual(g.serialize(format="turtle").decode().split("\n")[-3], + self.assertEqual(g.serialize(format="turtle").split("\n")[-3], '[] :first%20name "John" .') if __name__ == "__main__": diff --git a/test/test_issue_git_336.py b/test/test_issue_git_336.py index c3d4a581..e74c2c4a 100644 --- a/test/test_issue_git_336.py +++ b/test/test_issue_git_336.py @@ -33,12 +33,10 @@ def test_ns_localname_roundtrip(): rdflib.Literal("Junk"), ) ) - turtledump = g.serialize(format="turtle").decode("utf-8") - xmldump = g.serialize().decode("utf-8") + turtledump = g.serialize(format="turtle") + xmldump = g.serialize(format="xml") g1 = rdflib.Graph() - g1.parse(data=xmldump, format="xml") - g1.parse(data=turtledump, format="turtle") diff --git a/test/test_n3.py b/test/test_n3.py index 7cd394cd..47dddc03 100644 --- a/test/test_n3.py +++ b/test/test_n3.py @@ -125,8 +125,8 @@ class TestN3Case(unittest.TestCase): URIRef("http://example.com/people/Linda"), ) ) - s = g.serialize(base="http://example.com/", format="n3") - self.assertTrue("<people/Bob>".encode("latin-1") in s) + s = g.serialize(base="http://example.com/", format="n3", encoding="latin-1") + self.assertTrue(b"<people/Bob>" in s) g2 = ConjunctiveGraph() g2.parse(data=s, publicID="http://example.com/", format="n3") self.assertEqual(list(g), list(g2)) diff --git a/test/test_namespace.py b/test/test_namespace.py index 510d8515..2706467f 100644 --- a/test/test_namespace.py +++ b/test/test_namespace.py @@ -72,11 +72,11 @@ class NamespacePrefixTest(unittest.TestCase): URIRef("http://example.com/baz"), ) ) - n3 = g.serialize(format="n3") + n3 = g.serialize(format="n3", encoding='latin-1') # Gunnar disagrees that this is right: # self.assertTrue("<http://example.com/foo> ns1:bar <http://example.com/baz> ." in n3) # as this is much prettier, and ns1 is already defined: - self.assertTrue("ns1:foo ns1:bar ns1:baz .".encode("latin-1") in n3) + self.assertTrue(b"ns1:foo ns1:bar ns1:baz ." in n3) def test_n32(self): # this test not generating prefixes for subjects/objects @@ -88,12 +88,10 @@ class NamespacePrefixTest(unittest.TestCase): URIRef("http://example3.com/baz"), ) ) - n3 = g.serialize(format="n3") + n3 = g.serialize(format="n3", encoding="latin-1") self.assertTrue( - "<http://example1.com/foo> ns1:bar <http://example3.com/baz> .".encode( - "latin-1" - ) + b"<http://example1.com/foo> ns1:bar <http://example3.com/baz> ." in n3 ) diff --git a/test/test_nquads.py b/test/test_nquads.py index f99984dd..b88f4d4e 100644 --- a/test/test_nquads.py +++ b/test/test_nquads.py @@ -52,9 +52,9 @@ class NQuadsParserTest(unittest.TestCase): g.get_context(uri1).add((bob, likes, pizza)) g.get_context(uri2).add((bob, likes, pizza)) - s = g.serialize(format="nquads") + s = g.serialize(format="nquads", encoding="latin-1") self.assertEqual( - len([x for x in s.split("\n".encode("latin-1")) if x.strip()]), 2 + len([x for x in s.split(b"\n") if x.strip()]), 2 ) g2 = ConjunctiveGraph() diff --git a/test/test_nt_misc.py b/test/test_nt_misc.py index 399f7bff..164776b8 100644 --- a/test/test_nt_misc.py +++ b/test/test_nt_misc.py @@ -24,15 +24,15 @@ class NTTestCase(unittest.TestCase): def testIssue78(self): g = Graph() g.add((URIRef("foo"), URIRef("foo"), Literal("R\u00E4ksm\u00F6rg\u00E5s"))) - s = g.serialize(format="nt") + s = g.serialize(format="nt", encoding="latin-1") self.assertEqual(type(s), bytes) self.assertTrue(r"R\u00E4ksm\u00F6rg\u00E5s".encode("latin-1") in s) def testIssue146(self): g = Graph() g.add((URIRef("foo"), URIRef("foo"), Literal("test\n", lang="en"))) - s = g.serialize(format="nt").strip() - self.assertEqual(s, '<foo> <foo> "test\\n"@en .'.encode("latin-1")) + s = g.serialize(format="nt", encoding="latin-1").strip() + self.assertEqual(s, b'<foo> <foo> "test\\n"@en .') def testIssue1144_rdflib(self): fname = "test/nt/lists-02.nt" diff --git a/test/test_prefixTypes.py b/test/test_prefixTypes.py index 8a785094..045c6056 100644 --- a/test/test_prefixTypes.py +++ b/test/test_prefixTypes.py @@ -25,10 +25,10 @@ class PrefixTypesTest(unittest.TestCase): """ def test(self): - s = graph.serialize(format="n3") + s = graph.serialize(format="n3", encoding="latin-1") print(s) - self.assertTrue("foaf:Document".encode("latin-1") in s) - self.assertTrue("xsd:date".encode("latin-1") in s) + self.assertTrue(b"foaf:Document" in s) + self.assertTrue(b"xsd:date" in s) if __name__ == "__main__": diff --git a/test/test_prettyxml.py b/test/test_prettyxml.py index 4151c354..86027fb3 100644 --- a/test/test_prettyxml.py +++ b/test/test_prettyxml.py @@ -188,9 +188,7 @@ class TestPrettyXmlSerializer(SerializerTestBase): xmlrepr = g.serialize(format="pretty-xml") # then: assert ( - """<rdf:value rdf:parseType="Literal"><p xmlns="http://www.w3.org/1999/xhtml">See also <a href="#aring">Å</a></p></rdf:value>""".encode( - "utf-8" - ) + """<rdf:value rdf:parseType="Literal"><p xmlns="http://www.w3.org/1999/xhtml">See also <a href="#aring">Å</a></p></rdf:value>""" in xmlrepr ) @@ -202,9 +200,7 @@ class TestPrettyXmlSerializer(SerializerTestBase): xmlrepr = g.serialize(format="pretty-xml") # then: assert ( - """<rdf:value rdf:datatype="http://www.w3.org/1999/02/22-rdf-syntax-ns#XMLLiteral"><p """.encode( - "utf-8" - ) + """<rdf:value rdf:datatype="http://www.w3.org/1999/02/22-rdf-syntax-ns#XMLLiteral"><p """ in xmlrepr ) diff --git a/test/test_roundtrip.py b/test/test_roundtrip.py index 149e9eb5..5bb433f1 100644 --- a/test/test_roundtrip.py +++ b/test/test_roundtrip.py @@ -51,8 +51,7 @@ def roundtrip(e, verbose=False): if verbose: print("S:") - print(s) - print(s.decode()) + print(s, flush=True) g2 = rdflib.ConjunctiveGraph() g2.parse(data=s, format=testfmt) diff --git a/test/test_sparql.py b/test/test_sparql.py index fdf29c3c..ae11226c 100644 --- a/test/test_sparql.py +++ b/test/test_sparql.py @@ -1,4 +1,5 @@ -from rdflib import Graph, URIRef, Literal, BNode +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 @@ -103,7 +104,7 @@ def test_sparql_update_with_bnode_serialize_parse(): """ graph = Graph() graph.update("INSERT DATA { _:blankA <urn:type> <urn:Blank> }") - string = graph.serialize(format="ntriples").decode("utf-8") + string = graph.serialize(format="ntriples") raised = False try: Graph().parse(data=string, format="ntriples") @@ -112,6 +113,37 @@ def test_sparql_update_with_bnode_serialize_parse(): assert not raised +def test_named_filter_graph_query(): + g = ConjunctiveGraph() + g.namespace_manager.bind('rdf', RDF) + g.namespace_manager.bind('rdfs', RDFS) + ex = Namespace('https://ex.com/') + g.namespace_manager.bind('ex', ex) + g.get_context(ex.g1).parse(format="turtle", data=f""" + PREFIX ex: <{str(ex)}> + PREFIX rdfs: <{str(RDFS)}> + ex:Boris rdfs:label "Boris" . + ex:Susan rdfs:label "Susan" . + """) + g.get_context(ex.g2).parse(format="turtle", data=f""" + PREFIX ex: <{str(ex)}> + ex:Boris a ex:Person . + """) + + assert list(g.query("SELECT ?l WHERE { GRAPH ex:g1 { ?a rdfs:label ?l } ?a a ?type }", + initNs={'ex': ex})) == [(Literal('Boris'),)] + assert list(g.query("SELECT ?l WHERE { GRAPH ex:g1 { ?a rdfs:label ?l } FILTER EXISTS { ?a a ?type }}", + initNs={'ex': ex})) == [(Literal('Boris'),)] + assert list(g.query("SELECT ?l WHERE { GRAPH ex:g1 { ?a rdfs:label ?l } FILTER NOT EXISTS { ?a a ?type }}", + initNs={'ex': ex})) == [(Literal('Susan'),)] + assert list(g.query("SELECT ?l WHERE { GRAPH ?g { ?a rdfs:label ?l } ?a a ?type }", + initNs={'ex': ex})) == [(Literal('Boris'),)] + assert list(g.query("SELECT ?l WHERE { GRAPH ?g { ?a rdfs:label ?l } FILTER EXISTS { ?a a ?type }}", + initNs={'ex': ex})) == [(Literal('Boris'),)] + assert list(g.query("SELECT ?l WHERE { GRAPH ?g { ?a rdfs:label ?l } FILTER NOT EXISTS { ?a a ?type }}", + initNs={'ex': ex})) == [(Literal('Susan'),)] + + if __name__ == "__main__": import nose diff --git a/test/test_sparql_service.py b/test/test_sparql_service.py index 550bfcb2..ea1af413 100644 --- a/test/test_sparql_service.py +++ b/test/test_sparql_service.py @@ -2,6 +2,8 @@ from rdflib import Graph, URIRef, Literal, Variable from rdflib.plugins.sparql import prepareQuery from rdflib.compare import isomorphic +from . import helper + def test_service(): g = Graph() @@ -16,7 +18,7 @@ def test_service(): <http://www.w3.org/2000/01/rdf-schema#comment> ?dbpComment . } } } limit 2""" - results = g.query(q) + results = helper.query_with_retry(g, q) assert len(results) == 2 for r in results: @@ -38,7 +40,7 @@ def test_service_with_bind(): <http://dbpedia.org/ontology/deathPlace> ?dbpDeathPlace . } } } limit 2""" - results = g.query(q) + results = helper.query_with_retry(g, q) assert len(results) == 2 for r in results: @@ -60,7 +62,7 @@ def test_service_with_values(): <http://dbpedia.org/ontology/deathPlace> ?dbpDeathPlace . } } } limit 2""" - results = g.query(q) + results = helper.query_with_retry(g, q) assert len(results) == 2 for r in results: @@ -76,7 +78,7 @@ def test_service_with_implicit_select(): { values (?s ?p ?o) {(<http://example.org/a> <http://example.org/b> 1) (<http://example.org/a> <http://example.org/b> 2)} }} limit 2""" - results = g.query(q) + results = helper.query_with_retry(g, q) assert len(results) == 2 for r in results: @@ -93,7 +95,7 @@ def test_service_with_implicit_select_and_prefix(): { values (?s ?p ?o) {(ex:a ex:b 1) (<http://example.org/a> <http://example.org/b> 2)} }} limit 2""" - results = g.query(q) + results = helper.query_with_retry(g, q) assert len(results) == 2 for r in results: @@ -110,7 +112,7 @@ def test_service_with_implicit_select_and_base(): { values (?s ?p ?o) {(<a> <b> 1) (<a> <b> 2)} }} limit 2""" - results = g.query(q) + results = helper.query_with_retry(g, q) assert len(results) == 2 for r in results: @@ -127,7 +129,7 @@ def test_service_with_implicit_select_and_allcaps(): ?s <http://purl.org/linguistics/gold/hypernym> <http://dbpedia.org/resource/Leveller> . } } LIMIT 3""" - results = g.query(q) + results = helper.query_with_retry(g, q) assert len(results) == 3 diff --git a/test/test_sparqlstore.py b/test/test_sparqlstore.py index 63b475cc..8154b10c 100644 --- a/test/test_sparqlstore.py +++ b/test/test_sparqlstore.py @@ -7,6 +7,9 @@ from http.server import BaseHTTPRequestHandler, HTTPServer import socket from threading import Thread +from . import helper + + try: assert len(urlopen("http://dbpedia.org/sparql").read()) > 0 except: @@ -30,7 +33,7 @@ class SPARQLStoreDBPediaTestCase(unittest.TestCase): def test_Query(self): query = "select distinct ?Concept where {[] a ?Concept} LIMIT 1" - res = self.graph.query(query, initNs={}) + res = helper.query_with_retry(self.graph, query, initNs={}) for i in res: assert type(i[0]) == URIRef, i[0].n3() @@ -39,7 +42,7 @@ class SPARQLStoreDBPediaTestCase(unittest.TestCase): SELECT ?label WHERE { ?s a xyzzy:Concept ; xyzzy:prefLabel ?label . } LIMIT 10 """ - res = self.graph.query( + res = helper.query_with_retry(self.graph, query, initNs={"xyzzy": "http://www.w3.org/2004/02/skos/core#"} ) for i in res: @@ -60,12 +63,12 @@ class SPARQLStoreDBPediaTestCase(unittest.TestCase): SELECT ?label WHERE { ?s a xyzzy:Concept ; xyzzy:prefLabel ?label . } LIMIT 10 """ - res = self.graph.query(prologue + query) + 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): - q = """ + query = """ SELECT ?s WHERE { ?s ?p ?o . @@ -74,19 +77,21 @@ class SPARQLStoreDBPediaTestCase(unittest.TestCase): """ g = Graph("SPARQLStore") g.open(self.path) - c = 0 - for r in g.query(q): - c += 1 + count = 0 + result = helper.query_with_retry(g, query) + for _ in result: + count += 1 - assert c == 5, "Graph(\"SPARQLStore\") didn't return 5 records" + assert count == 5, "Graph(\"SPARQLStore\") didn't return 5 records" from rdflib.plugins.stores.sparqlstore import SPARQLStore st = SPARQLStore(query_endpoint=self.path) - c = 0 - for r in st.query(q): - c += 1 + count = 0 + result = helper.query_with_retry(st, query) + for _ in result: + count += 1 - assert c == 5, "SPARQLStore() didn't return 5 records" + assert count == 5, "SPARQLStore() didn't return 5 records" class SPARQLStoreUpdateTestCase(unittest.TestCase): diff --git a/test/test_sparqlupdatestore.py b/test/test_sparqlupdatestore.py index ca137beb..eea01136 100644 --- a/test/test_sparqlupdatestore.py +++ b/test/test_sparqlupdatestore.py @@ -183,7 +183,7 @@ class TestSparql11(unittest.TestCase): "INSERT DATA { GRAPH <urn:graph> { _:blankA <urn:type> <urn:Blank> } }" ) g = self.graph.get_context(graphuri) - string = g.serialize(format="ntriples").decode("utf-8") + string = g.serialize(format="ntriples") raised = False try: Graph().parse(data=string, format="ntriples") diff --git a/test/test_trig.py b/test/test_trig.py index d61667fc..7474640f 100644 --- a/test/test_trig.py +++ b/test/test_trig.py @@ -30,7 +30,7 @@ class TestTrig(unittest.TestCase): self.assertEqual(len(g.get_context("urn:a")), 1) self.assertEqual(len(g.get_context("urn:b")), 1) - s = g.serialize(format="trig") + s = g.serialize(format="trig", encoding="latin-1") self.assertTrue(b"{}" not in s) # no empty graphs! def testSameSubject(self): @@ -46,7 +46,7 @@ class TestTrig(unittest.TestCase): self.assertEqual(len(g.get_context("urn:a")), 1) self.assertEqual(len(g.get_context("urn:b")), 1) - s = g.serialize(format="trig") + s = g.serialize(format="trig", encoding="latin-1") self.assertEqual(len(re.findall(b"p1", s)), 1) self.assertEqual(len(re.findall(b"p2", s)), 1) @@ -58,15 +58,15 @@ class TestTrig(unittest.TestCase): g.add(TRIPLE + (rdflib.URIRef("http://example.com/graph1"),)) # In 4.2.0 the first serialization would fail to include the # prefix for the graph but later serialize() calls would work. - first_out = g.serialize(format="trig") - second_out = g.serialize(format="trig") + first_out = g.serialize(format="trig", encoding="latin-1") + second_out = g.serialize(format="trig", encoding="latin-1") self.assertTrue(b"@prefix ns1: <http://example.com/> ." in second_out) self.assertTrue(b"@prefix ns1: <http://example.com/> ." in first_out) def testGraphQnameSyntax(self): g = rdflib.ConjunctiveGraph() g.add(TRIPLE + (rdflib.URIRef("http://example.com/graph1"),)) - out = g.serialize(format="trig") + out = g.serialize(format="trig", encoding="latin-1") self.assertTrue(b"ns1:graph1 {" in out) def testGraphUriSyntax(self): @@ -74,13 +74,13 @@ class TestTrig(unittest.TestCase): # getQName will not abbreviate this, so it should serialize as # a '<...>' term. g.add(TRIPLE + (rdflib.URIRef("http://example.com/foo."),)) - out = g.serialize(format="trig") + out = g.serialize(format="trig", encoding="latin-1") self.assertTrue(b"<http://example.com/foo.> {" in out) def testBlankGraphIdentifier(self): g = rdflib.ConjunctiveGraph() g.add(TRIPLE + (rdflib.BNode(),)) - out = g.serialize(format="trig") + out = g.serialize(format="trig", encoding='latin-1') graph_label_line = out.splitlines()[-4] self.assertTrue(re.match(br"^_:[a-zA-Z0-9]+ \{", graph_label_line)) @@ -153,7 +153,7 @@ class TestTrig(unittest.TestCase): """ g = rdflib.ConjunctiveGraph() g.parse(data=data, format="trig") - data = g.serialize(format="trig") + data = g.serialize(format="trig", encoding="latin-1") self.assertTrue(b"None" not in data) @@ -173,7 +173,7 @@ class TestTrig(unittest.TestCase): cg = rdflib.ConjunctiveGraph() cg.parse(data=data, format="trig") - data = cg.serialize(format="trig") + data = cg.serialize(format="trig", encoding="latin-1") self.assertTrue(b"ns2: <http://ex.org/docs/" in data) self.assertTrue(b"<ns2:document1>" not in data) diff --git a/test/test_trix_serialize.py b/test/test_trix_serialize.py index 4fe78a18..d0824aa9 100644 --- a/test/test_trix_serialize.py +++ b/test/test_trix_serialize.py @@ -39,7 +39,7 @@ class TestTrixSerialize(unittest.TestCase): r3 = URIRef("resource:3") g.add((r3, label, Literal(4))) - r = g.serialize(format="trix") + r = g.serialize(format="trix", encoding="utf-8") g3 = ConjunctiveGraph() g3.parse(BytesIO(r), format="trix") @@ -86,7 +86,7 @@ class TestTrixSerialize(unittest.TestCase): graph = ConjunctiveGraph() graph.bind(None, "http://defaultnamespace") - sg = graph.serialize(format="trix").decode("UTF-8") + sg = graph.serialize(format="trix") self.assertTrue('xmlns="http://defaultnamespace"' not in sg, sg) self.assertTrue('xmlns="http://www.w3.org/2004/03/trix/trix-1/' in sg, sg) diff --git a/test/test_turtle_serialize.py b/test/test_turtle_serialize.py index 48c86442..9c073e8c 100644 --- a/test/test_turtle_serialize.py +++ b/test/test_turtle_serialize.py @@ -12,8 +12,8 @@ def testTurtleFinalDot(): u = URIRef("http://ex.org/bob.") g.bind("ns", "http://ex.org/") g.add((u, u, u)) - s = g.serialize(format="turtle") - assert "ns:bob.".encode("latin-1") not in s + s = g.serialize(format="turtle", encoding="latin-1") + assert b"ns:bob." not in s def testTurtleBoolList(): @@ -89,7 +89,7 @@ def test_turtle_namespace(): ) output = [ val - for val in graph.serialize(format="turtle").decode().splitlines() + for val in graph.serialize(format="turtle").splitlines() if not val.startswith("@prefix") ] output = " ".join(output) |