Skip to content

regression with Generic/ParamSpec between 1.4.1 and 1.5.0 #15844

Description

@jessemyers-lettuce

Bug Report

With 1.5.0, some of our software has started to surface a var-annotated ("Need type annotation for") error that it did not surface with 1.4.1; I could not find anything in the 1.5.0 release notes that suggested that this was intentional.

To Reproduce

Our actual software is a bit domain-specific, but I've tried to extract the details; the concept involves a data descriptor that attaches a callable to a class and generates a new callable that inverts how the callable's constructor and runtime arguments are supplied. The solution depends on ParamSpec to preserve the argument signatures and uses Generic so that the same internals can be used for different functions.

#!/usr/bin/env python3fromdataclassesimportdataclassfromtypingimportGeneric, ParamSpec, Protocol, Self, TypeVar, overloadP=ParamSpec("P")
T=TypeVar("T")
classTransform(Protocol[P, T]):
"""Generic protocol to transform a value using inputs."""def__init__(self, *args: P.args, **kwargs: P.kwargs) ->None:
raiseNotImplementedErrordef__call__(self, value: T) ->T:
raiseNotImplementedErrorclassBoundTransform(Generic[P, T]):
"""Wrapper around a transform function that performs late-binding."""def__init__(
self,
value: T,
transform_cls: type[Transform[P, T]],
) ->None:
self.value: T=valueself.transform_cls: type[Transform[P, T]] =transform_clsdef__call__(
self,
*args: P.args,
**kwargs: P.kwargs,
) ->T:
returnself.transform_cls(*args, **kwargs)(self.value)
classHasValue(Protocol[T]):
value: TclassTransformer(Generic[P, T]):
"""Data descriptor that applies the bound transformer to something with a value."""def__init__(
self,
transform_cls: type[Transform[P, T]],
) ->None:
self.transform_cls: type[Transform[P, T]] =transform_cls@overloaddef__get__(self, obj: None, objtype: type[HasValue[T]]) ->Self:
...
@overloaddef__get__(self, obj: HasValue[T], objtype: type[HasValue[T]]) ->BoundTransform[P, T]:
...
def__get__(self, obj: HasValue[T] |None, objtype: type[HasValue[T]]) ->Self|BoundTransform[P, T]:
ifobjisNone:
returnselfreturnBoundTransform(obj.value, self.transform_cls)
@dataclass(frozen=True)classAdd:
"""Transform implementation that adds two integers."""value: intdef__call__(self, value: int) ->int:
returnvalue+self.value@dataclass(frozen=True)classHasNumber(HasValue[int]):
"""HasValue implementation that holds an integer."""value: intadd=Transformer(Add)
if__name__=="__main__":
# Usage examplefoo=HasNumber(42)
bar=foo.add(-42)
assertbar==0

Expected Behavior

No errors from mypy. This is true for 1.4.1.

Actual Behavior

Errors. This is true for 1.5.0

main.py:81: error: Need type annotation for"add" [var-annotated]
Found 1 error in 1 file (checked 1 source file)

Your Environment

  • Mypy version used: 1.4.1 and 1.5.0
  • Mypy command-line flags: n/a
  • Mypy configuration options from mypy.ini (and other config files): n/a
  • Python version used: 3.11.4

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions