Skip to content

Commit 618166d

Browse files
committed
utils/modeling: support for annotations in python3.14
PEP 649 & PEP 749: Deferred evaluation of annotations The annotations on classes(ConfigSchema classes in our case) are no longer evaluated eagerly. They are evaluated only when necessary.
1 parent b6d6ccd commit 618166d

File tree

3 files changed

+16
-6
lines changed

3 files changed

+16
-6
lines changed

python/knot_resolver/utils/modeling/base_schema.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
from .exceptions import AggregateDataValidationError, DataDescriptionError, DataValidationError
1313
from .renaming import Renamed, renamed
1414
from .types import (
15+
get_annotations,
1516
get_generic_type_argument,
1617
get_generic_type_arguments,
1718
get_generic_type_wrapper_argument,
@@ -139,7 +140,8 @@ def _parse_attrs_docstrings(docstring: str) -> Optional[Dict[str, str]]:
139140

140141
def _get_properties_schema(typ: Type[Any]) -> Dict[Any, Any]:
141142
schema: Dict[Any, Any] = {}
142-
annot: Dict[str, Any] = typ.__dict__.get("__annotations__", {})
143+
annot = get_annotations(typ)
144+
143145
docstring: str = typ.__dict__.get("__doc__", "") or ""
144146
attribute_documentation = _parse_attrs_docstrings(docstring)
145147
for field_name, python_type in annot.items():
@@ -528,7 +530,7 @@ def _assign_fields(self, obj: Any, source: Union[Dict[str, Any], "BaseSchema", N
528530
2. assignments with conversion method
529531
"""
530532
cls = obj.__class__
531-
annot = cls.__dict__.get("__annotations__", {})
533+
annot = get_annotations(cls)
532534
errs: List[DataValidationError] = []
533535

534536
used_keys: Set[str] = set()
@@ -733,7 +735,7 @@ def __eq__(self, o: object) -> bool:
733735
if not isinstance(o, cls):
734736
return False
735737

736-
annot = cls.__dict__.get("__annotations__", {})
738+
annot = get_annotations(cls)
737739
for name in annot.keys():
738740
if getattr(self, name) != getattr(o, name):
739741
return False
@@ -775,7 +777,7 @@ def json_schema(
775777
def to_dict(self) -> Dict[Any, Any]:
776778
res: Dict[Any, Any] = {}
777779
cls = self.__class__
778-
annot = cls.__dict__.get("__annotations__", {})
780+
annot = get_annotations(cls)
779781

780782
for name in annot:
781783
res[name] = Serializable.serialize(getattr(self, name))

python/knot_resolver/utils/modeling/types.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,13 @@
1111
NoneType = type(None)
1212

1313

14+
def get_annotations(obj: Any) -> Dict[str, Any]:
15+
if hasattr(inspect, "get_annotations"):
16+
return inspect.get_annotations(obj)
17+
# TODO(bump to py3.10): Safe to remove. This fallback exists for older versions
18+
return obj.__dict__.get("__annotations__", {})
19+
20+
1421
def is_optional(tp: Any) -> bool:
1522
origin = getattr(tp, "__origin__", None)
1623
args = get_generic_type_arguments(tp)
@@ -83,7 +90,7 @@ def is_none_type(tp: Any) -> bool:
8390
def get_attr_type(obj: Any, attr_name: str) -> Any:
8491
assert hasattr(obj, attr_name)
8592
assert hasattr(obj, "__annotations__")
86-
annot = getattr(type(obj), "__annotations__")
93+
annot = get_annotations(type(obj))
8794
assert attr_name in annot
8895
return annot[attr_name]
8996

tests/manager/datamodel/test_config_schema.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from knot_resolver.datamodel.lua_schema import LuaSchema
77
from knot_resolver.utils.modeling import BaseSchema
88
from knot_resolver.utils.modeling.types import (
9+
get_annotations,
910
get_generic_type_argument,
1011
get_generic_type_arguments,
1112
get_optional_inner_type,
@@ -37,7 +38,7 @@ def _check_str_type(cls: Type[Any], object_path: str = ""):
3738
_check_str_type(inner_type, object_path)
3839

3940
elif inspect.isclass(cls) and issubclass(cls, BaseSchema):
40-
annot = cls.__dict__.get("__annotations__", {})
41+
annot = get_annotations(cls)
4142
for name, python_type in annot.items():
4243
# ignore lua section
4344
if python_type != LuaSchema:

0 commit comments

Comments
 (0)