python / python/cpython

`__future__` annotations breaks `TypedDict` `__required/optional_keys__`

Open
#97,727 7 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

stdlib topic-typing type-bug
Dominant language
Python
Stars
77.2k
Forks
36k
PR merge metrics
PR metrics pending

Description

Bug report

from __future__ import annotations appears to break TypedDict required/optional keys ending up in __required_keys__ and __optional_keys__. mypy works as expected though.

Using the example from https://peps.python.org/pep-0655/#usage-in-python-3-11 as the base

$ cat t.py
from __future__ import annotations

from typing_extensions import NotRequired, TypedDict

class Dog(TypedDict):
    name: str
    owner: NotRequired[str]

print("required", Dog.__required_keys__)
print("optional", Dog.__optional_keys__)
$ python3 t.py
required frozenset({'name', 'owner'})
optional frozenset()

With the __future__ import removed, works as expected:

$ cat t.py
from typing_extensions import NotRequired, TypedDict

class Dog(TypedDict):
    name: str
    owner: NotRequired[str]

print("required", Dog.__required_keys__)
print("optional", Dog.__optional_keys__)
$ python3 t.py
required frozenset({'name'})
optional frozenset({'owner'})

Note: breaks across different variations of total and Required/NotRequired and typing_extensions vs typing imports, above is just one example.

https://peps.python.org/pep-0655/#how-to-teach-this contains an example with the __future__ annotations import in place with no mention that it would not cause __required_keys__ and __optional_keys__ becoming populated as expected, so I'm assuming this is a bug.

Your environment

  • CPython versions tested on:

    • 3.9.7 + NotRequired and TypedDict imports from typing_extensions
    • 3.10.7 + above mentioned imports from typing_extensions
    • current 3.11.0rc2+ + above mentioned imports from typing_extensions
    • current 3.11.0rc2+ above mentioned imports from typing
  • Operating system and architecture: Linux x86_64

Contributor guide

Open the contributing guide

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

Start by running the t.py reproduction with and without from __future__ import annotations, across the listed Python versions and both typing and typing_extensions. Trace the TypedDict, Required, and NotRequired entry points to determine how postponed annotations affect key classification. Done means __required_keys__ and __optional_keys__ match the declared annotations for the reported variations.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
42/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.