import itertools import os from test import TEST_DIR from urllib.error import URLError import pytest from rdflib.graph import ConjunctiveGraph, Graph from rdflib.plugins.parsers.notation3 import BadSyntax, exponent_syntax from rdflib.term import Literal, URIRef test_data = """ # Definitions of terms describing the n3 model # @keywords a. @prefix n3: <#>. @prefix log: . @prefix rdf: . @prefix rdfs: . @prefix : <#> . @forAll :s, :p, :x, :y, :z. n3:Statement a rdf:Class . n3:StatementSet a rdf:Class . n3:includes a rdfs:Property . # Cf rdf:li n3:predicate a rdf:Property; rdfs:domain n3:statement . n3:subject a rdf:Property; rdfs:domain n3:statement . n3:object a rdf:Property; rdfs:domain n3:statement . n3:context a rdf:Property; rdfs:domain n3:statement; rdfs:range n3:StatementSet . ########### Rules { :x :p :y . } log:means { [ n3:subject :x; n3:predicate :p; n3:object :y ] a log:Truth}. # Needs more thought ... ideally, we have the implcit AND rules of # juxtaposition (introduction and elimination) { { { :x n3:includes :s. } log:implies { :y n3:includes :s. } . } forall :s1 . } log:implies { :x log:implies :y } . { { { :x n3:includes :s. } log:implies { :y n3:includes :s. } . } forall :s1 } log:implies { :x log:implies :y } . # I think n3:includes has to be axiomatic builtin. - unless you go to syntax description. # syntax.n3? """ class TestN3Case: def test_base_cumulative(self): """ Test that the n3 parser supports base declarations This is issue #22 """ input = """ @prefix : . # default base :name "Foo" . # change it @base . :name "Bar" . # and change it more - they are cumulative @base . :name "Bing" . # unless abosulute @base . :name "Bong" . """ g = Graph() g.parse(data=input, format="n3") print(list(g)) assert (None, None, Literal("Foo")) in g assert (URIRef("http://example.com/doc/bar"), None, None) in g assert (URIRef("http://example.com/doc/doc2/bing"), None, None) in g assert (URIRef("http://test.com/bong"), None, None) in g def test_base_explicit(self): """ Test that the n3 parser supports resolving relative URIs and that base will override """ input = """ @prefix : . # default base :name "Foo" . # change it @base . :name "Bar" . """ g = Graph() g.parse(data=input, publicID="http://blah.com/", format="n3") print(list(g)) assert (URIRef("http://blah.com/foo"), None, Literal("Foo")) in g assert (URIRef("http://example.com/doc/bar"), None, None) in g def test_base_serialize(self): g = Graph() g.add( ( URIRef("http://example.com/people/Bob"), URIRef("urn:knows"), URIRef("http://example.com/people/Linda"), ) ) s = g.serialize(base="http://example.com/", format="n3", encoding="latin-1") assert b"" in s g2 = ConjunctiveGraph() g2.parse(data=s, publicID="http://example.com/", format="n3") assert list(g) == list(g2) def test_issue23(self): input = """ "this word is in \\u201Cquotes\\u201D".""" g = Graph() g.parse(data=input, format="n3") # Note difference in case of hex code, cwm allows lower-case input = """ "this word is in \\u201cquotes\\u201d".""" g.parse(data=input, format="n3") def test_issue29(self): input = """@prefix foo-bar: . foo-bar:Ex foo-bar:name "Test" . """ g = Graph() g.parse(data=input, format="n3") def test_issue68(self): input = """@prefix : .\n\n:Brecon a :Place;\n\t:hasLord\n\t\t:Bernard_of_Neufmarch\xc3\xa9 .\n """ g = Graph() g.parse(data=input, format="n3") def test_issue156(self): """ Make sure n3 parser does not choke on UTF-8 BOM """ g = Graph() n3_path = os.path.relpath(os.path.join(TEST_DIR, "data/issue156.n3", os.curdir)) g.parse(n3_path, format="n3") def test_issue999(self): """ Make sure the n3 parser does recognize exponent and leading dot in ".171e-11" """ data = """ @prefix rdfs: . a ; .171e-11 ; 0e+00 ; "0.001-fold of the SI base unit metre divided by the unit year" ; ; "0112/2///62720#UAA868" ; "H66" ; rdfs:isDefinedBy ; rdfs:isDefinedBy ; rdfs:label "MilliM PER YR" ; "millimetre per year" ; . """ g = Graph() g.parse(data=data, format="n3") g.parse(data=data, format="turtle") def test_dot_in_prefix(self): g = Graph() g.parse( data="@prefix a.1: .\n a.1:cake . \n", format="n3", ) def test_model(self): g = ConjunctiveGraph() g.parse(data=test_data, format="n3") i = 0 for s, p, o in g: if isinstance(s, Graph): i += 1 assert i == 3 assert len(list(g.contexts())) == 13 g.close() def test_quoted_serialization(self): g = ConjunctiveGraph() g.parse(data=test_data, format="n3") g.serialize(format="n3") def test_parse(self): g = ConjunctiveGraph() try: g.parse( "http://groups.csail.mit.edu/dig/2005/09/rein/examples/troop42-policy.n3", format="n3", ) except URLError: pytest.skip("No network to retrieve the information, skipping test") def test_single_quoted_literals(self): test_data = [ """@prefix : <#> . :s :p 'o' .""", """@prefix : <#> . :s :p '''o''' .""", ] for data in test_data: # N3 doesn't accept single quotes around string literals g = ConjunctiveGraph() with pytest.raises(BadSyntax): g.parse(data=data, format="n3") g = ConjunctiveGraph() g.parse(data=data, format="turtle") assert len(g) == 1 for _, _, o in g: assert o == Literal("o") def test_empty_prefix(self): # this is issue https://github.com/RDFLib/rdflib/issues/312 g1 = Graph() g1.parse(data=":a :b :c .", format="n3") g2 = Graph() g2.parse(data="@prefix : <#> . :a :b :c .", format="n3") assert set(g1) == set( g2 ), "Document with declared empty prefix must match default #" class TestRegularExpressions: def test_exponents(self): signs = ("", "+", "-") mantissas = ( "1", "1.", ".1", "12", "12.", "1.2", ".12", "123", "123.", "12.3", "1.23", ".123", ) es = "eE" exps = ("1", "12", "+1", "-1", "+12", "-12") for parts in itertools.product(signs, mantissas, es, exps): expstring = "".join(parts) assert exponent_syntax.match(expstring) def test_invalid_exponents(self): # Add test cases as needed invalid = (".e1",) for expstring in invalid: assert not exponent_syntax.match(expstring)