You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The 0.16.0 default rule set is documented as an expansion, 413 rules up from 59. It is also a contraction: 18 rules that were enabled by default in 0.15.8 are not in the new default set. All 18 are stable, not deprecated, and not removed, so they are still perfectly good rules. They simply stopped running for anyone who was relying on the default.
I do not think the removals are wrong. They may well be deliberate and correct. My concern is only that they are not written down anywhere, so the people affected have no way to find out except by diffing the two rule sets themselves.
Projects with no lint configuration, and projects using extend-select, since that extends the default rather than replacing it. Projects using select are unaffected, because select replaces the default outright.
That second group is the awkward one. The migration blog's only line addressing existing configuration is:
Even if you're already using select or extend-select, we hope that this will draw your attention to helpful rules that you previously hadn't discovered.
Read as guidance, that suggests there is nothing to do beyond browsing the additions. An extend-select user who acts on it silently loses 18 rules.
I have not included a playground link because the claim is a difference between two ruff versions, and the playground runs one. Every command above uses --isolated, so no configuration of mine is involved in any of it.
Test for consolidation
I checked whether the removals were a consolidation, with newer default rules absorbing the old ones. This seems to not be the case. I used the following file as input:
Now a test with six of the dropped rules selected:
$ ruff check --isolated --no-cache dropped.py --select E711,E712,E713,E714,E721,F722dropped.py:5:9: E711 Comparison to `None` should be `cond is None`dropped.py:7:4: E712 Avoid equality comparisons to `True`; use `x:` for truth checksdropped.py:9:8: E713 Test for membership should be `not in`dropped.py:11:8: E714 Test for object identity should be `is not`dropped.py:13:4: E721 Use `is` and `is not` for type comparisons, or `isinstance()` for isinstance checksdropped.py:17:12: F722 Syntax error in forward annotation: Unexpected token at the end of an expressionFound 6 errors.
I ran the same check across all 18 and the result was the same, zero reported under defaults, all 18 reported when re-selected.
F722 is the one I would flag for a second look regardless of the documentation question. A syntax error in a forward annotation is the kind of thing the release notes single out as worth catching by default, and it is now silent unless the user opts back in.
Prior art
From BREAKING_CHANGES.md for 0.1.0, "Remove formatter-conflicting rules from the default rule set" (#7900):
Previously, Ruff enabled all implemented rules in Pycodestyle (E) by default. Ruff now only includes the Pycodestyle prefixes E4, E7, and E9 to exclude rules that conflict with automatic formatters. Consequently, the stable rule set no longer includes line-too-long (E501) and mixed-spaces-and-tabs (E101). [...] This change only affects those using Ruff under its default rule set. Users that include E in their select will experience no change in behavior.
That entry names the removed rules, gives the reason, and tells readers whether they are affected. This creates an expectation that similar rule drops that aren't folded into consolidations would be documented here.
The 0.16.0 entry in the same file is titled "New default rules" and reads, in full:
Ruff now enables a much larger set of rules by default (413, up from 59). See the blog post for more details and the new Default Rules page for a full listing of the enabled rules.
The Default Rules page it points to is a list of what is enabled, which does not help a reader work out what stopped being enabled. As far as I can tell the removals are unmentioned in BREAKING_CHANGES.md, the 0.16.0 release notes, the migration blog post, and the Default Rules page.
Before filing I checked whether narrowing the default set is routine, as documenting this in BREAKING_CHANGES.md might have fallen out of practice and would have made this issue pedantic. I dumped the enabled rule set for every minor release from 0.1.0 to 0.16.0 and diffed each against its predecessor:
0.1.0 through 0.7.0 60 rules
0.8.0 through 0.15.0 59 rules
0.16.0 413 rules
0.7.0 -> 0.8.0 1 rule left the default set
0.15.0 -> 0.16.0 18 rules left the default set
The set has been largely stable since 0.1.0. 0.8.0 is the outlier, but it is not a coverage reduction. This is where E999 syntax-error became unconditional rather than selectable, and 0.16.0 still reports syntax errors under --isolated with no configuration:
Discussion Feedback on new default rules #23203, the feedback thread for the new default set, searched for all 18 codes. The only hits are inside one participant's posted work configuration, where E402, E711, E731 and E741 appear in their own ignore list. That is a description of their setup, not a comment on the default set, and I mention it only because it is easy to mistake for one.
The 0.16.0 release notes, the migration blog post, BREAKING_CHANGES.md, and the Default Rules page. (as covered above)
General web searches (including forum scoped) for the rule codes alongside 0.16. Secondary coverage of the release is uniformly about the expansion. The closest thing to a description of the new set I found states that Ruff "decided to enable all rules that are considered stable by default".
It's possible that I missed something here, but I've attempted due diligence.
Conclusion
I believe that a BREAKING_CHANGES.md entry for 0.16.0 in the shape of the 0.1.0 one is warranted: the list of removed rules, a sentence on the reasoning, and a note on who is affected, specifically calling out extend-select users. Mirroring it into the release notes and the migration blog would help, since that is where people upgrading will look first.
If any of the 18 were dropped by oversight rather than by decision (F722 seems the most likely candidate), that would be worth a separate look.
Summary
The 0.16.0 default rule set is documented as an expansion, 413 rules up from 59. It is also a contraction: 18 rules that were enabled by default in 0.15.8 are not in the new default set. All 18 are stable, not deprecated, and not removed, so they are still perfectly good rules. They simply stopped running for anyone who was relying on the default.
I do not think the removals are wrong. They may well be deliberate and correct. My concern is only that they are not written down anywhere, so the people affected have no way to find out except by diffing the two rule sets themselves.
The 18:
Impact scope
Projects with no lint configuration, and projects using
extend-select, since that extends the default rather than replacing it. Projects usingselectare unaffected, becauseselectreplaces the default outright.That second group is the awkward one. The migration blog's only line addressing existing configuration is:
Read as guidance, that suggests there is nothing to do beyond browsing the additions. An
extend-selectuser who acts on it silently loses 18 rules.Reproduction
I have not included a playground link because the claim is a difference between two ruff versions, and the playground runs one. Every command above uses
--isolated, so no configuration of mine is involved in any of it.Test for consolidation
I checked whether the removals were a consolidation, with newer default rules absorbing the old ones. This seems to not be the case. I used the following file as input:
Under 0.16.0 defaults:
Now a test with six of the dropped rules selected:
I ran the same check across all 18 and the result was the same, zero reported under defaults, all 18 reported when re-selected.
F722 is the one I would flag for a second look regardless of the documentation question. A syntax error in a forward annotation is the kind of thing the release notes single out as worth catching by default, and it is now silent unless the user opts back in.
Prior art
From BREAKING_CHANGES.md for 0.1.0, "Remove formatter-conflicting rules from the default rule set" (#7900):
That entry names the removed rules, gives the reason, and tells readers whether they are affected. This creates an expectation that similar rule drops that aren't folded into consolidations would be documented here.
The 0.16.0 entry in the same file is titled "New default rules" and reads, in full:
The Default Rules page it points to is a list of what is enabled, which does not help a reader work out what stopped being enabled. As far as I can tell the removals are unmentioned in BREAKING_CHANGES.md, the 0.16.0 release notes, the migration blog post, and the Default Rules page.
Before filing I checked whether narrowing the default set is routine, as documenting this in BREAKING_CHANGES.md might have fallen out of practice and would have made this issue pedantic. I dumped the enabled rule set for every minor release from 0.1.0 to 0.16.0 and diffed each against its predecessor:
The set has been largely stable since 0.1.0. 0.8.0 is the outlier, but it is not a coverage reduction. This is where E999
syntax-errorbecame unconditional rather than selectable, and 0.16.0 still reports syntax errors under--isolatedwith no configuration:Net result: 0.16.0 is the first genuine reduction of the default rule set since 0.1.0, and a deviation from the documentation practice.
Due diligence
It goes without saying that adding a default rule is a loud change. Removing one is silent and goes unnoticed.
I looked for documentation of the rule narrowing before filing this issue:
CPY001exclude empty (in particular__init__.py) files by default 🙏 #27195 on CPY001,I001triggered unexpectedly #27145 and I001: Poor reformatting when autofixing multi-line re-exports #27149 on I001.ignorelist. That is a description of their setup, not a comment on the default set, and I mention it only because it is easy to mistake for one.It's possible that I missed something here, but I've attempted due diligence.
Conclusion
I believe that a BREAKING_CHANGES.md entry for 0.16.0 in the shape of the 0.1.0 one is warranted: the list of removed rules, a sentence on the reasoning, and a note on who is affected, specifically calling out
extend-selectusers. Mirroring it into the release notes and the migration blog would help, since that is where people upgrading will look first.If any of the 18 were dropped by oversight rather than by decision (F722 seems the most likely candidate), that would be worth a separate look.
Version