From b4c47e95b5558b0b0f2952076661f3438e5bf997 Mon Sep 17 00:00:00 2001 From: Etienne Wodey Date: Tue, 3 Jun 2025 12:50:07 +0200 Subject: [PATCH 1/2] Use similar-asserts for formatting tests. --- Cargo.lock | 121 ++++++++++++++++++ common/Cargo.toml | 5 +- common/src/tests/array_tests.rs | 2 +- common/src/tests/pep508_tests.rs | 6 +- pyproject-fmt/Cargo.toml | 5 +- .../rust/src/tests/build_systems_tests.rs | 2 +- .../rust/src/tests/dependency_groups_tests.rs | 2 +- pyproject-fmt/rust/src/tests/global_tests.rs | 2 +- pyproject-fmt/rust/src/tests/main_tests.rs | 12 +- pyproject-fmt/rust/src/tests/project_tests.rs | 2 +- pyproject-fmt/rust/src/tests/ruff_tests.rs | 5 +- tox-toml-fmt/Cargo.toml | 5 +- tox-toml-fmt/rust/src/tests/global_tests.rs | 2 +- tox-toml-fmt/rust/src/tests/main_tests.rs | 8 +- 14 files changed, 152 insertions(+), 27 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 47596cd..bcdf95b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -61,6 +61,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "234113d19d0d7d613b40e86fb654acf958910802bcceab913a4f9e7cda03b1a4" dependencies = [ "memchr", + "regex-automata", "serde", ] @@ -77,9 +78,22 @@ dependencies = [ "indoc", "pep508_rs", "rstest", + "similar-asserts", "taplo", ] +[[package]] +name = "console" +version = "0.15.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "054ccb5b10f9f2cbf51eb355ca1d05c2d279ce1804688d0db74b4733a5aeafd8" +dependencies = [ + "encode_unicode", + "libc", + "once_cell", + "windows-sys", +] + [[package]] name = "countme" version = "3.0.1" @@ -112,6 +126,12 @@ version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" +[[package]] +name = "encode_unicode" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" + [[package]] name = "equivalent" version = "1.0.2" @@ -596,6 +616,7 @@ dependencies = [ "pyo3", "regex", "rstest", + "similar-asserts", ] [[package]] @@ -755,6 +776,26 @@ dependencies = [ "serde", ] +[[package]] +name = "similar" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa" +dependencies = [ + "bstr", + "unicode-segmentation", +] + +[[package]] +name = "similar-asserts" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b441962c817e33508847a22bd82f03a30cff43642dc2fae8b050566121eb9a" +dependencies = [ + "console", + "similar", +] + [[package]] name = "slab" version = "0.4.9" @@ -930,6 +971,7 @@ dependencies = [ "pyo3", "regex", "rstest", + "similar-asserts", ] [[package]] @@ -969,6 +1011,12 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" +[[package]] +name = "unicode-segmentation" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" + [[package]] name = "unicode-width" version = "0.2.0" @@ -1025,6 +1073,79 @@ dependencies = [ "wit-bindgen-rt", ] +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + [[package]] name = "winnow" version = "0.7.10" diff --git a/common/Cargo.toml b/common/Cargo.toml index 8c3042a..6b3d0bb 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -12,5 +12,6 @@ taplo = { version = "0.13.2" } # formatter pep508_rs = { version = "0.8.1" } [dev-dependencies] -rstest = { version = "0.25.0" } # parametrized tests -indoc = { version = "2.0.6" } # dedented test cases for literal strings +rstest = { version = "0.25.0" } # parametrized tests +indoc = { version = "2.0.6" } # dedented test cases for literal strings +similar-asserts = { version = "1.7.0" } # diff-based assertions diff --git a/common/src/tests/array_tests.rs b/common/src/tests/array_tests.rs index cd85683..17e8cd9 100644 --- a/common/src/tests/array_tests.rs +++ b/common/src/tests/array_tests.rs @@ -71,7 +71,7 @@ fn test_normalize_requirement(#[case] start: &str, #[case] expected: &str, #[cas } } let res = format_syntax(root_ast, Options::default()); - assert_eq!(expected, res); + similar_asserts::assert_eq!(expected: expected, actual: res); } #[rstest] diff --git a/common/src/tests/pep508_tests.rs b/common/src/tests/pep508_tests.rs index b3fc455..236f402 100644 --- a/common/src/tests/pep508_tests.rs +++ b/common/src/tests/pep508_tests.rs @@ -6,7 +6,7 @@ use crate::pep508::{format_requirement, get_canonic_requirement_name}; #[case::lowercase("A", "a")] #[case::replace_dot_with_dash("a.b", "a-b")] fn test_get_canonic_requirement_name(#[case] start: &str, #[case] expected: &str) { - assert_eq!(get_canonic_requirement_name(start), expected); + assert_eq!(expected, get_canonic_requirement_name(start)); } #[rstest] #[case::strip_version( @@ -27,7 +27,7 @@ true )] fn test_format_requirement(#[case] start: &str, #[case] expected: &str, #[case] keep_full_version: bool) { let got = format_requirement(start, keep_full_version); - assert_eq!(got, expected); + similar_asserts::assert_eq!(expected: expected, actual: got); // formatting remains stable - assert_eq!(format_requirement(got.as_str(), keep_full_version), expected); + similar_asserts::assert_eq!(expected: expected, actual: format_requirement(got.as_str(), keep_full_version)); } diff --git a/pyproject-fmt/Cargo.toml b/pyproject-fmt/Cargo.toml index 7e9ca7e..de548c5 100644 --- a/pyproject-fmt/Cargo.toml +++ b/pyproject-fmt/Cargo.toml @@ -23,5 +23,6 @@ extension-module = ["pyo3/extension-module"] default = ["extension-module"] [dev-dependencies] -rstest = { version = "0.25.0" } # parametrized tests -indoc = { version = "2.0.6" } # dedented test cases for literal strings +rstest = { version = "0.25.0" } # parametrized tests +indoc = { version = "2.0.6" } # dedented test cases for literal strings +similar-asserts = { version = "1.7.0" } # diff-based assertions diff --git a/pyproject-fmt/rust/src/tests/build_systems_tests.rs b/pyproject-fmt/rust/src/tests/build_systems_tests.rs index 3ab6750..588bd85 100644 --- a/pyproject-fmt/rust/src/tests/build_systems_tests.rs +++ b/pyproject-fmt/rust/src/tests/build_systems_tests.rs @@ -86,5 +86,5 @@ fn evaluate(start: &str, keep_full_version: bool) -> String { false )] fn test_format_build_systems(#[case] start: &str, #[case] expected: &str, #[case] keep_full_version: bool) { - assert_eq!(evaluate(start, keep_full_version), expected); + similar_asserts::assert_eq!(expected: expected, actual: evaluate(start, keep_full_version)); } diff --git a/pyproject-fmt/rust/src/tests/dependency_groups_tests.rs b/pyproject-fmt/rust/src/tests/dependency_groups_tests.rs index 3bb7c46..9843d5f 100644 --- a/pyproject-fmt/rust/src/tests/dependency_groups_tests.rs +++ b/pyproject-fmt/rust/src/tests/dependency_groups_tests.rs @@ -139,5 +139,5 @@ fn evaluate(start: &str, keep_full_version: bool) -> String { false, )] fn test_format_dependency_groups(#[case] start: &str, #[case] expected: &str, #[case] keep_full_version: bool) { - assert_eq!(evaluate(start, keep_full_version), expected); + similar_asserts::assert_eq!(evaluate(start, keep_full_version), expected); } diff --git a/pyproject-fmt/rust/src/tests/global_tests.rs b/pyproject-fmt/rust/src/tests/global_tests.rs index 4a8ee6c..16f5f6f 100644 --- a/pyproject-fmt/rust/src/tests/global_tests.rs +++ b/pyproject-fmt/rust/src/tests/global_tests.rs @@ -108,5 +108,5 @@ fn test_reorder_table(#[case] start: &str, #[case] expected: &str) { ..Options::default() }; let got = format_syntax(root_ast, opt); - assert_eq!(got, expected); + similar_asserts::assert_eq!(expected: expected, actual: got); } diff --git a/pyproject-fmt/rust/src/tests/main_tests.rs b/pyproject-fmt/rust/src/tests/main_tests.rs index 5e89b55..b93b607 100644 --- a/pyproject-fmt/rust/src/tests/main_tests.rs +++ b/pyproject-fmt/rust/src/tests/main_tests.rs @@ -192,9 +192,9 @@ fn test_format_toml( min_supported_python: (3, 9), }; let got = format_toml(start, &settings); - assert_eq!(got, expected); + similar_asserts::assert_eq!(expected: expected, actual: got); let second = format_toml(got.as_str(), &settings); - assert_eq!(second, got); + similar_asserts::assert_eq!(expected: got, actual: second); } #[fixture] @@ -217,9 +217,9 @@ fn test_issue_24(data: PathBuf) { }; let got = format_toml(start.as_str(), &settings); let expected = read_to_string(data.join("ruff-order.expected.toml")).unwrap(); - assert_eq!(got, expected); + similar_asserts::assert_eq!(expected: expected, actual: got); let second = format_toml(got.as_str(), &settings); - assert_eq!(second, got); + similar_asserts::assert_eq!(expected: got, actual: second); } /// Test that the column width is respected, @@ -260,7 +260,7 @@ fn test_column_width() { "e>=1.5", ] "#}; - assert_eq!(got, expected); + similar_asserts::assert_eq!(expected: expected, actual: got); let second = format_toml(got.as_str(), &settings); - assert_eq!(second, got); + similar_asserts::assert_eq!(expected: got, actual: second); } diff --git a/pyproject-fmt/rust/src/tests/project_tests.rs b/pyproject-fmt/rust/src/tests/project_tests.rs index fb9f254..70c851c 100644 --- a/pyproject-fmt/rust/src/tests/project_tests.rs +++ b/pyproject-fmt/rust/src/tests/project_tests.rs @@ -516,5 +516,5 @@ fn test_format_project( #[case] keep_full_version: bool, #[case] max_supported_python: (u8, u8), ) { - assert_eq!(evaluate(start, keep_full_version, max_supported_python), expected); + similar_asserts::assert_eq!(evaluate(start, keep_full_version, max_supported_python), expected); } diff --git a/pyproject-fmt/rust/src/tests/ruff_tests.rs b/pyproject-fmt/rust/src/tests/ruff_tests.rs index 48e3587..0f474d1 100644 --- a/pyproject-fmt/rust/src/tests/ruff_tests.rs +++ b/pyproject-fmt/rust/src/tests/ruff_tests.rs @@ -39,7 +39,8 @@ fn test_order_ruff(data: PathBuf) { let start = read_to_string(data.join("ruff-order.start.toml")).unwrap(); let got = evaluate(start.as_str()); let expected = read_to_string(data.join("ruff-order.expected.toml")).unwrap(); - assert_eq!(got, expected); + + similar_asserts::assert_eq!(expected: expected, actual: got); } #[rstest] @@ -47,5 +48,5 @@ fn test_ruff_comment_21(data: PathBuf) { let start = read_to_string(data.join("ruff-21.start.toml")).unwrap(); let got = evaluate(start.as_str()); let expected = read_to_string(data.join("ruff-21.expected.toml")).unwrap(); - assert_eq!(got, expected); + similar_asserts::assert_eq!(expected: expected, actual: got); } diff --git a/tox-toml-fmt/Cargo.toml b/tox-toml-fmt/Cargo.toml index 3a8dc68..8564586 100644 --- a/tox-toml-fmt/Cargo.toml +++ b/tox-toml-fmt/Cargo.toml @@ -23,5 +23,6 @@ extension-module = ["pyo3/extension-module"] default = ["extension-module"] [dev-dependencies] -rstest = { version = "0.25.0" } # parametrized tests -indoc = { version = "2.0.6" } # dedented test cases for literal strings +rstest = { version = "0.25.0" } # parametrized tests +indoc = { version = "2.0.6" } # dedented test cases for literal strings +similar-asserts = { version = "1.7.0" } # diff-based assertions diff --git a/tox-toml-fmt/rust/src/tests/global_tests.rs b/tox-toml-fmt/rust/src/tests/global_tests.rs index 5c2c84a..47036ef 100644 --- a/tox-toml-fmt/rust/src/tests/global_tests.rs +++ b/tox-toml-fmt/rust/src/tests/global_tests.rs @@ -51,5 +51,5 @@ fn test_reorder_table(#[case] start: &str, #[case] expected: &str) { ..Options::default() }; let got = format_syntax(root_ast, opt); - assert_eq!(got, expected); + similar_asserts::assert_eq!(expected: expected, actual: got); } diff --git a/tox-toml-fmt/rust/src/tests/main_tests.rs b/tox-toml-fmt/rust/src/tests/main_tests.rs index ed0092f..3174a94 100644 --- a/tox-toml-fmt/rust/src/tests/main_tests.rs +++ b/tox-toml-fmt/rust/src/tests/main_tests.rs @@ -44,9 +44,9 @@ fn test_format_toml(#[case] start: &str, #[case] expected: &str, #[case] indent: indent, }; let got = format_toml(start, &settings); - assert_eq!(got, expected); + similar_asserts::assert_eq!(expected: expected, actual: got); let second = format_toml(got.as_str(), &settings); - assert_eq!(second, got); + similar_asserts::assert_eq!(expected: got, actual: second); } /// Test that the column width is respected, @@ -78,7 +78,7 @@ fn test_column_width() { "pkg_meta", ] "#}; - assert_eq!(got, expected); + similar_asserts::assert_eq!(expected: expected, actual: got); let second = format_toml(got.as_str(), &settings); - assert_eq!(second, got); + similar_asserts::assert_eq!(expected: got, actual: second); } From 06db3b6559b838cc098194545e3ac8d2e1c055a5 Mon Sep 17 00:00:00 2001 From: Etienne Wodey Date: Tue, 3 Jun 2025 14:45:56 +0200 Subject: [PATCH 2/2] pyproject-fmt: preserve string type for Ruff regex fields --- common/src/array.rs | 4 +- common/src/create.rs | 23 +++++++--- common/src/string.rs | 36 +++++++++++++-- .../rust/src/data/ruff-order.expected.toml | 4 +- pyproject-fmt/rust/src/dependency_groups.rs | 4 +- pyproject-fmt/rust/src/project.rs | 44 +++++++++++-------- pyproject-fmt/rust/src/ruff.rs | 9 ++-- pyproject-fmt/rust/src/tests/ruff_tests.rs | 38 ++++++++++++++++ 8 files changed, 126 insertions(+), 36 deletions(-) diff --git a/common/src/array.rs b/common/src/array.rs index acfa502..0712287 100644 --- a/common/src/array.rs +++ b/common/src/array.rs @@ -6,7 +6,7 @@ use taplo::syntax::SyntaxKind::{ARRAY, COMMA, NEWLINE, STRING, VALUE, WHITESPACE use taplo::syntax::{SyntaxElement, SyntaxKind, SyntaxNode}; use crate::create::{make_comma, make_newline}; -use crate::string::{load_text, update_content}; +use crate::string::{load_text, update_content, StringUpdateMode}; use crate::util::{find_first, iter}; pub fn transform(node: &SyntaxNode, transform: &F) @@ -14,7 +14,7 @@ where F: Fn(&str) -> String, { iter(node, [ARRAY, VALUE].as_ref(), &|array_entry| { - update_content(array_entry, transform); + update_content(array_entry, transform, StringUpdateMode::ConvertToString); }); } diff --git a/common/src/create.rs b/common/src/create.rs index 7edb24e..af37a4e 100644 --- a/common/src/create.rs +++ b/common/src/create.rs @@ -1,10 +1,19 @@ use taplo::parser::parse; use taplo::syntax::SyntaxElement; -use taplo::syntax::SyntaxKind::{ARRAY, COMMA, ENTRY, KEY, NEWLINE, STRING, VALUE}; +use taplo::syntax::SyntaxKind::{ + ARRAY, COMMA, ENTRY, KEY, MULTI_LINE_STRING, MULTI_LINE_STRING_LITERAL, NEWLINE, STRING, STRING_LITERAL, VALUE, +}; -pub fn make_string_node(text: &str) -> SyntaxElement { - let expr = &format!("a = \"{}\"", text.replace('"', "\\\"")); - for root in parse(expr) +use crate::string::StringType; + +pub fn make_string_node(text: &str, target_type: StringType) -> SyntaxElement { + let expr = match target_type { + StringType::String => format!("a = \"{}\"", text.replace('"', "\\\"")), + StringType::Multiline => format!("a = \"\"\"{}\"\"\"", text.replace('"', "\\\"")), + StringType::Literal => format!("a = '{}'", text), + StringType::MultilineLiteral => format!("a = '''{}'''", text), + }; + for root in parse(&expr) .into_syntax() .clone_for_update() .first_child() @@ -13,7 +22,11 @@ pub fn make_string_node(text: &str) -> SyntaxElement { { if root.kind() == VALUE { for entries in root.as_node().unwrap().children_with_tokens() { - if entries.kind() == STRING { + if (target_type == StringType::String && entries.kind() == STRING) + || (target_type == StringType::Multiline && entries.kind() == MULTI_LINE_STRING) + || (target_type == StringType::Literal && entries.kind() == STRING_LITERAL) + || (target_type == StringType::MultilineLiteral && entries.kind() == MULTI_LINE_STRING_LITERAL) + { return entries; } } diff --git a/common/src/string.rs b/common/src/string.rs index ed722b2..74326e6 100644 --- a/common/src/string.rs +++ b/common/src/string.rs @@ -25,7 +25,24 @@ pub fn load_text(value: &str, kind: SyntaxKind) -> String { res } -pub fn update_content(entry: &SyntaxNode, transform: F) +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum StringUpdateMode { + /// Preserve the string type. + PreserveType, + + /// Convert to a simple string (non-literal, non-multiline). + ConvertToString, +} + +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum StringType { + String, + Literal, + Multiline, + MultilineLiteral, +} + +pub fn update_content(entry: &SyntaxNode, transform: F, mode: StringUpdateMode) where F: Fn(&str) -> String, { @@ -38,9 +55,22 @@ where let found_str_value = load_text(child.as_token().unwrap().text(), kind); let output = transform(found_str_value.as_str()); - changed = output != found_str_value || kind != STRING; + changed = output != found_str_value || (mode == StringUpdateMode::ConvertToString && kind != STRING); if changed { - child = make_string_node(output.as_str()); + let literal = [STRING_LITERAL, MULTI_LINE_STRING_LITERAL].contains(&kind); + let multiline = [MULTI_LINE_STRING, MULTI_LINE_STRING_LITERAL].contains(&kind); + + let target_type = match mode { + StringUpdateMode::ConvertToString => StringType::String, + StringUpdateMode::PreserveType => match (literal, multiline) { + (false, false) => StringType::String, + (true, false) => StringType::Literal, + (false, true) => StringType::Multiline, + (true, true) => StringType::MultilineLiteral, + }, + }; + + child = make_string_node(output.as_str(), target_type); } } to_insert.push(child); diff --git a/pyproject-fmt/rust/src/data/ruff-order.expected.toml b/pyproject-fmt/rust/src/data/ruff-order.expected.toml index 666a0f7..cede7bb 100644 --- a/pyproject-fmt/rust/src/data/ruff-order.expected.toml +++ b/pyproject-fmt/rust/src/data/ruff-order.expected.toml @@ -118,7 +118,7 @@ lint.allowed-confusables = [ "∗", "ρ", ] -lint.dummy-variable-rgx = "^_$" +lint.dummy-variable-rgx = '^_$' lint.external = [ "ALPHA", "Bar", @@ -146,7 +146,7 @@ lint.flake8-builtins.builtins-ignorelist = [ ] lint.flake8-comprehensions.allow-dict-calls-with-keyword-arguments = true lint.flake8-copyright.author = "Ruff" -lint.flake8-copyright.notice-rgx = "(?i)Copyright \\(C\\) \\d{4}" +lint.flake8-copyright.notice-rgx = '(?i)Copyright \\(C\\) \\d{4}' lint.flake8-errmsg.max-string-length = 20 lint.flake8-gettext.extend-function-names = [ "ALPHA", diff --git a/pyproject-fmt/rust/src/dependency_groups.rs b/pyproject-fmt/rust/src/dependency_groups.rs index c757aac..1c845e9 100644 --- a/pyproject-fmt/rust/src/dependency_groups.rs +++ b/pyproject-fmt/rust/src/dependency_groups.rs @@ -1,6 +1,6 @@ use common::array::{sort, transform}; use common::pep508::{format_requirement, get_canonic_requirement_name}; -use common::string::{load_text, update_content}; +use common::string::{load_text, update_content, StringUpdateMode}; use common::table::{collapse_sub_tables, find_key, for_entries, reorder_table_keys, Tables}; use common::taplo::syntax::SyntaxKind::{ARRAY, ENTRY, INLINE_TABLE, STRING, VALUE}; use common::util::iter; @@ -21,7 +21,7 @@ pub fn fix(tables: &mut Tables, keep_full_version: bool) { // update inline table values to double-quoted string, e.g. include-group iter(entry, [ARRAY, VALUE, INLINE_TABLE, ENTRY, VALUE].as_ref(), &|node| { - update_content(node, |s| String::from(s)); + update_content(node, |s| String::from(s), StringUpdateMode::ConvertToString); }); // sort array elements diff --git a/pyproject-fmt/rust/src/project.rs b/pyproject-fmt/rust/src/project.rs index aef08a9..cef3ee9 100644 --- a/pyproject-fmt/rust/src/project.rs +++ b/pyproject-fmt/rust/src/project.rs @@ -1,7 +1,7 @@ use common::array::{sort, sort_strings, transform}; use common::create::{make_array, make_array_entry, make_comma, make_entry_of_string, make_newline}; use common::pep508::{format_requirement, get_canonic_requirement_name}; -use common::string::{load_text, update_content}; +use common::string::{load_text, update_content, StringUpdateMode}; use common::table::{collapse_sub_tables, for_entries, reorder_table_keys, Tables}; use common::taplo::syntax::SyntaxKind::{ ARRAY, BRACKET_END, BRACKET_START, COMMA, ENTRY, IDENT, INLINE_TABLE, KEY, NEWLINE, STRING, VALUE, @@ -29,29 +29,37 @@ pub fn fix( expand_entry_points_inline_tables(table); for_entries(table, &mut |key, entry| match key.split('.').next().unwrap() { "name" => { - update_content(entry, get_canonic_requirement_name); + update_content(entry, get_canonic_requirement_name, StringUpdateMode::ConvertToString); } "version" | "readme" | "license-files" | "scripts" | "entry-points" | "gui-scripts" => { - update_content(entry, |s| String::from(s)); + update_content(entry, |s| String::from(s), StringUpdateMode::ConvertToString); } "description" => { - update_content(entry, |s| { - s.trim() - .lines() - .map(|part| { - part.trim() - .split(char::is_whitespace) - .filter(|part| !part.trim().is_empty()) - .collect::>() - .join(" ") - .replace(" .", ".") - }) - .collect::>() - .join(" ") - }); + update_content( + entry, + |s| { + s.trim() + .lines() + .map(|part| { + part.trim() + .split(char::is_whitespace) + .filter(|part| !part.trim().is_empty()) + .collect::>() + .join(" ") + .replace(" .", ".") + }) + .collect::>() + .join(" ") + }, + StringUpdateMode::ConvertToString, + ); } "requires-python" => { - update_content(entry, |s| s.split_whitespace().collect()); + update_content( + entry, + |s| s.split_whitespace().collect(), + StringUpdateMode::ConvertToString, + ); } "dependencies" | "optional-dependencies" => { transform(entry, &|s| format_requirement(s, keep_full_version)); diff --git a/pyproject-fmt/rust/src/ruff.rs b/pyproject-fmt/rust/src/ruff.rs index 8f35c8d..61009ca 100644 --- a/pyproject-fmt/rust/src/ruff.rs +++ b/pyproject-fmt/rust/src/ruff.rs @@ -1,5 +1,5 @@ use common::array::{sort_strings, transform}; -use common::string::update_content; +use common::string::{update_content, StringUpdateMode}; use common::table::{collapse_sub_tables, for_entries, reorder_table_keys, Tables}; use lexical_sort::natural_lexical_cmp; @@ -20,9 +20,7 @@ pub fn fix(tables: &mut Tables) { | "format.indent-style" | "format.line-ending" | "format.quote-style" - | "lint.dummy-variable-rgx" | "lint.flake8-copyright.author" - | "lint.flake8-copyright.notice-rgx" | "lint.flake8-pytest-style.parametrize-names-type" | "lint.flake8-pytest-style.parametrize-values-row-type" | "lint.flake8-pytest-style.parametrize-values-type" @@ -34,7 +32,10 @@ pub fn fix(tables: &mut Tables) { | "lint.isort.known-third-party" | "lint.isort.relative-imports-order" | "lint.pydocstyle.convention" => { - update_content(entry, |s| String::from(s)); + update_content(entry, |s| String::from(s), StringUpdateMode::ConvertToString); + } + "lint.dummy-variable-rgx" | "lint.flake8-copyright.notice-rgx" => { + update_content(entry, |s| String::from(s), StringUpdateMode::PreserveType); } "exclude" | "extend-exclude" diff --git a/pyproject-fmt/rust/src/tests/ruff_tests.rs b/pyproject-fmt/rust/src/tests/ruff_tests.rs index 0f474d1..430f68b 100644 --- a/pyproject-fmt/rust/src/tests/ruff_tests.rs +++ b/pyproject-fmt/rust/src/tests/ruff_tests.rs @@ -4,6 +4,7 @@ use std::path::{Path, PathBuf}; use common::taplo::formatter::{format_syntax, Options}; use common::taplo::parser::parse; use common::taplo::syntax::SyntaxElement; +use indoc::indoc; use rstest::{fixture, rstest}; use crate::ruff::fix; @@ -50,3 +51,40 @@ fn test_ruff_comment_21(data: PathBuf) { let expected = read_to_string(data.join("ruff-21.expected.toml")).unwrap(); similar_asserts::assert_eq!(expected: expected, actual: got); } + +#[rstest] +#[case::string( + indoc! {r#" + [tool.ruff] + lint.flake8-copyright.notice-rgx = "Copyright author year" + "#}, +)] +#[case::string_literal( + // https://github.com/tox-dev/toml-fmt/issues/22 + indoc! {r#" + [tool.ruff] + lint.flake8-copyright.notice-rgx = 'SPDX-License-Identifier: MPL-2\.0' + "#}, +)] +#[case::multi_line_string( + indoc! {r#" + [tool.ruff] + lint.flake8-copyright.notice-rgx = """ + Copyright author year + Some more terms + """ + "#}, +)] +#[case::multi_line_string_literal( + indoc! {r#" + [tool.ruff] + lint.flake8-copyright.notice-rgx = ''' + Copyright author year\. + Some more terms\. + ''' + "#}, +)] +fn test_flake8_copyright_notice_preserve_string_type(#[case] start: &str) { + let got = evaluate(start); + similar_asserts::assert_eq!(expected: start, actual: got); +}