Description
openedon Dec 23, 2021
Note: if you are reporting a wrong signature of a function or a class in the standard library, then the typeshed tracker is better suited for this report: https://github.com/python/typeshed/issues.
Describe the bug
A clear and concise description of what the bug is.
I'm trying to start typing SQLAlchemy for v2, and I'm currently facing an issue typing the generative decorator it uses to make a method of a class generative.
The current wip is at https://gerrit.sqlalchemy.org/c/sqlalchemy/sqlalchemy/+/3423.
Below is an test script that reproduces the error outside sqlalchemy
To Reproduce
Steps to reproduce the behavior.
import typing
_Fn = typing.TypeVar("_Fn", bound=typing.Callable)
_Ret = typing.TypeVar("_Ret")
_Args = typing.ParamSpec("_Args")
_Self = typing.TypeVar("_Self", bound="_GenerativeType")
def decorator(
target: typing.Callable[typing.Concatenate[_Fn, _Args], _Ret]
) -> typing.Callable[[_Fn], typing.Callable[_Args, _Ret]]:
def decorate(fn: _Fn):
def wrapper(*a: _Args.args, **k: _Args.kwargs) -> _Ret:
return target(fn, *a, **k)
return wrapper
return decorate
class _GenerativeType(typing.Protocol):
def _generate(self: "_Self") -> "_Self":
...
def generative(
fn: typing.Callable[typing.Concatenate[_Self, _Args], None]
) -> typing.Callable[typing.Concatenate[_Self, _Args], _Self]:
@decorator
def _generative(
fn: typing.Callable[typing.Concatenate[_Self, _Args], None],
self: _Self,
*args: _Args.args,
**kw: _Args.kwargs
) -> _Self:
"""Mark a method as generative."""
self = self._generate()
x = fn(self, *args, **kw)
assert x is None, "generative methods must have no return value"
return self
decorated = _generative(fn)
# decorated.non_generative = fn
return decorated
running pyright on this snipped I get the following error:
No configuration file found.
No pyproject.toml file found.
stubPath path\to\foo\typings is not a valid directory.
Assuming Python platform Windows
Searching for source files
Found 1 source file
path\to\foo\test.py
path\to\foo\test.py:45:12 - error: Expression of type "(self: _Self@generative, **_Args@generative) -> _Ret@decorator" cannot be assigned to return type "(_Self@generative, **_Args@generative) -> _Self@generative"
Type "(self: _Self@generative, **_Args@generative) -> _Ret@decorator" cannot be assigned to type "(_Self@generative, **_Args@generative) -> _Self@generative"
Function return type "_Ret@decorator" is incompatible with type "_Self@generative"
Type "_Ret@decorator" cannot be assigned to type "_GenerativeType" (reportGeneralTypeIssues)
1 error, 0 warnings, 0 infos
Completed in 0.725sec
Trial and error seems to point to the ParamSpec
in the inner _generative
. If I replace it with this version not error is found:
def generative(
fn: typing.Callable[typing.Concatenate[_Self, _Args], None]
) -> typing.Callable[typing.Concatenate[_Self, _Args], _Self]:
@decorator
def _generative(
fn: typing.Callable[typing.Concatenate[_Self, _Args], None],
self: _Self,
) -> _Self:
"""Mark a method as generative."""
self = self._generate()
x = fn(self)
assert x is None, "generative methods must have no return value"
return self
decorated = _generative(fn)
# decorated.non_generative = fn
return decorated
Expected behavior
A clear and concise description of what you expected to happen.
I believe the original type is correct, so pyright should type check correctly
Screenshots or Code
see above
VS Code extension or command-line
Are you running pyright as a VS Code extension or a command-line tool? Which version? You can find the version of the VS Code extension by clicking on the Pyright icon in the extensions panel.
command line;
> pyright --version
pyright 1.1.199
Additional context
Add any other context about the problem here.
cc @zzzeek @erictraut microsoft/pylance-release#840 (comment)