You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
In the project I am working on, it is important for me to be able to create a function that takes in a parameter of Optional[T] type and return that same var of type T if it is not None, else raise a RuntimeError. This way I can access properties of the expected object when I know that it should not be None (e.g., after everything is initialized).
Here is a simple example to illustrate this point:
import random
from typing import NoReturn, Optional, TypeVar, overload
T = TypeVar("T")
class MyClass:
def __init__(self, property: int):
self.property: int = property
def get_obj_or_none() -> Optional[MyClass]:
obj = MyClass(1)
return obj if random.random() > 0.001 else None
@overload
def require_type(x: None) -> NoReturn:
...
@overload
def require_type(x: T) -> T:
...
def require_type(x: Optional[T]) -> T:
if x is None:
raise RuntimeError("x is None")
return x
x = get_obj_or_none() # x should have type str | None
y = require_type(x) # y should have type str
y_property = y.property # property is accessible and correctly typed as int
print(y_property)
In this example, I find that y, although it I want it to be typed as MyClass, is typed as MyClass | None by pylance / pyright. See screenshot below:
However, when I commend out the overloads, it is typed correctly:
This makes sense based on the pyright overload handling rules I found here: https://microsoft.github.io/pyright/#/type-concepts-advanced?id=overloads
Since the input to the require_type function is of union type (Optional[T] is syntax for T | Non), I fall into case 5 in the documentation and the following happens:
If so, these union types are expanded into their constituent subtypes, and the entire process of overload matching is repeated with the expanded argument types. If two or more overloads match, the union of their respective return types form the final return type for the call expression.
This is problematic for me, because I also use mypy and I need the overloads structured in this way to pass mypy type checking and also ensure that mypy correctly interprets the types of variables after I use the require_type function python/mypy#9424 . Further, it says here #2660 (reply in thread) that at least as of Dec 2023 there is no plan to conform the way mypy and pyright handle overloads.
Thus, my question is, how can I require both pyright / pylance and mypy to interpret variables as non-optional after I call some kind of require_type function on said variable? If there is no other way to do this specifically, how can i solve this problem of needing to caste optional variables as non-None?
Thank you!
The text was updated successfully, but these errors were encountered:
It's not clear to me why you're using an overload here. It seems unnecessary — and the cause of the problem you're seeing. Have you tried simply deleting the overload signatures for require_type? That seems to work fine in both pyright and mypy.
Thanks @erictraut ! I have tried deleting the overloads and did get mypy errors, but I'm realizing I'm running mypy 1.7.1, so will try updating and running again. Thanks again!
Hi! Hope you are well :)
In the project I am working on, it is important for me to be able to create a function that takes in a parameter of
Optional[T]
type and return that same var of typeT
if it is notNone
, else raise aRuntimeError
. This way I can access properties of the expected object when I know that it should not be None (e.g., after everything is initialized).Here is a simple example to illustrate this point:
In this example, I find that y, although it I want it to be typed as
![image](https://private-user-images.githubusercontent.com/28873065/323318503-78343c4b-ebed-4e8b-993e-1ca79fb8d36f.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MzkyNzc0NzEsIm5iZiI6MTczOTI3NzE3MSwicGF0aCI6Ii8yODg3MzA2NS8zMjMzMTg1MDMtNzgzNDNjNGItZWJlZC00ZThiLTk5M2UtMWNhNzlmYjhkMzZmLnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNTAyMTElMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjUwMjExVDEyMzI1MVomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTllNTJiMjc3MTNmZGMyNmU1OGZlZTA4MDNkMTM2ZTJmYTgyMGM5NmY1MWZiNTE1OWQ3NDJmMTYyY2U0YmVlMmUmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.XwojDyFReQqUEZzohtwq5UJWPpGGL9H4lFBwLhtC1pc)
MyClass
, is typed asMyClass | None
bypylance
/pyright
. See screenshot below:However, when I commend out the overloads, it is typed correctly:
![image](https://private-user-images.githubusercontent.com/28873065/323318690-b87c6af5-ff89-416f-91a3-22a8ae834499.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MzkyNzc0NzEsIm5iZiI6MTczOTI3NzE3MSwicGF0aCI6Ii8yODg3MzA2NS8zMjMzMTg2OTAtYjg3YzZhZjUtZmY4OS00MTZmLTkxYTMtMjJhOGFlODM0NDk5LnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNTAyMTElMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjUwMjExVDEyMzI1MVomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTk0ZWQyYjVhMmUxODRhN2FhYmNmODk5MmU3YzdjOTEwM2ZmOGFkZTJhOTgwNzI2Mzk1MTliMTZmYzUxYzNkNDcmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.Y1SgqPlS1e0N6Z9bOLgOpFoJYpA76LReAEh3F5EKO9k)
This makes sense based on the pyright overload handling rules I found here: https://microsoft.github.io/pyright/#/type-concepts-advanced?id=overloads
Since the input to the
require_type
function is of union type (Optional[T]
is syntax forT | Non
), I fall into case 5 in the documentation and the following happens:This is problematic for me, because I also use
mypy
and I need the overloads structured in this way to passmypy
type checking and also ensure thatmypy
correctly interprets the types of variables after I use therequire_type
function python/mypy#9424 . Further, it says here #2660 (reply in thread) that at least as of Dec 2023 there is no plan to conform the waymypy
andpyright
handle overloads.Thus, my question is, how can I require both
pyright
/pylance
andmypy
to interpret variables as non-optional after I call some kind ofrequire_type
function on said variable? If there is no other way to do this specifically, how can i solve this problem of needing to caste optional variables as non-None
?Thank you!
The text was updated successfully, but these errors were encountered: