-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow variable redefinition if lifetimes don't overlap #6232
Comments
Not sure if this would need to be split into a separate issue, or if it is relevant here, but I have some code like this: try:
...
except AssertionError as e:
errors.append(e)
if condition:
e = AssertionError("message")
errors.append(e) Essentially the same as Django's |
This is exactly what I see as a common pattern in code - quite often due to for loops or exceptions - exactly as in the above examples. So I'm also raising my hand for prioritizing this 😉. |
My case, which as far as I can tell is related to this issue, is with the following. I am (ab)using context managers in the following pattern, which is used in some configuration building code written by end-users of my tool. Heavily simplified: toolmodule.py: import contextlib
import typing
class A:
a: int
b: str
def get_A(name: str) -> typing.Generator[A, None, None]:
...
class B:
c: bool
def get_B(name: str) -> typing.Generator[B, None, None]:
... userwritten.py: import toolmodule
with get_A("") as x:
x.a = 1
x.b = ""
with get_B("") as x:
x.c = True
for i in [1]:
with get_A("") as x: # <- error: Incompatible types in assignment (expression has type "A", variable has type "B")
x.a = 1 (In actual code, I suspected that there could be some nuances related to context managers, but the following code has the same problem: import typing as tp
x = 1
if tp.TYPE_CHECKING:
reveal_type(x)
print(x)
x = [1]
if tp.TYPE_CHECKING:
reveal_type(x)
print(x)
if True:
x = "" # <- error: Incompatible types in assignment (expression has type "str", variable has type "List[int]")
if tp.TYPE_CHECKING:
reveal_type(x)
print(x)
for i in [1]:
x = "" # <- error: Incompatible types in assignment (expression has type "str", variable has type "List[int]")
if tp.TYPE_CHECKING:
reveal_type(x)
print(x) Rhetorically and off-topic: I really wish Python had some scoping statement, akin to: scoped:
x = 1
x # <- error: undefined
scoped for i in []:
...
i # <- error: undefined
scoped with f() as y:
...
y # <- error: undefined |
Is there any progress on this? Having type "redefinition" errors, just because I used a variable that's named the same as the one I used in a for loop couple of lines earlier, is getting quite tiresome. The flag that allows redefinitions doesn't sound that great for my usage case either. IMO, if someone is using a variable in a for loop, it should redefine the type of the variable, even without the "allow redefinitions" flag - consider this: my_list: List[int]
my_other_list: List[Thing]
for x in my_list:
reveal_type(x) # int
reveal_type(x) # int (still, persistent)
for x in my_other_list: # redefines type of x
reveal_type(x) # Thing
x = "test" # str (redefines type of x as well) Perhaps the variable could be tagged as "reassignable" internally by MyPy somehow? This would also handle @ShadowLNC's case. |
Can this be a related benign redefinition case too: from pathlib import Path
for x in ['a/b']:
reveal_type(x) # str, ok
x = Path(x) # can’t redefine
reveal_type(x) # str instead of Path
reveal_type(x.stem) # error accessing, and Any because of that With no |
I'm not sure if this is the same issue, but I have a similar problem... I have the following code: def get_menus(date: datetime.date) -> dict[str, Optional[dict[str, str]]]:
# SnackMenu and LunchMenu are SQLAlchemy 2.0 models
snack = Session.query(SnackMenu).filter(SnackMenu.date == date).first()
lunch = Session.query(LunchMenu).filter(LunchMenu.date == date).first()
reveal_type(snack) # Revealed type is "Union[gimvicurnik.database.SnackMenu, None]"
reveal_type(lunch) # Revealed type is "Union[gimvicurnik.database.LunchMenu, None]"
if snack:
snack = {
"normal": snack.normal,
"poultry": snack.poultry,
"vegetarian": snack.vegetarian,
"fruitvegetable": snack.fruitvegetable,
}
if lunch:
lunch = {
"normal": lunch.normal,
"vegetarian": lunch.vegetarian,
}
return {
"snack": snack,
"lunch": lunch,
} When running mypy with the following configuration (notice that [tool.mypy]
python_version = 3.9
show_column_numbers = true
show_error_codes = true
allow_redefinition = true
disallow_untyped_decorators = true
disallow_untyped_defs = true
disallow_incomplete_defs = true
no_implicit_optional = true
warn_redundant_casts = true
warn_unused_configs = true
warn_unused_ignores = true
warn_no_return = true
warn_return_any = true
warn_unreachable = true I get the following type errors:
I would expect that mypy would not reject this code, especially since |
It looks like a different issue, of |
As a follow-up to #1174 and #6197, we should perhaps allow two assignments to create independent variables whenever the lifetimes of the variables don't overlap (when using
--allow-redefinitions
).Example:
Another example:
The text was updated successfully, but these errors were encountered: