agronholm / typeguard

Run-time type checker for Python
Other
1.5k stars 112 forks source link

"TypedDict does not support instance and class checks": interaction between `typing_extension`, `typeguard_ignore`, `attrs` #443

Closed ryan-williams closed 5 months ago

ryan-williams commented 5 months ago

Things to check first

Typeguard version

4.1.5

Python version

3.11.8

What happened?

See test_typeddict.py:

from typing import Any

import attrs
from typing_extensions import TypedDict
# from typing import TypedDict  # ✅ uncommenting this fixes ``test_typeddict`` below

import typeguard

# ✅ uncommenting this also fixes ``test_typeddict`` below (even though it's not used!)
# from typeguard import typeguard_ignore
typeguard_ignore = typeguard.typeguard_ignore

class Spec(TypedDict):
    num: int

@typeguard_ignore
def converter(arg: dict[str, Spec]) -> dict[str, Any]:
    return {}

@attrs.define()
class Class:
    field: dict[str, Any] = attrs.field(factory=dict, converter=converter)

# ❌ As written, this fails with `TypeError: TypedDict does not support instance and class checks`
# Uncommenting either of the "✅" lines above makes it work though 😵‍💫
def test_typeddict():
    Class(field={'aaa': { 'num': 111 }})

How can we reproduce the bug?

ryan-williams/typeguard-issues has a working repro; here's the error in Github Actions.

agronholm commented 5 months ago

This appears to be caused by typing.is_typeddict() not recognizing typing_extensions.TypedDict. I'll follow up with a fix.

ryan-williams commented 5 months ago

ty!

FWIW, in my actual codebase, I worked around this by moving from typing_extensions.TypedDict to typing.TypedDict, which is possible in Python ≥3.8.

Whatever's happening here seems pretty niche, but appreciate your looking into it!

agronholm commented 5 months ago

Hm, I'm having trouble reproducing the problem on Python 3.11 and latest typing_extensions. Just to be sure, could you convert that into a standalone script that repros the issue?

ryan-williams commented 5 months ago

It should be standalone here in my repro repo.

Here's the failure in a simple Github Action. Just above you can see pip list:

Package                Version Editable project location
---------------------- ------- ---------------------------------------------------
attrs                  23.2.0
iniconfig              2.0.0
packaging              24.0
pip                    24.0
pluggy                 1.4.0
pytest                 8.1.1
setuptools             65.5.0
typeguard              4.1.5
typeguard-callable-bug 0.0.0   /home/runner/work/typeguard-issues/typeguard-issues
typing_extensions      4.10.0

Seems to be on latest typing_extensions, 4.10.0.

ryan-williams commented 5 months ago

Here's a Dockerfile:

FROM python:3.11.8
RUN git clone https://github.com/ryan-williams/typeguard-issues
WORKDIR typeguard-issues
RUN pip install -e .
RUN pytest src/test_typeddict.py  # ❌ TypeError: TypedDict does not support instance and class checks
agronholm commented 5 months ago

Thanks, I'll test it shortly.

agronholm commented 5 months ago

Ok, I managed to repro it without Docker or pytest. I have a fix in place, just need to write a test.