Skip to content
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

F401 - Recommend adding unused import bindings to __all__ #11314

Merged
merged 49 commits into from
May 15, 2024
Merged

Conversation

plredmond
Copy link
Contributor

@plredmond plredmond commented May 6, 2024

Followup on #11168 and resolve #10391

User facing changes

  • F401 now recommends a fix to add unused import bindings to to __all__ if a single __all__ list or tuple is found in __init__.py.
    • If there are no __all__ found in the file, fall back to recommending redundant-aliases.
    • If there are multiple __all__ or only one but of the wrong type (non list or tuple) then diagnostics are generated without fixes.
  • fix_title is updated to reflect what the fix/recommendation is.

Subtlety: For a renamed import such as import foo as bees, we can generate a fix to add bees to __all__ but cannot generate a fix to produce a redundant import (because that would break uses of the binding bees).

Implementation changes

  • Add name field to ImportBinding to contain the name of the binding we want to add to __all__ (important for the import foo as bees case). It previously only contained the AnyImport which can give us information about the import but not the binding.
    • Add binding field to UnusedImport to contain the same. (Naming note: the field name field already existed on UnusedImport and contains the qualified name of the imported symbol/module)
  • Change fix_by_reexporting to branch on the size of dunder_all: Vec<&Expr>
    • For length 0 call the edit-producing function make_redundant_alias.
    • For length 1 call edit-producing function add_to_dunder_all.
    • Otherwise, produce no fix.
  • Implement the edit-producing function add_to_dunder_all and add unit tests.
  • Implement several fixture tests: empty __all__ = [], nonempty __all__ = ["foo"], mis-typed __all__ = None, plus-eq __all__ += ["foo"]
  • UnusedImportContext::Init variant now has two fields: whether the fix is in __init__.py and how many __all__ were found.

Other changes

  • Remove a spurious pattern match and instead use field lookups b/c the addition of a field would have required changing the unrelated pattern.
  • Tweak input type of make_redundant_alias

@plredmond
Copy link
Contributor Author

Oops, didn't add clippy to my pre-push hook. Added now.

Copy link
Contributor

github-actions bot commented May 6, 2024

ruff-ecosystem results

Linter (stable)

✅ ecosystem check detected no linter changes.

Linter (preview)

✅ ecosystem check detected no linter changes.

@plredmond plredmond marked this pull request as ready for review May 6, 2024 20:07
@plredmond
Copy link
Contributor Author

I swear I have fixed my pre-push hook now.

@plredmond plredmond requested a review from AlexWaygood May 8, 2024 16:35
@plredmond
Copy link
Contributor Author

Almost there, maybe? @zanieb @AlexWaygood Two unresolved threads left.

@plredmond
Copy link
Contributor Author

I believe that i've resolved the outstanding requests. @AlexWaygood it might make sense to do a pass over the fixture tests now since there has been some churn, to see if you agree with how each case is resolved?

Copy link
Member

@AlexWaygood AlexWaygood left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Much improved, thanks for your patience! A few more comments below.

@plredmond
Copy link
Contributor Author

This is ready for review again.

Copy link
Member

@zanieb zanieb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome, this is a huge improvement to this rule 🎉

@charliermarsh
Copy link
Member

(A few small comments but for clarity no need to wait on my approval to merge.)

Copy link

codspeed-hq bot commented May 14, 2024

CodSpeed Performance Report

Merging #11314 will degrade performances by 6.83%

Comparing ruff.all (dde9756) with main (96f6288)

Summary

❌ 1 regressions
✅ 29 untouched benchmarks

⚠️ Please fix the performance issues or acknowledge them on CodSpeed.

Benchmarks breakdown

Benchmark main ruff.__all__ Change
linter/default-rules[pydantic/types.py] 7.5 ms 8 ms -6.83%

@charliermarsh
Copy link
Member

I suspect the CodSpeed regression is a false positive.

@plredmond
Copy link
Contributor Author

Maybe it'll re-run after this last pull and resolve (if codespeed updates its comments).

@AlexWaygood
Copy link
Member

AlexWaygood commented May 14, 2024

Rebasing or merging in main often gets CodSpeed to change its mind as well

@plredmond
Copy link
Contributor Author

Ah, that's a good point. If we're comparing to main the performance could very well be different on an outdated branch.

@plredmond
Copy link
Contributor Author

Rebasing.

@plredmond
Copy link
Contributor Author

I've updated the PR description to reflect the diff after all review comments.

Not sure what to do next. CodeSpeed might be a false-positive, but that should have been mitigated by rebasing.

&lexer::lex(raw, Mode::Expression).collect::<Vec<_>>(),
&locator,
);
// SUT
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does SUT mean?

Copy link
Contributor Author

@plredmond plredmond May 14, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

system under test -- the test is long so i'm marking the bit that's unit tested

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This acronym was also unfamiliar to me FWIW

@charliermarsh
Copy link
Member

I think it's ok to merge personally.

@charliermarsh
Copy link
Member

I'm looking through the changes again just to see if anything sticks out.

@charliermarsh
Copy link
Member

The only thing that stands out is that we're allocating an additional string for UnusedImport and we increased the size of the struct.

@charliermarsh
Copy link
Member

We could consider using binding everywhere for the diagnostic instead of the qualified name, see if that helps? But I think it's fine to merge as-is.

plredmond and others added 3 commits May 14, 2024 11:20
Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
…ding-name field (named as .name); update fixture test results
@plredmond
Copy link
Contributor Author

Trying out Charlie's suggestion of using only one string in the violation struct. This caused /a lot/ of fixture changes to have cosmetic changes to help text and rule titles. If it doesn't correct the regression I'll revert.

@plredmond
Copy link
Contributor Author

Ok, that didn't work so I'm going to revert and then merge once tests pass.

… the binding-name field (named as .name); update fixture test results"

This reverts commit 0696df5.
@plredmond
Copy link
Contributor Author

Ok! I've tried (and reverted) both of the suggested performance improvements. Do we want to just merge this? I have no more commits to push.

@charliermarsh
Copy link
Member

Yeah, I'm fine with going ahead and merging.

@plredmond plredmond merged commit da882b6 into main May 15, 2024
18 of 19 checks passed
@plredmond plredmond deleted the ruff.__all__ branch May 15, 2024 00:02
plredmond added a commit that referenced this pull request May 15, 2024
plredmond added a commit that referenced this pull request May 15, 2024
plredmond added a commit that referenced this pull request May 21, 2024
#11436)

## Summary

* Update documentation for F401 following recent PRs
  * #11168
  * #11314
* Deprecate `ignore_init_module_imports`
* Add a deprecation pragma to the option and a "warn user once" message
when the option is used.
* Restore the old behavior for stable (non-preview) mode:
* When `ignore_init_module_imports` is set to `true` (default) there are
no `__init_.py` fixes (but we get nice fix titles!).
* When `ignore_init_module_imports` is set to `false` there are unsafe
`__init__.py` fixes to remove unused imports.
* When preview mode is enabled, it overrides
`ignore_init_module_imports`.
* Fixed a bug in fix titles where `import foo as bar` would recommend
reexporting `bar as bar`. It now says to reexport `foo as foo`. (In this
case we don't issue a fix, fwiw; it was just a fix title bug.)

## Test plan

Added new fixture tests that reuse the existing fixtures for
`__init__.py` files. Each of the three situations listed above has
fixture tests. The F401 "stable" tests cover:

> * When `ignore_init_module_imports` is set to `true` (default) there
are no `__init_.py` fixes (but we get nice fix titles!).

The F401 "deprecated option" tests cover:

> * When `ignore_init_module_imports` is set to `false` there are unsafe
`__init__.py` fixes to remove unused imports.

These complement existing "preview" tests that show the new behavior
which recommends fixes in `__init__.py` according to whether the import
is 1st party and other circumstances (for more on that behavior see:
#11314).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add fix to re-export unused first-party imports in __init__.py files
5 participants