Skip to content

try from typing import ParamSpec except from typing_ext import ParamSpec not working #16903

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
ghost opened this issue Feb 11, 2024 · 4 comments
Labels
bug mypy got something wrong

Comments

@ghost
Copy link

ghost commented Feb 11, 2024

Bug Report
try-except imported ParamSpec is unusable.

try:
    from typing import ParamSpec
except ImportError:
    from typing_extensions import ParamSpec

This makes ParamSpec("P") become an invaild type.

To Reproduce

from typing import Callable

try:
    from typing import ParamSpec  # type: ignore[attr-defined,unused-ignore]
except ImportError:
    from typing_extensions import ParamSpec  # type: ignore[import,unused-ignore]

P = ParamSpec("P")

def func(arg: Callable[P, None]) -> None:
    return None

Expected Behavior
No error

Actual Behavior
error: The first argument to Callable must be a list of types, parameter specification, or "..." [valid-type]

Your Environment

  • OS: Ubuntu 22.04.3 LTS (GNU/Linux 5.15.0-94-generic x86_64)
  • Mypy version used: 1.8.0 (compiled: yes)
  • Mypy command-line flags: None
  • Mypy configuration options from mypy.ini (and other config files): None
  • Python version used: 3.8.18

Reproduce repository

@ghost ghost added the bug mypy got something wrong label Feb 11, 2024
@hamdanal
Copy link
Collaborator

This way of conditional import is not currently supported by mypy. You'll have to use a version check to do the import.
This code achieves the same thing and type checks correctly by mypy:

import sys
from typing import Callable

if sys.version_info >= (3, 10):
    from typing import ParamSpec
else:
    from typing_extensions import ParamSpec

P = ParamSpec("P")

def func(arg: Callable[P, None]) -> None:
    return None

You can read more about it here
https://mypy.readthedocs.io/en/stable/runtime_troubles.html#using-new-additions-to-the-typing-module

@ghost ghost closed this as completed Feb 12, 2024
@ghost ghost reopened this Feb 12, 2024
@AlexWaygood
Copy link
Member

Duplicate of #14220

@AlexWaygood AlexWaygood marked this as a duplicate of #14220 Feb 12, 2024
@AlexWaygood AlexWaygood closed this as not planned Won't fix, can't repro, duplicate, stale Feb 12, 2024
@ghost
Copy link
Author

ghost commented Feb 12, 2024

Hmm... it doesn't works very well.
Once I use from sys import ...:

from sys import version_info

if version_info >= (3, 10):
    from typing import ParamSpec
else:
    from typing_extensions import ParamSpec

Mypy says 6:5: error: Incompatible import of "ParamSpec" (imported name has type "type[typing_extensions.ParamSpec]", local name has type "type[typing.ParamSpec]") [assignment]

@AlexWaygood
Copy link
Member

Correct. You need to do this:

import sys

if sys.version_info >= (3, 10):
    from typing import ParamSpec
else:
    from typing_extensions import ParamSpec

You can't do from sys import version_info and expect mypy to understand it in the same way, I'm afraid. It doesn't have the ability to understand arbitrary constructs like this; only a small selection of special-cased constructs are supported. See the relevant section in PEP 484: https://peps.python.org/pep-0484/#version-and-platform-checking

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug mypy got something wrong
Projects
None yet
Development

No branches or pull requests

2 participants