Skip to content

Commit

Permalink
fix: DefinedNamespace: fixed handling of _NS attribute
Browse files Browse the repository at this point in the history
This patch changes `DefinedNamespace` to always raise `AttributeError` for
the name `_NS` from `__getattr__`.

Without doign this `inspect.signature` recurses
infinitely when inspecting `rdflib.namespace.DefinedNamespace`.

One situation in which this occurs is when sphinx autodoc is generating
documentation from type hints:

```
WARNING: error while formatting signature for rdflib.namespace.DefinedNamespace: Handler <function record_typehints at 0x7fbf2696dd40> for event 'autodoc-process-signature' threw an exception (exception: maximum recursion depth exceeded while calling a Python object)
```

Also:
- fix: handling of `_NS` in `__contains__`. Without this `dir` on an empty
  `DefinedNamespace` does not behave correctly.
  • Loading branch information
aucampia committed Apr 15, 2022
1 parent 57f993d commit 0a5957e
Show file tree
Hide file tree
Showing 2 changed files with 420 additions and 3 deletions.
17 changes: 14 additions & 3 deletions rdflib/namespace/__init__.py
Expand Up @@ -3,7 +3,7 @@
import warnings
from functools import lru_cache
from pathlib import Path
from typing import TYPE_CHECKING, Any, Dict, Iterable, List, Optional, Tuple, Union
from typing import TYPE_CHECKING, Any, Dict, Iterable, List, Optional, Set, Tuple, Union
from unicodedata import category
from urllib.parse import urldefrag, urljoin

Expand Down Expand Up @@ -190,6 +190,13 @@ def __repr__(self) -> str:
return f"URIPattern({super().__repr__()})"


# _DFNS_RESERVED_ATTRS are attributes for which DefinedNamespaceMeta should
# always raise AttributeError if they are not defined.
_DFNS_RESERVED_ATTRS: Set[str] = {
"_NS",
}


class DefinedNamespaceMeta(type):
"""Utility metaclass for generating URIRefs with a common prefix."""

Expand All @@ -215,10 +222,14 @@ def __getitem__(cls, name: str, default=None) -> URIRef:
return cls._NS[name]

def __getattr__(cls, name: str):
if name in _DFNS_RESERVED_ATTRS:
raise AttributeError(
f"DefinedNamespace like object has no attribute {name!r}"
)
return cls.__getitem__(name)

def __repr__(cls) -> str:
return f'Namespace("{cls._NS}")'
return f'Namespace({str(cls._NS)!r})'

def __str__(cls) -> str:
return str(cls._NS)
Expand All @@ -229,7 +240,7 @@ def __add__(cls, other: str) -> URIRef:
def __contains__(cls, item: str) -> bool:
"""Determine whether a URI or an individual item belongs to this namespace"""
item_str = str(item)
if item_str.startswith("__"):
if item_str.startswith("__") or item_str in _DFNS_RESERVED_ATTRS:
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)) :]
Expand Down

0 comments on commit 0a5957e

Please sign in to comment.