pulumi
                                
                                
                                
                                    pulumi copied to clipboard
                            
                            
                            
                        classmethods on pulumi.Output are no longer typechecking successfully in python with pyright>=1.1.354
What happened?
we use a lot of methods like pulumi.Output.from_input, but when trying to update the version of pyright we use, we are now getting type errors
Example
with a pulumi python project that looks like this:
# pyright: strict
import pulumi
output = pulumi.Output.from_input("foo")
this used to produce no errors, but now fails with:
/home/doy/tmp/pulumi-pyright/__main__.py
  /home/doy/tmp/pulumi-pyright/__main__.py:5:1 - error: Type of "output" is partially unknown
    Type of "output" is "Output[Unknown]" (reportUnknownVariableType)
  /home/doy/tmp/pulumi-pyright/__main__.py:5:10 - error: Type of "from_input" is partially unknown
    Type of "from_input" is "(val: Unknown | Awaitable[Unknown] | Output[Unknown]) -> Output[Unknown]" (reportUnknownMemberType)
2 errors, 0 warnings, 0 informations
Output of pulumi about
CLI          
Version      3.112.0
Go Version   go1.22.1
Go Compiler  gc
Plugins
NAME    VERSION
python  unknown
Host     
OS       arch
Version  
Arch     x86_64
This project is written in python: executable='/home/doy/tmp/pulumi-pyright/venv/bin/python3' version='3.11.8'
Current Stack: doy-materialize-com/pulumi-pyright/dev
Found no resources associated with dev
Found no pending operations associated with dev
Backend        
Name           pulumi.com
URL            https://app.pulumi.com/doy-materialize-com
User           doy-materialize-com
Organizations  doy-materialize-com, materialize
Token type     personal
Dependencies:
NAME        VERSION
pip         24.0
pulumi      3.112.0
setuptools  69.2.0
wheel       0.43.0
Pulumi locates its logs in /tmp by default
Additional context
this appears likely to be related to this changelog entry from pyright 1.1.354:
Changed the behavior when accessing a class attribute from a generic class that is not specialized. The class is now automatically specialized in the case using default type parameter values (from PEP 696) or Unknown. This change is required for conformance with PEP 696.
Contributing
Vote on this issue by adding a 👍 reaction. To contribute a fix for this issue, leave a comment (and link to your pull request, if you've opened one already).
Thanks for reporting this!
Trying out a minimal repro in Pyright Playground:
# pyright: strict
from typing import (
    TypeVar,
    Generic,
    Union,
    Awaitable,
    cast,
)
T = TypeVar("T")
T_co = TypeVar("T_co", covariant=True)
U_co = TypeVar("U_co", covariant=True)
Input = Union[T, Awaitable[T], "Output[T]"]
class Output(Generic[T_co]):
    def __init__(self, value: T_co):
        self.value = value
    @staticmethod
    def from_input_old(val: Input[T_co]) -> "Output[T_co]":
        return Output(cast(T_co, val))
    @staticmethod
    def from_input_new(val: Input[U_co]) -> "Output[U_co]":
        return Output(cast(U_co, val))
output1 = Output.from_input_old("foo")
output2 = Output.from_input_new("foo")
I can repro the current issue, with output1 = Output.from_input_old("foo"):
Type of "from_input_old" is partially unknown
  Type of "from_input_old" is "(val: Unknown | Awaitable[Unknown] | Output[Unknown]) -> Output[Unknown]"  (reportUnknownMemberType)
Type of "output1" is partially unknown
  Type of "output1" is "Output[Unknown]"  (reportUnknownVariableType)
However, if we use a new TypeVar (e.g. use U_co rather than T_co in from_input_new), then we don't get any reported issues from pyright.
The latest mypy doesn't complain on either of these.
I'm not sure if that's the recommended approach to typing a static factory method on a generic class, but seems to address the problem. We should check all the other static methods on Output to see if they have the same problem and fix in the same way.