-
Notifications
You must be signed in to change notification settings - Fork 882
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
Magic Trailing Commas in isort #1363
Merged
Merged
Changes from 36 commits
Commits
Show all changes
37 commits
Select commit
Hold shift + click to select a range
33e2744
Added magic comma support
colin99d ddc7be6
Removed print
colin99d 5cc06bb
Updated test py file
colin99d a2cec4c
Got tests working
colin99d 027747b
Cleaned up code
colin99d 0bddc50
Clippy and fmt
colin99d c7ed221
Added requested test cases
colin99d bcaa370
Added some more fixes
colin99d eb68853
Minor formatting updates
colin99d c406311
Added some documentation
colin99d 01adfee
Improved the logic
colin99d 519de3a
reverted to previous change
colin99d aa9a801
Could be what we do next
colin99d 227d548
Refactored to send location as another paramter
colin99d 151e94c
Got it working
colin99d 5c445f9
Merge branch 'main' into 1200
colin99d d8f2711
Removed prints, fmt, clippy
colin99d d2872de
Added clippy fixes
colin99d 4b694ea
split comma checker into a separate function
colin99d d8d7010
Made separate function use a for statement
colin99d df06afa
Got it working
colin99d 7ede557
Got fixes added
colin99d 3411079
Added the option
colin99d d6d8682
Actually use the option
colin99d 9332e36
Merge and resolve conflicts
colin99d 46e12fe
Fixed outdated README
colin99d 075f169
Added some more fixes
colin99d d4dcda8
Fixed line too long
colin99d de7520a
Use lexer-based detection
charliermarsh 45a9739
Fixed clippy
colin99d 8161e98
Make setting true by default
charliermarsh 097d620
Invert tests
charliermarsh 561d477
Update snapshots
charliermarsh ba855d5
Merge branch '1200' of github.com:colin99d/ruff into 1200
charliermarsh f66b8f4
Generate options, etc.
charliermarsh de1843b
Tweak signature
charliermarsh 8998f45
Remove repeated comment
charliermarsh File filter
Filter by extension
Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
# This has a magic trailing comma, will be sorted, but not rolled into one line | ||
from sys import ( | ||
stderr, | ||
argv, | ||
stdout, | ||
exit, | ||
) | ||
|
||
# No magic comma, this will be rolled into one line. | ||
from os import ( | ||
path, | ||
environ, | ||
execl, | ||
execv | ||
) | ||
colin99d marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
from glob import ( | ||
glob, | ||
iglob, | ||
escape, # Ends with a comment, should still treat as magic trailing comma. | ||
) | ||
|
||
# These will be combined, but without a trailing comma. | ||
from foo import bar | ||
from foo import baz | ||
|
||
# These will be combined, _with_ a trailing comma. | ||
from module1 import member1 | ||
from module1 import ( | ||
member2, | ||
member3, | ||
) | ||
|
||
# These will be combined, _with_ a trailing comma. | ||
from module2 import member1, member2 | ||
from module2 import ( | ||
member3, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,11 +9,14 @@ use rustpython_ast::{Stmt, StmtKind}; | |
|
||
use crate::isort::categorize::{categorize, ImportType}; | ||
use crate::isort::comments::Comment; | ||
use crate::isort::helpers::trailing_comma; | ||
use crate::isort::sorting::{cmp_import_froms, cmp_members, cmp_modules}; | ||
use crate::isort::track::{Block, Trailer}; | ||
use crate::isort::types::{ | ||
AliasData, CommentSet, ImportBlock, ImportFromData, Importable, OrderedImportBlock, | ||
TrailingComma, | ||
}; | ||
use crate::SourceCodeLocator; | ||
|
||
mod categorize; | ||
mod comments; | ||
|
@@ -32,6 +35,7 @@ pub struct AnnotatedAliasData<'a> { | |
pub atop: Vec<Comment<'a>>, | ||
pub inline: Vec<Comment<'a>>, | ||
} | ||
|
||
#[derive(Debug)] | ||
pub enum AnnotatedImport<'a> { | ||
Import { | ||
|
@@ -45,12 +49,15 @@ pub enum AnnotatedImport<'a> { | |
level: Option<&'a usize>, | ||
atop: Vec<Comment<'a>>, | ||
inline: Vec<Comment<'a>>, | ||
trailing_comma: TrailingComma, | ||
}, | ||
} | ||
|
||
fn annotate_imports<'a>( | ||
imports: &'a [&'a Stmt], | ||
comments: Vec<Comment<'a>>, | ||
locator: &SourceCodeLocator, | ||
split_on_trailing_comma: bool, | ||
) -> Vec<AnnotatedImport<'a>> { | ||
let mut annotated = vec![]; | ||
let mut comments_iter = comments.into_iter().peekable(); | ||
|
@@ -137,6 +144,11 @@ fn annotate_imports<'a>( | |
module: module.as_ref(), | ||
names: aliases, | ||
level: level.as_ref(), | ||
trailing_comma: if split_on_trailing_comma { | ||
trailing_comma(import, locator) | ||
} else { | ||
TrailingComma::default() | ||
}, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I also tweaked the order of operations: instead of collecting locations, and looking at the locations at the end, we detect a trailing comma for each block, and then propagate it through the code as we merge imports. |
||
atop, | ||
inline, | ||
}); | ||
|
@@ -190,7 +202,9 @@ fn normalize_imports(imports: Vec<AnnotatedImport>, combine_as_imports: bool) -> | |
level, | ||
atop, | ||
inline, | ||
trailing_comma, | ||
} => { | ||
// Associate the comments with the first alias (best effort). | ||
let single_import = names.len() == 1; | ||
|
||
// If we're dealing with a multi-import block (i.e., a non-star, non-aliased | ||
|
@@ -289,6 +303,15 @@ fn normalize_imports(imports: Vec<AnnotatedImport>, combine_as_imports: bool) -> | |
entry.inline.push(comment.value); | ||
} | ||
} | ||
|
||
// Propagate trailing commas. | ||
if matches!(trailing_comma, TrailingComma::Present) { | ||
if let Some(entry) = | ||
block.import_from.get_mut(&ImportFromData { module, level }) | ||
{ | ||
entry.2 = trailing_comma; | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
@@ -412,6 +435,7 @@ fn sort_imports(block: ImportBlock) -> OrderedImportBlock { | |
inline: comments.inline, | ||
}, | ||
)]), | ||
TrailingComma::Absent, | ||
), | ||
) | ||
}), | ||
|
@@ -439,40 +463,44 @@ fn sort_imports(block: ImportBlock) -> OrderedImportBlock { | |
inline: comments.inline, | ||
}, | ||
)]), | ||
TrailingComma::Absent, | ||
), | ||
) | ||
}), | ||
) | ||
.map(|(import_from, (comments, aliases))| { | ||
.map(|(import_from, (comments, aliases, locations))| { | ||
// Within each `StmtKind::ImportFrom`, sort the members. | ||
( | ||
import_from, | ||
comments, | ||
locations, | ||
aliases | ||
.into_iter() | ||
.sorted_by(|(alias1, _), (alias2, _)| cmp_members(alias1, alias2)) | ||
.collect::<Vec<(AliasData, CommentSet)>>(), | ||
) | ||
}) | ||
.sorted_by(|(import_from1, _, aliases1), (import_from2, _, aliases2)| { | ||
cmp_import_froms(import_from1, import_from2).then_with(|| { | ||
match (aliases1.first(), aliases2.first()) { | ||
(None, None) => Ordering::Equal, | ||
(None, Some(_)) => Ordering::Less, | ||
(Some(_), None) => Ordering::Greater, | ||
(Some((alias1, _)), Some((alias2, _))) => cmp_members(alias1, alias2), | ||
} | ||
}) | ||
}), | ||
.sorted_by( | ||
|(import_from1, _, _, aliases1), (import_from2, _, _, aliases2)| { | ||
cmp_import_froms(import_from1, import_from2).then_with(|| { | ||
match (aliases1.first(), aliases2.first()) { | ||
(None, None) => Ordering::Equal, | ||
(None, Some(_)) => Ordering::Less, | ||
(Some(_), None) => Ordering::Greater, | ||
(Some((alias1, _)), Some((alias2, _))) => cmp_members(alias1, alias2), | ||
} | ||
}) | ||
}, | ||
), | ||
); | ||
|
||
ordered | ||
} | ||
|
||
#[allow(clippy::too_many_arguments)] | ||
pub fn format_imports( | ||
block: &Block, | ||
comments: Vec<Comment>, | ||
locator: &SourceCodeLocator, | ||
line_length: usize, | ||
src: &[PathBuf], | ||
package: Option<&Path>, | ||
|
@@ -481,9 +509,10 @@ pub fn format_imports( | |
extra_standard_library: &BTreeSet<String>, | ||
combine_as_imports: bool, | ||
force_wrap_aliases: bool, | ||
split_on_trailing_comma: bool, | ||
) -> String { | ||
let trailer = &block.trailer; | ||
let block = annotate_imports(&block.imports, comments); | ||
let block = annotate_imports(&block.imports, comments, locator, split_on_trailing_comma); | ||
|
||
// Normalize imports (i.e., deduplicate, aggregate `from` imports). | ||
let block = normalize_imports(block, combine_as_imports); | ||
|
@@ -521,14 +550,15 @@ pub fn format_imports( | |
} | ||
|
||
// Format `StmtKind::ImportFrom` statements. | ||
for (import_from, comments, aliases) in &import_block.import_from { | ||
for (import_from, comments, trailing_comma, aliases) in &import_block.import_from { | ||
output.append(&format::format_import_from( | ||
import_from, | ||
comments, | ||
aliases, | ||
line_length, | ||
force_wrap_aliases, | ||
is_first_statement, | ||
split_on_trailing_comma && matches!(trailing_comma, TrailingComma::Present), | ||
)); | ||
is_first_statement = false; | ||
} | ||
|
@@ -588,6 +618,7 @@ mod tests { | |
#[test_case(Path::new("split.py"))] | ||
#[test_case(Path::new("trailing_suffix.py"))] | ||
#[test_case(Path::new("type_comments.py"))] | ||
#[test_case(Path::new("magic_trailing_comma.py"))] | ||
fn default(path: &Path) -> Result<()> { | ||
let snapshot = format!("{}", path.to_string_lossy()); | ||
let mut checks = test_path( | ||
|
@@ -646,4 +677,25 @@ mod tests { | |
insta::assert_yaml_snapshot!(snapshot, checks); | ||
Ok(()) | ||
} | ||
|
||
#[test_case(Path::new("magic_trailing_comma.py"))] | ||
fn no_split_on_trailing_comma(path: &Path) -> Result<()> { | ||
let snapshot = format!("split_on_trailing_comma_{}", path.to_string_lossy()); | ||
let mut checks = test_path( | ||
Path::new("./resources/test/fixtures/isort") | ||
.join(path) | ||
.as_path(), | ||
&Settings { | ||
isort: isort::settings::Settings { | ||
split_on_trailing_comma: false, | ||
..isort::settings::Settings::default() | ||
}, | ||
src: vec![Path::new("resources/test/fixtures/isort").to_path_buf()], | ||
..Settings::for_rule(CheckCode::I001) | ||
}, | ||
)?; | ||
checks.sort_by_key(|check| check.location); | ||
insta::assert_yaml_snapshot!(snapshot, checks); | ||
Ok(()) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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 also made this the default, to match isort's
profile = "black"
.