-
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
Ignore NPY201
inside except
blocks for compatibility with older numpy versions
#12490
Conversation
e3ffb37
to
a2a6aaf
Compare
CodSpeed Performance ReportMerging #12490 will not alter performanceComparing Summary
|
|
The lexer benchmark is drunk! |
Hey, I'll take it! |
return false; | ||
}; | ||
let suspended_exceptions = Exceptions::from_try_stmt(try_node, semantic); | ||
if !suspended_exceptions.contains(Exceptions::ATTRIBUTE_ERROR) { |
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.
Can we check semantic.handled_exceptions
instead? Does that work? Then we wouldn't need to find the try statement or anything.
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.
No, semantic.handled_exceptions
records the exceptions if we're visiting the try
block of a try
/except
statement. But here we're visiting the except
block of a try
/except
statement. Hence "suspended_exceptions" rather than "handled_exceptions".
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.
Also we still need to find the node for the try
statement so that we can check whether it was accessed via the undeprecated call path in the try
block
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.
Looks good. Maybe give @charliermarsh a grace period of a day to look at the semantic model changes ;)
/// AST visitor that searches an AST tree for [`ast::StmtImportFrom`] nodes | ||
/// that match a certain [`QualifiedName`]. | ||
struct ImportSearcher<'a> { | ||
module: &'a str, | ||
name: &'a str, | ||
found_import: bool, | ||
} |
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.
I don't think it matters much because we only run this code in the error case, but it is kind of expensive. Do we have no way of resolving the statement in which a binding is declared and then traverse upwards (by using the parent API?)
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.
The situation is that we're visiting an except
block in a try
/except
statement. We find a deprecated numpy access in that except
block. We need to find out if there's an undeprecated access in the try
block of the try
/except
statement. The way I do this is by traversing upwards from the node we're linting in the except
block (using the parent API) to find the StmtTry
node, then from the StmtTry
node I then traverse downwards into the try
block using the ImportSearcher
to find if there are any imports using the undeprecated API.
@@ -1853,6 +1841,10 @@ impl<'a> Checker<'a> { | |||
self.semantic.scope_id | |||
}; | |||
|
|||
if self.semantic.in_exception_handler() { | |||
flags |= BindingFlags::IN_EXCEPT_HANDLER; | |||
} |
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.
Idly wondering if we should just store the semantic model flags on the binding, in theory it's tiny.
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.
As in, get rid of the separate BindingFlags
struct altogether, and store the semantic-model flags on Binding
instead? Or store the semantic-model flags in addition to the BindingFlags
?
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.
Store them in addition (and then remove this flag from BindingFlags
). But, it's ok, no need to change.
Summary
Fixes #12476.
This PR makes it so that deprecated imports and attribute accesses of numpy members are ignored in the following conditions:
np.ComplexWarning
), we only ignore the violation if it's inside anexcept AttributeError
block, and the member is accessed through its non-deprecated name in the associatedtry
block.numpy
member where it's simply anExprName
node, we check to see how thenumpy
member was bound. If it was bound via afrom numpy import foo
statement, we check to see if that import statement took place inside anexcept ImportError
orexcept ModuleNotFoundError
block. If so, and if thenumpy
member was imported through its non-deprecated name in the associated try block, we ignore the violation in the same way.Examples:
This was more complex than I expected, since we currently track handled exceptions in the semantic model, but we don't track suspended exceptions. I.e., if we're in a lint rule and we're examining a node inside a
try
block, we know which exceptions the enclosingStmtTry
node handles. But if we're in a lint rule and we're examining a node inside anexcept
block, we don't have that information easily to hand.Test Plan
Added some fixtures and snapshots.