Ignore NPY201 inside except blocks for compatibility with older numpy versions#12490
Ignore NPY201 inside except blocks for compatibility with older numpy versions#12490AlexWaygood merged 6 commits intomainfrom
NPY201 inside except blocks for compatibility with older numpy versions#12490Conversation
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.
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.
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.
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
MichaReiser
left a comment
There was a problem hiding this comment.
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.
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.
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.
|
|
||
| if self.semantic.in_exception_handler() { | ||
| flags |= BindingFlags::IN_EXCEPT_HANDLER; | ||
| } |
There was a problem hiding this comment.
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.
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.
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 AttributeErrorblock, and the member is accessed through its non-deprecated name in the associatedtryblock.numpymember where it's simply anExprNamenode, we check to see how thenumpymember was bound. If it was bound via afrom numpy import foostatement, we check to see if that import statement took place inside anexcept ImportErrororexcept ModuleNotFoundErrorblock. If so, and if thenumpymember 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
tryblock, we know which exceptions the enclosingStmtTrynode handles. But if we're in a lint rule and we're examining a node inside anexceptblock, we don't have that information easily to hand.Test Plan
Added some fixtures and snapshots.