Skip to content

Incorrect annotation for forward reference in generated constructor #1596

Description

@jjudas-resistant

When a class is decorated with @define or @frozen, and an attribute references a type declared later in the file, the generated __init__ method contains a type annotation that is different from the one on a hand-written __init__ method.

In Python 3.14 without from __future__ import annotations:

import inspect

from attrs import define


class Works:
    def __init__(self, foo: Foo) -> None:
        self._foo = foo


@define
class DoesNotWork:
    _foo: Foo


class Foo:
    pass


# prints `(foo: __main__.Foo) -> None`
print(inspect.signature(Works))

# prints `(foo: Foo) -> None` (a ForwardRef)
print(inspect.signature(DoesNotWork))

With from __future__ import annotations (tested on both 3.14 and 3.13 - same result):

from __future__ import annotations

import inspect

from attrs import define


class Works:
    def __init__(self, foo: Foo) -> None:
        self._foo = foo


@define
class DoesNotWork:
    _foo: Foo


class Foo:
    pass


# prints `(foo: __main__.Foo) -> None`
print(inspect.signature(Works, eval_str=True))

# crashes with `NameError: name 'Foo' is not defined`
print(inspect.signature(DoesNotWork, eval_str=True))

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