Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions packages/dexpace-sdk-core/src/dexpace/sdk/core/serde/codec.py
Original file line number Diff line number Diff line change
Expand Up @@ -908,10 +908,12 @@ def _resolve_info(target: type) -> _ModelInfo:
localns = {tp.__name__: tp for tp in type_params} or None
try:
hints = get_type_hints(target, include_extras=True, localns=localns)
except NameError as err:
except (NameError, AttributeError, TypeError, SyntaxError) as err:
# An unresolvable forward reference (a string annotation whose name is
# not in scope) surfaces as a bare ``NameError`` from ``get_type_hints``;
# wrap it so the codec keeps its ``CodecError`` contract.
# other evaluation failures (stale qualified references, malformed
# expressions) raise ``AttributeError``, ``TypeError``, or ``SyntaxError``.
# Wrap them all so the codec keeps its ``CodecError`` contract.
raise CodecError(
f"cannot resolve a type hint on {target.__name__}: {err}",
target_name=target.__name__,
Expand Down
24 changes: 24 additions & 0 deletions packages/dexpace-sdk-core/tests/serde/test_codec.py
Original file line number Diff line number Diff line change
Expand Up @@ -786,6 +786,30 @@ class HasBadRef:
assert "resolve" in str(info.value)


def test_decode_stale_qualified_ref_raises_codec_error(codec: Codec) -> None:
# ``get_type_hints`` raises ``AttributeError`` for a string annotation
# referencing a non-existent attribute on a valid module.
@dataclass(frozen=True, slots=True)
class HasStaleRef:
value: "os.ThisDoesNotExist" # type: ignore[name-defined] # noqa: F821

with pytest.raises(CodecError) as info:
codec.decode({"value": 1}, HasStaleRef)
assert "resolve" in str(info.value)


def test_decode_malformed_expression_raises_codec_error(codec: Codec) -> None:
# ``get_type_hints`` raises ``SyntaxError`` for a string annotation
# that is not a valid expression.
@dataclass(frozen=True, slots=True)
class HasBadSyntax:
value: "def f(" # type: ignore[name-defined] # noqa: F821

with pytest.raises(CodecError) as info:
codec.decode({"value": 1}, HasBadSyntax)
assert "resolve" in str(info.value)


@dataclass(frozen=True, slots=True)
class _Box[T]:
item: T
Expand Down