Skip to content
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

Generic with ParamSpec raise TypeError #126

Open
omaxx opened this issue Mar 12, 2023 · 3 comments
Open

Generic with ParamSpec raise TypeError #126

omaxx opened this issue Mar 12, 2023 · 3 comments
Labels

Comments

@omaxx
Copy link

omaxx commented Mar 12, 2023

I create generic class with specifying __init__ arguments through ParamSpec:

from typing import Generic
from typing_extensions import ParamSpec

P = ParamSpec('P')

class CLS(Generic[P]):
    def __init__(self, *args: P.args, **kwargs: P.kwargs):
        ...

class ONE(CLS[int]):
    ...

class TWO(CLS[int, int]):
    ...

# should pass type checks:
ONE(1)
TWO(1, 2)
# should fail type checks:
ONE(1, 2)
TWO(1)

mypy type checking works as expected, but during runtime I got next error:

Traceback (most recent call last):
  File "temp/issue.py", line 13, in <module>
    class TWO(CLS[int, int]):
  File "/usr/local/Cellar/python@3.9/3.9.16/Frameworks/Python.framework/Versions/3.9/lib/python3.9/typing.py", line 277, in inner
    return func(*args, **kwds)
  File "/usr/local/Cellar/python@3.9/3.9.16/Frameworks/Python.framework/Versions/3.9/lib/python3.9/typing.py", line 1004, in __class_getitem__
    _check_generic(cls, params, len(cls.__parameters__))
  File "/usr/local/lib/python3.9/site-packages/typing_extensions.py", line 109, in _check_generic
    raise TypeError(f"Too {'many' if alen > elen else 'few'} parameters for {cls};"
TypeError: Too many parameters for <class '__main__.CLS'>; actual 2, expected 1

Is it a bug? It works fine in 3.10 and 3.11

@JelleZijlstra
Copy link
Member

I believe this is covered by the note in the README that says "Certain PEP 612 special cases in user-defined Generics are also not available." We could create a typing_extensions.Generic to add support for this though, if we can't hack it into typing.Generic.

@omaxx
Copy link
Author

omaxx commented Mar 13, 2023

It works with that hack:

def define_func(func: Callable[P, None]) -> Callable[P, CLS[P]]:
    def _func(*args: P.args, **kwargs: P.kwargs) -> CLS[P]:
        return CLS(*args, **kwargs)
    return _func

def single(x: int) -> None: pass
def double(x: int, y: int) -> None: pass

ONE = define_func(single)
TWO = define_func(double)

ONE(1)
TWO(1, 2)
ONE(1, 2)
TWO(1)

@JelleZijlstra
Copy link
Member

I added a reference to this limitation to the docs in #171. I'd still accept a PR fixing it.

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

No branches or pull requests

3 participants