From 0f759af3cf5682e5d334150b725426b4545097aa Mon Sep 17 00:00:00 2001 From: konsti Date: Wed, 11 Oct 2023 13:35:41 +0200 Subject: [PATCH] Remove spaces from import statements (#7859) **Summary** Remove spaces from import statements such as ```python import tqdm . tqdm from tqdm . auto import tqdm ``` See also #7760 for a better solution. **Test Plan** New fixtures --- .../test/fixtures/ruff/statement/import.py | 2 ++ .../fixtures/ruff/statement/import_from.py | 2 ++ .../src/other/identifier.rs | 21 +++++++++++++++---- .../format@statement__import.py.snap | 4 ++++ .../format@statement__import_from.py.snap | 4 ++++ 5 files changed, 29 insertions(+), 4 deletions(-) diff --git a/crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/import.py b/crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/import.py index 68bf5e812a..656ca27768 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/import.py +++ b/crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/import.py @@ -9,6 +9,8 @@ import foo\ from foo\ .bar import baz +import tqdm . tqdm + # At the top-level, force one empty line after an import, but allow up to two empty # lines. import os diff --git a/crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/import_from.py b/crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/import_from.py index 43376564ab..879fe9aeff 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/import_from.py +++ b/crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/import_from.py @@ -35,3 +35,5 @@ from a import \ ( # comment bar, ) + +from tqdm . auto import tqdm diff --git a/crates/ruff_python_formatter/src/other/identifier.rs b/crates/ruff_python_formatter/src/other/identifier.rs index 03d674635c..cc62f25947 100644 --- a/crates/ruff_python_formatter/src/other/identifier.rs +++ b/crates/ruff_python_formatter/src/other/identifier.rs @@ -1,5 +1,6 @@ use ruff_formatter::{FormatOwnedWithRule, FormatRefWithRule}; use ruff_python_ast::Identifier; +use ruff_python_trivia::is_python_whitespace; use ruff_text_size::Ranged; use crate::prelude::*; @@ -31,6 +32,7 @@ impl<'ast> IntoFormat> for Identifier { /// A formatter for a dot-delimited identifier, as seen in import statements: /// ```python /// import foo.bar +/// from tqdm . auto import tqdm /// ``` /// /// Dot-delimited identifiers can contain newlines via continuations (backslashes) after the @@ -54,14 +56,25 @@ impl<'a> DotDelimitedIdentifier<'a> { impl Format> for DotDelimitedIdentifier<'_> { fn fmt(&self, f: &mut PyFormatter) -> FormatResult<()> { - // An import identifier can contain newlines by inserting continuations (backslashes) after + // An import identifier can contain whitespace around the dots: + // ```python + // import importlib . metadata + // ``` + // It can also contain newlines by inserting continuations (backslashes) after // a dot-delimited segment, as in: // ```python // import foo\ - // .bar + // .bar // ``` - if memchr::memchr(b'\\', f.context().source()[self.0.range()].as_bytes()).is_some() { - text(self.0.as_str(), Some(self.0.start())).fmt(f) + if f.context().source()[self.0.range()] + .chars() + .any(|c| is_python_whitespace(c) || matches!(c, '\n' | '\r' | '\\')) + { + let no_whitespace: String = f.context().source()[self.0.range()] + .chars() + .filter(|c| !is_python_whitespace(*c) && !matches!(c, '\n' | '\r' | '\\')) + .collect(); + text(&no_whitespace, Some(self.0.start())).fmt(f) } else { source_text_slice(self.0.range()).fmt(f) } diff --git a/crates/ruff_python_formatter/tests/snapshots/format@statement__import.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@statement__import.py.snap index 1118a8378f..336ee1db4f 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@statement__import.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@statement__import.py.snap @@ -15,6 +15,8 @@ import foo\ from foo\ .bar import baz +import tqdm . tqdm + # At the top-level, force one empty line after an import, but allow up to two empty # lines. import os @@ -110,6 +112,8 @@ import foo.bar from foo.bar import baz +import tqdm.tqdm + # At the top-level, force one empty line after an import, but allow up to two empty # lines. import os diff --git a/crates/ruff_python_formatter/tests/snapshots/format@statement__import_from.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@statement__import_from.py.snap index 6b3942ea0c..af7f8e1fa0 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@statement__import_from.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@statement__import_from.py.snap @@ -41,6 +41,8 @@ from a import \ ( # comment bar, ) + +from tqdm . auto import tqdm ``` ## Output @@ -115,6 +117,8 @@ from a import ( from a import ( # comment bar, ) + +from tqdm.auto import tqdm ```