diff --git a/rdflib/namespace/__init__.py b/rdflib/namespace/__init__.py
index 3e8753393..f8e69bfaa 100644
--- a/rdflib/namespace/__init__.py
+++ b/rdflib/namespace/__init__.py
@@ -491,10 +491,27 @@ def qname(self, uri: str) -> str:
return ":".join((prefix, name))
def curie(self, uri: str) -> str:
- """From a URI, generate a valid CURIE.
+ """
+ From a URI, generate a valid CURIE.
+
+ Result is guaranteed to contain a colon separating the prefix from the
+ name, even if the prefix is an empty string.
+
+ .. warning::
+
+ If there is no matching namespace for the URI in the namespace
+ manager then a new namespace will be added with prefix
+ ``ns{index}``.
+
+ Because of this side effect this is not a pure function.
+
+ This is the same behaviour as `NamespaceManager.qname`.
+
+
+
+ :param uri: URI to generate CURIE for.
+ :return: CURIE for the URI.
- Result is guaranteed to contain a colon separating the prefix from the name,
- even if the prefix is an empty string.
"""
prefix, namespace, name = self.compute_qname(uri)
return ":".join((prefix, name))
diff --git a/test/data/owl/test_ontology.owl b/test/data/owl/test_ontology.owl
deleted file mode 100644
index 51ff107ac..000000000
--- a/test/data/owl/test_ontology.owl
+++ /dev/null
@@ -1,315 +0,0 @@
-
-
-
- Orson B Osborn
- Test OBO ontology
- 0.1.0
-
-
-
-
-
-
-
-
-
-
-
-
- editor preferred term
-
- The concise, meaningful, and human-friendly name for a class or property preferred by the ontology developers. (US-English)
- PERSON:Daniel Schober
- GROUP:OBI:<http://purl.obolibrary.org/obo/obi>
-
- editor preferred term
-
-
-
-
-
-
-
- example
- example of usage
-
- A phrase describing how a class name should be used. May also include other kinds of examples that facilitate immediate understanding of a class semantics, such as widely known prototypical subclasses or instances of the class. Although essential for high level terms, examples for low level terms (e.g., Affymetrix HU133 array) are not
- A phrase describing how a term should be used and/or a citation to a work which uses it. May also include other kinds of examples that facilitate immediate understanding, such as widely know prototypes or instances of a class, or cases where a relation is said to hold.
- PERSON:Daniel Schober
- GROUP:OBI:<http://purl.obolibrary.org/obo/obi>
- IAO:0000112
- uberon
- example_of_usage
- true
- example_of_usage
-
- example of usage
-
-
-
-
-
-
-
- has curation status
-
-
-
-
-
-
-
- definition
-
-
-
-
-
-
-
- term editor
-
-
-
-
-
-
-
- alternative term
-
-
-
-
-
-
-
- definition source
-
-
-
-
-
-
-
- is direct form of
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- precedes
- x precedes y if and only if the time point at which x ends is before or equivalent to the time point at which y starts. Formally: x precedes y iff ω(x) <= α(y), where α is a function that maps a process to a start point, and ω is a function that maps a process to an end point.
- BFO:0000063
- uberon
- precedes
-
- precedes
- precedes
-
-
-
-
-
-
-
-
- David Osumi-Sutherland
- ends_at_start_of
- meets
-
-
- X immediately_precedes_Y iff: end(X) simultaneous_with start(Y)
- immediately precedes
-
-
-
-
-
-
-
-
-
- Chris Mungall
- A relation that holds between two occurrents. This is a grouping relation that collects together all the Allen relations.
- temporally related to
-
-
-
-
-
-
-
-
-
-
-
-
-
- entity
-
-
-
-
-
-
-
-
- occurrent
-
-
-
-
-
-
-
-
- continuant
-
-
-
-
-
-
-
-
- Jeff Lerman
- 2023-03-29T00:33:04Z
- This is a comment which will be a fallback definition.
- chair
-
-
-
-
-
-
-
-
- Jeff Lerman
- 2023-03-29T00:32:55Z
- furniture item
-
-
-
-
-
-
-
-
- Jeff Lerman
- 2023-03-29T00:33:24Z
- office chair
-
-
-
-
-
-
-
-
- Jeff Lerman
- 2023-03-29T00:32:46Z
- table
-
-
-
-
-
-
-
diff --git a/test/test_namespace/test_namespacemanager.py b/test/test_namespace/test_namespacemanager.py
index 979d51601..d66f0dc98 100644
--- a/test/test_namespace/test_namespacemanager.py
+++ b/test/test_namespace/test_namespacemanager.py
@@ -5,6 +5,7 @@
import sys
from contextlib import ExitStack
from pathlib import Path
+from test.utils.exceptions import ExceptionChecker
from typing import TYPE_CHECKING, Any, Dict, Mapping, Optional, Set, Tuple, Type, Union
import pytest
@@ -486,67 +487,100 @@ def check() -> None:
check()
+def make_test_nsm() -> NamespaceManager:
+ namespaces = [
+ ("rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#"),
+ ("", "http://example.org/"),
+ (
+ # Because of this
+ # will have no effect on the namespace manager.
+ "eg",
+ "http://example.org/",
+ ),
+ ]
+ graph = Graph(bind_namespaces="none")
+ for prefix, namespace in namespaces:
+ graph.bind(prefix, namespace, override=False)
+
+ return graph.namespace_manager
+
+
+@pytest.fixture(scope="session")
+def test_nsm_session() -> NamespaceManager:
+ return make_test_nsm()
+
+
+@pytest.fixture(scope="function")
+def test_nsm_function() -> NamespaceManager:
+ return make_test_nsm()
+
+
@pytest.mark.parametrize(
- "curie, expected_uri, expected_exception, expected_exc_patt",
+ ["curie", "expected_result"],
[
- ("rdf:type", "http://www.w3.org/1999/02/22-rdf-syntax-ns#type", None, ""),
- ("obo:IAO_0000111", "http://purl.obolibrary.org/obo/IAO_0000111", None, ""),
- ("obo:nonexistent", "http://purl.obolibrary.org/obo/nonexistent", None, ""),
- ("too_small", "irrelevant", ValueError, "Malformed curie argument"),
+ ("rdf:type", "http://www.w3.org/1999/02/22-rdf-syntax-ns#type"),
+ (":foo", "http://example.org/foo"),
+ ("too_small", ExceptionChecker(ValueError, "Malformed curie argument")),
(
- "blah:chair",
- "http://blah.org/ontology#chair",
- ValueError,
- 'Prefix "blah" not bound to any namespace',
+ "egdo:bar",
+ ExceptionChecker(ValueError, 'Prefix "egdo" not bound to any namespace'),
),
- # next case only works with fix for https://github.com/RDFLib/rdflib/issues/2348
- (":chair", "http://www.example.org/ontologies/mini-ont#chair", None, ""),
pytest.param(
- # failure case that should succeed once https://github.com/RDFLib/rdflib/issues/2077 is fixed
- "mini-ont:chair",
- "http://www.example.org/ontologies/mini-ont#chair",
- None,
- "",
- marks=pytest.mark.xfail,
+ "eg:foo",
+ "http://example.org/foo",
+ marks=pytest.mark.xfail(
+ raises=ValueError,
+ reason="This is failing because of https://github.com/RDFLib/rdflib/issues/2077",
+ ),
),
],
)
def test_expand_curie(
- test_owl_graph: Graph,
+ test_nsm_session: NamespaceManager,
curie: str,
- expected_uri: str,
- expected_exception: Optional[Type[Exception]],
- expected_exc_patt: str,
-):
- """Confirm that NamespaceManager.expand_curie() handles various CURIEs correctly."""
- nsm = test_owl_graph.namespace_manager
- if expected_exception is None:
- actual_uri = nsm.expand_curie(curie)
- assert actual_uri == URIRef(expected_uri)
- else:
- with pytest.raises(
- expected_exception=expected_exception, match=expected_exc_patt
- ):
- _ = nsm.expand_curie(curie)
+ expected_result: Union[ExceptionChecker, str],
+) -> None:
+ nsm = test_nsm_session
+ with ExitStack() as xstack:
+ if isinstance(expected_result, ExceptionChecker):
+ xstack.enter_context(expected_result)
+ result = nsm.expand_curie(curie)
+
+ if not isinstance(expected_result, ExceptionChecker):
+ assert URIRef(expected_result) == result
@pytest.mark.parametrize(
- "uri, expected_curie",
+ ["uri", "expected_result"],
[
("http://www.w3.org/1999/02/22-rdf-syntax-ns#type", "rdf:type"),
- ("http://purl.obolibrary.org/obo/BFO_0000002", "obo:BFO_0000002"),
- ("http://www.example.org/ontologies/mini-ont#chair", ":chair"),
- ("http://bogus.org/our_ontology#chair", "ns1:chair"),
- ("http://bogus.org/their_ontology#chair", "ns2:chair"),
+ ("http://example.org/foo", ":foo"),
+ ("http://example.com/a#chair", "ns1:chair"),
+ ("http://example.com/b#chair", "ns1:chair"),
+ ("http://example.com/c", "ns1:c"),
+ ("", ExceptionChecker(ValueError, "Can't split ''")),
+ (
+ "http://example.com/",
+ ExceptionChecker(ValueError, "Can't split 'http://example.com/'"),
+ ),
],
)
-def test_generate_curie(test_owl_graph: Graph, uri: str, expected_curie: str):
- """Confirm that NamespaceManager.curie() generates the expected CURIE given a URI.
+def test_generate_curie(
+ test_nsm_function: NamespaceManager,
+ uri: str,
+ expected_result: Union[ExceptionChecker, str],
+) -> None:
+ """
+ .. note::
- Includes demonstration that unknown namespaces are auto-populated into the
- NamespaceManager, and that entities in the default namespace get a CURIE that starts
- with a colon.
+ This is using the function scoped nsm fixture because curie has side
+ effects and will modify the namespace manager.
"""
- nsm = test_owl_graph.namespace_manager
- actual_curie = nsm.curie(uri)
- assert actual_curie == expected_curie
+ nsm = test_nsm_function
+ with ExitStack() as xstack:
+ if isinstance(expected_result, ExceptionChecker):
+ xstack.enter_context(expected_result)
+ result = nsm.curie(uri)
+
+ if not isinstance(expected_result, ExceptionChecker):
+ assert expected_result == result
diff --git a/test/utils/exceptions.py b/test/utils/exceptions.py
index a814f9b40..94cfd9c29 100644
--- a/test/utils/exceptions.py
+++ b/test/utils/exceptions.py
@@ -1,15 +1,32 @@
+from __future__ import annotations
+
import logging
import re
from dataclasses import dataclass
-from typing import Any, Dict, Optional, Pattern, Type, Union
+from types import TracebackType
+from typing import Any, ContextManager, Dict, Optional, Pattern, Type, Union
+
+import pytest
+from pytest import ExceptionInfo
-@dataclass(frozen=True)
-class ExceptionChecker:
+@dataclass
+class ExceptionChecker(ContextManager[ExceptionInfo[Exception]]):
type: Type[Exception]
pattern: Optional[Union[Pattern[str], str]] = None
attributes: Optional[Dict[str, Any]] = None
+ def __post_init__(self) -> None:
+ self._catcher = pytest.raises(self.type, match=self.pattern)
+ self._exception_info: Optional[ExceptionInfo[Exception]] = None
+
+ def _check_attributes(self, exception: Exception) -> None:
+ if self.attributes is not None:
+ for key, value in self.attributes.items():
+ logging.debug("checking exception attribute %s=%r", key, value)
+ assert hasattr(exception, key)
+ assert getattr(exception, key) == value
+
def check(self, exception: Exception) -> None:
logging.debug("checking exception %s/%r", type(exception), exception)
pattern = self.pattern
@@ -19,11 +36,22 @@ def check(self, exception: Exception) -> None:
assert isinstance(exception, self.type)
if pattern is not None:
assert pattern.match(f"{exception}")
- if self.attributes is not None:
- for key, value in self.attributes.items():
- logging.debug("checking exception attribute %s=%r", key, value)
- assert hasattr(exception, key)
- assert getattr(exception, key) == value
+ self._check_attributes(exception)
except Exception:
logging.error("problem checking exception", exc_info=exception)
raise
+
+ def __enter__(self) -> ExceptionInfo[Exception]:
+ self._exception_info = self._catcher.__enter__()
+ return self._exception_info
+
+ def __exit__(
+ self,
+ __exc_type: Optional[Type[BaseException]],
+ __exc_value: Optional[BaseException],
+ __traceback: Optional[TracebackType],
+ ) -> bool:
+ result = self._catcher.__exit__(__exc_type, __exc_value, __traceback)
+ if self._exception_info is not None:
+ self._check_attributes(self._exception_info.value)
+ return result