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 68bf5e812a66eb..656ca27768fdff 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 @@ 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 43376564abd0b5..879fe9aeffb033 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 @@ ( # 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 03d674635c688e..afb90b6ce692ce 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,16 @@ 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 - // a dot-delimited segment, as in: - // ```python - // import foo\ - // .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) + // The backslashes are line continuations + 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 1118a8378f574e..336ee1db4fd2b1 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 6b3942ea0c9ea5..af7f8e1fa0e0e7 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 ```