-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
refine pyupgrade's TimeoutErrorAlias lint (UP041) to remove false positives #8587
Conversation
00802b1
to
ba22f95
Compare
|
ba22f95
to
02bff11
Compare
@BurntSushi hi! Thanks for the PR! If I understand correctly, you decide to leave linting |
@charliermarsh yes. /// Return `true` if an [`Expr`] is an alias of `TimeoutError`.
fn is_alias(expr: &Expr, semantic: &SemanticModel, target_version: PythonVersion) -> bool {
semantic.resolve_call_path(expr).is_some_and(|call_path| {
if target_version >= PythonVersion::Py311 {
matches!(
call_path.as_slice(),
[""] | ["asyncio", "TimeoutError"] | ["socket", "timeout"]
)
} else {
matches!(call_path.as_slice(), [""] | ["socket", "timeout"])
}
})
} ^ to minimize a difference from the current code. Or maybe something like /// Return `true` if an [`Expr`] is an alias of `TimeoutError`.
fn is_alias(expr: &Expr, semantic: &SemanticModel, target_version: PythonVersion) -> bool {
semantic
.resolve_call_path(expr)
.is_some_and(|call_path| match call_path.as_slice() {
[""] => true,
["socket", "timeout"] if target_version >= PythonVersion::Py310 => true,
["asyncio", "TimeoutError"] if target_version >= PythonVersion::Py311 => true,
_ => false,
})
} or (implicitly used the information that target_version >= py310) /// Return `true` if an [`Expr`] is an alias of `TimeoutError`.
fn is_alias(expr: &Expr, semantic: &SemanticModel, target_version: PythonVersion) -> bool {
semantic
.resolve_call_path(expr)
.is_some_and(|call_path| {
matches!(call_path.as_slice(), [""] | ["socket", "timeout"])
|| matches!(call_path.as_slice(), ["asyncio", "TimeoutError"] if target_version >= PythonVersion::Py311)
})
} P.S. I am actually does not understand why the check for [""] is here 😄 |
Right, the |
02bff11
to
745fd62
Compare
Okay, I've dropped the last commit and updated the PR description. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Excellent, thanks!
crates/ruff_linter/src/rules/pyupgrade/rules/timeout_error_alias.rs
Outdated
Show resolved
Hide resolved
Previously, this lint had its alias detection logic a little backwards. That is, for Python 3.11+, it would *only* detect asyncio.TimeoutError as an alias, but it should have also detected socket.timeout as an alias. And in Python <3.11, it would falsely detect asyncio.TimeoutError as an alias where it should have only detected socket.timeout as an alias. We fix it so that both asyncio.TimeoutError and socket.timeout are detected as aliases in Python 3.11+, and only socket.timeout is detected as an alias in Python 3.10.
Without this assert, the lint could falsely trigger a safe fix that is actually unsafe if the higher level logic calling the lint changes. That is, right now, the lint is only invoked for 3.10+ so everything is fine, but nothing is stopping that from changing. So we make the assumption clear: if it changes, then we should get a pretty loud panic.
This new test checks that safe fixes are not suggested for replacing asyncio.TimeoutError with TimeoutError in Python <3.11. Namely, before 3.11, these were distinct types. So switching from asyncio.TimeoutError to TimeoutError could result in a change of semantics.
745fd62
to
1e45679
Compare
Previously, this lint had its alias detection logic a little
backwards. That is, for Python 3.11+, it would only detect
asyncio.TimeoutError as an alias, but it should have also detected
socket.timeout as an alias. And in Python <3.11, it would falsely
detect asyncio.TimeoutError as an alias where it should have only
detected socket.timeout as an alias.
We fix it so that both asyncio.TimeoutError and socket.timeout are
detected as aliases in Python 3.11+, and only socket.timeout is
detected as an alias in Python 3.10.
Fixes #8565
Test Plan
I tested this by updating the existing snapshot test which had erroneously
asserted that socket.timeout should not be replaced with TimeoutError in Python
3.11+. I also added a new regression test that targets Python 3.10 and ensures
that the suggestion to replace asyncio.TimeoutError with TimeoutError does not
occur.