eclipse-cyclonedds / eclipse-cyclonedds/cyclonedds-python

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

Open
#305 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Python
Stars
110
Forks
68
Avg merge
1h 8m
Merged PRs (30d)
1

Description

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.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Reproduce the failure with the Dockerfile's fails target, then inspect cyclonedds/idl/_type_normalize.py along the reported _strip_unextended_type and get_extended_type_hints stack. Compare the behavior with the works target and verify that the same Message example succeeds when postponed annotations are enabled without raising the shown TypeError.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
backend
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.