Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Raise ValueError for unsupported bind_namespace values #1845

Merged
merged 1 commit into from
Apr 19, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions rdflib/graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from io import BytesIO
from typing import (
IO,
TYPE_CHECKING,
Any,
BinaryIO,
Generator,
Expand Down Expand Up @@ -38,6 +39,9 @@
assert Literal # avoid warning
assert Namespace # avoid warning

if TYPE_CHECKING:
from rdflib.namespace import _NamespaceSetString

logger = logging.getLogger(__name__)

__doc__ = """\
Expand Down Expand Up @@ -329,7 +333,7 @@ def __init__(
identifier: Optional[Union[IdentifiedNode, str]] = None,
namespace_manager: Optional[NamespaceManager] = None,
base: Optional[str] = None,
bind_namespaces: str = "core",
bind_namespaces: "_NamespaceSetString" = "core",
):
super(Graph, self).__init__()
self.base = base
Expand All @@ -344,7 +348,7 @@ def __init__(
else:
self.__store = store
self.__namespace_manager = namespace_manager
self.bind_namespaces = bind_namespaces
self._bind_namespaces = bind_namespaces
self.context_aware = False
self.formula_aware = False
self.default_union = False
Expand All @@ -363,7 +367,7 @@ def namespace_manager(self):
this graph's namespace-manager
"""
if self.__namespace_manager is None:
self.__namespace_manager = NamespaceManager(self, self.bind_namespaces)
self.__namespace_manager = NamespaceManager(self, self._bind_namespaces)
return self.__namespace_manager

@namespace_manager.setter
Expand Down
25 changes: 18 additions & 7 deletions rdflib/namespace/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import json
import logging
import sys
import warnings
from functools import lru_cache
from pathlib import Path
Expand Down Expand Up @@ -342,6 +343,14 @@ def _ipython_key_completions_(self) -> List[str]:

XMLNS = Namespace("http://www.w3.org/XML/1998/namespace")

if TYPE_CHECKING:
if sys.version_info >= (3, 8):
from typing import Literal as PyLiteral
else:
from typing_extensions import Literal as PyLiteral

_NamespaceSetString = PyLiteral["core", "rdflib", "none"]


class NamespaceManager(object):
"""Class for managing prefix => namespace mappings
Expand Down Expand Up @@ -386,7 +395,7 @@ class NamespaceManager(object):

"""

def __init__(self, graph: "Graph", bind_namespaces: str = "core"):
def __init__(self, graph: "Graph", bind_namespaces: "_NamespaceSetString" = "core"):
self.graph = graph
self.__cache: Dict[str, Tuple[str, URIRef, str]] = {}
self.__cache_strict: Dict[str, Tuple[str, URIRef, str]] = {}
Expand All @@ -405,21 +414,23 @@ def __init__(self, graph: "Graph", bind_namespaces: str = "core"):
pass
elif bind_namespaces == "rdflib":
# bind all the Namespaces shipped with RDFLib
for prefix, ns in NAMESPACE_PREFIXES_RDFLIB.items():
for prefix, ns in _NAMESPACE_PREFIXES_RDFLIB.items():
self.bind(prefix, ns)
# ... don't forget the core ones too
for prefix, ns in NAMESPACE_PREFIXES_CORE.items():
for prefix, ns in _NAMESPACE_PREFIXES_CORE.items():
self.bind(prefix, ns)
elif bind_namespaces == "cc":
# bind any prefix that can be found with lookups to prefix.cc
# first bind core and rdflib ones
# work out remainder - namespaces without prefixes
# only look those ones up
raise NotImplementedError("Haven't got to this option yet")
else: # bind_namespaces == "core":
elif bind_namespaces == "core":
# bind a few core RDF namespaces - default
for prefix, ns in NAMESPACE_PREFIXES_CORE.items():
for prefix, ns in _NAMESPACE_PREFIXES_CORE.items():
self.bind(prefix, ns)
else:
raise ValueError(f"unsupported namespace set {bind_namespaces}")

def __contains__(self, ref: str) -> bool:
# checks if a reference is in any of the managed namespaces with syntax
Expand Down Expand Up @@ -828,7 +839,7 @@ def get_longest_namespace(trie: Dict[str, Any], value: str) -> Optional[str]:
from rdflib.namespace._XSD import XSD

# prefixes for the core Namespaces shipped with RDFLib
NAMESPACE_PREFIXES_CORE = {
_NAMESPACE_PREFIXES_CORE = {
"owl": OWL,
"rdf": RDF,
"rdfs": RDFS,
Expand All @@ -839,7 +850,7 @@ def get_longest_namespace(trie: Dict[str, Any], value: str) -> Optional[str]:


# prefixes for all the non-core Namespaces shipped with RDFLib
NAMESPACE_PREFIXES_RDFLIB = {
_NAMESPACE_PREFIXES_RDFLIB = {
"brick": BRICK,
"csvw": CSVW,
"dc": DC,
Expand Down
94 changes: 89 additions & 5 deletions test/test_namespacemanager.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,22 @@
import logging
import sys
from contextlib import ExitStack
from pathlib import Path
from typing import Any, Dict, Optional, Set, Tuple, Type, Union

import pytest

from rdflib.graph import Dataset
from rdflib.term import URIRef

sys.path.append(str(Path(__file__).parent.parent.absolute()))
from rdflib import Graph
from rdflib.namespace import (
NAMESPACE_PREFIXES_CORE,
NAMESPACE_PREFIXES_RDFLIB,
_NAMESPACE_PREFIXES_CORE,
_NAMESPACE_PREFIXES_RDFLIB,
OWL,
RDFS,
NamespaceManager,
)


Expand All @@ -18,7 +25,7 @@ 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_CORE)
pre = sorted([x[0] for x in list(g.namespaces())])
assert pre == ["owl", "rdf", "rdfs", "xml", "xsd"]

Expand All @@ -27,8 +34,8 @@ def test_rdflib_prefixes_bound():
g = Graph(bind_namespaces="rdflib")

# the core 5 + the extra 23 namespaces with prefixes
assert len(list(g.namespaces())) == len(NAMESPACE_PREFIXES_CORE) + len(
list(NAMESPACE_PREFIXES_RDFLIB)
assert len(list(g.namespaces())) == len(_NAMESPACE_PREFIXES_CORE) + len(
list(_NAMESPACE_PREFIXES_RDFLIB)
)


Expand Down Expand Up @@ -78,3 +85,80 @@ def test_replace():
assert ("rdfs", URIRef("http://example.com")) in list(
g.namespace_manager.namespaces()
)


def test_invalid_selector() -> None:
graph = Graph()
with pytest.raises(ValueError):
NamespaceManager(graph, bind_namespaces="invalid") # type: ignore[arg-type]


NamespaceSet = Set[Tuple[str, URIRef]]


def check_graph_ns(
graph: Graph,
expected_nsmap: Dict[str, Any],
check_namespaces: Optional[NamespaceSet] = None,
) -> None:
expected_namespaces = {
(prefix, URIRef(f"{uri}")) for prefix, uri in expected_nsmap.items()
}
logging.debug("expected_namespaces = %s", expected_namespaces)
graph_namespaces = {*graph.namespaces()}
assert expected_namespaces == graph_namespaces
nman_namespaces = {*graph.namespace_manager.namespaces()}
assert expected_namespaces == nman_namespaces
if check_namespaces is not None:
assert expected_namespaces == check_namespaces
logging.debug("check_namespaces = %s", check_namespaces)


@pytest.mark.parametrize(
["selector", "expected_result"],
[
(None, ValueError),
("invalid", ValueError),
("core", _NAMESPACE_PREFIXES_CORE),
("rdflib", {**_NAMESPACE_PREFIXES_CORE, **_NAMESPACE_PREFIXES_RDFLIB}),
("none", {}),
],
)
def test_graph_bind_namespaces(
selector: Any,
expected_result: Union[Dict[str, Any], Type[Exception]],
) -> None:
namespaces: Optional[NamespaceSet] = None
with ExitStack() as xstack:
if not isinstance(expected_result, dict):
xstack.enter_context(pytest.raises(expected_result))
graph = Graph(bind_namespaces=selector)
namespaces = {*graph.namespaces()}
if isinstance(expected_result, dict):
assert namespaces is not None
check_graph_ns(graph, expected_result, namespaces)
else:
assert namespaces is None


@pytest.mark.parametrize(
["selector", "expected_result"],
[
(None, ValueError),
("invalid", ValueError),
("core", _NAMESPACE_PREFIXES_CORE),
("rdflib", {**_NAMESPACE_PREFIXES_CORE, **_NAMESPACE_PREFIXES_RDFLIB}),
("none", {}),
],
)
def test_nman_bind_namespaces(
selector: Any,
expected_result: Union[Dict[str, Any], Type[Exception]],
) -> None:
with ExitStack() as xstack:
if not isinstance(expected_result, dict):
xstack.enter_context(pytest.raises(expected_result))
graph = Dataset()
graph.namespace_manager = NamespaceManager(graph, selector)
if isinstance(expected_result, dict):
check_graph_ns(graph, expected_result)