-
Notifications
You must be signed in to change notification settings - Fork 1.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
Add a rule/autofix to sort __slots__
and __match_args__
#9564
Conversation
|
code | total | + violation | - violation | + fix | - fix |
---|---|---|---|---|---|
RUF023 | 150 | 150 | 0 | 0 | 0 |
23cfdbc
to
39a059b
Compare
__match_args__
__match_args__
Okay, after the latest push, we now fix all but one violation in CPython (there's only one place in CPython where a multiline dict is used for |
CodSpeed Performance ReportMerging #9564 will not alter performanceComparing Summary
|
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.
Nice work. My only concern is that the use of impl FnMut
for the comparator leads multiple copies of the same code because of monomorpization. I recommend introducing an enum
with variants for the two sort options that you need.
} | ||
|
||
#[derive(Debug)] | ||
struct NodeAnalysis<'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.
Nit: The name here isn't telling me much. What kind of analysis is it? Is it like the SortDunderAnalysis
? Or can we give that structure another name, because the structure isn't the analysis. What does it represent?
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.
Pushed a rename and some more docs in cf6ca75 -- any better?
I really struggled with naming this the other day, but coming back to it after a few days made it seem obvious :)
I'm really astonished how quickly you closed #1198 and brought to live this follow-up PR - big kudos!
Just wanted to let you know that I'd be very interested in autofixes for multline tuple- |
Have no fear, the description in my PR summary is already slightly out of date — I've already implemented the autofix for multiline tuple |
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.
Very nice, a couple questions and comments!
} | ||
} | ||
|
||
fn create_fix( |
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.
Should this be a method on StringLiteralDisplay
?
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.
Not sure... it makes the signature cleaner, but I was thinking of this struct as just a pretty simple container for heterogenous data; this breaks my mental model of that slightly. Anyway, I implemented it as a method in e64879a :)
} | ||
} | ||
|
||
impl Eq for IsortSortKey<'_> {} |
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.
@BurntSushi - Do these Ord
/ PartialOrd
/ PartialEq
/ Eq
implementations look right / consistent to you? (I've never properly learned the relationships between them.)
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.
(FWIW: these haven't changed in this PR, just moved to a different file, and Micha reviewed these in my previous PR (my initial implementations in my previous PR had some issues, which Micha pointed out))
where | ||
F: FnMut(&str, &str) -> Ordering, | ||
{ | ||
assert_eq!(elts.len(), elements.len()); |
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 he's suggesting creating a dedicated struct like that. Since you're allocating below anyway with collect_vec
, perhaps you want to do something like:
struct Whatever<'a>(Vec<(&'a Expr, &'a str)>)
That is: store the zipped elements, so that the constraint is always enforced once you've created the struct.
} | ||
} | ||
|
||
/// Collect data on each line of a multiline string sequence. |
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.
How much of the below is new code vs. moved from the isort rule?
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 everything below this point is entirely unchanged, just moved, except that a few things have been renamed and a few comments tweaked (e.g. collect_dunder_all_lines()
has been renamed to collect_string_sequence_lines()
, etc.)
…ring literals after a string literal that uses implicit concatenation
__match_args__
__slots__
and __match_args__
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.
Looks good to me!
// Safe from underflow, as the constructor guarantees | ||
// that the underlying vector has length >= 2 | ||
self.0.len() - 1 | ||
} |
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 feel like I'd find it clearer to just have .len()
on this and do if i < element_trios.len() - 1
, since that's such a common pattern in iteration.
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 definitely know what you mean, but here specifically I do quite like having this logic right next to the assertions in the constructor method that maintain the invariant that protect us from underflow here
d5606fa
to
333fe62
Compare
Thanks both for the reviews! :D I've had two approvals, so I'm landing this now, but very happy to tackle any further comments in followup PRs :) |
Summary
This PR introduces a new rule to sort
__slots__
and__match_args__
according to a natural sort, as was requested in #1198 (comment).The implementation here generalises some of the machinery introduced in 3aae16f so that different kinds of sorts can be applied to lists of string literals. (We use an "isort-style" sort for
__all__
, but that isn't really appropriate for__slots__
and__match_args__
, where nearly all items will be snake_case.) Several sections of code have been moved fromsort_dunder_all.rs
to a new module,sorting_helpers.rs
, whichsort_dunder_all.rs
andsort_dunder_slots.rs
both make use of.__match_args__
is very similar to__all__
, in that it can only be a tuple or a list.__slots__
differs from the other two, however, in that it can be any iterable of strings. If slots is a dictionary, the values are used by the builtinhelp()
function as per-attribute docstrings that show up in the output ofhelp()
. (There's no particular use-case for making__slots__
a set, but it's perfectly legal at runtime, so there's no reason for us not to handle it in this rule.)Currently I've only implemented an autofix for
__match_args__
and__slots__
if the definition is on a single line. That's for two reasons:__slots__
and__match_args__
definitions are much rarer than multiline__all__
definitions, so there's probably less value in implementing the autofix for those.Implementing an autofix for multiline
__match_args__
wouldn't be too hard: I'd just have to move more code fromsort_dunder_all.rs
tosorting_helpers.rs
. The same is true for__slots__
when it's a tuple, list or set. I don't feel enthused about implementing an autofix for multiline__slots__
definitions where__slots__
is a dict, however. That would require a lot of extra code, and using a dict for__slots__
is pretty rare.If we're interested in autofixes for multiline
__slots__
and__match_args__
definitions, let me know whether you'd prefer it in this PR or a followup!Test Plan
cargo test
/cargo insta review
.I also ran this rule on CPython. The autofix fixed 45 violations:
Diff from the autofix
The following 17 violations were flagged but left unfixed by the rule as it currently stands. (They were unfixed because they're multiline definitions):