Repository navigation
Description
Describe the bug
Starting with Pyright 1.1.412, Container[Any].copy() becomes Any instead of Container[Any], losing the outer container type and suppressing the nonexistent-member error. Expected: preserve Container[Any] and report the invalid attribute, since every overload returns a container.
Code or Screenshots
from typing import Any, Generic, Never, TypeVar, overload, reveal_type
T = TypeVar("T")
class Container(Generic[T]):
@overload
def copy(self: "Container[Never]") -> "Container[Any]": ...
@overload
def copy(self: "Container[int]") -> "Container[int]": ...
@overload
def copy(self: "Container[float]") -> "Container[float]": ...
def copy(self) -> "Container[Any]":
return self
def example(value: Container[Any], concrete: Container[int]) -> None:
reveal_type(value.copy())
reveal_type(concrete.copy())
value.copy().nonexistent_member()VS Code extension or command-line
- https://pyright-play.net/?code=GYJw9gtgBALgngBwJYDsDmUkQWEMoCCKcANFAOICmKlISAxmQHKUButZAKopQGoCGIMmHYgANmH4ATMiDaV%2BYgPrwElAFDrOUALxRuagSAAUAIk6mAlJvpj%2BAZ3tQAwmBQx%2BqWsao069AG1OAF1LAC51KCioAAERWglpSOipSmAoejAEOGN7SjFgMKhTV3dPPwCWUWCrKABaAD5i0o8vEACiOBqigDo%2B5Ki40USpAahU9Mzs3PzC5rdWitQYGst6ppKF8toA5e6oPp6xoYTJUejxtIysnLyCos2ytoDgRJXaxvmnitfJd97%2BhcJtdpndgGtPo9FjtOt0xhc5DAAK4gFBQMGaYGUAAe-GwYkoxlYiiRlCKLW27VhZEyKHoiLJLi2zz2EKaTDcZLGcnYihUPCJJMoPSmOUsaygAGIoNk6GgABb4NBIdhOTrc%2BR81SE2n0ygwYWi4ziqLS2VIBVKlWUJwUlnuYJjYliUkim7GnooTnYpD2A3uJQQSgQABG3glZrgcsV4zANqgXvwIE8eSAA
- https://pyrefly.org/sandbox/?project=v2.pVXLDoIwEPyVjRzQS3vnZOIPeOCmxihW5GBrpBr9e6cvpCIk6LXdGXbLzOzYyGxy0SdeE2G9eZSjb181XU_y9cT-Q2fFhZIaU4jr1POu8k2Q4Dwwvp1VqMvT-irDSzTYlW1lA2KjtvYFOsZxRoyxsZxQ0jdGd_wT4xFVXznDRYs1oukbq-NUUxxCRLiQCxkSg7FDlCyAim7MbJ-Gbf1LR8VsW7MZUUKQf1WeNJWQVm3k0cWE7_TDPt72neUewiS6eSDFhdTbszjvIZaI5qDAAss4p3ZdmdDSHZAXuBn-WJU3bD3YFC-eYOEJOml9qTPOA1xdSy4kP6ii5hGCkwmg3X1X2V0a05GyKVKD9p84SF0apENhkJosQMWgv18
Version 1.1.411 exits with status 1; the later versions exit with status 0.
| Pyright | Generic result | Missing-member error |
|---|---|---|
| 1.1.411 | Container[Any] |
Reported |
| 1.1.412–1.1.414 | Any |
Missed |
All four versions infer Container[int] for the concrete control.
#11601 intentionally handles ambiguity from nested Any/Unknown in invariant nominal type arguments, with specialized-self and pandas-like tests covering precision loss. This report asks whether the shared outer container can be preserved to retain attribute checking; it does not claim a typing-specification violation.
On unchanged pandas-stubs main at pandas-dev/pandas-stubs@507243e, Pyright 1.1.414 reports 240 reportAssertTypeFailure errors versus zero in 1.1.411; related work: pandas-dev/pandas-stubs#1941 and temporary pin pandas-dev/pandas-stubs#1942.
Activity
cmp0xff commentedon Sep 10, 2026
Additional context: python/typing#2350 explicitly permits more precise gradual results for ambiguous overloads, while keeping
Anycompliant. Carl Meyer’s discussion specifically identifies pandas-stubs’ leadingNeveroverloads and describes preservingSeries[Any]as a way forward.The practical concern here is lost error detection: the nonexistent-member access in the reproducer now passes. Could Pyright preserve
Container[Any]in this case, and shared generic container structure more generally where the specification’s assignability and supported-operation requirements are satisfied?The
copy()method is a minimal illustration. The affected pandas arithmetic overloads include type promotion and different result families, so replacing them all with a single type-preserving generic signature would not preserve their behaviour.Preserve container types for ambiguous overload returns (#11732)
cmp0xff commentedon Oct 12, 2026
Could this be prioritised now that mypy nightly (python/mypy#22011) aligns with ty's existing gradual receiver ambiguity handling (astral-sh/ty#4055)? This blocks a consistent approach in pandas-stubs without losing useful container checking.
This reduced case still returns
Anyand misses the invalid attribute in Pyright 1.1.414. Nightly mypy preservesContainer[Any]and reports the error.rchiodo commentedon Oct 12, 2026
The container erasure and missing attribute error are gone in the
mainbuild I checked, but the broader specialized-selfambiguity isn't fully handled yet.The latest public release is still 1.1.414, published September 9, before the changes below. So today's result with released 1.1.414 is expected. The source build also displays 1.1.414, which makes the version string a bit misleading here. The checks below used a fresh build of
mainat543798c, not the released package, with a Python 3.12 target and basic mode.On that build, the original example's
value.copy()revealsContainer[Any], and.nonexistent_member()correctly reports an unknown attribute onContainer[Any].Today's reduced example behaves differently:
gradual.copy()revealsContainer[int], and the nonexistent-member call also reports an error. That's first-match behavior, though. It drops thestralternative rather than preserving the requested gradual container result. The concrete receiver returnsContainer[int]in both examples.The history explains why this isn't simply "the container fix landed":
#11732 initially added shared-container preservation. #11739 then rolled back the nested materialization work and the checker portions of that fix, restoring the earlier first-match behavior. That's what accounts for the current results, rather than the original container-preservation implementation remaining intact.
#11780 later enabled bounded overload alternatives for supported direct function calls, but it intentionally doesn't cover bound-method producers like
value.copy().So the original erasure/missed-error symptom is resolved in that build of
main, but hasn't shipped yet. Correctly retaining the gradual specialized-selfalternatives remains open. These checks cover the two examples here, not the broader pandas-stubs cases or an independent mypy comparison.Retain specialized receiver overload alternatives
Retain alternatives for specialized instance-method overloads (#11864)