-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
[flake8-simplify
] Also simplify annotated assignments (SIM108
)
#15665
base: main
Are you sure you want to change the base?
Conversation
I also took the liberty to do some minor refactoring. Feel free to revert if they are undesired. |
|
code | total | + violation | - violation | + fix | - fix |
---|---|---|---|---|---|
SIM108 | 12 | 12 | 0 | 0 | 0 |
Thanks for working on this. As mentioned on the issue, I'm not sure if we should do this (as discussed in the issue) because it can lead to new or different typing errors. |
In fact annotating both branches is considered a redefinition error (even if both annotations are the same), so this should be fine. What I do think is worth looking into however is if we can handle type declarations that have been moved outside the two branches. I find myself doing that quite often, since it makes it more clear that the variable is shared between the two branches and that the value will be used afterwards. So concretely the following: x: int
if foo:
x = 5
else:
x = 0 becomes: x: int = 5 if foo else 0 rather than x: int
x = 5 if foo else 0 |
I'd have to test if that's true for all existing type checkers or is this defined anywhere in the typing spec? I'm still leaning towards leaving it as is because I currently can't prioritize doing the necessary research to see if this is safe for all type checker and while nice, it doesn't seem urgent. I can try to find time to review this change if someone invests the necessary time and documents the PR accordingly (where does it provide fixes, why, and why is it safe in those circumstnaces) |
It is rather hard to explain why the fix is safe (it is actually always marked as unsafe). Here's how I would explain it for someone who has basic knowledge of static typing in Python:
Is that easy to understand? |
I think the other thing @MichaReiser is worried about is inference behavior if one of the branches doesn't match the annotated type of the other branch. Unfortunately it seems like pytype is actually extremely forgiving here, so the following would have a different output for pytype: if flag:
a: int = 1
else:
a = '2'
reveal_type(a) # Union[int, str] than the reformatted version: a: int = 1 if flag else '2' # error: annotation-type-mismatch
reveal_type(a) # int But other than that I don't think there's any type checker that would pass the above example. Even pyre disallows it, but it allows you to have different annotations for each branch and then infers the union outside the branch, just like pytype. |
I think this is not too big a problem, considering that the fix is marked as unsafe, but, yes, it is nevertheless a major drawback of the PR. |
I think this airflow example is interesting because it changes the declared types: |
@MichaReiser I'm not sure if I follow. That block would be simplified to: timeout: type[TimeoutWindows | TimeoutPosix] = TimeoutWindows if IS_WINDOWS else TimeoutPosix ...which is perfectly fine type-checking-wise as far as I can tell. |
It's fine for timeout: type[TimeoutPosix] = TimeoutPosix at least if the type checker understands the platform-specific branches. |
@MichaReiser Normally import sys
if sys.platform == 'win32':
timeout = TimeoutWindows
else:
timeout = TimeoutPosix
|
Summary
Resolves #15554.
Test Plan
cargo nextest run
andcargo insta test
.