Skip to content

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

@AlfredWilmot

Description

@AlfredWilmot

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions