Add support for combine-as-imports import formatting (#1022)

This commit is contained in:
Charlie Marsh
2022-12-04 00:11:48 -05:00
committed by GitHub
parent 97684b7215
commit ddae3586d5
7 changed files with 97 additions and 6 deletions

View File

@@ -145,7 +145,7 @@ fn annotate_imports<'a>(
annotated
}
fn normalize_imports(imports: Vec<AnnotatedImport>) -> ImportBlock {
fn normalize_imports(imports: Vec<AnnotatedImport>, combine_as_imports: bool) -> ImportBlock {
let mut block = ImportBlock::default();
for import in imports {
match import {
@@ -191,7 +191,7 @@ fn normalize_imports(imports: Vec<AnnotatedImport>) -> ImportBlock {
} => {
// Associate the comments with the first alias (best effort).
if let Some(alias) = names.first() {
if alias.asname.is_none() {
if alias.asname.is_none() || combine_as_imports {
let entry = &mut block
.import_from
.entry(ImportFromData { module, level })
@@ -225,7 +225,7 @@ fn normalize_imports(imports: Vec<AnnotatedImport>) -> ImportBlock {
// Create an entry for every alias.
for alias in names {
if alias.asname.is_none() {
if alias.asname.is_none() || combine_as_imports {
let entry = block
.import_from
.entry(ImportFromData { module, level })
@@ -397,6 +397,7 @@ fn sort_imports(block: ImportBlock) -> OrderedImportBlock {
ordered
}
#[allow(clippy::too_many_arguments)]
pub fn format_imports(
block: &[&Stmt],
comments: Vec<Comment>,
@@ -405,11 +406,12 @@ pub fn format_imports(
known_first_party: &BTreeSet<String>,
known_third_party: &BTreeSet<String>,
extra_standard_library: &BTreeSet<String>,
combine_as_imports: bool,
) -> String {
let block = annotate_imports(block, comments);
// Normalize imports (i.e., deduplicate, aggregate `from` imports).
let block = normalize_imports(block);
let block = normalize_imports(block, combine_as_imports);
// Categorize by type (e.g., first-party vs. third-party).
let block_by_type = categorize_imports(
@@ -466,9 +468,10 @@ mod tests {
use crate::checks::CheckCode;
use crate::linter::test_path;
use crate::Settings;
use crate::{isort, Settings};
#[test_case(Path::new("add_newline_before_comments.py"))]
#[test_case(Path::new("combine_as_imports.py"))]
#[test_case(Path::new("combine_import_froms.py"))]
#[test_case(Path::new("comments.py"))]
#[test_case(Path::new("deduplicate_imports.py"))]
@@ -490,7 +493,7 @@ mod tests {
#[test_case(Path::new("sort_similar_imports.py"))]
#[test_case(Path::new("trailing_suffix.py"))]
#[test_case(Path::new("type_comments.py"))]
fn isort(path: &Path) -> Result<()> {
fn default(path: &Path) -> Result<()> {
let snapshot = format!("{}", path.to_string_lossy());
let mut checks = test_path(
Path::new("./resources/test/fixtures/isort")
@@ -506,4 +509,26 @@ mod tests {
insta::assert_yaml_snapshot!(snapshot, checks);
Ok(())
}
#[test_case(Path::new("combine_as_imports.py"))]
fn combine_as_imports(path: &Path) -> Result<()> {
let snapshot = format!("combine_as_imports_{}", path.to_string_lossy());
let mut checks = test_path(
Path::new("./resources/test/fixtures/isort")
.join(path)
.as_path(),
&Settings {
isort: isort::settings::Settings {
combine_as_imports: true,
..isort::settings::Settings::default()
},
src: vec![Path::new("resources/test/fixtures/isort").to_path_buf()],
..Settings::for_rule(CheckCode::I001)
},
true,
)?;
checks.sort_by_key(|check| check.location);
insta::assert_yaml_snapshot!(snapshot, checks);
Ok(())
}
}

View File

@@ -60,6 +60,7 @@ pub fn check_imports(
&settings.isort.known_first_party,
&settings.isort.known_third_party,
&settings.isort.extra_standard_library,
settings.isort.combine_as_imports,
);
if has_leading_content || has_trailing_content {

View File

@@ -7,6 +7,7 @@ use serde::{Deserialize, Serialize};
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Default)]
#[serde(deny_unknown_fields, rename_all = "kebab-case")]
pub struct Options {
pub combine_as_imports: Option<bool>,
pub known_first_party: Option<Vec<String>>,
pub known_third_party: Option<Vec<String>>,
pub extra_standard_library: Option<Vec<String>>,
@@ -14,6 +15,7 @@ pub struct Options {
#[derive(Debug, Hash, Default)]
pub struct Settings {
pub combine_as_imports: bool,
pub known_first_party: BTreeSet<String>,
pub known_third_party: BTreeSet<String>,
pub extra_standard_library: BTreeSet<String>,
@@ -22,6 +24,7 @@ pub struct Settings {
impl Settings {
pub fn from_options(options: Options) -> Self {
Self {
combine_as_imports: options.combine_as_imports.unwrap_or_default(),
known_first_party: BTreeSet::from_iter(options.known_first_party.unwrap_or_default()),
known_third_party: BTreeSet::from_iter(options.known_third_party.unwrap_or_default()),
extra_standard_library: BTreeSet::from_iter(

View File

@@ -0,0 +1,20 @@
---
source: src/isort/mod.rs
expression: checks
---
- kind: UnsortedImports
location:
row: 1
column: 0
end_location:
row: 5
column: 0
fix:
content: "from module import CONSTANT, function\nfrom module import Class as C\nfrom module import function as f\n"
location:
row: 1
column: 0
end_location:
row: 5
column: 0

View File

@@ -0,0 +1,20 @@
---
source: src/isort/mod.rs
expression: checks
---
- kind: UnsortedImports
location:
row: 1
column: 0
end_location:
row: 5
column: 0
fix:
content: "from module import CONSTANT, Class as C, function, function as f\n"
location:
row: 1
column: 0
end_location:
row: 5
column: 0