-
Notifications
You must be signed in to change notification settings - Fork 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
[pylint] redefined-loop-name (W2901) #3022
[pylint] redefined-loop-name (W2901) #3022
Conversation
Slightly broadens W2901 to cover `with` statements too. Closes #2972.
Perhaps update the pylint issue with your findings, quite some nice insights (since it will be closed when merging this) |
Done, and opened a new issue with the potential PyCharm-derived inspections: #3040 |
.map(|range| checker.locator.slice(range)) | ||
.collect(); | ||
|
||
for outer_name in &outer_names { |
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.
(Just out of interest, how closely does this match Pylint's own implementation? Did you look at the Pylint source, or is it implemented from scratch?)
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.
It was implemented from scratch, but after I learned Pylint has it too, I did look at the Pylint source later to compare. Pylint has a slightly more efficient algorithm, using a single recursion over the AST, keeping track of defined names using a stack, and pushing and popping the names on entering and leaving each for loop. This could probably be done with a deeper integration into ast.rs
.
…' into pylint-redefined-loop-name
Examples: ``` test.py:2:9: PLW2901 Outer for loop variable `i` overwritten by for loop target with same name test.py:6:9: PLW2901 Outer with statement variable `i` overwritten by for loop target with same name test.py:12:5: PLW2901 Outer for loop variable `i` overwritten by assignment target with same name ```
So I just ran this over Zulip as a smoke test, and it looks like the rule is currently flagging usages like this: for email in verified_emails:
existing_account = common_get_active_user(email, realm, {})
if existing_account is not None:
existing_account_emails.append(email)
avatars[email] = avatar_url(existing_account) Also attribute assignments, like |
Oh gosh, great point! I will know to run on some larger codebases when testing in future. Agreed, we need to avoid the lexer and traverse the AST of the target. It's really interesting learning new intricacies of Python syntax. I had never considered these, for example: >>> d = {}
>>> for d["i"] in range(2):
... print(d["i"])
...
0
1
>>> a = [None]
>>> for a[0] in range(2):
... print(a[0])
...
0
1
>>> i = 0
>>> for a[i] in range(2):
... print(a[i])
... i = 0 # no error
...
0
1 I'll try to think through all these edge cases, add tests, and get this fixed later today or tomorrow. |
No rush! Sorry for not noticing this earlier :) Let me know if you have questions as you work through it. |
Ran this new version on Zulip - still quite a few "false positives", only a few of which are IMO bad code smells. The most noisy false positives tend to be of the form: for line in file:
line = line.strip() # PLW2901 which are flagged by Pylint's redefined-loop-name extension and by my code here, but which in practice are of course commonplace and harmless, and where the developer has to jump through an annoying hoop to avoid the warning e.g. using a new On the other extreme we have this (from queue_processors.py) which does seem worth flagging, since another developer may not remember Python's unique scope rules and might add code that uses the outer with configure_scope() as scope:
scope.set_context(
# ...
)
if isinstance(exception, WorkerTimeoutError):
with sentry_sdk.push_scope() as scope: # PLW2901
scope.fingerprint = ["worker-timeout", self.queue_name]
logging.exception(exception, stack_info=True)
else:
logging.exception(
"Problem handling data on queue %s", self.queue_name, stack_info=True
) Similarly we have cases like this one (from test_openapi.py) where the code works and is correct, but again another developer may add code to the outer loop expecting for element in diff:
vname = element[0]
for element in openapi_params: # PLW2901
if element[0] == vname:
opvtype = element[1]
break
for element in function_params: # PLW2901
if element[0] == vname:
fdvtype = element[1]
break Finally we have an example in between (from rocketchat.py), where the name reuse is gratuitous, and while not an actual type error, arguably a notional error in regards to the "semantic type" of for reaction_dict in reactions:
emoji_name = reaction_dict["name"]
user_id = reaction_dict["user_id"]
# Check in realm emoji
if emoji_name in realmemoji:
# ...
reaction_id = NEXT_ID("reaction")
reaction = Reaction(
# ...
)
reaction_dict = model_to_dict(reaction, exclude=["message", "user_profile"]) # PLW2901
reaction_dict["message"] = message_id
reaction_dict["user_profile"] = user_id
total_reactions.append(reaction_dict) |
Awesome! Will review this shortly. |
I agree with the analysis in your comment. One other lens to apply here: where does this version deviate from Pylint, and where is it the same? (The less it deviates, the less strongly I feel about things that might feel excessive in practice.) (I know you mention that Pylint flags the first example -- wondering if it's the case for the others too.) |
Good question. As the code currently stands, for the Zulip codebase, this version exactly matches Pylint with the only difference being this version works not just for This version finds 35 (34
Pylint finds 34 (34
|
Ok cool, I'm happy with that level of parity then. I'll move on to reviewing the actual code. |
This raises a couple of questions in my mind learning Ruff's "best practices":
If rules can overlap, perhaps one way out of the dilemma would be to have two rules which share the same codebase:
|
Good questions!
It's not strictly forbidden but we try to avoid this. In fact over time we've actually removed some rules that turned out to be duplicates.
No, but we try to be intentional about deviations (so the upstream package is seen as the reference implementation, and any deviations should be intentional). We often deviate in the case of clear bugs or Pareto improvements (strictly fewer false positives or false negatives). There's also some precedent for deviating with Pylint rules specifically. For example, we changed the defaults in the magic-value checks to avoid flagging comparisons to string and bytes, which felt noisy. (That's another strategy: deviate by way of configuration.) |
fn assignment_targets_from_expr<'a, U>( | ||
expr: &'a Expr<U>, | ||
dummy_variable_rgx: &'a HashableRegex, | ||
) -> Box<dyn Iterator<Item = &'a Expr<U>> + 'a> { |
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.
Another approach would be to pass in a mutable vector, and have the various arms push to it. Would that work? Perhaps not as nice conceptually, but a bit simpler.
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.
Certainly could, but may be less efficient overall because it will require an additional temporary vector for each call. This is because the outputs of these methods can't be pushed directly to the InnerForWithAssignTargetsVisitor.assignment_targets vector as they first need to be paired with the appropriate BindingKind variant by the caller, which depends on the call path; so the intermediate Vec<Expr> would be immediately discarded each time.
On the other hand, I suppose the Boxes also necessitate a heap allocation, albeit one that has a fixed size and doesn't get expanded...
An alternative would be to pass in both a &mut Vec, and also the BindingKind, to these methods, and have them push ExprWithBindingKind into the vector.
Thanks again for the thorough and educational review and the quick merge. |
Thank you for all the work! Have been really impressed by your thoroughness and attention to detail, not to mention the quality of your code. |
[![Mend Renovate](https://app.renovatebot.com/images/banner.svg)](https://renovatebot.com) This PR contains the following updates: | Package | Change | Age | Adoption | Passing | Confidence | |---|---|---|---|---|---| | [ruff](https://togithub.com/charliermarsh/ruff) | `^0.0.251` -> `^0.0.252` | [![age](https://badges.renovateapi.com/packages/pypi/ruff/0.0.252/age-slim)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://badges.renovateapi.com/packages/pypi/ruff/0.0.252/adoption-slim)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://badges.renovateapi.com/packages/pypi/ruff/0.0.252/compatibility-slim/0.0.251)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://badges.renovateapi.com/packages/pypi/ruff/0.0.252/confidence-slim/0.0.251)](https://docs.renovatebot.com/merge-confidence/) | --- ### Release Notes <details> <summary>charliermarsh/ruff</summary> ### [`v0.0.252`](https://togithub.com/charliermarsh/ruff/releases/tag/v0.0.252) [Compare Source](https://togithub.com/charliermarsh/ruff/compare/v0.0.251...v0.0.252) <!-- Release notes generated using configuration in .github/release.yml at main --> #### What's Changed ##### Rules - \[`pylint`] `redefined-loop-name` (`W2901`) by [@​matthewlloyd](https://togithub.com/matthewlloyd) in [astral-sh/ruff#3022 - \[`pylint`] ` logging-too-many-args ` (`E1205`) by [@​md384](https://togithub.com/md384) in [astral-sh/ruff#3084 - \[`pylint`] ` logging-too-few-args ` (`E1206`) by [@​md384](https://togithub.com/md384) in [astral-sh/ruff#3084 ##### Bug Fixes - Include file permissions in cache key by [@​charliermarsh](https://togithub.com/charliermarsh) in [astral-sh/ruff#3104 - Skip EXE001 and EXE002 rules on Windows by [@​charliermarsh](https://togithub.com/charliermarsh) in [astral-sh/ruff#3111 - Mark `typing.assert_never` as no return by [@​bluetech](https://togithub.com/bluetech) in [astral-sh/ruff#3121 - Use file-specific quote for C408 by [@​charliermarsh](https://togithub.com/charliermarsh) in [astral-sh/ruff#3128 - Avoid match statement misidentification in token rules by [@​charliermarsh](https://togithub.com/charliermarsh) in [astral-sh/ruff#3129 - Upgrade RustPython to handle trailing commas in map patterns by [@​charliermarsh](https://togithub.com/charliermarsh) in [astral-sh/ruff#3130 - Avoid useless-else-on-loop for break within match by [@​charliermarsh](https://togithub.com/charliermarsh) in [astral-sh/ruff#3136 - Fix isort `no-lines-before` preceded by an empty section by [@​bluetech](https://togithub.com/bluetech) in [astral-sh/ruff#3139 - Support shell expansion for --config argument by [@​charliermarsh](https://togithub.com/charliermarsh) in [astral-sh/ruff#3107 - Fix =/== error in `ManualDictLookup` by [@​Rupt](https://togithub.com/Rupt) in [astral-sh/ruff#3117 - Include match in nested block check by [@​charliermarsh](https://togithub.com/charliermarsh) in [astral-sh/ruff#3137 - Upgrade RustPython to match new flattened exports by [@​charliermarsh](https://togithub.com/charliermarsh) in [astral-sh/ruff#3141 #### New Contributors - [@​md384](https://togithub.com/md384) made their first contribution in [astral-sh/ruff#3084 - [@​Rupt](https://togithub.com/Rupt) made their first contribution in [astral-sh/ruff#3117 - [@​marijncv](https://togithub.com/marijncv) made their first contribution in [astral-sh/ruff#3133 **Full Changelog**: astral-sh/ruff@v0.0.251...v0.0.252 </details> --- ### Configuration 📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Enabled. ♻ **Rebasing**: Whenever PR is behind base branch, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box --- This PR has been generated by [Mend Renovate](https://www.mend.io/free-developer-tools/renovate/). View repository job log [here](https://app.renovatebot.com/dashboard#github/ixm-one/pytest-cmake-presets). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzNC4xNDguMCIsInVwZGF0ZWRJblZlciI6IjM0LjE0OC4wIn0=--> Signed-off-by: Renovate Bot <bot@renovateapp.com> Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Was this intended to trigger when the with open("something") as f:
for line in f:
line = line.strip() Produces: $ pipx run ruff --select PL tmp.py --isolated
tmp.py:3:9: PLW2901 Outer for loop variable `line` overwritten by inner assignment target
Found 1 error. This does not produce a warning with pylint. From what I gathered above, this is deviating from pylint intentionally, but the I could go through and change the places where this happens, but it seems like a common and harmless pattern? (If this was a unique warning number for |
This doesn't produce a warning with pylint by default because the entire W2901 check is optional and only enabled if the https://pylint.readthedocs.io/en/latest/user_guide/messages/warning/redefined-loop-name.html Note that the presence of the outer Ultimately it's a matter of personal preference. When I wrote this code, I was thinking I would add an option to disable the error for simple reassignments within a loop, since it seemed over the top. Then when I ran it on my codebase and weighed the pros and cons, I realized I would rather change my harmless habit (that wasn't really so harmless!), and instead write: for raw_line in f:
line = raw_line.strip() The reasons being:
for i in range(10):
# ... many lines of code
i = 10 # possibly buried in nested code
# ... many lines of code
print(i) # developer expected `i` to contain the original iteration value We'd have establish a whitelist of loop variable names that are allowed to be reassigned to, or a privileged position within the loop where it is permitted (e.g. the first line only). However that complicates the rule and is also fragile since it's impossible to cover every case. IMHO it's better to just flag it as an error, and rename the variable or add a |
Practically speaking one option would be to separate out "assignment within a loop" from "reuse as another loop variable" into two separate rules, e.g. PLW2901A and PLW2901, so users could choose to ignore PLW2901A while still catching more obviously unintentional errors like this as PLW2901: for i in range(10):
for i in range(10): # PLW2901
pass |
Ahh, I missed that it was an optional pylint flag! I could have sworn I've seen that error before, and I'm pretty bad about digging up the optional pylint extensions. Since it's not triggering due to the with, I'm fine with it. The wording of the error (with "outer") is a tiny bit confusing - if it just said it was a variable reassignment for the loop, I'd have understood it wasn't a false positive. I think. :) |
That's a great point, we should perhaps only use the word "outer" when there are two loops involved. Thanks for your feedback! |
That would be great! |
[![Mend Renovate](https://app.renovatebot.com/images/banner.svg)](https://renovatebot.com) This PR contains the following updates: | Package | Change | Age | Adoption | Passing | Confidence | |---|---|---|---|---|---| | [ruff](https://togithub.com/charliermarsh/ruff) | `==0.0.247` -> `==0.0.253` | [![age](https://badges.renovateapi.com/packages/pypi/ruff/0.0.253/age-slim)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://badges.renovateapi.com/packages/pypi/ruff/0.0.253/adoption-slim)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://badges.renovateapi.com/packages/pypi/ruff/0.0.253/compatibility-slim/0.0.247)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://badges.renovateapi.com/packages/pypi/ruff/0.0.253/confidence-slim/0.0.247)](https://docs.renovatebot.com/merge-confidence/) | --- ### Release Notes <details> <summary>charliermarsh/ruff</summary> ### [`v0.0.253`](https://togithub.com/charliermarsh/ruff/releases/tag/v0.0.253) [Compare Source](https://togithub.com/charliermarsh/ruff/compare/v0.0.252...v0.0.253) <!-- Release notes generated using configuration in .github/release.yml at 386ca7c9a1bb7ebeb1457b605695c6a09e67092b --> #### What's Changed ##### Rules - \[`pyupgrade`] Avoid rewriting any PEP 604 runtime annotations by [@​charliermarsh](https://togithub.com/charliermarsh) in [astral-sh/ruff#3217 - \[`pycodestyle`] Missing whitespace after keyword by [@​carlosmiei](https://togithub.com/carlosmiei) in [astral-sh/ruff#3225 - \[`pycodestyle`] trailing-whitespace, blank-line-contains-whitespace (W291, W293) by [@​mknaw](https://togithub.com/mknaw) in [astral-sh/ruff#3122 - \[`flake8-pyi`]: PYI009, PYI010, PYI021 by [@​sbdchd](https://togithub.com/sbdchd) in [astral-sh/ruff#3230 - \[`flake8-pyi`]: PYI011, PYI014 by [@​sbdchd](https://togithub.com/sbdchd) in [astral-sh/ruff#3238 - \[`flake8-django`] DJ003, DJ006, DJ007 by [@​lkh42t](https://togithub.com/lkh42t) in [astral-sh/ruff#3236 - \[`pylint`] Implement pylint's `else-if-used` rule (`PLR5501`) by [@​chanman3388](https://togithub.com/chanman3388) in [astral-sh/ruff#3231 - \[`pylint`] W0603: global-statement by [@​igozali](https://togithub.com/igozali) in [astral-sh/ruff#3227 - \[`flake8-pie`] Unnecessary list comprehension, with autofix (PIE802) by [@​matthewlloyd](https://togithub.com/matthewlloyd) in [astral-sh/ruff#3149 ##### Settings - Allow ruff.toml file to be dot-prefixed (as .ruff.toml) by [@​charliermarsh](https://togithub.com/charliermarsh) in [astral-sh/ruff#3221 - \[`pydocstyle`]: Implement `ignore-decorators` by [@​edgarrmondragon](https://togithub.com/edgarrmondragon) in [astral-sh/ruff#3229 ##### Bug Fixes - Avoid suggesting 'is' for constant literals by [@​charliermarsh](https://togithub.com/charliermarsh) in [astral-sh/ruff#3146 - Omit non-.py\[i] files from module naming rules by [@​charliermarsh](https://togithub.com/charliermarsh) in [astral-sh/ruff#3153 - Bind star patterns in match statements by [@​charliermarsh](https://togithub.com/charliermarsh) in [astral-sh/ruff#3169 - Update RustPython to support \*tuple annotations by [@​charliermarsh](https://togithub.com/charliermarsh) in [astral-sh/ruff#3178 - Use `writeln` with --show-settings by [@​charliermarsh](https://togithub.com/charliermarsh) in [astral-sh/ruff#3180 - Avoid boolean-trap rules for ConfigParser get() methods by [@​monosans](https://togithub.com/monosans) in [astral-sh/ruff#3209 - Avoid flagging logging-too-few-args with no arguments by [@​charliermarsh](https://togithub.com/charliermarsh) in [astral-sh/ruff#3220 - Expand the range of the COM812 autofix to include the preceding token by [@​matthewlloyd](https://togithub.com/matthewlloyd) in [astral-sh/ruff#3241 - Avoid flagging Pylint logging rules with starred arguments by [@​charliermarsh](https://togithub.com/charliermarsh) in [astral-sh/ruff#3244 - Avoid flagging unfixable `TypedDict` and `NamedTuple` definitions by [@​charliermarsh](https://togithub.com/charliermarsh) in [astral-sh/ruff#3148 - Fix ExceptionGroup F821 false positive by [@​JonathanPlasse](https://togithub.com/JonathanPlasse) in [astral-sh/ruff#3167 - Avoid autofixing some PT violations when comments are present by [@​charliermarsh](https://togithub.com/charliermarsh) in [astral-sh/ruff#3198 - Exclude globsets for --show-settings by [@​charliermarsh](https://togithub.com/charliermarsh) in [astral-sh/ruff#3201 - \[`flake8-tidy-imports`] fix autofix for relative imports by [@​sciyoshi](https://togithub.com/sciyoshi) in [astral-sh/ruff#3197 - Fix Markdown errors in docs by [@​JonathanPlasse](https://togithub.com/JonathanPlasse) in [astral-sh/ruff#3187 - Normalize treatment of aliased and unaliased imports by [@​charliermarsh](https://togithub.com/charliermarsh) in [astral-sh/ruff#3216 - Avoid EXE001 and EXE002 errors from stdin input by [@​charliermarsh](https://togithub.com/charliermarsh) in [astral-sh/ruff#3218 - \[bandit]: Do not treat "passed" as "password" for `S105`/`S106`/`S107` by [@​edgarrmondragon](https://togithub.com/edgarrmondragon) in [astral-sh/ruff#3222 #### New Contributors - [@​mknaw](https://togithub.com/mknaw) made their first contribution in [astral-sh/ruff#3122 - [@​monosans](https://togithub.com/monosans) made their first contribution in [astral-sh/ruff#3209 - [@​lkh42t](https://togithub.com/lkh42t) made their first contribution in [astral-sh/ruff#3236 - [@​igozali](https://togithub.com/igozali) made their first contribution in [astral-sh/ruff#3227 **Full Changelog**: astral-sh/ruff@v0.0.252...v0.0.253 ### [`v0.0.252`](https://togithub.com/charliermarsh/ruff/releases/tag/v0.0.252) [Compare Source](https://togithub.com/charliermarsh/ruff/compare/v0.0.251...v0.0.252) <!-- Release notes generated using configuration in .github/release.yml at main --> #### What's Changed ##### Rules - \[`pylint`] `redefined-loop-name` (`W2901`) by [@​matthewlloyd](https://togithub.com/matthewlloyd) in [astral-sh/ruff#3022 - \[`pylint`] ` logging-too-many-args ` (`E1205`) by [@​md384](https://togithub.com/md384) in [astral-sh/ruff#3084 - \[`pylint`] ` logging-too-few-args ` (`E1206`) by [@​md384](https://togithub.com/md384) in [astral-sh/ruff#3084 ##### Bug Fixes - Include file permissions in cache key by [@​charliermarsh](https://togithub.com/charliermarsh) in [astral-sh/ruff#3104 - Skip EXE001 and EXE002 rules on Windows by [@​charliermarsh](https://togithub.com/charliermarsh) in [astral-sh/ruff#3111 - Mark `typing.assert_never` as no return by [@​bluetech](https://togithub.com/bluetech) in [astral-sh/ruff#3121 - Use file-specific quote for C408 by [@​charliermarsh](https://togithub.com/charliermarsh) in [astral-sh/ruff#3128 - Avoid match statement misidentification in token rules by [@​charliermarsh](https://togithub.com/charliermarsh) in [astral-sh/ruff#3129 - Upgrade RustPython to handle trailing commas in map patterns by [@​charliermarsh](https://togithub.com/charliermarsh) in [astral-sh/ruff#3130 - Avoid useless-else-on-loop for break within match by [@​charliermarsh](https://togithub.com/charliermarsh) in [astral-sh/ruff#3136 - Fix isort `no-lines-before` preceded by an empty section by [@​bluetech](https://togithub.com/bluetech) in [astral-sh/ruff#3139 - Support shell expansion for --config argument by [@​charliermarsh](https://togithub.com/charliermarsh) in [astral-sh/ruff#3107 - Fix =/== error in `ManualDictLookup` by [@​Rupt](https://togithub.com/Rupt) in [astral-sh/ruff#3117 - Include match in nested block check by [@​charliermarsh](https://togithub.com/charliermarsh) in [astral-sh/ruff#3137 - Upgrade RustPython to match new flattened exports by [@​charliermarsh](https://togithub.com/charliermarsh) in [astral-sh/ruff#3141 #### New Contributors - [@​md384](https://togithub.com/md384) made their first contribution in [astral-sh/ruff#3084 - [@​Rupt](https://togithub.com/Rupt) made their first contribution in [astral-sh/ruff#3117 - [@​marijncv](https://togithub.com/marijncv) made their first contribution in [astral-sh/ruff#3133 **Full Changelog**: astral-sh/ruff@v0.0.251...v0.0.252 ### [`v0.0.251`](https://togithub.com/charliermarsh/ruff/releases/tag/v0.0.251) [Compare Source](https://togithub.com/charliermarsh/ruff/compare/v0.0.250...v0.0.251) <!-- Release notes generated using configuration in .github/release.yml at main --> #### What's Changed ##### Bug Fixes - Create bindings for `MatchAs` patterns by [@​charliermarsh](https://togithub.com/charliermarsh) in [astral-sh/ruff#3098 - Avoid prefer-list-builtin for lambdas with `*args` or `**kwargs` by [@​charliermarsh](https://togithub.com/charliermarsh) in [astral-sh/ruff#3102 **Full Changelog**: astral-sh/ruff@v0.0.250...v0.0.251 ### [`v0.0.250`](https://togithub.com/charliermarsh/ruff/releases/tag/v0.0.250) [Compare Source](https://togithub.com/charliermarsh/ruff/compare/v0.0.249...v0.0.250) <!-- Release notes generated using configuration in .github/release.yml at main --> #### What's Changed **Ruff now supports all Python 3.10 and 3.11 language features**, including: - Structural Pattern Patching (`match` statements) ([PEP 634](https://peps.python.org/pep-0634/#class-patterns)) - Exception Groups (`except*` statements) ([PEP 654](https://peps.python.org/pep-0654/)) ##### Rules - \[`flake8-bugbear`] Add B029 (`except-with-empty-tuple`) from flake8-bugbear by [@​carlosmiei](https://togithub.com/carlosmiei) in [astral-sh/ruff#3068 - \[`flake8-bugbear`] Add B032 (`unintentional-type-annotation`) from flake8\_bugbear by [@​carlosmiei](https://togithub.com/carlosmiei) in [astral-sh/ruff#3085 - \[`tryceratops`]: Add TRY401 (`verbose-log-messages`) by [@​colin99d](https://togithub.com/colin99d) in [astral-sh/ruff#3036 - \[`flake8-simplify`]: Add SIM116 (`manual-dict-lookup`) by [@​colin99d](https://togithub.com/colin99d) in [astral-sh/ruff#2767 ##### Features - Add support for TryStar by [@​charliermarsh](https://togithub.com/charliermarsh) in [astral-sh/ruff#3089 - Add support for structural pattern matching by [@​charliermarsh](https://togithub.com/charliermarsh) in [astral-sh/ruff#3047 ##### Bug Fixes - \[`flake8-pytest`] Use LibCST to fix chained assertions by [@​charliermarsh](https://togithub.com/charliermarsh) in [astral-sh/ruff#3087 - \[`flake8-boolean-trap`] Avoid boolean-trap rules for positional-only builtin calls by [@​charliermarsh](https://togithub.com/charliermarsh) in [astral-sh/ruff#3075 - \[`flake8-boolean-trap`] Ignore setters in flake8-boolean-trap by [@​charliermarsh](https://togithub.com/charliermarsh) in [astral-sh/ruff#3092 - \[`flake8-return`] Omit `while-True` loops from implicit return enforcement by [@​charliermarsh](https://togithub.com/charliermarsh) in [astral-sh/ruff#3076 #### New Contributors - [@​carlosmiei](https://togithub.com/carlosmiei) made their first contribution in [astral-sh/ruff#3068 **Full Changelog**: astral-sh/ruff@v0.0.249...v0.0.250 ### [`v0.0.249`](https://togithub.com/charliermarsh/ruff/releases/tag/v0.0.249) [Compare Source](https://togithub.com/charliermarsh/ruff/compare/v0.0.248...v0.0.249) <!-- Release notes generated using configuration in .github/release.yml at 4cfa350112a82fb631909fc555588f3da8ba5750 --> #### What's Changed ##### Bug Fixes - Relax constraints on pep8-naming module validation by [@​charliermarsh](https://togithub.com/charliermarsh) in [astral-sh/ruff#3043 - Do not autofix `E731` in class bodies by [@​JoshKarpel](https://togithub.com/JoshKarpel) in [astral-sh/ruff#3050 - Avoid assert() to assert statement conversion in expressions by [@​charliermarsh](https://togithub.com/charliermarsh) in [astral-sh/ruff#3062 #### New Contributors - [@​matthewlloyd](https://togithub.com/matthewlloyd) made their first contribution in [astral-sh/ruff#3048 - [@​JoshKarpel](https://togithub.com/JoshKarpel) made their first contribution in [astral-sh/ruff#3050 **Full Changelog**: astral-sh/ruff@v0.0.248...v0.0.249 ### [`v0.0.248`](https://togithub.com/charliermarsh/ruff/releases/tag/v0.0.248) [Compare Source](https://togithub.com/charliermarsh/ruff/compare/v0.0.247...v0.0.248) <!-- Release notes generated using configuration in .github/release.yml at main --> #### What's Changed ##### Rules - \[`numpy`] numpy-legacy-random by [@​sbrugman](https://togithub.com/sbrugman) in [astral-sh/ruff#2960 - \[`pycodestyle`] autofix useless semicolons by [@​sbrugman](https://togithub.com/sbrugman) in [astral-sh/ruff#3001 - \[`pep8-naming`] Implement `flake8-module-naming` by [@​sbrugman](https://togithub.com/sbrugman) in [astral-sh/ruff#2855 - \[`flake8-self`] Ignore namedtuple methods in flake8-self by [@​charliermarsh](https://togithub.com/charliermarsh) in [astral-sh/ruff#2998 - \[`flake8-simplify`] Merge convert-loop-to-any & convert-loop-to-all to reimplemented-builtin by [@​not-my-profile](https://togithub.com/not-my-profile) in [astral-sh/ruff#2903 - \[`ruff`] Add support for `ensure_future` for RUF006 by [@​Lunarmagpie](https://togithub.com/Lunarmagpie) in [astral-sh/ruff#2943 - \[`pylint`] error when `__init__` returns a value by [@​r3m0t](https://togithub.com/r3m0t) in [astral-sh/ruff#3007 - \[`flake8-pytest-style`] autofix for composite-assertion (PT018) by [@​sbrugman](https://togithub.com/sbrugman) in [astral-sh/ruff#2732 - \[`flake8-tidy-imports`] extend autofix of relative imports by [@​sbrugman](https://togithub.com/sbrugman) in [astral-sh/ruff#2990 ##### Settings - Add support for file-scoped `noqa` directives by [@​charliermarsh](https://togithub.com/charliermarsh) in [astral-sh/ruff#2978 - Add configuration option for C408 to allow dict calls with keyword arguments. by [@​manueljacob](https://togithub.com/manueljacob) in [astral-sh/ruff#2977 - feat(isort): Implement isort.force_to_top by [@​spaceone](https://togithub.com/spaceone) in [astral-sh/ruff#2877 ##### Bug Fixes - Fix add-required-import with multi-line offsets by [@​charliermarsh](https://togithub.com/charliermarsh) in [astral-sh/ruff#2946 - Support positional messages in assertion rewrites by [@​charliermarsh](https://togithub.com/charliermarsh) in [astral-sh/ruff#3002 - Avoid false-positives for break in with by [@​charliermarsh](https://togithub.com/charliermarsh) in [astral-sh/ruff#3032 - Avoid trying to fix implicit returns with control flow by [@​charliermarsh](https://togithub.com/charliermarsh) in [astral-sh/ruff#2962 - Handle non-from **future** imports by [@​charliermarsh](https://togithub.com/charliermarsh) in [astral-sh/ruff#2974 - Enforce D403 on methods by [@​charliermarsh](https://togithub.com/charliermarsh) in [astral-sh/ruff#2992 - Avoid zero-indexed column for IOError by [@​charliermarsh](https://togithub.com/charliermarsh) in [astral-sh/ruff#2995 - Fix for F541 unescape f-string by [@​sbrugman](https://togithub.com/sbrugman) in [astral-sh/ruff#2971 - Avoid raising `B027` violations in `.pyi` files by [@​JonathanPlasse](https://togithub.com/JonathanPlasse) in [astral-sh/ruff#3016 #### New Contributors - [@​Lunarmagpie](https://togithub.com/Lunarmagpie) made their first contribution in [astral-sh/ruff#2943 - [@​manueljacob](https://togithub.com/manueljacob) made their first contribution in [astral-sh/ruff#2966 - [@​mwtoews](https://togithub.com/mwtoews) made their first contribution in [astral-sh/ruff#2973 - [@​ortem](https://togithub.com/ortem) made their first contribution in [astral-sh/ruff#2976 - [@​thatlittleboy](https://togithub.com/thatlittleboy) made their first contribution in [astral-sh/ruff#3027 - [@​r3m0t](https://togithub.com/r3m0t) made their first contribution in [astral-sh/ruff#3007 **Full Changelog**: astral-sh/ruff@v0.0.247...v0.0.248 </details> --- ### Configuration 📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Enabled. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box --- This PR has been generated by [Mend Renovate](https://www.mend.io/free-developer-tools/renovate/). View repository job log [here](https://app.renovatebot.com/dashboard#github/allenporter/flux-local). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzNC4xNTMuMiIsInVwZGF0ZWRJblZlciI6IjM0LjE1My4yIn0=--> Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Slightly broadens W2901 to cover
with
statements too.Closes #2972.