1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176
|
From: Ashley Sommer <ashleysommer@gmail.com>
Date: Fri, 1 Nov 2024 14:24:41 +1000
Subject: Fix defined namespace warnings (#2964) (#2965)
* Fix defined namespace warnings
Current docs-generation tests are polluted by lots of warnings that occur when Sphinx tries to read various parts of DefinedNamespace.
* Fix tests that no longer need incorrect exceptions handled.
* fix black formatting in test file
* Undo typing changes, so this works on current pre-3.9 branch
* better handling for any/all double-underscore properties
* Don't include __slots__ in dir().
---
rdflib/namespace/__init__.py | 44 ++++++++++++++++++----------
test/test_namespace/test_definednamespace.py | 28 ++++++------------
2 files changed, 38 insertions(+), 34 deletions(-)
diff --git a/rdflib/namespace/__init__.py b/rdflib/namespace/__init__.py
index 4077b0b..eb8e2ee 100644
--- a/rdflib/namespace/__init__.py
+++ b/rdflib/namespace/__init__.py
@@ -226,6 +226,7 @@ class URIPattern(str):
# considered part of __dir__ results. These should be all annotations on
# `DefinedNamespaceMeta`.
_DFNS_RESERVED_ATTRS: Set[str] = {
+ "__slots__",
"_NS",
"_warn",
"_fail",
@@ -244,6 +245,8 @@ _IGNORED_ATTR_LOOKUP: Set[str] = {
class DefinedNamespaceMeta(type):
"""Utility metaclass for generating URIRefs with a common prefix."""
+ __slots__: Tuple[str, ...] = tuple()
+
_NS: Namespace
_warn: bool = True
_fail: bool = False # True means mimic ClosedNamespace
@@ -255,15 +258,11 @@ class DefinedNamespaceMeta(type):
name = str(name)
if name in _DFNS_RESERVED_ATTRS:
- raise AttributeError(
- f"DefinedNamespace like object has no attribute {name!r}"
+ raise KeyError(
+ f"DefinedNamespace like object has no access item named {name!r}"
)
elif name in _IGNORED_ATTR_LOOKUP:
raise KeyError()
- if str(name).startswith("__"):
- # NOTE on type ignore: This seems to be a real bug, super() does not
- # implement this method, it will fail if it is ever reached.
- return super().__getitem__(name, default) # type: ignore[misc] # undefined in superclass
if (cls._warn or cls._fail) and name not in cls:
if cls._fail:
raise AttributeError(f"term '{name}' not in namespace '{cls._NS}'")
@@ -277,26 +276,39 @@ class DefinedNamespaceMeta(type):
def __getattr__(cls, name: str):
if name in _IGNORED_ATTR_LOOKUP:
raise AttributeError()
+ elif name in _DFNS_RESERVED_ATTRS:
+ raise AttributeError(
+ f"DefinedNamespace like object has no attribute {name!r}"
+ )
+ elif name.startswith("__"):
+ return super(DefinedNamespaceMeta, cls).__getattribute__(name)
return cls.__getitem__(name)
def __repr__(cls) -> str:
- return f"Namespace({str(cls._NS)!r})"
+ try:
+ ns_repr = repr(cls._NS)
+ except AttributeError:
+ ns_repr = "<DefinedNamespace>"
+ return f"Namespace({ns_repr})"
def __str__(cls) -> str:
- return str(cls._NS)
+ try:
+ return str(cls._NS)
+ except AttributeError:
+ return "<DefinedNamespace>"
def __add__(cls, other: str) -> URIRef:
return cls.__getitem__(other)
def __contains__(cls, item: str) -> bool:
"""Determine whether a URI or an individual item belongs to this namespace"""
+ try:
+ this_ns = cls._NS
+ except AttributeError:
+ return False
item_str = str(item)
- if item_str.startswith("__"):
- # NOTE on type ignore: This seems to be a real bug, super() does not
- # implement this method, it will fail if it is ever reached.
- return super().__contains__(item) # type: ignore[misc] # undefined in superclass
- if item_str.startswith(str(cls._NS)):
- item_str = item_str[len(str(cls._NS)) :]
+ if item_str.startswith(str(this_ns)):
+ item_str = item_str[len(str(this_ns)) :]
return any(
item_str in c.__annotations__
or item_str in c._extras
@@ -313,7 +325,7 @@ class DefinedNamespaceMeta(type):
return values
def as_jsonld_context(self, pfx: str) -> dict: # noqa: N804
- """Returns this DefinedNamespace as a a JSON-LD 'context' object"""
+ """Returns this DefinedNamespace as a JSON-LD 'context' object"""
terms = {pfx: str(self._NS)}
for key, term in self.__annotations__.items():
if issubclass(term, URIRef):
@@ -328,6 +340,8 @@ class DefinedNamespace(metaclass=DefinedNamespaceMeta):
Warnings are emitted if unknown members are referenced if _warn is True
"""
+ __slots__: Tuple[str, ...] = tuple()
+
def __init__(self):
raise TypeError("namespace may not be instantiated")
diff --git a/test/test_namespace/test_definednamespace.py b/test/test_namespace/test_definednamespace.py
index ea8e129..5860e8e 100644
--- a/test/test_namespace/test_definednamespace.py
+++ b/test/test_namespace/test_definednamespace.py
@@ -299,14 +299,9 @@ def test_repr(dfns: Type[DefinedNamespace]) -> None:
ns_uri = f"{prefix}{dfns_info.suffix}"
logging.debug("ns_uri = %s", ns_uri)
- repr_str: Optional[str] = None
-
- with ExitStack() as xstack:
- if dfns_info.suffix is None:
- xstack.enter_context(pytest.raises(AttributeError))
- repr_str = f"{dfns_info.dfns!r}"
+ repr_str: str = f"{dfns_info.dfns!r}"
if dfns_info.suffix is None:
- assert repr_str is None
+ assert "<DefinedNamespace>" in repr_str
else:
assert repr_str is not None
repro = eval(repr_str)
@@ -368,20 +363,15 @@ def test_contains(
dfns_info = get_dfns_info(dfns)
if dfns_info.suffix is not None:
logging.debug("dfns_info = %s", dfns_info)
- if dfns_info.has_attrs is False:
+ if dfns_info.has_attrs is False or dfns_info.suffix is None:
is_defined = False
- does_contain: Optional[bool] = None
- with ExitStack() as xstack:
- if dfns_info.suffix is None:
- xstack.enter_context(pytest.raises(AttributeError))
- does_contain = attr_name in dfns
- if dfns_info.suffix is not None:
- if is_defined:
- assert does_contain is True
- else:
- assert does_contain is False
+
+ does_contain: bool = attr_name in dfns
+
+ if is_defined:
+ assert does_contain is True
else:
- assert does_contain is None
+ assert does_contain is False
@pytest.mark.parametrize(
|