Update to Rust 1.74 and use new clippy lints table (#8722)

Update to [Rust
1.74](https://blog.rust-lang.org/2023/11/16/Rust-1.74.0.html) and use
the new clippy lints table.

The update itself introduced a new clippy lint about superfluous hashes
in raw strings, which got removed.

I moved our lint config from `rustflags` to the newly stabilized
[workspace.lints](https://doc.rust-lang.org/stable/cargo/reference/workspaces.html#the-lints-table).
One consequence is that we have to `unsafe_code = "warn"` instead of
"forbid" because the latter now actually bans unsafe code:

```
error[E0453]: allow(unsafe_code) incompatible with previous forbid
  --> crates/ruff_source_file/src/newlines.rs:62:17
   |
62 |         #[allow(unsafe_code)]
   |                 ^^^^^^^^^^^ overruled by previous forbid
   |
   = note: `forbid` lint level was set on command line
```

---------

Co-authored-by: Charlie Marsh <charlie.r.marsh@gmail.com>
This commit is contained in:
konsti 2023-11-17 00:12:46 +01:00 committed by GitHub
parent 6d5d079a18
commit 14e65afdc6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
71 changed files with 1124 additions and 1054 deletions

View file

@ -1,37 +1,3 @@
[alias]
dev = "run --package ruff_dev --bin ruff_dev"
benchmark = "bench -p ruff_benchmark --bench linter --bench formatter --"
[target.'cfg(all())']
rustflags = [
# CLIPPY LINT SETTINGS
# This is a workaround to configure lints for the entire workspace, pending the ability to configure this via TOML.
# See: `https://github.com/rust-lang/cargo/issues/5034`
# `https://github.com/EmbarkStudios/rust-ecosystem/issues/22#issuecomment-947011395`
"-Dunsafe_code",
"-Wclippy::pedantic",
# Allowed pedantic lints
"-Wclippy::char_lit_as_u8",
"-Aclippy::collapsible_else_if",
"-Aclippy::collapsible_if",
"-Aclippy::implicit_hasher",
"-Aclippy::match_same_arms",
"-Aclippy::missing_errors_doc",
"-Aclippy::missing_panics_doc",
"-Aclippy::module_name_repetitions",
"-Aclippy::must_use_candidate",
"-Aclippy::similar_names",
"-Aclippy::too_many_lines",
# Disallowed restriction lints
"-Wclippy::print_stdout",
"-Wclippy::print_stderr",
"-Wclippy::dbg_macro",
"-Wclippy::empty_drop",
"-Wclippy::empty_structs_with_brackets",
"-Wclippy::exit",
"-Wclippy::get_unwrap",
"-Wclippy::rc_buffer",
"-Wclippy::rc_mutex",
"-Wclippy::rest_pat_in_fully_bound_structs",
"-Wunreachable_pub"
]

View file

@ -55,6 +55,38 @@ unicode-width = { version = "0.1.11" }
uuid = { version = "1.5.0", features = ["v4", "fast-rng", "macro-diagnostics", "js"] }
wsl = { version = "0.1.0" }
[workspace.lints.rust]
unsafe_code = "warn"
unreachable_pub = "warn"
[workspace.lints.clippy]
pedantic = { level = "warn", priority = -2 }
# Allowed pedantic lints
char_lit_as_u8 = "allow"
collapsible_else_if = "allow"
collapsible_if = "allow"
implicit_hasher = "allow"
match_same_arms = "allow"
missing_errors_doc = "allow"
missing_panics_doc = "allow"
module_name_repetitions = "allow"
must_use_candidate = "allow"
similar_names = "allow"
too_many_lines = "allow"
# To allow `#[allow(clippy::all)]` in `crates/ruff_python_parser/src/python.rs`.
needless_raw_string_hashes = "allow"
# Disallowed restriction lints
print_stdout = "warn"
print_stderr = "warn"
dbg_macro = "warn"
empty_drop = "warn"
empty_structs_with_brackets = "warn"
exit = "warn"
get_unwrap = "warn"
rc_buffer = "warn"
rc_mutex = "warn"
rest_pat_in_fully_bound_structs = "warn"
[profile.release]
lto = "fat"
codegen-units = 1

View file

@ -34,3 +34,6 @@ toml = { workspace = true }
[dev-dependencies]
pretty_assertions = "1.3.0"
[lints]
workspace = true

View file

@ -46,6 +46,9 @@ ruff_python_formatter = { path = "../ruff_python_formatter" }
ruff_python_index = { path = "../ruff_python_index" }
ruff_python_parser = { path = "../ruff_python_parser" }
[lints]
workspace = true
[features]
codspeed = ["codspeed-criterion-compat"]

View file

@ -20,3 +20,6 @@ seahash = "4.1.0"
[dev-dependencies]
ruff_macros = { path = "../ruff_macros" }
[lints]
workspace = true

View file

@ -76,3 +76,6 @@ mimalloc = "0.1.39"
[target.'cfg(all(not(target_os = "windows"), not(target_os = "openbsd"), any(target_arch = "x86_64", target_arch = "aarch64", target_arch = "powerpc64")))'.dependencies]
tikv-jemallocator = "0.5.0"
[lints]
workspace = true

View file

@ -202,12 +202,12 @@ fn lint_path(
match result {
Ok(inner) => inner,
Err(error) => {
let message = r#"This indicates a bug in Ruff. If you could open an issue at:
let message = r"This indicates a bug in Ruff. If you could open an issue at:
https://github.com/astral-sh/ruff/issues/new?title=%5BLinter%20panic%5D
...with the relevant file contents, the `pyproject.toml` settings, and the following stack trace, we'd be very appreciative!
"#;
";
error!(
"{}{}{} {message}\n{error}",

View file

@ -660,12 +660,12 @@ impl Display for FormatCommandError {
}
}
Self::Panic(path, err) => {
let message = r#"This indicates a bug in Ruff. If you could open an issue at:
let message = r"This indicates a bug in Ruff. If you could open an issue at:
https://github.com/astral-sh/ruff/issues/new?title=%5BFormatter%20panic%5D
...with the relevant file contents, the `pyproject.toml` settings, and the following stack trace, we'd be very appreciative!
"#;
";
if let Some(path) = path {
write!(
f,

View file

@ -63,7 +63,7 @@ fn format_rule_text(rule: Rule) -> String {
if rule.is_preview() || rule.is_nursery() {
output.push_str(
r#"This rule is in preview and is not stable. The `--preview` flag is required for use."#,
r"This rule is in preview and is not stable. The `--preview` flag is required for use.",
);
output.push('\n');
output.push('\n');

View file

@ -395,9 +395,9 @@ fn deprecated_options() -> Result<()> {
let ruff_toml = tempdir.path().join("ruff.toml");
fs::write(
&ruff_toml,
r#"
r"
tab-size = 2
"#,
",
)?;
insta::with_settings!({filters => vec![
@ -407,10 +407,10 @@ tab-size = 2
.args(["format", "--config"])
.arg(&ruff_toml)
.arg("-")
.pass_stdin(r#"
.pass_stdin(r"
if True:
pass
"#), @r###"
"), @r###"
success: true
exit_code: 0
----- stdout -----
@ -443,9 +443,9 @@ format = "json"
.args(["check", "--select", "F401", "--no-cache", "--config"])
.arg(&ruff_toml)
.arg("-")
.pass_stdin(r#"
.pass_stdin(r"
import os
"#), @r###"
"), @r###"
success: false
exit_code: 2
----- stdout -----

View file

@ -48,9 +48,12 @@ tracing-indicatif = { workspace = true }
tracing-subscriber = { workspace = true, features = ["env-filter"] }
imara-diff = "0.1.5"
[dev-dependencies]
indoc = "2.0.4"
[features]
# Turn off rayon for profiling
singlethreaded = []
[dev-dependencies]
indoc = "2.0.4"
[lints]
workspace = true

View file

@ -49,7 +49,7 @@ pub(crate) fn main(args: &Args) -> Result<()> {
if rule.is_preview() || rule.is_nursery() {
output.push_str(
r#"This rule is unstable and in [preview](../preview.md). The `--preview` flag is required for use."#,
r"This rule is unstable and in [preview](../preview.md). The `--preview` flag is required for use.",
);
output.push('\n');
output.push('\n');

View file

@ -29,3 +29,6 @@ insta = { workspace = true }
[features]
serde = ["dep:serde", "ruff_text_size/serde"]
schemars = ["dep:schemars", "ruff_text_size/schemars"]
[lints]
workspace = true

View file

@ -1711,14 +1711,14 @@ mod tests {
));
assert_eq!(
r#"a
"a
b
c
d
d
c
b
a"#,
a",
formatted.as_code()
);
}
@ -2047,10 +2047,10 @@ two lines`,
assert_eq!(
printed.as_code(),
r#"Group with id-2
"Group with id-2
Group with id-1 does not fit on the line because it exceeds the line width of 80 characters by
Group 2 fits
Group 1 breaks"#
Group 1 breaks"
);
}

View file

@ -17,3 +17,6 @@ ruff_macros = { path = "../ruff_macros" }
[dev-dependencies]
static_assertions = "1.1.0"
[lints]
workspace = true

View file

@ -86,3 +86,6 @@ default = []
schemars = ["dep:schemars"]
# Enables the UnreachableCode rule
unreachable-code = []
[lints]
workspace = true

View file

@ -171,7 +171,7 @@ mod tests {
#[test]
fn empty_file() {
let locator = Locator::new(r#""#);
let locator = Locator::new(r"");
let diagnostics = create_diagnostics([]);
let FixResult {
code,
@ -225,10 +225,10 @@ print("hello world")
#[test]
fn apply_one_replacement() {
let locator = Locator::new(
r#"
r"
class A(object):
...
"#
"
.trim(),
);
let diagnostics = create_diagnostics([Edit::replacement(
@ -243,10 +243,10 @@ class A(object):
} = apply_fixes(diagnostics.iter(), &locator);
assert_eq!(
code,
r#"
r"
class A(Bar):
...
"#
"
.trim(),
);
assert_eq!(fixes.values().sum::<usize>(), 1);
@ -262,10 +262,10 @@ class A(Bar):
#[test]
fn apply_one_removal() {
let locator = Locator::new(
r#"
r"
class A(object):
...
"#
"
.trim(),
);
let diagnostics = create_diagnostics([Edit::deletion(TextSize::new(7), TextSize::new(15))]);
@ -276,10 +276,10 @@ class A(object):
} = apply_fixes(diagnostics.iter(), &locator);
assert_eq!(
code,
r#"
r"
class A:
...
"#
"
.trim()
);
assert_eq!(fixes.values().sum::<usize>(), 1);
@ -295,10 +295,10 @@ class A:
#[test]
fn apply_two_removals() {
let locator = Locator::new(
r#"
r"
class A(object, object, object):
...
"#
"
.trim(),
);
let diagnostics = create_diagnostics([
@ -313,10 +313,10 @@ class A(object, object, object):
assert_eq!(
code,
r#"
r"
class A(object):
...
"#
"
.trim()
);
assert_eq!(fixes.values().sum::<usize>(), 2);
@ -334,10 +334,10 @@ class A(object):
#[test]
fn ignore_overlapping_fixes() {
let locator = Locator::new(
r#"
r"
class A(object):
...
"#
"
.trim(),
);
let diagnostics = create_diagnostics([
@ -351,10 +351,10 @@ class A(object):
} = apply_fixes(diagnostics.iter(), &locator);
assert_eq!(
code,
r#"
r"
class A:
...
"#
"
.trim(),
);
assert_eq!(fixes.values().sum::<usize>(), 1);

View file

@ -373,18 +373,18 @@ mod tests {
Insertion::own_line("", TextSize::from(40), "\n")
);
let contents = r#"
let contents = r"
x = 1
"#
"
.trim_start();
assert_eq!(
insert(contents)?,
Insertion::own_line("", TextSize::from(0), "\n")
);
let contents = r#"
let contents = r"
#!/usr/bin/env python3
"#
"
.trim_start();
assert_eq!(
insert(contents)?,
@ -457,10 +457,10 @@ x = 1
Insertion::inline("", TextSize::from(9), "; ")
);
let contents = r#"
let contents = r"
if True:
pass
"#
"
.trim_start();
assert_eq!(
insert(contents, TextSize::from(0)),

View file

@ -199,7 +199,7 @@ def fibonacci(n):
TextSize::from(99),
)));
let file_2 = r#"if a == 1: pass"#;
let file_2 = r"if a == 1: pass";
let undefined_name = Diagnostic::new(
DiagnosticKind {

View file

@ -12,11 +12,11 @@ mod tests {
#[test]
fn notice() {
let diagnostics = test_snippet(
r#"
r"
# Copyright 2023
import os
"#
"
.trim(),
&settings::LinterSettings::for_rules(vec![Rule::MissingCopyrightNotice]),
);
@ -26,11 +26,11 @@ import os
#[test]
fn notice_with_c() {
let diagnostics = test_snippet(
r#"
r"
# Copyright (C) 2023
import os
"#
"
.trim(),
&settings::LinterSettings::for_rules(vec![Rule::MissingCopyrightNotice]),
);
@ -40,11 +40,11 @@ import os
#[test]
fn notice_with_caps() {
let diagnostics = test_snippet(
r#"
r"
# COPYRIGHT (C) 2023
import os
"#
"
.trim(),
&settings::LinterSettings::for_rules(vec![Rule::MissingCopyrightNotice]),
);
@ -54,11 +54,11 @@ import os
#[test]
fn notice_with_range() {
let diagnostics = test_snippet(
r#"
r"
# Copyright (C) 2021-2023
import os
"#
"
.trim(),
&settings::LinterSettings::for_rules(vec![Rule::MissingCopyrightNotice]),
);
@ -68,11 +68,11 @@ import os
#[test]
fn valid_author() {
let diagnostics = test_snippet(
r#"
r"
# Copyright (C) 2023 Ruff
import os
"#
"
.trim(),
&settings::LinterSettings {
flake8_copyright: super::settings::Settings {
@ -88,11 +88,11 @@ import os
#[test]
fn invalid_author() {
let diagnostics = test_snippet(
r#"
r"
# Copyright (C) 2023 Some Author
import os
"#
"
.trim(),
&settings::LinterSettings {
flake8_copyright: super::settings::Settings {
@ -108,9 +108,9 @@ import os
#[test]
fn small_file() {
let diagnostics = test_snippet(
r#"
r"
import os
"#
"
.trim(),
&settings::LinterSettings {
flake8_copyright: super::settings::Settings {
@ -126,7 +126,7 @@ import os
#[test]
fn late_notice() {
let diagnostics = test_snippet(
r#"
r"
# Content Content Content Content Content Content Content Content Content Content
# Content Content Content Content Content Content Content Content Content Content
# Content Content Content Content Content Content Content Content Content Content
@ -149,7 +149,7 @@ import os
# Content Content Content Content Content Content Content Content Content Content
# Copyright 2023
"#
"
.trim(),
&settings::LinterSettings::for_rules(vec![Rule::MissingCopyrightNotice]),
);
@ -159,8 +159,8 @@ import os
#[test]
fn char_boundary() {
let diagnostics = test_snippet(
r#"কককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককক
"#
r"কককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককককক
"
.trim(),
&settings::LinterSettings::for_rules(vec![Rule::MissingCopyrightNotice]),
);

View file

@ -171,18 +171,18 @@ mod tests {
}
#[test_case(
r#"
r"
from __future__ import annotations
import pandas as pd
def f(x: pd.DataFrame):
pass
"#,
",
"no_typing_import"
)]
#[test_case(
r#"
r"
from __future__ import annotations
from typing import TYPE_CHECKING
@ -191,11 +191,11 @@ mod tests {
def f(x: pd.DataFrame):
pass
"#,
",
"typing_import_before_package_import"
)]
#[test_case(
r#"
r"
from __future__ import annotations
import pandas as pd
@ -204,11 +204,11 @@ mod tests {
def f(x: pd.DataFrame):
pass
"#,
",
"typing_import_after_package_import"
)]
#[test_case(
r#"
r"
from __future__ import annotations
import pandas as pd
@ -217,11 +217,11 @@ mod tests {
pass
from typing import TYPE_CHECKING
"#,
",
"typing_import_after_usage"
)]
#[test_case(
r#"
r"
from __future__ import annotations
from typing import TYPE_CHECKING
@ -233,11 +233,11 @@ mod tests {
def f(x: pd.DataFrame):
pass
"#,
",
"type_checking_block_own_line"
)]
#[test_case(
r#"
r"
from __future__ import annotations
from typing import TYPE_CHECKING
@ -248,11 +248,11 @@ mod tests {
def f(x: pd.DataFrame):
pass
"#,
",
"type_checking_block_inline"
)]
#[test_case(
r#"
r"
from __future__ import annotations
from typing import TYPE_CHECKING
@ -265,11 +265,11 @@ mod tests {
def f(x: pd.DataFrame):
pass
"#,
",
"type_checking_block_comment"
)]
#[test_case(
r#"
r"
from __future__ import annotations
from typing import TYPE_CHECKING
@ -281,11 +281,11 @@ mod tests {
if TYPE_CHECKING:
import os
"#,
",
"type_checking_block_after_usage"
)]
#[test_case(
r#"
r"
from __future__ import annotations
from pandas import (
@ -295,11 +295,11 @@ mod tests {
def f(x: DataFrame):
pass
"#,
",
"import_from"
)]
#[test_case(
r#"
r"
from __future__ import annotations
from typing import TYPE_CHECKING
@ -314,11 +314,11 @@ mod tests {
def f(x: DataFrame):
pass
"#,
",
"import_from_type_checking_block"
)]
#[test_case(
r#"
r"
from __future__ import annotations
from typing import TYPE_CHECKING
@ -330,11 +330,11 @@ mod tests {
def f(x: DataFrame, y: Series):
pass
"#,
",
"multiple_members"
)]
#[test_case(
r#"
r"
from __future__ import annotations
from typing import TYPE_CHECKING
@ -343,11 +343,11 @@ mod tests {
def f(x: os, y: sys):
pass
"#,
",
"multiple_modules_same_type"
)]
#[test_case(
r#"
r"
from __future__ import annotations
from typing import TYPE_CHECKING
@ -356,7 +356,7 @@ mod tests {
def f(x: os, y: pandas):
pass
"#,
",
"multiple_modules_different_types"
)]
fn contents(contents: &str, snapshot: &str) {

View file

@ -166,10 +166,10 @@ mod tests {
#[test]
fn trivial() -> Result<()> {
let source = r#"
let source = r"
def trivial():
pass
"#;
";
let stmts = parse_suite(source, "<filename>")?;
assert_eq!(get_complexity_number(&stmts), 1);
Ok(())
@ -177,10 +177,10 @@ def trivial():
#[test]
fn expr_as_statement() -> Result<()> {
let source = r#"
let source = r"
def expr_as_statement():
0xF00D
"#;
";
let stmts = parse_suite(source, "<filename>")?;
assert_eq!(get_complexity_number(&stmts), 1);
Ok(())
@ -188,12 +188,12 @@ def expr_as_statement():
#[test]
fn sequential() -> Result<()> {
let source = r#"
let source = r"
def sequential(n):
k = n + 4
s = k + n
return s
"#;
";
let stmts = parse_suite(source, "<filename>")?;
assert_eq!(get_complexity_number(&stmts), 1);
Ok(())
@ -234,11 +234,11 @@ def nested_ifs():
#[test]
fn for_loop() -> Result<()> {
let source = r#"
let source = r"
def for_loop():
for i in range(10):
print(i)
"#;
";
let stmts = parse_suite(source, "<filename>")?;
assert_eq!(get_complexity_number(&stmts), 2);
Ok(())
@ -246,13 +246,13 @@ def for_loop():
#[test]
fn for_else() -> Result<()> {
let source = r#"
let source = r"
def for_else(mylist):
for i in mylist:
print(i)
else:
print(None)
"#;
";
let stmts = parse_suite(source, "<filename>")?;
assert_eq!(get_complexity_number(&stmts), 2);
Ok(())
@ -260,13 +260,13 @@ def for_else(mylist):
#[test]
fn recursive() -> Result<()> {
let source = r#"
let source = r"
def recursive(n):
if n > 4:
return f(n - 1)
else:
return n
"#;
";
let stmts = parse_suite(source, "<filename>")?;
assert_eq!(get_complexity_number(&stmts), 2);
Ok(())
@ -274,7 +274,7 @@ def recursive(n):
#[test]
fn nested_functions() -> Result<()> {
let source = r#"
let source = r"
def nested_functions():
def a():
def b():
@ -283,7 +283,7 @@ def nested_functions():
b()
a()
"#;
";
let stmts = parse_suite(source, "<filename>")?;
assert_eq!(get_complexity_number(&stmts), 3);
Ok(())
@ -291,7 +291,7 @@ def nested_functions():
#[test]
fn try_else() -> Result<()> {
let source = r#"
let source = r"
def try_else():
try:
print(1)
@ -301,7 +301,7 @@ def try_else():
print(3)
else:
print(4)
"#;
";
let stmts = parse_suite(source, "<filename>")?;
assert_eq!(get_complexity_number(&stmts), 4);
Ok(())
@ -309,7 +309,7 @@ def try_else():
#[test]
fn nested_try_finally() -> Result<()> {
let source = r#"
let source = r"
def nested_try_finally():
try:
try:
@ -318,7 +318,7 @@ def nested_try_finally():
print(2)
finally:
print(3)
"#;
";
let stmts = parse_suite(source, "<filename>")?;
assert_eq!(get_complexity_number(&stmts), 1);
Ok(())
@ -326,7 +326,7 @@ def nested_try_finally():
#[test]
fn foobar() -> Result<()> {
let source = r#"
let source = r"
async def foobar(a, b, c):
await whatever(a, b, c)
if await b:
@ -335,7 +335,7 @@ async def foobar(a, b, c):
pass
async for x in a:
pass
"#;
";
let stmts = parse_suite(source, "<filename>")?;
assert_eq!(get_complexity_number(&stmts), 3);
Ok(())
@ -343,10 +343,10 @@ async def foobar(a, b, c):
#[test]
fn annotated_assign() -> Result<()> {
let source = r#"
let source = r"
def annotated_assign():
x: Any = None
"#;
";
let stmts = parse_suite(source, "<filename>")?;
assert_eq!(get_complexity_number(&stmts), 1);
Ok(())
@ -354,7 +354,7 @@ def annotated_assign():
#[test]
fn class() -> Result<()> {
let source = r#"
let source = r"
class Class:
def handle(self, *args, **options):
if args:
@ -382,7 +382,7 @@ class Class:
pass
return ServiceProvider(Logger())
"#;
";
let stmts = parse_suite(source, "<filename>")?;
assert_eq!(get_complexity_number(&stmts), 9);
Ok(())
@ -390,13 +390,13 @@ class Class:
#[test]
fn finally() -> Result<()> {
let source = r#"
let source = r"
def process_detect_lines():
try:
pass
finally:
pass
"#;
";
let stmts = parse_suite(source, "<filename>")?;
assert_eq!(get_complexity_number(&stmts), 1);
Ok(())
@ -419,12 +419,12 @@ def process_detect_lines():
#[test]
fn with() -> Result<()> {
let source = r#"
let source = r"
def with_lock():
with lock:
if foo:
print('bar')
"#;
";
let stmts = parse_suite(source, "<filename>")?;
assert_eq!(get_complexity_number(&stmts), 2);
Ok(())

View file

@ -30,17 +30,17 @@ mod tests {
"PD002_fail"
)]
#[test_case(
r#"
r"
import pandas as pd
nas = pd.isna(val)
"#,
",
"PD003_pass"
)]
#[test_case(
r#"
r"
import pandas as pd
nulls = pd.isnull(val)
"#,
",
"PD003_fail"
)]
#[test_case(
@ -51,17 +51,17 @@ mod tests {
"PD003_allows_other_calls"
)]
#[test_case(
r#"
r"
import pandas as pd
not_nas = pd.notna(val)
"#,
",
"PD004_pass"
)]
#[test_case(
r#"
r"
import pandas as pd
not_nulls = pd.notnull(val)
"#,
",
"PD004_fail"
)]
#[test_case(
@ -73,11 +73,11 @@ mod tests {
"PD007_pass_loc"
)]
#[test_case(
r#"
r"
import pandas as pd
x = pd.DataFrame()
new_x = x.iloc[[1, 3, 5], [1, 3]]
"#,
",
"PD007_pass_iloc"
)]
#[test_case(
@ -134,19 +134,19 @@ mod tests {
"PD008_fail"
)]
#[test_case(
r#"
r"
import pandas as pd
x = pd.DataFrame()
index = x.iloc[:, 1:3]
"#,
",
"PD009_pass"
)]
#[test_case(
r#"
r"
import pandas as pd
x = pd.DataFrame()
index = x.iat[:, 1:3]
"#,
",
"PD009_fail"
)]
#[test_case(
@ -178,80 +178,80 @@ mod tests {
"PD010_fail_pivot"
)]
#[test_case(
r#"
r"
import pandas as pd
x = pd.DataFrame()
result = x.to_array()
"#,
",
"PD011_pass_to_array"
)]
#[test_case(
r#"
r"
import pandas as pd
x = pd.DataFrame()
result = x.array
"#,
",
"PD011_pass_array"
)]
#[test_case(
r#"
r"
import pandas as pd
x = pd.DataFrame()
result = x.values
"#,
",
"PD011_fail_values"
)]
#[test_case(
r#"
r"
import pandas as pd
x = pd.DataFrame()
result = x.values()
"#,
",
"PD011_pass_values_call"
)]
#[test_case(
r#"
r"
import pandas as pd
x = pd.DataFrame()
x.values = 1
"#,
",
"PD011_pass_values_store"
)]
#[test_case(
r#"
r"
class Class:
def __init__(self, values: str) -> None:
self.values = values
print(self.values)
"#,
",
"PD011_pass_values_instance"
)]
#[test_case(
r#"
r"
import pandas as pd
result = {}.values
"#,
",
"PD011_pass_values_dict"
)]
#[test_case(
r#"
r"
import pandas as pd
result = pd.values
"#,
",
"PD011_pass_values_import"
)]
#[test_case(
r#"
r"
import pandas as pd
result = x.values
"#,
",
"PD011_pass_values_unbound"
)]
#[test_case(
r#"
r"
import pandas as pd
result = values
"#,
",
"PD011_pass_node_name"
)]
#[test_case(
@ -267,33 +267,33 @@ mod tests {
"PD013_pass"
)]
#[test_case(
r#"
r"
import numpy as np
arrays = [np.random.randn(3, 4) for _ in range(10)]
np.stack(arrays, axis=0).shape
"#,
",
"PD013_pass_numpy"
)]
#[test_case(
r#"
r"
import pandas as pd
y = x.stack(level=-1, dropna=True)
"#,
",
"PD013_pass_unbound"
)]
#[test_case(
r#"
r"
import pandas as pd
x = pd.DataFrame()
y = x.stack(level=-1, dropna=True)
"#,
",
"PD013_fail_stack"
)]
#[test_case(
r#"
r"
import pandas as pd
pd.stack(
"#,
",
"PD015_pass_merge_on_dataframe"
)]
#[test_case(
@ -306,12 +306,12 @@ mod tests {
"PD015_pass_merge_on_dataframe_with_multiple_args"
)]
#[test_case(
r#"
r"
import pandas as pd
x = pd.DataFrame()
y = pd.DataFrame()
pd.merge(x, y)
"#,
",
"PD015_fail_merge_on_pandas_object"
)]
#[test_case(
@ -321,31 +321,31 @@ mod tests {
"PD015_pass_other_pd_function"
)]
#[test_case(
r#"
r"
import pandas as pd
employees = pd.DataFrame(employee_dict)
"#,
",
"PD901_pass_non_df"
)]
#[test_case(
r#"
r"
import pandas as pd
employees_df = pd.DataFrame(employee_dict)
"#,
",
"PD901_pass_part_df"
)]
#[test_case(
r#"
r"
import pandas as pd
my_function(df=data)
"#,
",
"PD901_pass_df_param"
)]
#[test_case(
r#"
r"
import pandas as pd
df = pd.DataFrame()
"#,
",
"PD901_fail_df_var"
)]
fn contents(contents: &str, snapshot: &str) {

View file

@ -518,10 +518,10 @@ mod tests {
#[test]
fn multi_line() {
assert_logical_lines(
r#"
r"
x = 1
y = 2
z = x + 1"#
z = x + 1"
.trim(),
&["x = 1", "y = 2", "z = x + 1"],
);
@ -530,14 +530,14 @@ z = x + 1"#
#[test]
fn indented() {
assert_logical_lines(
r#"
r"
x = [
1,
2,
3,
]
y = 2
z = x + 1"#
z = x + 1"
.trim(),
&["x = [\n 1,\n 2,\n 3,\n]", "y = 2", "z = x + 1"],
);
@ -551,10 +551,10 @@ z = x + 1"#
#[test]
fn function_definition() {
assert_logical_lines(
r#"
r"
def f():
x = 1
f()"#
f()"
.trim(),
&["def f():", "x = 1", "f()"],
);
@ -583,11 +583,11 @@ f()"#
#[test]
fn empty_line() {
assert_logical_lines(
r#"
r"
if False:
print()
"#
"
.trim(),
&["if False:", "print()", ""],
);

View file

@ -44,7 +44,7 @@ impl Violation for TripleSingleQuotes {
let TripleSingleQuotes { expected_quote } = self;
match expected_quote {
Quote::Double => format!(r#"Use triple double quotes `"""`"#),
Quote::Single => format!(r#"Use triple single quotes `'''`"#),
Quote::Single => format!(r"Use triple single quotes `'''`"),
}
}

File diff suppressed because it is too large Load diff

View file

@ -187,7 +187,7 @@ mod tests {
#[test]
fn if_else_nested_if_else() -> Result<()> {
let source: &str = r#"
let source: &str = r"
if x == 0: # 3
return
else:
@ -195,19 +195,19 @@ else:
pass
else:
pass
"#;
";
test_helper(source, 4)?;
Ok(())
}
#[test]
fn for_else() -> Result<()> {
let source: &str = r#"
let source: &str = r"
for _ in range(x): # 2
pass
else:
pass
"#;
";
test_helper(source, 2)?;
Ok(())
@ -215,14 +215,14 @@ else:
#[test]
fn while_if_else_if() -> Result<()> {
let source: &str = r#"
let source: &str = r"
while x < 1: # 4
if x:
pass
else:
if x:
pass
"#;
";
test_helper(source, 4)?;
Ok(())
@ -230,7 +230,7 @@ else:
#[test]
fn nested_def() -> Result<()> {
let source: &str = r#"
let source: &str = r"
if x: # 2
pass
else:
@ -241,7 +241,7 @@ def g(x):
pass
return 1
"#;
";
test_helper(source, 2)?;
Ok(())
@ -249,7 +249,7 @@ return 1
#[test]
fn try_except_except_else_finally() -> Result<()> {
let source: &str = r#"
let source: &str = r"
try:
pass
except:
@ -260,7 +260,7 @@ else:
pass
finally:
pass
"#;
";
test_helper(source, 5)?;
Ok(())

View file

@ -110,7 +110,7 @@ mod tests {
#[test]
fn if_() -> Result<()> {
let source = r#"
let source = r"
x = 1
if x == 1: # 9
return
@ -130,7 +130,7 @@ if x == 8:
return
if x == 9:
return
"#;
";
test_helper(source, 9)?;
Ok(())
@ -138,12 +138,12 @@ if x == 9:
#[test]
fn for_else() -> Result<()> {
let source = r#"
let source = r"
for _i in range(10):
return
else:
return
"#;
";
test_helper(source, 2)?;
Ok(())
@ -151,12 +151,12 @@ else:
#[test]
fn async_for_else() -> Result<()> {
let source = r#"
let source = r"
async for _i in range(10):
return
else:
return
"#;
";
test_helper(source, 2)?;
Ok(())
@ -164,7 +164,7 @@ else:
#[test]
fn nested_def_ignored() -> Result<()> {
let source = r#"
let source = r"
def f():
return
@ -173,7 +173,7 @@ if x == 1:
print()
else:
print()
"#;
";
test_helper(source, 0)?;
Ok(())
@ -181,7 +181,7 @@ else:
#[test]
fn while_nested_if() -> Result<()> {
let source = r#"
let source = r"
x = 1
while x < 10:
print()
@ -189,7 +189,7 @@ while x < 10:
return
x += 1
return
"#;
";
test_helper(source, 2)?;
Ok(())
@ -197,12 +197,12 @@ return
#[test]
fn with_if() -> Result<()> {
let source = r#"
let source = r"
with a as f:
return
if f == 1:
return
"#;
";
test_helper(source, 2)?;
Ok(())
@ -210,12 +210,12 @@ with a as f:
#[test]
fn async_with_if() -> Result<()> {
let source = r#"
let source = r"
async with a as f:
return
if f == 1:
return
"#;
";
test_helper(source, 2)?;
Ok(())
@ -223,7 +223,7 @@ async with a as f:
#[test]
fn try_except_except_else_finally() -> Result<()> {
let source = r#"
let source = r"
try:
print()
return
@ -235,7 +235,7 @@ else:
return
finally:
return
"#;
";
test_helper(source, 5)?;
Ok(())
@ -243,14 +243,14 @@ finally:
#[test]
fn class_def_ignored() -> Result<()> {
let source = r#"
let source = r"
class A:
def f(self):
return
def g(self):
return
"#;
";
test_helper(source, 0)?;
Ok(())

View file

@ -163,10 +163,10 @@ mod tests {
#[test]
fn pass() -> Result<()> {
let source: &str = r#"
let source: &str = r"
def f():
pass
"#;
";
let stmts = parse_suite(source, "<filename>")?;
assert_eq!(num_statements(&stmts), 2);
Ok(())
@ -174,13 +174,13 @@ def f():
#[test]
fn if_else() -> Result<()> {
let source: &str = r#"
let source: &str = r"
def f():
if a:
print()
else:
print()
"#;
";
let stmts = parse_suite(source, "<filename>")?;
assert_eq!(num_statements(&stmts), 5);
Ok(())
@ -188,14 +188,14 @@ def f():
#[test]
fn if_else_if_corner() -> Result<()> {
let source: &str = r#"
let source: &str = r"
def f():
if a:
print()
else:
if a:
print()
"#;
";
let stmts = parse_suite(source, "<filename>")?;
assert_eq!(num_statements(&stmts), 6);
Ok(())
@ -203,13 +203,13 @@ def f():
#[test]
fn if_elif() -> Result<()> {
let source: &str = r#"
let source: &str = r"
def f():
if a:
print()
elif a:
print()
"#;
";
let stmts = parse_suite(source, "<filename>")?;
assert_eq!(num_statements(&stmts), 5);
Ok(())
@ -217,7 +217,7 @@ def f():
#[test]
fn if_elif_else() -> Result<()> {
let source: &str = r#"
let source: &str = r"
def f():
if a:
print()
@ -227,7 +227,7 @@ def f():
print()
else:
print()
"#;
";
let stmts = parse_suite(source, "<filename>")?;
assert_eq!(num_statements(&stmts), 9);
Ok(())
@ -235,7 +235,7 @@ def f():
#[test]
fn many_statements() -> Result<()> {
let source: &str = r#"
let source: &str = r"
async def f():
a = 1
b = 2
@ -256,7 +256,7 @@ async def f():
a -= 1
import time
pass
"#;
";
let stmts = parse_suite(source, "<filename>")?;
assert_eq!(num_statements(&stmts), 19);
Ok(())
@ -264,11 +264,11 @@ async def f():
#[test]
fn for_() -> Result<()> {
let source: &str = r#"
let source: &str = r"
def f():
for i in range(10):
pass
"#;
";
let stmts = parse_suite(source, "<filename>")?;
assert_eq!(num_statements(&stmts), 2);
Ok(())
@ -276,13 +276,13 @@ def f():
#[test]
fn for_else() -> Result<()> {
let source: &str = r#"
let source: &str = r"
def f():
for i in range(10):
print()
else:
print()
"#;
";
let stmts = parse_suite(source, "<filename>")?;
assert_eq!(num_statements(&stmts), 3);
Ok(())
@ -290,14 +290,14 @@ def f():
#[test]
fn nested_def() -> Result<()> {
let source: &str = r#"
let source: &str = r"
def f():
def g():
print()
print()
print()
"#;
";
let stmts = parse_suite(source, "<filename>")?;
assert_eq!(num_statements(&stmts), 5);
Ok(())
@ -305,7 +305,7 @@ def f():
#[test]
fn nested_class() -> Result<()> {
let source: &str = r#"
let source: &str = r"
def f():
class A:
def __init__(self):
@ -315,7 +315,7 @@ def f():
pass
print()
"#;
";
let stmts = parse_suite(source, "<filename>")?;
assert_eq!(num_statements(&stmts), 3);
Ok(())
@ -323,10 +323,10 @@ def f():
#[test]
fn return_not_counted() -> Result<()> {
let source: &str = r#"
let source: &str = r"
def f():
return
"#;
";
let stmts = parse_suite(source, "<filename>")?;
assert_eq!(num_statements(&stmts), 1);
Ok(())
@ -334,7 +334,7 @@ def f():
#[test]
fn with() -> Result<()> {
let source: &str = r#"
let source: &str = r"
def f():
with a:
if a:
@ -342,7 +342,7 @@ def f():
else:
print()
"#;
";
let stmts = parse_suite(source, "<filename>")?;
assert_eq!(num_statements(&stmts), 6);
Ok(())
@ -350,13 +350,13 @@ def f():
#[test]
fn try_except() -> Result<()> {
let source: &str = r#"
let source: &str = r"
def f():
try:
print()
except Exception:
raise
"#;
";
let stmts = parse_suite(source, "<filename>")?;
assert_eq!(num_statements(&stmts), 5);
Ok(())
@ -364,7 +364,7 @@ def f():
#[test]
fn try_except_else() -> Result<()> {
let source: &str = r#"
let source: &str = r"
def f():
try:
print()
@ -372,7 +372,7 @@ def f():
pass
else:
print()
"#;
";
let stmts = parse_suite(source, "<filename>")?;
assert_eq!(num_statements(&stmts), 7);
Ok(())
@ -380,7 +380,7 @@ def f():
#[test]
fn try_except_else_finally() -> Result<()> {
let source: &str = r#"
let source: &str = r"
def f():
try:
print()
@ -390,7 +390,7 @@ def f():
print()
finally:
pass
"#;
";
let stmts = parse_suite(source, "<filename>")?;
assert_eq!(num_statements(&stmts), 10);
Ok(())
@ -398,7 +398,7 @@ def f():
#[test]
fn try_except_except() -> Result<()> {
let source: &str = r#"
let source: &str = r"
def f():
try:
print()
@ -406,7 +406,7 @@ def f():
pass
except Exception:
raise
"#;
";
let stmts = parse_suite(source, "<filename>")?;
assert_eq!(num_statements(&stmts), 8);
Ok(())
@ -414,7 +414,7 @@ def f():
#[test]
fn try_except_except_finally() -> Result<()> {
let source: &str = r#"
let source: &str = r"
def f():
try:
print()
@ -424,7 +424,7 @@ def f():
pass
finally:
print()
"#;
";
let stmts = parse_suite(source, "<filename>")?;
assert_eq!(num_statements(&stmts), 11);
Ok(())
@ -432,11 +432,11 @@ def f():
#[test]
fn yield_() -> Result<()> {
let source: &str = r#"
let source: &str = r"
def f():
for i in range(10):
yield i
"#;
";
let stmts = parse_suite(source, "<filename>")?;
assert_eq!(num_statements(&stmts), 2);
Ok(())

View file

@ -104,145 +104,145 @@ mod tests {
#[test]
fn once() {
let source = r#"from foo import bar, baz, bop, qux as q"#;
let expected = r#"from foo import bar, baz, qux as q"#;
let source = r"from foo import bar, baz, bop, qux as q";
let expected = r"from foo import bar, baz, qux as q";
let actual = remove_import_members(source, &["bop"]);
assert_eq!(expected, actual);
}
#[test]
fn twice() {
let source = r#"from foo import bar, baz, bop, qux as q"#;
let expected = r#"from foo import bar, qux as q"#;
let source = r"from foo import bar, baz, bop, qux as q";
let expected = r"from foo import bar, qux as q";
let actual = remove_import_members(source, &["baz", "bop"]);
assert_eq!(expected, actual);
}
#[test]
fn aliased() {
let source = r#"from foo import bar, baz, bop as boop, qux as q"#;
let expected = r#"from foo import bar, baz, qux as q"#;
let source = r"from foo import bar, baz, bop as boop, qux as q";
let expected = r"from foo import bar, baz, qux as q";
let actual = remove_import_members(source, &["bop"]);
assert_eq!(expected, actual);
}
#[test]
fn parenthesized() {
let source = r#"from foo import (bar, baz, bop, qux as q)"#;
let expected = r#"from foo import (bar, baz, qux as q)"#;
let source = r"from foo import (bar, baz, bop, qux as q)";
let expected = r"from foo import (bar, baz, qux as q)";
let actual = remove_import_members(source, &["bop"]);
assert_eq!(expected, actual);
}
#[test]
fn last_import() {
let source = r#"from foo import bar, baz, bop, qux as q"#;
let expected = r#"from foo import bar, baz, bop"#;
let source = r"from foo import bar, baz, bop, qux as q";
let expected = r"from foo import bar, baz, bop";
let actual = remove_import_members(source, &["qux"]);
assert_eq!(expected, actual);
}
#[test]
fn first_import() {
let source = r#"from foo import bar, baz, bop, qux as q"#;
let expected = r#"from foo import baz, bop, qux as q"#;
let source = r"from foo import bar, baz, bop, qux as q";
let expected = r"from foo import baz, bop, qux as q";
let actual = remove_import_members(source, &["bar"]);
assert_eq!(expected, actual);
}
#[test]
fn first_two_imports() {
let source = r#"from foo import bar, baz, bop, qux as q"#;
let expected = r#"from foo import bop, qux as q"#;
let source = r"from foo import bar, baz, bop, qux as q";
let expected = r"from foo import bop, qux as q";
let actual = remove_import_members(source, &["bar", "baz"]);
assert_eq!(expected, actual);
}
#[test]
fn first_two_imports_multiline() {
let source = r#"from foo import (
let source = r"from foo import (
bar,
baz,
bop,
qux as q
)"#;
let expected = r#"from foo import (
)";
let expected = r"from foo import (
bop,
qux as q
)"#;
)";
let actual = remove_import_members(source, &["bar", "baz"]);
assert_eq!(expected, actual);
}
#[test]
fn multiline_once() {
let source = r#"from foo import (
let source = r"from foo import (
bar,
baz,
bop,
qux as q,
)"#;
let expected = r#"from foo import (
)";
let expected = r"from foo import (
bar,
baz,
qux as q,
)"#;
)";
let actual = remove_import_members(source, &["bop"]);
assert_eq!(expected, actual);
}
#[test]
fn multiline_twice() {
let source = r#"from foo import (
let source = r"from foo import (
bar,
baz,
bop,
qux as q,
)"#;
let expected = r#"from foo import (
)";
let expected = r"from foo import (
bar,
qux as q,
)"#;
)";
let actual = remove_import_members(source, &["baz", "bop"]);
assert_eq!(expected, actual);
}
#[test]
fn multiline_comment() {
let source = r#"from foo import (
let source = r"from foo import (
bar,
baz,
# This comment should be removed.
bop,
# This comment should be retained.
qux as q,
)"#;
let expected = r#"from foo import (
)";
let expected = r"from foo import (
bar,
baz,
# This comment should be retained.
qux as q,
)"#;
)";
let actual = remove_import_members(source, &["bop"]);
assert_eq!(expected, actual);
}
#[test]
fn multi_comment_first_import() {
let source = r#"from foo import (
let source = r"from foo import (
# This comment should be retained.
bar,
# This comment should be removed.
baz,
bop,
qux as q,
)"#;
let expected = r#"from foo import (
)";
let expected = r"from foo import (
# This comment should be retained.
baz,
bop,
qux as q,
)"#;
)";
let actual = remove_import_members(source, &["bar"]);
assert_eq!(expected, actual);
}

View file

@ -1045,7 +1045,7 @@ mod tests {
#[test_case("match.py")]
fn control_flow_graph(filename: &str) {
let path = PathBuf::from_iter(["resources/test/fixtures/control-flow-graph", filename]);
let source = fs::read_to_string(&path).expect("failed to read file");
let source = fs::read_to_string(path).expect("failed to read file");
let stmts = parse(&source, Mode::Module, filename)
.unwrap_or_else(|err| panic!("failed to parse source: '{source}': {err}"))
.expect_module()

View file

@ -21,3 +21,6 @@ proc-macro2 = { workspace = true }
quote = { workspace = true }
syn = { workspace = true, features = ["derive", "parsing", "extra-traits", "full"] }
itertools = { workspace = true }
[lints]
workspace = true

View file

@ -64,7 +64,7 @@ pub(crate) fn derive_impl(input: DeriveInput) -> syn::Result<proc_macro2::TokenS
.iter()
.find(|attr| attr.path().is_ident("doc"))
else {
return Err(Error::new(variant.span(), r#"expected a doc comment"#));
return Err(Error::new(variant.span(), "expected a doc comment"));
};
let variant_ident = variant.ident;
@ -155,7 +155,7 @@ fn parse_doc_attr(doc_attr: &Attribute) -> syn::Result<(String, String)> {
.ok_or_else(|| {
Error::new(
doc_lit.span(),
r#"expected doc comment to be in the form of `/// [name](https://example.com/)`"#,
"expected doc comment to be in the form of `/// [name](https://example.com/)`",
)
})
}

View file

@ -29,3 +29,6 @@ uuid = { workspace = true }
[dev-dependencies]
insta = { workspace = true }
test-case = { workspace = true }
[lints]
workspace = true

View file

@ -33,3 +33,6 @@ ruff_python_parser = { path = "../ruff_python_parser" }
[features]
serde = ["dep:serde", "ruff_text_size/serde"]
[lints]
workspace = true

View file

@ -229,7 +229,7 @@ mod tests {
#[test]
fn extract_global_names() {
let contents = r#"global X,Y, Z"#.trim();
let contents = r"global X,Y, Z".trim();
let mut names = IdentifierTokenizer::new(
contents,

View file

@ -5,12 +5,12 @@ use ruff_python_ast::identifier;
#[test]
fn extract_else_range() -> Result<(), ParseError> {
let contents = r#"
let contents = r"
for x in y:
pass
else:
pass
"#
"
.trim();
let stmts = parse_suite(contents, "<filename>")?;
let stmt = stmts.first().unwrap();

View file

@ -5,7 +5,7 @@ use ruff_text_size::TextRange;
#[test]
fn test_parenthesized_name() {
let source_code = r#"(x) + 1"#;
let source_code = r"(x) + 1";
let expr = parse_expression(source_code, "<filename>").unwrap();
let bin_op = expr.as_bin_op_expr().unwrap();
@ -22,7 +22,7 @@ fn test_parenthesized_name() {
#[test]
fn test_non_parenthesized_name() {
let source_code = r#"x + 1"#;
let source_code = r"x + 1";
let expr = parse_expression(source_code, "<filename>").unwrap();
let bin_op = expr.as_bin_op_expr().unwrap();
@ -39,7 +39,7 @@ fn test_non_parenthesized_name() {
#[test]
fn test_parenthesized_argument() {
let source_code = r#"f((a))"#;
let source_code = r"f((a))";
let expr = parse_expression(source_code, "<filename>").unwrap();
let call = expr.as_call_expr().unwrap();
@ -57,7 +57,7 @@ fn test_parenthesized_argument() {
#[test]
fn test_non_parenthesized_argument() {
let source_code = r#"f(a)"#;
let source_code = r"f(a)";
let expr = parse_expression(source_code, "<filename>").unwrap();
let call = expr.as_call_expr().unwrap();
@ -75,7 +75,7 @@ fn test_non_parenthesized_argument() {
#[test]
fn test_parenthesized_tuple_member() {
let source_code = r#"(a, (b))"#;
let source_code = r"(a, (b))";
let expr = parse_expression(source_code, "<filename>").unwrap();
let tuple = expr.as_tuple_expr().unwrap();
@ -92,7 +92,7 @@ fn test_parenthesized_tuple_member() {
#[test]
fn test_non_parenthesized_tuple_member() {
let source_code = r#"(a, b)"#;
let source_code = r"(a, b)";
let expr = parse_expression(source_code, "<filename>").unwrap();
let tuple = expr.as_tuple_expr().unwrap();
@ -109,7 +109,7 @@ fn test_non_parenthesized_tuple_member() {
#[test]
fn test_twice_parenthesized_name() {
let source_code = r#"((x)) + 1"#;
let source_code = r"((x)) + 1";
let expr = parse_expression(source_code, "<filename>").unwrap();
let bin_op = expr.as_bin_op_expr().unwrap();
@ -126,7 +126,7 @@ fn test_twice_parenthesized_name() {
#[test]
fn test_twice_parenthesized_argument() {
let source_code = r#"f(((a + 1)))"#;
let source_code = r"f(((a + 1)))";
let expr = parse_expression(source_code, "<filename>").unwrap();
let call = expr.as_call_expr().unwrap();

View file

@ -17,7 +17,7 @@ use ruff_python_parser::{parse_tokens, Mode};
#[test]
fn function_arguments() {
let source = r#"def a(b, c,/, d, e = 20, *args, named=5, other=20, **kwargs): pass"#;
let source = r"def a(b, c,/, d, e = 20, *args, named=5, other=20, **kwargs): pass";
let trace = trace_preorder_visitation(source);
@ -26,7 +26,7 @@ fn function_arguments() {
#[test]
fn function_positional_only_with_default() {
let source = r#"def a(b, c = 34,/, e = 20, *args): pass"#;
let source = r"def a(b, c = 34,/, e = 20, *args): pass";
let trace = trace_preorder_visitation(source);
@ -35,7 +35,7 @@ fn function_positional_only_with_default() {
#[test]
fn compare() {
let source = r#"4 < x < 5"#;
let source = r"4 < x < 5";
let trace = trace_preorder_visitation(source);
@ -71,13 +71,13 @@ fn set_comprehension() {
#[test]
fn match_class_pattern() {
let source = r#"
let source = r"
match x:
case Point2D(0, 0):
...
case Point3D(x=0, y=0, z=0):
...
"#;
";
let trace = trace_preorder_visitation(source);
@ -86,7 +86,7 @@ match x:
#[test]
fn decorators() {
let source = r#"
let source = r"
@decorator
def a():
pass
@ -94,7 +94,7 @@ def a():
@test
class A:
pass
"#;
";
let trace = trace_preorder_visitation(source);
@ -103,7 +103,7 @@ class A:
#[test]
fn type_aliases() {
let source = r#"type X[T: str, U, *Ts, **P] = list[T]"#;
let source = r"type X[T: str, U, *Ts, **P] = list[T]";
let trace = trace_preorder_visitation(source);
@ -112,7 +112,7 @@ fn type_aliases() {
#[test]
fn class_type_parameters() {
let source = r#"class X[T: str, U, *Ts, **P]: ..."#;
let source = r"class X[T: str, U, *Ts, **P]: ...";
let trace = trace_preorder_visitation(source);
@ -121,7 +121,7 @@ fn class_type_parameters() {
#[test]
fn function_type_parameters() {
let source = r#"def X[T: str, U, *Ts, **P](): ..."#;
let source = r"def X[T: str, U, *Ts, **P](): ...";
let trace = trace_preorder_visitation(source);

View file

@ -18,7 +18,7 @@ use ruff_python_ast::{
#[test]
fn function_arguments() {
let source = r#"def a(b, c,/, d, e = 20, *args, named=5, other=20, **kwargs): pass"#;
let source = r"def a(b, c,/, d, e = 20, *args, named=5, other=20, **kwargs): pass";
let trace = trace_visitation(source);
@ -27,7 +27,7 @@ fn function_arguments() {
#[test]
fn function_positional_only_with_default() {
let source = r#"def a(b, c = 34,/, e = 20, *args): pass"#;
let source = r"def a(b, c = 34,/, e = 20, *args): pass";
let trace = trace_visitation(source);
@ -36,7 +36,7 @@ fn function_positional_only_with_default() {
#[test]
fn compare() {
let source = r#"4 < x < 5"#;
let source = r"4 < x < 5";
let trace = trace_visitation(source);
@ -72,13 +72,13 @@ fn set_comprehension() {
#[test]
fn match_class_pattern() {
let source = r#"
let source = r"
match x:
case Point2D(0, 0):
...
case Point3D(x=0, y=0, z=0):
...
"#;
";
let trace = trace_visitation(source);
@ -87,7 +87,7 @@ match x:
#[test]
fn decorators() {
let source = r#"
let source = r"
@decorator
def a():
pass
@ -95,7 +95,7 @@ def a():
@test
class A:
pass
"#;
";
let trace = trace_visitation(source);
@ -104,7 +104,7 @@ class A:
#[test]
fn type_aliases() {
let source = r#"type X[T: str, U, *Ts, **P] = list[T]"#;
let source = r"type X[T: str, U, *Ts, **P] = list[T]";
let trace = trace_visitation(source);
@ -113,7 +113,7 @@ fn type_aliases() {
#[test]
fn class_type_parameters() {
let source = r#"class X[T: str, U, *Ts, **P]: ..."#;
let source = r"class X[T: str, U, *Ts, **P]: ...";
let trace = trace_visitation(source);
@ -122,7 +122,7 @@ fn class_type_parameters() {
#[test]
fn function_type_parameters() {
let source = r#"def X[T: str, U, *Ts, **P](): ..."#;
let source = r"def X[T: str, U, *Ts, **P](): ...";
let trace = trace_visitation(source);

View file

@ -20,3 +20,6 @@ ruff_source_file = { path = "../ruff_source_file" }
once_cell = { workspace = true }
[lints]
workspace = true

View file

@ -1473,7 +1473,7 @@ mod tests {
assert_round_trip!("return await (await bar())");
assert_round_trip!("(5).foo");
assert_round_trip!(r#"our_dict = {"a": 1, **{"b": 2, "c": 3}}"#);
assert_round_trip!(r#"j = [1, 2, 3]"#);
assert_round_trip!(r"j = [1, 2, 3]");
assert_round_trip!(
r#"def test(a1, a2, b1=j, b2="123", b3={}, b4=[]):
pass"#
@ -1511,32 +1511,32 @@ mod tests {
pass"#
);
assert_round_trip!(
r#"class Foo(Bar, object):
pass"#
r"class Foo(Bar, object):
pass"
);
assert_round_trip!(
r#"class Foo[T]:
pass"#
r"class Foo[T]:
pass"
);
assert_round_trip!(
r#"class Foo[T](Bar):
pass"#
r"class Foo[T](Bar):
pass"
);
assert_round_trip!(
r#"class Foo[*Ts]:
pass"#
r"class Foo[*Ts]:
pass"
);
assert_round_trip!(
r#"class Foo[**P]:
pass"#
r"class Foo[**P]:
pass"
);
assert_round_trip!(
r#"class Foo[T, U, *Ts, **P]:
pass"#
r"class Foo[T, U, *Ts, **P]:
pass"
);
assert_round_trip!(
r#"def f() -> (int, str):
pass"#
r"def f() -> (int, str):
pass"
);
assert_round_trip!("[await x async for x in y]");
assert_round_trip!("[await i for i in b if await c]");
@ -1550,102 +1550,102 @@ mod tests {
return datum"#
);
assert_round_trip!(
r#"def f() -> (int, int):
pass"#
r"def f() -> (int, int):
pass"
);
assert_round_trip!(
r#"def test(a, b, /, c, *, d, **kwargs):
pass"#
r"def test(a, b, /, c, *, d, **kwargs):
pass"
);
assert_round_trip!(
r#"def test(a=3, b=4, /, c=7):
pass"#
r"def test(a=3, b=4, /, c=7):
pass"
);
assert_round_trip!(
r#"def test(a, b=4, /, c=8, d=9):
pass"#
r"def test(a, b=4, /, c=8, d=9):
pass"
);
assert_round_trip!(
r#"def test[T]():
pass"#
r"def test[T]():
pass"
);
assert_round_trip!(
r#"def test[*Ts]():
pass"#
r"def test[*Ts]():
pass"
);
assert_round_trip!(
r#"def test[**P]():
pass"#
r"def test[**P]():
pass"
);
assert_round_trip!(
r#"def test[T, U, *Ts, **P]():
pass"#
r"def test[T, U, *Ts, **P]():
pass"
);
assert_round_trip!(
r#"def call(*popenargs, timeout=None, **kwargs):
pass"#
r"def call(*popenargs, timeout=None, **kwargs):
pass"
);
assert_round_trip!(
r#"@functools.lru_cache(maxsize=None)
r"@functools.lru_cache(maxsize=None)
def f(x: int, y: int) -> int:
return x + y"#
return x + y"
);
assert_round_trip!(
r#"try:
r"try:
pass
except Exception as e:
pass"#
pass"
);
assert_round_trip!(
r#"try:
r"try:
pass
except* Exception as e:
pass"#
pass"
);
assert_round_trip!(
r#"match x:
r"match x:
case [1, 2, 3]:
return 2
case 4 as y:
return y"#
return y"
);
assert_eq!(round_trip(r#"x = (1, 2, 3)"#), r#"x = 1, 2, 3"#);
assert_eq!(round_trip(r#"-(1) + ~(2) + +(3)"#), r#"-1 + ~2 + +3"#);
assert_eq!(round_trip(r"x = (1, 2, 3)"), r"x = 1, 2, 3");
assert_eq!(round_trip(r"-(1) + ~(2) + +(3)"), r"-1 + ~2 + +3");
assert_round_trip!(
r#"def f():
r"def f():
def f():
pass"#
pass"
);
assert_round_trip!(
r#"@foo
r"@foo
def f():
@foo
def f():
pass"#
pass"
);
assert_round_trip!(
r#"@foo
r"@foo
class Foo:
@foo
def f():
pass"#
pass"
);
assert_round_trip!(r#"[lambda n: n for n in range(10)]"#);
assert_round_trip!(r#"[n[0:2] for n in range(10)]"#);
assert_round_trip!(r#"[n[0] for n in range(10)]"#);
assert_round_trip!(r#"[(n, n * 2) for n in range(10)]"#);
assert_round_trip!(r#"[1 if n % 2 == 0 else 0 for n in range(10)]"#);
assert_round_trip!(r#"[n % 2 == 0 or 0 for n in range(10)]"#);
assert_round_trip!(r#"[(n := 2) for n in range(10)]"#);
assert_round_trip!(r#"((n := 2) for n in range(10))"#);
assert_round_trip!(r#"[n * 2 for n in range(10)]"#);
assert_round_trip!(r#"{n * 2 for n in range(10)}"#);
assert_round_trip!(r#"{i: n * 2 for i, n in enumerate(range(10))}"#);
assert_round_trip!(r"[lambda n: n for n in range(10)]");
assert_round_trip!(r"[n[0:2] for n in range(10)]");
assert_round_trip!(r"[n[0] for n in range(10)]");
assert_round_trip!(r"[(n, n * 2) for n in range(10)]");
assert_round_trip!(r"[1 if n % 2 == 0 else 0 for n in range(10)]");
assert_round_trip!(r"[n % 2 == 0 or 0 for n in range(10)]");
assert_round_trip!(r"[(n := 2) for n in range(10)]");
assert_round_trip!(r"((n := 2) for n in range(10))");
assert_round_trip!(r"[n * 2 for n in range(10)]");
assert_round_trip!(r"{n * 2 for n in range(10)}");
assert_round_trip!(r"{i: n * 2 for i, n in enumerate(range(10))}");
assert_round_trip!(
"class SchemaItem(NamedTuple):
fields: ((\"property_key\", str),)"
@ -1659,25 +1659,25 @@ class Foo:
assert_round_trip!("x += (i := 1)");
// Type aliases
assert_round_trip!(r#"type Foo = int | str"#);
assert_round_trip!(r#"type Foo[T] = list[T]"#);
assert_round_trip!(r#"type Foo[*Ts] = ..."#);
assert_round_trip!(r#"type Foo[**P] = ..."#);
assert_round_trip!(r#"type Foo[T, U, *Ts, **P] = ..."#);
assert_round_trip!(r"type Foo = int | str");
assert_round_trip!(r"type Foo[T] = list[T]");
assert_round_trip!(r"type Foo[*Ts] = ...");
assert_round_trip!(r"type Foo[**P] = ...");
assert_round_trip!(r"type Foo[T, U, *Ts, **P] = ...");
// https://github.com/astral-sh/ruff/issues/6498
assert_round_trip!(r#"f(a=1, *args, **kwargs)"#);
assert_round_trip!(r#"f(*args, a=1, **kwargs)"#);
assert_round_trip!(r#"f(*args, a=1, *args2, **kwargs)"#);
assert_round_trip!(r"f(a=1, *args, **kwargs)");
assert_round_trip!(r"f(*args, a=1, **kwargs)");
assert_round_trip!(r"f(*args, a=1, *args2, **kwargs)");
assert_round_trip!("class A(*args, a=2, *args2, **kwargs):\n pass");
}
#[test]
fn quote() {
assert_eq!(round_trip(r#""hello""#), r#""hello""#);
assert_eq!(round_trip(r#"'hello'"#), r#""hello""#);
assert_eq!(round_trip(r#"u'hello'"#), r#"u"hello""#);
assert_eq!(round_trip(r#"r'hello'"#), r#""hello""#);
assert_eq!(round_trip(r#"b'hello'"#), r#"b"hello""#);
assert_eq!(round_trip(r"'hello'"), r#""hello""#);
assert_eq!(round_trip(r"u'hello'"), r#"u"hello""#);
assert_eq!(round_trip(r"r'hello'"), r#""hello""#);
assert_eq!(round_trip(r"b'hello'"), r#"b"hello""#);
assert_eq!(round_trip(r#"("abc" "def" "ghi")"#), r#""abcdefghi""#);
assert_eq!(round_trip(r#""he\"llo""#), r#"'he"llo'"#);
assert_eq!(round_trip(r#"f"abc{'def'}{1}""#), r#"f"abc{'def'}{1}""#);
@ -1697,16 +1697,16 @@ class Foo:
fn indent() {
assert_eq!(
round_trip(
r#"
r"
if True:
pass
"#
"
.trim(),
),
r#"
r"
if True:
pass
"#
"
.trim()
.replace('\n', LineEnding::default().as_str())
);
@ -1730,14 +1730,14 @@ if True:
LineEnding::default(),
r#""hello""#
),
r#"'hello'"#
r"'hello'"
);
assert_eq!(
round_trip_with(
&Indentation::default(),
Quote::Double,
LineEnding::default(),
r#"'hello'"#
r"'hello'"
),
r#""hello""#
);
@ -1746,9 +1746,9 @@ if True:
&Indentation::default(),
Quote::Single,
LineEnding::default(),
r#"'hello'"#
r"'hello'"
),
r#"'hello'"#
r"'hello'"
);
}
@ -1759,16 +1759,16 @@ if True:
&Indentation::new(" ".to_string()),
Quote::default(),
LineEnding::default(),
r#"
r"
if True:
pass
"#
"
.trim(),
),
r#"
r"
if True:
pass
"#
"
.trim()
.replace('\n', LineEnding::default().as_str())
);
@ -1777,16 +1777,16 @@ if True:
&Indentation::new(" ".to_string()),
Quote::default(),
LineEnding::default(),
r#"
r"
if True:
pass
"#
"
.trim(),
),
r#"
r"
if True:
pass
"#
"
.trim()
.replace('\n', LineEnding::default().as_str())
);
@ -1795,16 +1795,16 @@ if True:
&Indentation::new("\t".to_string()),
Quote::default(),
LineEnding::default(),
r#"
r"
if True:
pass
"#
"
.trim(),
),
r#"
r"
if True:
pass
"#
"
.trim()
.replace('\n', LineEnding::default().as_str())
);

View file

@ -190,7 +190,7 @@ mod tests {
#[test]
fn indentation() {
let contents = r#"x = 1"#;
let contents = r"x = 1";
let locator = Locator::new(contents);
let tokens: Vec<_> = lex(contents, Mode::Module).collect();
assert_eq!(
@ -198,10 +198,10 @@ mod tests {
&Indentation::default()
);
let contents = r#"
let contents = r"
if True:
pass
"#;
";
let locator = Locator::new(contents);
let tokens: Vec<_> = lex(contents, Mode::Module).collect();
assert_eq!(
@ -209,10 +209,10 @@ if True:
&Indentation(" ".to_string())
);
let contents = r#"
let contents = r"
if True:
pass
"#;
";
let locator = Locator::new(contents);
let tokens: Vec<_> = lex(contents, Mode::Module).collect();
assert_eq!(
@ -220,10 +220,10 @@ if True:
&Indentation(" ".to_string())
);
let contents = r#"
let contents = r"
if True:
pass
"#;
";
let locator = Locator::new(contents);
let tokens: Vec<_> = lex(contents, Mode::Module).collect();
assert_eq!(
@ -232,13 +232,13 @@ if True:
);
// TODO(charlie): Should non-significant whitespace be detected?
let contents = r#"
let contents = r"
x = (
1,
2,
3,
)
"#;
";
let locator = Locator::new(contents);
let tokens: Vec<_> = lex(contents, Mode::Module).collect();
assert_eq!(
@ -247,11 +247,11 @@ x = (
);
// formfeed indent, see `detect_indention` comment.
let contents = r#"
let contents = r"
class FormFeedIndent:
def __init__(self, a=[]):
print(a)
"#;
";
let locator = Locator::new(contents);
let tokens: Vec<_> = lex(contents, Mode::Module).collect();
assert_eq!(
@ -262,7 +262,7 @@ class FormFeedIndent:
#[test]
fn quote() {
let contents = r#"x = 1"#;
let contents = r"x = 1";
let locator = Locator::new(contents);
let tokens: Vec<_> = lex(contents, Mode::Module).collect();
assert_eq!(
@ -270,7 +270,7 @@ class FormFeedIndent:
Quote::default()
);
let contents = r#"x = '1'"#;
let contents = r"x = '1'";
let locator = Locator::new(contents);
let tokens: Vec<_> = lex(contents, Mode::Module).collect();
assert_eq!(
@ -278,7 +278,7 @@ class FormFeedIndent:
Quote::Single
);
let contents = r#"x = f'1'"#;
let contents = r"x = f'1'";
let locator = Locator::new(contents);
let tokens: Vec<_> = lex(contents, Mode::Module).collect();
assert_eq!(
@ -373,9 +373,9 @@ a = f"v"
Quote::Double
);
let contents = r#"
let contents = r"
f'''Module docstring.'''
"#;
";
let locator = Locator::new(contents);
let tokens: Vec<_> = lex(contents, Mode::Module).collect();
assert_eq!(

View file

@ -55,3 +55,6 @@ required-features = ["serde"]
default = ["serde"]
serde = ["dep:serde", "ruff_formatter/serde", "ruff_source_file/serde", "ruff_python_ast/serde"]
schemars = ["dep:schemars", "ruff_formatter/schemars"]
[lints]
workspace = true

View file

@ -198,11 +198,11 @@ mod tests {
range: TextRange::default(),
});
let source = r#"# leading comment
let source = r"# leading comment
continue; # trailing
# break leading
break;
"#;
";
let source_code = SourceCode::new(source);

View file

@ -610,11 +610,11 @@ test(10, 20)
#[test]
fn only_comments() {
let source = r#"
let source = r"
# Some comment
# another comment
"#;
";
let test_case = CommentsTestCase::from_code(source);
let comments = test_case.to_comments();
@ -624,7 +624,7 @@ test(10, 20)
#[test]
fn empty_file() {
let source = r#""#;
let source = r"";
let test_case = CommentsTestCase::from_code(source);
let comments = test_case.to_comments();
@ -634,12 +634,12 @@ test(10, 20)
#[test]
fn dangling_comment() {
let source = r#"
let source = r"
def test(
# Some comment
):
pass
"#;
";
let test_case = CommentsTestCase::from_code(source);
let comments = test_case.to_comments();
@ -649,12 +649,12 @@ def test(
#[test]
fn parenthesized_expression() {
let source = r#"
let source = r"
a = ( # Trailing comment
10 + # More comments
3
)
"#;
";
let test_case = CommentsTestCase::from_code(source);
let comments = test_case.to_comments();
@ -664,11 +664,11 @@ a = ( # Trailing comment
#[test]
fn parenthesized_trailing_comment() {
let source = r#"(
let source = r"(
a
# comment
)
"#;
";
let test_case = CommentsTestCase::from_code(source);
let comments = test_case.to_comments();
@ -728,7 +728,7 @@ print("test")
#[test]
fn if_elif_else_comments() {
let source = r#"
let source = r"
if x == y:
pass # trailing `pass` comment
# Root `if` trailing comment
@ -741,7 +741,7 @@ elif x < y:
else:
pass
# `else` trailing comment
"#;
";
let test_case = CommentsTestCase::from_code(source);
let comments = test_case.to_comments();
@ -751,7 +751,7 @@ else:
#[test]
fn if_elif_if_else_comments() {
let source = r#"
let source = r"
if x == y:
pass
elif x < y:
@ -761,7 +761,7 @@ elif x < y:
# Leading else comment
else:
pass
"#;
";
let test_case = CommentsTestCase::from_code(source);
let comments = test_case.to_comments();
@ -855,10 +855,10 @@ print("Next statement");
#[test]
fn leading_most_outer() {
let source = r#"
let source = r"
# leading comment
x
"#;
";
let test_case = CommentsTestCase::from_code(source);
let comments = test_case.to_comments();
@ -869,10 +869,10 @@ x
// Comment should be attached to the statement
#[test]
fn trailing_most_outer() {
let source = r#"
let source = r"
x # trailing comment
y # trailing last node
"#;
";
let test_case = CommentsTestCase::from_code(source);
let comments = test_case.to_comments();
@ -882,11 +882,11 @@ y # trailing last node
#[test]
fn trailing_most_outer_nested() {
let source = r#"
let source = r"
x + (
3 # trailing comment
) # outer
"#;
";
let test_case = CommentsTestCase::from_code(source);
let comments = test_case.to_comments();
@ -896,12 +896,12 @@ x + (
#[test]
fn trailing_after_comma() {
let source = r#"
let source = r"
def test(
a, # Trailing comment for argument `a`
b,
): pass
"#;
";
let test_case = CommentsTestCase::from_code(source);
let comments = test_case.to_comments();
@ -911,7 +911,7 @@ def test(
#[test]
fn positional_argument_only_comment() {
let source = r#"
let source = r"
def test(
a, # trailing positional comment
# Positional arguments only after here
@ -919,7 +919,7 @@ def test(
# leading b comment
b,
): pass
"#;
";
let test_case = CommentsTestCase::from_code(source);
let comments = test_case.to_comments();
@ -929,7 +929,7 @@ def test(
#[test]
fn positional_argument_only_leading_comma_comment() {
let source = r#"
let source = r"
def test(
a # trailing positional comment
# Positional arguments only after here
@ -937,7 +937,7 @@ def test(
# leading b comment
b,
): pass
"#;
";
let test_case = CommentsTestCase::from_code(source);
let comments = test_case.to_comments();
@ -947,14 +947,14 @@ def test(
#[test]
fn positional_argument_only_comment_without_following_node() {
let source = r#"
let source = r"
def test(
a, # trailing positional comment
# Positional arguments only after here
/, # trailing positional argument comment.
# Trailing on new line
): pass
"#;
";
let test_case = CommentsTestCase::from_code(source);
let comments = test_case.to_comments();
@ -964,7 +964,7 @@ def test(
#[test]
fn non_positional_arguments_with_defaults() {
let source = r#"
let source = r"
def test(
a=10 # trailing positional comment
# Positional arguments only after here
@ -972,7 +972,7 @@ def test(
# leading comment for b
b=20
): pass
"#;
";
let test_case = CommentsTestCase::from_code(source);
let comments = test_case.to_comments();
@ -982,12 +982,12 @@ def test(
#[test]
fn non_positional_arguments_slash_on_same_line() {
let source = r#"
let source = r"
def test(a=10,/, # trailing positional argument comment.
# leading comment for b
b=20
): pass
"#;
";
let test_case = CommentsTestCase::from_code(source);
let comments = test_case.to_comments();
@ -997,7 +997,7 @@ def test(a=10,/, # trailing positional argument comment.
#[test]
fn binary_expression_left_operand_comment() {
let source = r#"
let source = r"
a = (
5
# trailing left comment
@ -1005,7 +1005,7 @@ a = (
# leading right comment
3
)
"#;
";
let test_case = CommentsTestCase::from_code(source);
let comments = test_case.to_comments();
@ -1015,14 +1015,14 @@ a = (
#[test]
fn binary_expression_left_operand_trailing_end_of_line_comment() {
let source = r#"
let source = r"
a = (
5 # trailing left comment
+ # trailing operator comment
# leading right comment
3
)
"#;
";
let test_case = CommentsTestCase::from_code(source);
let comments = test_case.to_comments();
@ -1032,7 +1032,7 @@ a = (
#[test]
fn nested_binary_expression() {
let source = r#"
let source = r"
a = (
(5 # trailing left comment
*
@ -1041,7 +1041,7 @@ a = (
# leading right comment
3
)
"#;
";
let test_case = CommentsTestCase::from_code(source);
let comments = test_case.to_comments();
@ -1051,10 +1051,10 @@ a = (
#[test]
fn while_trailing_end_of_line_comment() {
let source = r#"while True:
let source = r"while True:
if something.changed:
do.stuff() # trailing comment
"#;
";
let test_case = CommentsTestCase::from_code(source);
@ -1065,11 +1065,11 @@ a = (
#[test]
fn while_trailing_else_end_of_line_comment() {
let source = r#"while True:
let source = r"while True:
pass
else: # trailing comment
pass
"#;
";
let test_case = CommentsTestCase::from_code(source);

View file

@ -2281,10 +2281,10 @@ mod tests {
assert_eq!(
max_empty_lines(
r#"# This multiline comments section
r"# This multiline comments section
# should be split from the statement
# above by two lines.
"#
"
),
0
);

View file

@ -51,7 +51,7 @@ impl<'a> AnyString<'a> {
.slice(f_string.range)
.trim_start_matches(|c| c != '"' && c != '\'');
let triple_quoted =
unprefixed.starts_with(r#"""""#) || unprefixed.starts_with(r#"'''"#);
unprefixed.starts_with(r#"""""#) || unprefixed.starts_with(r"'''");
if f_string.values.iter().any(|value| match value {
Expr::FormattedValue(ast::ExprFormattedValue { range, .. }) => {
let string_content = locator.slice(*range);

View file

@ -183,17 +183,17 @@ mod tests {
/// Very basic test intentionally kept very similar to the CLI
#[test]
fn basic() -> Result<()> {
let input = r#"
let input = r"
# preceding
if True:
pass
# trailing
"#;
let expected = r#"# preceding
";
let expected = r"# preceding
if True:
pass
# trailing
"#;
";
let actual = format_module_source(input, PyFormatOptions::default())?
.as_code()
.to_string();
@ -241,11 +241,11 @@ def main() -> None:
assert_eq!(
printed.as_code(),
r#"for converter in connection.ops.get_db_converters(
r"for converter in connection.ops.get_db_converters(
expression
) + expression.get_db_converters(connection):
...
"#
"
);
}
@ -304,9 +304,9 @@ def main() -> None:
// 77 after g group (leading quote)
let fits =
r#"aaaaaaaaaa bbbbbbbbbb cccccccccc dddddddddd eeeeeeeeee ffffffffff gggggggggg h"#;
r"aaaaaaaaaa bbbbbbbbbb cccccccccc dddddddddd eeeeeeeeee ffffffffff gggggggggg h";
let breaks =
r#"aaaaaaaaaa bbbbbbbbbb cccccccccc dddddddddd eeeeeeeeee ffffffffff gggggggggg hh"#;
r"aaaaaaaaaa bbbbbbbbbb cccccccccc dddddddddd eeeeeeeeee ffffffffff gggggggggg hh";
let output = format!(
SimpleFormatContext::default(),

View file

@ -685,7 +685,7 @@ mod tests {
use crate::PyFormatOptions;
fn format_suite(level: SuiteKind) -> String {
let source = r#"
let source = r"
a = 10
@ -704,7 +704,7 @@ def func():
pass
def trailing_func():
pass
"#;
";
let statements = parse_suite(source, "test.py").unwrap();
@ -730,7 +730,7 @@ def trailing_func():
assert_eq!(
formatted,
r#"a = 10
r"a = 10
three_leading_newlines = 80
@ -755,7 +755,7 @@ def func():
def trailing_func():
pass
"#
"
);
}
@ -765,7 +765,7 @@ def trailing_func():
assert_eq!(
formatted,
r#"a = 10
r"a = 10
three_leading_newlines = 80
@ -784,7 +784,7 @@ def func():
def trailing_func():
pass
"#
"
);
}
}

View file

@ -23,3 +23,6 @@ ruff_text_size = { path = "../ruff_text_size" }
itertools = { workspace = true }
[dev-dependencies]
[lints]
workspace = true

View file

@ -238,18 +238,18 @@ mod tests {
#[test]
fn continuation() {
let contents = r#"x = 1"#;
let contents = r"x = 1";
let lxr: Vec<LexResult> = lexer::lex(contents, Mode::Module).collect();
let indexer = Indexer::from_tokens(&lxr, &Locator::new(contents));
assert_eq!(indexer.continuation_line_starts(), &[]);
let contents = r#"
let contents = r"
# Hello, world!
x = 1
y = 2
"#
"
.trim();
let lxr: Vec<LexResult> = lexer::lex(contents, Mode::Module).collect();

View file

@ -21,3 +21,6 @@ unic-ucd-category = "0.9"
[dev-dependencies]
rand = "0.8.5"
[lints]
workspace = true

View file

@ -35,3 +35,6 @@ insta = { workspace = true }
anyhow = { workspace = true }
lalrpop = { version = "0.20.0", default-features = false, optional = true }
tiny-keccak = { version = "2", features = ["sha3"] }
[lints]
workspace = true

View file

@ -1973,9 +1973,9 @@ def f(arg=%timeit a = b):
#[test]
fn tet_too_low_dedent() {
let tokens: Vec<_> = lex(
r#"if True:
"if True:
pass
pass"#,
pass",
Mode::Module,
)
.collect();
@ -2198,10 +2198,10 @@ f"{(lambda x:{x})}"
assert_eq!(lex_fstring_error(r#"f"""{""""#), UnclosedLbrace);
assert_eq!(lex_fstring_error(r#"f""#), UnterminatedString);
assert_eq!(lex_fstring_error(r#"f'"#), UnterminatedString);
assert_eq!(lex_fstring_error(r"f'"), UnterminatedString);
assert_eq!(lex_fstring_error(r#"f""""#), UnterminatedTripleQuotedString);
assert_eq!(lex_fstring_error(r#"f'''"#), UnterminatedTripleQuotedString);
assert_eq!(lex_fstring_error(r"f'''"), UnterminatedTripleQuotedString);
assert_eq!(
lex_fstring_error(r#"f"""""#),
UnterminatedTripleQuotedString

View file

@ -741,12 +741,12 @@ array[3:5, *indexes_to_select]
#[test]
fn test_try() {
let parse_ast = parse_suite(
r#"try:
r"try:
raise ValueError(1)
except TypeError as e:
print(f'caught {type(e)}')
except OSError as e:
print(f'caught {type(e)}')"#,
print(f'caught {type(e)}')",
"<test>",
)
.unwrap();
@ -865,7 +865,7 @@ x = type = 1
#[test]
fn numeric_literals() {
let source = r#"x = 123456789
let source = r"x = 123456789
x = 123456
x = .1
x = 1.
@ -883,14 +883,14 @@ x = 0O777
x = 0.000000006
x = 10000
x = 133333
"#;
";
insta::assert_debug_snapshot!(parse_suite(source, "<test>").unwrap());
}
#[test]
fn numeric_literals_attribute_access() {
let source = r#"x = .1.is_integer()
let source = r"x = .1.is_integer()
x = 1. .imag
x = 1E+1.imag
x = 1E-1.real
@ -910,7 +910,7 @@ if 10 .real:
y = 100[no]
y = 100(no)
"#;
";
assert_debug_snapshot!(parse_suite(source, "<test>").unwrap());
}
@ -1173,9 +1173,9 @@ match x:
#[test]
fn test_variadic_generics() {
let parse_ast = parse_suite(
r#"
r"
def args_to_tuple(*args: *Ts) -> Tuple[*Ts]: ...
"#,
",
"<test>",
)
.unwrap();
@ -1185,7 +1185,7 @@ def args_to_tuple(*args: *Ts) -> Tuple[*Ts]: ...
#[test]
fn decorator_ranges() {
let parse_ast = parse_suite(
r#"
r"
@my_decorator
def test():
pass
@ -1193,7 +1193,7 @@ def test():
@class_decorator
class Abcd:
pass
"#
"
.trim(),
"<test>",
)
@ -1280,10 +1280,10 @@ foo.bar[0].baz[2].egg??
#[test]
fn test_ipython_escape_command_parse_error() {
let source = r#"
let source = r"
a = 1
%timeit a == 1
"#
"
.trim();
let lxr = lexer::lex_starts_at(source, Mode::Ipython, TextSize::default());
let parse_err = parse_tokens(lxr, source, Mode::Module, "<test>").unwrap_err();

View file

@ -20,3 +20,6 @@ log = { workspace = true }
env_logger = "0.10.0"
tempfile = "3.8.1"
insta = { workspace = true }
[lints]
workspace = true

View file

@ -116,7 +116,7 @@ fn find_paths_from_pth_files(parent_dir: &Path) -> io::Result<impl Iterator<Item
file_len > 0 && file_len < 64 * 1024
})
.filter_map(|path| {
let data = fs::read_to_string(&path).ok()?;
let data = fs::read_to_string(path).ok()?;
for line in data.lines() {
let trimmed_line = line.trim();
if !trimmed_line.is_empty()

View file

@ -26,3 +26,6 @@ smallvec = { workspace = true }
[dev-dependencies]
ruff_python_parser = { path = "../ruff_python_parser" }
[lints]
workspace = true

View file

@ -14,3 +14,6 @@ license = { workspace = true }
[dependencies]
unicode-ident = { workspace = true }
[lints]
workspace = true

View file

@ -23,3 +23,6 @@ unicode-ident = { workspace = true }
insta = { workspace = true }
ruff_python_ast = { path = "../ruff_python_ast" }
ruff_python_parser = { path = "../ruff_python_parser" }
[lints]
workspace = true

View file

@ -337,10 +337,10 @@ mod tests {
#[test]
fn dedent_non_python_whitespace() {
let text = r#"        C = int(f.rea1,0],[-1,0,1]],
let text = r"        C = int(f.rea1,0],[-1,0,1]],
[[-1,-1,1],[1,1,-1],[0,-1,0]],
[[-1,-1,-1],[1,1,0],[1,0,1]]
]"#;
]";
assert_eq!(dedent(text), text);
}
}

View file

@ -1184,9 +1184,9 @@ mod tests {
#[test]
fn tokenize_slash() {
let source = r#" # trailing positional comment
let source = r" # trailing positional comment
# Positional arguments only after here
,/"#;
,/";
let test_case = tokenize(source);
@ -1229,8 +1229,8 @@ mod tests {
#[test]
fn triple_quoted_multiline_string_containing_comment() {
let test_case = tokenize(
r#"'''This string contains a hash looking like a comment
# This is not a comment'''"#,
r"'''This string contains a hash looking like a comment
# This is not a comment'''",
);
assert_debug_snapshot!(test_case.tokenize_reverse());
@ -1274,7 +1274,7 @@ mod tests {
#[test]
fn empty_string_literal() {
let test_case = tokenize(r#"'' # a comment '"#);
let test_case = tokenize(r"'' # a comment '");
assert_debug_snapshot!(test_case.tokenize_reverse());
}

View file

@ -114,10 +114,10 @@ mod tests {
let locator = Locator::new(contents);
assert!(!has_trailing_content(stmt.end(), &locator));
let contents = r#"
let contents = r"
x = 1
y = 2
"#
"
.trim();
let program = parse_suite(contents, "<filename>")?;
let stmt = program.first().unwrap();

View file

@ -16,3 +16,6 @@ ruff_text_size = { path = "../ruff_text_size" }
shlex = "1.2.0"
tracing = { workspace = true }
tracing-subscriber = { workspace = true, features = ["env-filter"] }
[lints]
workspace = true

View file

@ -21,6 +21,8 @@ serde = { workspace = true, optional = true }
[dev-dependencies]
insta = { workspace = true }
[features]
serde = ["dep:serde", "ruff_text_size/serde"]
[lints]
workspace = true

View file

@ -16,6 +16,9 @@ static_assertions = { version = "1.1.0" }
[features]
serde = ["dep:serde"]
[lints]
workspace = true
[[test]]
name = "serde"
path = "tests/serde.rs"

View file

@ -42,3 +42,6 @@ js-sys = { version = "0.3.61" }
[dev-dependencies]
wasm-bindgen-test = { version = "0.3.34" }
[lints]
workspace = true

View file

@ -44,8 +44,9 @@ toml = { workspace = true }
[dev-dependencies]
tempfile = "3.8.1"
[features]
default = []
schemars = [ "dep:schemars", "ruff_formatter/schemars", "ruff_python_formatter/schemars" ]
default = []
[lints]
workspace = true

View file

@ -169,21 +169,21 @@ mod tests {
#[test]
fn deserialize() -> Result<()> {
let pyproject: Pyproject = toml::from_str(r#""#)?;
let pyproject: Pyproject = toml::from_str(r"")?;
assert_eq!(pyproject.tool, None);
let pyproject: Pyproject = toml::from_str(
r#"
r"
[tool.black]
"#,
",
)?;
assert_eq!(pyproject.tool, Some(Tools { ruff: None }));
let pyproject: Pyproject = toml::from_str(
r#"
r"
[tool.black]
[tool.ruff]
"#,
",
)?;
assert_eq!(
pyproject.tool,
@ -193,11 +193,11 @@ mod tests {
);
let pyproject: Pyproject = toml::from_str(
r#"
r"
[tool.black]
[tool.ruff]
line-length = 79
"#,
",
)?;
assert_eq!(
pyproject.tool,
@ -275,11 +275,11 @@ ignore = ["E501"]
);
assert!(toml::from_str::<Pyproject>(
r#"
r"
[tool.black]
[tool.ruff]
line_length = 79
"#,
",
)
.is_err());
@ -293,12 +293,12 @@ select = ["E123"]
.is_err());
assert!(toml::from_str::<Pyproject>(
r#"
r"
[tool.black]
[tool.ruff]
line-length = 79
other-attribute = 1
"#,
",
)
.is_err());

View file

@ -1,2 +1,2 @@
[toolchain]
channel = "1.73"
channel = "1.74"