cyclonedds-python icon indicating copy to clipboard operation
cyclonedds-python copied to clipboard

Postponed Evaluation of Annotations causes TypeError in cyclonedds/idl/_type_normalize.py

Open AlfredWilmot opened this issue 3 months ago • 0 comments
trafficstars

Postponed evaluation of annotations is characterized by the following import statement:

from __future__ import annotations

This is sometimes required for type-hints (e.g. allowing writing union types as X | Y in Python 3.10).

My issue is that I get the following stack-trace when including the above import statement while trying to instantiate cyclonedds.topic.Topic:

0.437 Traceback (most recent call last):
0.437   File "/usr/local/lib/python3.10/site-packages/cyclonedds/idl/_type_normalize.py", line 38, in _strip_unextended_type
0.437     return _strip_unextended_type(modulename, getattr(pymodule, typename))
0.437 AttributeError: module '__main__' has no attribute 'str'
0.437
0.437 During handling of the above exception, another exception occurred:
0.437
0.437 Traceback (most recent call last):
0.437   File "<stdin>", line 14, in <module>
0.437   File "/usr/local/lib/python3.10/site-packages/cyclonedds/topic.py", line 54, in __init__
0.438     data_type.__idl__.populate()
0.438   File "/usr/local/lib/python3.10/site-packages/cyclonedds/idl/_main.py", line 89, in populate
0.438     for name, _ in get_extended_type_hints(self.datatype).items():
0.438   File "/usr/local/lib/python3.10/site-packages/cyclonedds/idl/_type_normalize.py", line 106, in get_extended_type_hints
0.438     _normalize_idl_class(cls)
0.438   File "/usr/local/lib/python3.10/site-packages/cyclonedds/idl/_type_normalize.py", line 93, in _normalize_idl_class
0.439     cls.__idl_type_annotations__ = _make_extended_type_hints(cls)
0.439   File "/usr/local/lib/python3.10/site-packages/cyclonedds/idl/_type_normalize.py", line 84, in _make_extended_type_hints
0.439     return {k: _strip_unextended_type(cls.__module__, v) for k, v in hints.items() if not k.startswith("__")}
0.439   File "/usr/local/lib/python3.10/site-packages/cyclonedds/idl/_type_normalize.py", line 84, in <dictcomp>
0.439     return {k: _strip_unextended_type(cls.__module__, v) for k, v in hints.items() if not k.startswith("__")}
0.439   File "/usr/local/lib/python3.10/site-packages/cyclonedds/idl/_type_normalize.py", line 40, in _strip_unextended_type
0.439     raise TypeError(f"Type {_type} as used in {module} cannot be resolved.")
0.439 TypeError: Type str as used in __main__ cannot be resolved.

Here's a Dockerfile for reproducing this bug (the Python code is derived from the cyclonedds Python API docs here):

FROM python:3.10-alpine3.22 AS base
RUN <<EOF
apk update
pip install --upgrade pip
pip install cyclonedds=="0.10.5"
EOF

FROM base AS works

RUN python3 <<EOF
from cyclonedds.domain import DomainParticipant
from cyclonedds.topic import Topic
from cyclonedds.pub import DataWriter
from dataclasses import dataclass
from cyclonedds.idl import IdlStruct

@dataclass
class Message(IdlStruct):
    text: str

participant = DomainParticipant()
topic = Topic(participant, "someTopic", Message)
writer = DataWriter(participant, topic)
writer.write(Message(text="some text"))

EOF

FROM base AS fails

RUN python3 <<EOF
from __future__ import annotations  # <--- THIS CAUSES ERROR

from cyclonedds.domain import DomainParticipant
from cyclonedds.topic import Topic
from cyclonedds.pub import DataWriter
from dataclasses import dataclass
from cyclonedds.idl import IdlStruct

@dataclass
class Message(IdlStruct):
    text: str

participant = DomainParticipant()
topic = Topic(participant, "someTopic", Message)
writer = DataWriter(participant, topic)
writer.write(Message(text="some text"))

EOF

With the above Dockerfile in your current directory, the works target can be successfully built by running:

docker build --target works .

Whereas building the fails target will result in the above stack-trace (the only difference between the two is the from __future__ import annotations import statement):

docker build --target fails .

Although postponed evaluation of annotations isn't necessary in this example code, I've found it is necessary for correct type-hinting in some circumstances. In any-case it's good to bring some attention to this bug (I couldn't see any other issues flagging it) and the work-around for dealing with it at time of writing.

AlfredWilmot avatar Jul 31 '25 17:07 AlfredWilmot