Skip to content

Commit

Permalink
fix: restore the 6.1.1 default bound namespaces (#2313)
Browse files Browse the repository at this point in the history
The namespaces bound by default by `rdflib.graph.Graph` and
`rdflib.namespace.NamespaceManager` was reduced in version 6.2.0 of RDFLib,
however, this also would cause code that worked with 6.1.1 to break, so this
constituted a breaking change. This change restores the previous behaviour,
binding the same namespaces as was bound in 6.1.1.

To bind a reduced set of namespaces, the `bind_namespaces` parameter of
`rdflib.graph.Graph` or `rdflib.namespace.NamespaceManager` can be used.

- Closes <#2103>.
  • Loading branch information
aucampia committed Mar 26, 2023
1 parent 4da67f9 commit 57bb428
Show file tree
Hide file tree
Showing 7 changed files with 121 additions and 20 deletions.
2 changes: 1 addition & 1 deletion rdflib/graph.py
Expand Up @@ -437,7 +437,7 @@ def __init__(
identifier: Optional[Union[_ContextIdentifierType, str]] = None,
namespace_manager: Optional[NamespaceManager] = None,
base: Optional[str] = None,
bind_namespaces: "_NamespaceSetString" = "core",
bind_namespaces: "_NamespaceSetString" = "rdflib",
):
super(Graph, self).__init__()
self.base = base
Expand Down
15 changes: 12 additions & 3 deletions rdflib/namespace/__init__.py
Expand Up @@ -360,20 +360,28 @@ class NamespaceManager(object):
* core:
* binds several core RDF prefixes only
* owl, rdf, rdfs, xsd, xml from the NAMESPACE_PREFIXES_CORE object
* this is default
* rdflib:
* binds all the namespaces shipped with RDFLib as DefinedNamespace instances
* all the core namespaces and all the following: brick, csvw, dc, dcat
* dcmitype, dcterms, dcam, doap, foaf, geo, odrl, org, prof, prov, qb, schema
* sh, skos, sosa, ssn, time, vann, void
* see the NAMESPACE_PREFIXES_RDFLIB object for the up-to-date list
* this is default
* none:
* binds no namespaces to prefixes
* note this is NOT default behaviour
* cc:
* using prefix bindings from prefix.cc which is a online prefixes database
* not implemented yet - this is aspirational
.. attention::
The namespaces bound for specific values of ``bind_namespaces``
constitute part of RDFLib's public interface, so changes to them should
only be additive within the same minor version. Removing values, or
removing namespaces that are bound by default, constitutes a breaking
change.
See the
Sample usage
Expand All @@ -390,10 +398,11 @@ class NamespaceManager(object):
>>> all_ns = [n for n in g.namespace_manager.namespaces()]
>>> assert ('ex', rdflib.term.URIRef('http://example.com/')) in all_ns
>>>
"""

def __init__(self, graph: "Graph", bind_namespaces: "_NamespaceSetString" = "core"):
def __init__(
self, graph: "Graph", bind_namespaces: "_NamespaceSetString" = "rdflib"
):
self.graph = graph
self.__cache: Dict[str, Tuple[str, URIRef, str]] = {}
self.__cache_strict: Dict[str, Tuple[str, URIRef, str]] = {}
Expand Down
3 changes: 2 additions & 1 deletion test/test_graph/test_namespace_rebinding.py
Expand Up @@ -3,7 +3,7 @@
import pytest

from rdflib import ConjunctiveGraph, Graph, Literal
from rdflib.namespace import OWL, Namespace
from rdflib.namespace import OWL, Namespace, NamespaceManager
from rdflib.plugins.stores.memory import Memory
from rdflib.term import URIRef

Expand Down Expand Up @@ -294,6 +294,7 @@ def test_multigraph_bindings():

# Including newly-created objects that use the store
cg = ConjunctiveGraph(store=store)
cg.namespace_manager = NamespaceManager(cg, bind_namespaces="core")

assert ("foaf", foaf1_uri) not in list(cg.namespaces())
assert ("friend-of-a-friend", foaf1_uri) in list(cg.namespaces())
Expand Down
96 changes: 91 additions & 5 deletions test/test_namespace/test_namespacemanager.py
Expand Up @@ -33,9 +33,41 @@ def test_core_prefixes_bound():
g = Graph()

# prefixes in Graph
assert len(list(g.namespaces())) == len(_NAMESPACE_PREFIXES_CORE)
assert len(list(g.namespaces())) == len(
{**_NAMESPACE_PREFIXES_RDFLIB, **_NAMESPACE_PREFIXES_CORE}
)
pre = sorted([x[0] for x in list(g.namespaces())])
assert pre == ["owl", "rdf", "rdfs", "xml", "xsd"]
assert pre == [
"brick",
"csvw",
"dc",
"dcam",
"dcat",
"dcmitype",
"dcterms",
"doap",
"foaf",
"geo",
"odrl",
"org",
"owl",
"prof",
"prov",
"qb",
"rdf",
"rdfs",
"schema",
"sh",
"skos",
"sosa",
"ssn",
"time",
"vann",
"void",
"wgs",
"xml",
"xsd",
]


def test_rdflib_prefixes_bound():
Expand Down Expand Up @@ -175,6 +207,40 @@ def test_nman_bind_namespaces(
@pytest.mark.parametrize(
["selector", "expected_bindings"],
[
(
None,
{
"brick": "https://brickschema.org/schema/Brick#",
"csvw": "http://www.w3.org/ns/csvw#",
"dc": "http://purl.org/dc/elements/1.1/",
"dcat": "http://www.w3.org/ns/dcat#",
"dcmitype": "http://purl.org/dc/dcmitype/",
"dcterms": "http://purl.org/dc/terms/",
"dcam": "http://purl.org/dc/dcam/",
"doap": "http://usefulinc.com/ns/doap#",
"foaf": "http://xmlns.com/foaf/0.1/",
"odrl": "http://www.w3.org/ns/odrl/2/",
"geo": "http://www.opengis.net/ont/geosparql#",
"org": "http://www.w3.org/ns/org#",
"owl": "http://www.w3.org/2002/07/owl#",
"prof": "http://www.w3.org/ns/dx/prof/",
"prov": "http://www.w3.org/ns/prov#",
"qb": "http://purl.org/linked-data/cube#",
"rdf": "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
"rdfs": "http://www.w3.org/2000/01/rdf-schema#",
"schema": "https://schema.org/",
"sh": "http://www.w3.org/ns/shacl#",
"skos": "http://www.w3.org/2004/02/skos/core#",
"sosa": "http://www.w3.org/ns/sosa/",
"ssn": "http://www.w3.org/ns/ssn/",
"time": "http://www.w3.org/2006/time#",
"vann": "http://purl.org/vocab/vann/",
"void": "http://rdfs.org/ns/void#",
"wgs": "https://www.w3.org/2003/01/geo/wgs84_pos#",
"xsd": "http://www.w3.org/2001/XMLSchema#",
"xml": "http://www.w3.org/XML/1998/namespace",
},
),
(
"rdflib",
{
Expand Down Expand Up @@ -208,19 +274,39 @@ def test_nman_bind_namespaces(
"xsd": "http://www.w3.org/2001/XMLSchema#",
"xml": "http://www.w3.org/XML/1998/namespace",
},
)
),
(
"core",
{
"owl": "http://www.w3.org/2002/07/owl#",
"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#",
"xml": "http://www.w3.org/XML/1998/namespace",
},
),
],
)
def test_bound_namespaces_subset(
selector: Any, expected_bindings: Dict[str, str]
selector: Optional[Any], expected_bindings: Dict[str, str]
) -> None:
graph = Graph(bind_namespaces=selector)
if selector is not None:
graph = Graph(bind_namespaces=selector)
else:
graph = Graph()
bound_namespaces = dict(
(key, str(value)) for key, value in graph.namespace_manager.namespaces()
)
assert (
expected_bindings.items() <= bound_namespaces.items()
), f"missing items {expected_bindings.items() - bound_namespaces.items()}"
empty_graph = Graph(bind_namespaces="none")
if selector is not None:
nman = NamespaceManager(empty_graph, bind_namespaces=selector)
else:
nman = NamespaceManager(empty_graph)
nman_bound_namespaces = dict((key, str(value)) for key, value in nman.namespaces())
assert bound_namespaces == nman_bound_namespaces


def test_compute_qname_no_generate() -> None:
Expand Down
4 changes: 2 additions & 2 deletions test/test_serializers/test_xmlwriter_qname.py
Expand Up @@ -10,7 +10,7 @@


def test_xmlwriter_namespaces():
g = rdflib.Graph()
g = rdflib.Graph(bind_namespaces="core")

with tempfile.TemporaryFile() as fp:
xmlwr = XMLWriter(fp, g.namespace_manager, extra_ns={"": TRIXNS, "ex": EXNS})
Expand All @@ -32,7 +32,7 @@ def test_xmlwriter_namespaces():


def test_xmlwriter_decl():
g = rdflib.Graph()
g = rdflib.Graph(bind_namespaces="core")

with tempfile.TemporaryFile() as fp:
xmlwr = XMLWriter(fp, g.namespace_manager, decl=0, extra_ns={"": TRIXNS})
Expand Down
16 changes: 9 additions & 7 deletions test/test_sparql/test_service.py
Expand Up @@ -330,14 +330,16 @@ def test_with_mock(
"head": {"vars": ["var"]},
"results": {"bindings": [{"var": item} for item in response_bindings]},
}
function_httpmock.responses[MethodName.GET].append(
MockHTTPResponse(
200,
"OK",
json.dumps(response).encode("utf-8"),
{"Content-Type": ["application/sparql-results+json"]},
)
mock_response = MockHTTPResponse(
200,
"OK",
json.dumps(response).encode("utf-8"),
{"Content-Type": ["application/sparql-results+json"]},
)
# Adding the same response for GET and POST as the method used by RDFLib is
# dependent on the size of the service query.
function_httpmock.responses[MethodName.GET].append(mock_response)
function_httpmock.responses[MethodName.POST].append(mock_response)
catcher: Optional[pytest.ExceptionInfo[Exception]] = None

with ExitStack() as xstack:
Expand Down
5 changes: 4 additions & 1 deletion test/utils/httpservermock.py
Expand Up @@ -96,7 +96,10 @@ def do_handler(handler: BaseHTTPRequestHandler) -> None:
logging.debug("headers %s", request.headers)
requests[method_name].append(request)

response = responses[method_name].pop(0)
try:
response = responses[method_name].pop(0)
except IndexError as error:
raise ValueError(f"No response for {method_name} request") from error
handler.send_response(response.status_code, response.reason_phrase)
apply_headers_to(response.headers, handler)
handler.end_headers()
Expand Down

0 comments on commit 57bb428

Please sign in to comment.