-
Notifications
You must be signed in to change notification settings - Fork 192
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
AddImportsVisitor: add imports before the first non-import statement #1024
Conversation
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## main #1024 +/- ##
==========================================
+ Coverage 91.04% 91.05% +0.01%
==========================================
Files 255 255
Lines 26366 26414 +48
==========================================
+ Hits 24004 24052 +48
Misses 2362 2362 ☔ View full report in Codecov by Sentry. |
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 think the current behavior is useful in cases like:
from a import side_effect
a()
from b import foo
...
bar()
When we request the import for b.bar
, the current behavior extends the second ImportFrom
statement, but with this PR, we would end up with:
from a import side_effect
from b import bar
a()
from b import foo
...
bar()
Which is at least a bit unfortunate. It's also unfortunate that we don't capture this in any test case.
I think my main concern stems from the fact that we'd be always inserting imports before the first non-import statement even if it isn't necessary. If you could change the PR to only apply the new behavior when the old would obviously break code, I'd be happy to accept it
class _GatherTopImportsBeforeStatements(GatherImportsVisitor): | ||
""" | ||
Works similarly to GatherImportsVisitor, but only considers imports | ||
declared before any other statements of the module with the exception | ||
of docstrings and __strict__ flag. | ||
""" | ||
|
||
def leave_Module(self, original_node: libcst.Module) -> None: |
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.
This isn't a great use of inheritance, _GatherTopImportsBeforeStatements
doesn't really specialize the behavior of GatherImportsVisitor
, it completely changes it.
A better way to model this would be to extract the two _handle_...
methods into a mixin class and let both visitors inherit from that.
Then _GatherTopImportsBeforeStatements
won't need to override visit_ImportFrom
and visit_Import
with dummy implementations (and potentially others in the future). Instead you could just implement visit_Module
and return False
at the end. Bonus points for making it significantly faster for large documents.
1abbaa5
to
80dcbf8
Compare
Thanks for pointing the issues. I've hopefully fixed most of them with the last commit. I do have some questions about what is the expected behavior of First, note that the current behavior is a bit more problematic than it seems. Consider the following and suppose we want to add foo()
def f():
from x import a
pass
from x import b
bar()
from x import c The current behavior would add bar to Now consider: foo()
def f():
from x import a
bar()
from x import b
foo()
from x import c
bar() What do you feel is the best place(s) to add Do we want it to always add it to the "nearest" import block? or do we want a single import that covers all references to Nevertheless, I feel that a general solution that cover these properties would be far more complex than what we have and the proposed solution in this PR is a good compromise. Of course, if you have a good/simple solution for this, I'd be happy to accept suggestions. |
I agree, And to directly answer your question: no, I have no solution for the cases you point out that wouldn't make The changes in this PR look good at a quick glance, but give me a bit more time to properly review them again, before merging. |
Thanks for putting this together, @andrecsilva! |
…nstagram#1024) * AddImportsVisitor will now only add at the top of module - Also added new tests to cover these cases * Fixed an issue with from imports * Added a couple tests for AddImportsVisitor * Refactoring of GatherImportsVisitor * Refactors, typos and typing changes
Summary
Proposed fix for #1023. It changes
AddImportsVisitor
so it only considers adding new imports after/at the first import block before any other statements, if any.Test Plan
Added a few tests to
test_add_imports.py