Skip to content

Document that accessing __annotations__ through __dict__ no longer works #139140

Closed

Description

@patrick-kidger

Bug report

Bug description:

The following code crashes on 3.14.0a4 but runs without error on 3.13:

import dataclasses

def my_dataclass(cls):
    try:
        annotations = cls.__dict__["__annotations__"]
    except KeyError:
        cls = dataclasses.dataclass()(cls)
    else:
        new_annotations = dict(annotations)
        for name in annotations.keys():
            if name == "ignore_this_annotation":
                new_annotations.pop(name)
        cls.__annotations__ = new_annotations
        cls = dataclasses.dataclass()(cls)
        cls.__annotations__ = annotations
    return cls

@my_dataclass
class X:
    x: int = 3
    ignore_this_annotation: int

with:

TypeError: non-default argument 'ignore_this_annotation' follows default argument 'x'

Python installed via uv venv --python=3.14.

x-ref patrick-kidger/optimistix#168 patrick-kidger/equinox#1096)

CPython versions tested on:

3.14

Operating systems tested on:

macOS

Linked PRs

Activity

  1. picnixz commented on Sep 18, 2025

    @picnixz
    Member

    Does it reproduce for 3.14.0rc3? (I believe that you meant an RC version as your Python is coming from uv which IIRC usea rc2 at least).

    Otherwise, cc @JelleZijlstra @ericvsmith

  2. added
    stdlibStandard Library Python modules in the Lib/ directory
    3.14bugs and security fixes
    3.15bugs and security fixes
    on Sep 18, 2025
  3. JelleZijlstra commented on Sep 18, 2025

    @JelleZijlstra
    Member

    Reading annotations from the __dict__ is no longer supported as a result of the implementation of PEP-649. Use annotationlib.get_annotations instead.

  4. patrick-kidger commented on Sep 18, 2025

    @patrick-kidger
    Author

    Thank you both for your response!

    Does it reproduce for 3.14.0rc3? (I believe that you meant an RC version as your Python is coming from uv which IIRC usea rc2 at least).

    I'm just repeating what uv reports 😁

    ❯ uv run python
    Python 3.14.0a4 (main, Jan 14 2025, 23:28:13) [Clang 19.1.6 ] on darwin
    Type "help", "copyright", "credits" or "license" for more information.
    >>> 
    

    Reading annotations from the __dict__ is no longer supported as a result of the implementation of PEP-649. Use annotationlib.get_annotations instead.

    IIUC, all instances of cls.__dict__['__annotations__'] should now be:

    import sys
    
    if sys.version_info >= (3, 14):
        import annotationlib
        x = annotationlib.get_annotations(cls)
    else:
        x = cls.__dict__['__annotations__']

    ?

    It seems that the meaning of existing code is being silently changed. (As is the case here.) At minimum could it be arranged for cls.__dict__['__annotations__'] to emit an error of some kind? For example, directing them to this issue or suggesting the above fix?

  5. JelleZijlstra commented on Sep 18, 2025

    @JelleZijlstra
    Member

    You can use inspect.get_annotations on most versions (since 3.10), and typing_extensions.get_annotations on all.

    At minimum could it be arranged for cls.dict['annotations'] to emit an error of some kind? For example, directing them to this issue or suggesting the above fix?

    No, there's no plausible way we could emit a warning on dict access to an arbitrary key. However, there is a Ruff rule for this: https://docs.astral.sh/ruff/rules/access-annotations-from-class-dict/

  6. picnixz commented on Sep 19, 2025

    @picnixz
    Member

    Considering this is the expected behaviour I am going to close this one as "not an issue"

  7. JelleZijlstra commented on Sep 19, 2025

    @JelleZijlstra
    Member

    I think we should document better that raw __dict__ access no longer works reliably.

  8. added
    docsDocumentation in the Doc dir
    and removed
    type-bugAn unexpected behavior, bug, or error
    on Sep 19, 2025
  9. changed the title [-]Python 3.14.0a4: dataclasses no longer respects `__annotations__` being set.[/-] [+]Document that accessing `__annotations__` through `__dict__` no longer works[/+] on Sep 19, 2025
  10. Builder106 commented on Jun 19, 2026

    @Builder106
    Contributor

    @JelleZijlstra — I'd be happy to write up the docs clarification you flagged here, if you're not already planning to.

    My read: in Doc/howto/annotations.rst, the "earlier versions of Python" note still suggests cls.__dict__.get('__annotations__', None) as a general fallback, but under PEP 649/749 the class __dict__ storage is lazily populated and a private implementation detail on 3.14+, so that pattern isn't reliable there anymore. I'd re-scope that line to Python 3.9 and earlier only, and point 3.10+/3.14+ readers to inspect.get_annotations / annotationlib.get_annotations (the APIs you mentioned upthread).

    Does that match what you had in mind? I'll put a PR together for this.

  11. JelleZijlstra commented on Jun 19, 2026

    @JelleZijlstra
    Member

    Yes that makes sense!

  12. added a commit that references this issue on Nov 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    3.14bugs and security fixes3.15bugs and security fixesdocsDocumentation in the Doc dirstdlibStandard Library Python modules in the Lib/ directorytopic-typing

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions