From 8654291676156b0f87b0c1a0a484bcd7a051deaf Mon Sep 17 00:00:00 2001 From: Nils Philippsen Date: Thu, 20 Mar 2025 23:23:44 +0100 Subject: [PATCH] Cope with Namespace annotations in Python 3.14 The __annotations__ member can be incomplete, use the get_annotations() helper from annotationlib (Python >= 3.14) or inspect (Python >= 3.10) if available. Related: #3083 Signed-off-by: Nils Philippsen --- rdflib/namespace/__init__.py | 22 +++++++++++++++++++--- test_reports/rdflib_w3c_sparql10-HEAD.ttl | 2 +- test_reports/rdflib_w3c_sparql11-HEAD.ttl | 20 ++++++++++---------- 3 files changed, 30 insertions(+), 14 deletions(-) diff --git a/rdflib/namespace/__init__.py b/rdflib/namespace/__init__.py index c0c388022..14700a6c2 100644 --- a/rdflib/namespace/__init__.py +++ b/rdflib/namespace/__init__.py @@ -75,6 +75,22 @@ import logging import warnings from collections.abc import Iterable + +try: + # Python >= 3.14 + from annotationlib import ( + get_annotations, # type: ignore[attr-defined,unused-ignore] + ) +except ImportError: # pragma: no cover + try: + # Python >= 3.10 + from inspect import get_annotations # type: ignore[attr-defined,unused-ignore] + except ImportError: + + def get_annotations(thing: Any) -> dict: + return thing.__annotations__ + + from functools import lru_cache from pathlib import Path from typing import TYPE_CHECKING, Any @@ -311,7 +327,7 @@ def __contains__(cls, item: str) -> bool: if item_str.startswith(str(this_ns)): item_str = item_str[len(str(this_ns)) :] return any( - item_str in c.__annotations__ + item_str in get_annotations(c) or item_str in c._extras or (cls._underscore_num and item_str[0] == "_" and item_str[1:].isdigit()) for c in cls.mro() @@ -319,7 +335,7 @@ def __contains__(cls, item: str) -> bool: ) def __dir__(cls) -> Iterable[str]: - attrs = {str(x) for x in cls.__annotations__} + attrs = {str(x) for x in get_annotations(cls)} # Removing these as they should not be considered part of the namespace. attrs.difference_update(_DFNS_RESERVED_ATTRS) values = {cls[str(x)] for x in attrs} @@ -328,7 +344,7 @@ def __dir__(cls) -> Iterable[str]: def as_jsonld_context(self, pfx: str) -> dict: # noqa: N804 """Returns this DefinedNamespace as a JSON-LD 'context' object""" terms = {pfx: str(self._NS)} - for key, term in self.__annotations__.items(): + for key, term in get_annotations(self).items(): if issubclass(term, URIRef): terms[key] = f"{pfx}:{key}" diff --git a/test_reports/rdflib_w3c_sparql10-HEAD.ttl b/test_reports/rdflib_w3c_sparql10-HEAD.ttl index b8369a94d..f3ac4255d 100644 --- a/test_reports/rdflib_w3c_sparql10-HEAD.ttl +++ b/test_reports/rdflib_w3c_sparql10-HEAD.ttl @@ -1603,7 +1603,7 @@ earl:assertedBy ; earl:mode earl:automatic ; earl:result [ a earl:TestResult ; - earl:outcome earl:passed ] ; + earl:outcome earl:failed ] ; earl:subject ; earl:test . diff --git a/test_reports/rdflib_w3c_sparql11-HEAD.ttl b/test_reports/rdflib_w3c_sparql11-HEAD.ttl index 6140fa914..6d498df8b 100644 --- a/test_reports/rdflib_w3c_sparql11-HEAD.ttl +++ b/test_reports/rdflib_w3c_sparql11-HEAD.ttl @@ -691,7 +691,7 @@ earl:assertedBy ; earl:mode earl:automatic ; earl:result [ a earl:TestResult ; - earl:outcome earl:passed ] ; + earl:outcome earl:failed ] ; earl:subject ; earl:test . @@ -699,7 +699,7 @@ earl:assertedBy ; earl:mode earl:automatic ; earl:result [ a earl:TestResult ; - earl:outcome earl:passed ] ; + earl:outcome earl:failed ] ; earl:subject ; earl:test . @@ -707,7 +707,7 @@ earl:assertedBy ; earl:mode earl:automatic ; earl:result [ a earl:TestResult ; - earl:outcome earl:passed ] ; + earl:outcome earl:failed ] ; earl:subject ; earl:test . @@ -715,7 +715,7 @@ earl:assertedBy ; earl:mode earl:automatic ; earl:result [ a earl:TestResult ; - earl:outcome earl:passed ] ; + earl:outcome earl:failed ] ; earl:subject ; earl:test . @@ -723,7 +723,7 @@ earl:assertedBy ; earl:mode earl:automatic ; earl:result [ a earl:TestResult ; - earl:outcome earl:passed ] ; + earl:outcome earl:failed ] ; earl:subject ; earl:test . @@ -731,7 +731,7 @@ earl:assertedBy ; earl:mode earl:automatic ; earl:result [ a earl:TestResult ; - earl:outcome earl:passed ] ; + earl:outcome earl:failed ] ; earl:subject ; earl:test . @@ -1939,7 +1939,7 @@ earl:assertedBy ; earl:mode earl:automatic ; earl:result [ a earl:TestResult ; - earl:outcome earl:passed ] ; + earl:outcome earl:failed ] ; earl:subject ; earl:test . @@ -1947,7 +1947,7 @@ earl:assertedBy ; earl:mode earl:automatic ; earl:result [ a earl:TestResult ; - earl:outcome earl:passed ] ; + earl:outcome earl:failed ] ; earl:subject ; earl:test . @@ -2251,7 +2251,7 @@ earl:assertedBy ; earl:mode earl:automatic ; earl:result [ a earl:TestResult ; - earl:outcome earl:passed ] ; + earl:outcome earl:failed ] ; earl:subject ; earl:test . @@ -2259,7 +2259,7 @@ earl:assertedBy ; earl:mode earl:automatic ; earl:result [ a earl:TestResult ; - earl:outcome earl:passed ] ; + earl:outcome earl:failed ] ; earl:subject ; earl:test .