ruff/crates/ty/tests/cli/rule_selection.rs
renovate[bot] c9f95e8714
Update Rust crate toml to 0.9.0 (#19320)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [toml](https://redirect.github.com/toml-rs/toml) |
workspace.dependencies | minor | `0.8.11` -> `0.9.0` |

---

> [!WARNING]
> Some dependencies could not be looked up. Check the Dependency
Dashboard for more information.

---

### Release Notes

<details>
<summary>toml-rs/toml (toml)</summary>

###
[`v0.9.2`](https://redirect.github.com/toml-rs/toml/compare/toml-v0.9.1...toml-v0.9.2)

[Compare
Source](https://redirect.github.com/toml-rs/toml/compare/toml-v0.9.1...toml-v0.9.2)

###
[`v0.9.1`](https://redirect.github.com/toml-rs/toml/compare/toml-v0.9.0...toml-v0.9.1)

[Compare
Source](https://redirect.github.com/toml-rs/toml/compare/toml-v0.9.0...toml-v0.9.1)

###
[`v0.9.0`](https://redirect.github.com/toml-rs/toml/compare/toml-v0.8.23...toml-v0.9.0)

[Compare
Source](https://redirect.github.com/toml-rs/toml/compare/toml-v0.8.23...toml-v0.9.0)

</details>

---

### Configuration

📅 **Schedule**: Branch creation - "before 4am on Monday" (UTC),
Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/astral-sh/ruff).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0MS4yMy4yIiwidXBkYXRlZEluVmVyIjoiNDEuMjMuMiIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOlsiaW50ZXJuYWwiXX0=-->

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Dhruv Manilawala <dhruvmanila@gmail.com>
2025-07-14 13:11:10 +05:30

902 lines
24 KiB
Rust

use insta_cmd::assert_cmd_snapshot;
use crate::CliTest;
/// The rule severity can be changed in the configuration file
#[test]
fn configuration_rule_severity() -> anyhow::Result<()> {
let case = CliTest::with_file(
"test.py",
r#"
y = 4 / 0
for a in range(0, int(y)):
x = a
prin(x) # unresolved-reference
"#,
)?;
// Assert that there's an `unresolved-reference` diagnostic (error).
assert_cmd_snapshot!(case.command(), @r###"
success: false
exit_code: 1
----- stdout -----
error[unresolved-reference]: Name `prin` used when not defined
--> test.py:7:1
|
5 | x = a
6 |
7 | prin(x) # unresolved-reference
| ^^^^
|
info: rule `unresolved-reference` is enabled by default
Found 1 diagnostic
----- stderr -----
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
"###);
case.write_file(
"pyproject.toml",
r#"
[tool.ty.rules]
division-by-zero = "warn" # promote to warn
unresolved-reference = "ignore"
"#,
)?;
assert_cmd_snapshot!(case.command(), @r"
success: true
exit_code: 0
----- stdout -----
warning[division-by-zero]: Cannot divide object of type `Literal[4]` by zero
--> test.py:2:5
|
2 | y = 4 / 0
| ^^^^^
3 |
4 | for a in range(0, int(y)):
|
info: rule `division-by-zero` was selected in the configuration file
Found 1 diagnostic
----- stderr -----
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
");
Ok(())
}
/// The rule severity can be changed using `--ignore`, `--warn`, and `--error`
#[test]
fn cli_rule_severity() -> anyhow::Result<()> {
let case = CliTest::with_file(
"test.py",
r#"
import does_not_exit
y = 4 / 0
for a in range(0, int(y)):
x = a
prin(x) # unresolved-reference
"#,
)?;
// Assert that there's an `unresolved-reference` diagnostic (error)
// and an unresolved-import (error) diagnostic by default.
assert_cmd_snapshot!(case.command(), @r###"
success: false
exit_code: 1
----- stdout -----
error[unresolved-import]: Cannot resolve imported module `does_not_exit`
--> test.py:2:8
|
2 | import does_not_exit
| ^^^^^^^^^^^^^
3 |
4 | y = 4 / 0
|
info: make sure your Python environment is properly configured: https://docs.astral.sh/ty/modules/#python-environment
info: rule `unresolved-import` is enabled by default
error[unresolved-reference]: Name `prin` used when not defined
--> test.py:9:1
|
7 | x = a
8 |
9 | prin(x) # unresolved-reference
| ^^^^
|
info: rule `unresolved-reference` is enabled by default
Found 2 diagnostics
----- stderr -----
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
"###);
assert_cmd_snapshot!(
case
.command()
.arg("--ignore")
.arg("unresolved-reference")
.arg("--warn")
.arg("division-by-zero")
.arg("--warn")
.arg("unresolved-import"),
@r"
success: true
exit_code: 0
----- stdout -----
warning[unresolved-import]: Cannot resolve imported module `does_not_exit`
--> test.py:2:8
|
2 | import does_not_exit
| ^^^^^^^^^^^^^
3 |
4 | y = 4 / 0
|
info: make sure your Python environment is properly configured: https://docs.astral.sh/ty/modules/#python-environment
info: rule `unresolved-import` was selected on the command line
warning[division-by-zero]: Cannot divide object of type `Literal[4]` by zero
--> test.py:4:5
|
2 | import does_not_exit
3 |
4 | y = 4 / 0
| ^^^^^
5 |
6 | for a in range(0, int(y)):
|
info: rule `division-by-zero` was selected on the command line
Found 2 diagnostics
----- stderr -----
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
"
);
Ok(())
}
/// The rule severity can be changed using `--ignore`, `--warn`, and `--error` and
/// values specified last override previous severities.
#[test]
fn cli_rule_severity_precedence() -> anyhow::Result<()> {
let case = CliTest::with_file(
"test.py",
r#"
y = 4 / 0
for a in range(0, int(y)):
x = a
prin(x) # unresolved-reference
"#,
)?;
// Assert that there's a `unresolved-reference` diagnostic (error) by default.
assert_cmd_snapshot!(case.command(), @r###"
success: false
exit_code: 1
----- stdout -----
error[unresolved-reference]: Name `prin` used when not defined
--> test.py:7:1
|
5 | x = a
6 |
7 | prin(x) # unresolved-reference
| ^^^^
|
info: rule `unresolved-reference` is enabled by default
Found 1 diagnostic
----- stderr -----
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
"###);
assert_cmd_snapshot!(
case
.command()
.arg("--warn")
.arg("unresolved-reference")
.arg("--warn")
.arg("division-by-zero")
.arg("--ignore")
.arg("unresolved-reference"),
@r"
success: true
exit_code: 0
----- stdout -----
warning[division-by-zero]: Cannot divide object of type `Literal[4]` by zero
--> test.py:2:5
|
2 | y = 4 / 0
| ^^^^^
3 |
4 | for a in range(0, int(y)):
|
info: rule `division-by-zero` was selected on the command line
Found 1 diagnostic
----- stderr -----
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
"
);
Ok(())
}
/// ty warns about unknown rules specified in a configuration file
#[test]
fn configuration_unknown_rules() -> anyhow::Result<()> {
let case = CliTest::with_files([
(
"pyproject.toml",
r#"
[tool.ty.rules]
division-by-zer = "warn" # incorrect rule name
"#,
),
("test.py", "print(10)"),
])?;
assert_cmd_snapshot!(case.command(), @r#"
success: true
exit_code: 0
----- stdout -----
warning[unknown-rule]: Unknown lint rule `division-by-zer`
--> pyproject.toml:3:1
|
2 | [tool.ty.rules]
3 | division-by-zer = "warn" # incorrect rule name
| ^^^^^^^^^^^^^^^
|
Found 1 diagnostic
----- stderr -----
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
"#);
Ok(())
}
/// ty warns about unknown rules specified in a CLI argument
#[test]
fn cli_unknown_rules() -> anyhow::Result<()> {
let case = CliTest::with_file("test.py", "print(10)")?;
assert_cmd_snapshot!(case.command().arg("--ignore").arg("division-by-zer"), @r"
success: true
exit_code: 0
----- stdout -----
warning[unknown-rule]: Unknown lint rule `division-by-zer`
Found 1 diagnostic
----- stderr -----
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
");
Ok(())
}
/// Basic override functionality: override rules for specific files
#[test]
fn overrides_basic() -> anyhow::Result<()> {
let case = CliTest::with_files([
(
"pyproject.toml",
r#"
[tool.ty.rules]
division-by-zero = "error"
unresolved-reference = "error"
[[tool.ty.overrides]]
include = ["tests/**"]
[tool.ty.overrides.rules]
division-by-zero = "warn"
unresolved-reference = "ignore"
"#,
),
(
"main.py",
r#"
y = 4 / 0 # division-by-zero: error (global)
x = 1
prin(x) # unresolved-reference: error (global)
"#,
),
(
"tests/test_main.py",
r#"
y = 4 / 0 # division-by-zero: warn (override)
x = 1
prin(x) # unresolved-reference: ignore (override)
"#,
),
])?;
assert_cmd_snapshot!(case.command(), @r###"
success: false
exit_code: 1
----- stdout -----
error[division-by-zero]: Cannot divide object of type `Literal[4]` by zero
--> main.py:2:5
|
2 | y = 4 / 0 # division-by-zero: error (global)
| ^^^^^
3 | x = 1
4 | prin(x) # unresolved-reference: error (global)
|
info: rule `division-by-zero` was selected in the configuration file
error[unresolved-reference]: Name `prin` used when not defined
--> main.py:4:1
|
2 | y = 4 / 0 # division-by-zero: error (global)
3 | x = 1
4 | prin(x) # unresolved-reference: error (global)
| ^^^^
|
info: rule `unresolved-reference` was selected in the configuration file
warning[division-by-zero]: Cannot divide object of type `Literal[4]` by zero
--> tests/test_main.py:2:5
|
2 | y = 4 / 0 # division-by-zero: warn (override)
| ^^^^^
3 | x = 1
4 | prin(x) # unresolved-reference: ignore (override)
|
info: rule `division-by-zero` was selected in the configuration file
Found 3 diagnostics
----- stderr -----
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
"###);
Ok(())
}
/// Multiple overrides: later overrides take precedence
#[test]
fn overrides_precedence() -> anyhow::Result<()> {
let case = CliTest::with_files([
(
"pyproject.toml",
r#"
[tool.ty.rules]
division-by-zero = "error"
# First override: all test files
[[tool.ty.overrides]]
include = ["tests/**"]
[tool.ty.overrides.rules]
division-by-zero = "warn"
# Second override: specific test file (takes precedence)
[[tool.ty.overrides]]
include = ["tests/important.py"]
[tool.ty.overrides.rules]
division-by-zero = "ignore"
"#,
),
(
"tests/test_main.py",
r#"
y = 4 / 0 # division-by-zero: warn (first override)
"#,
),
(
"tests/important.py",
r#"
y = 4 / 0 # division-by-zero: ignore (second override)
"#,
),
])?;
assert_cmd_snapshot!(case.command(), @r"
success: true
exit_code: 0
----- stdout -----
warning[division-by-zero]: Cannot divide object of type `Literal[4]` by zero
--> tests/test_main.py:2:5
|
2 | y = 4 / 0 # division-by-zero: warn (first override)
| ^^^^^
|
info: rule `division-by-zero` was selected in the configuration file
Found 1 diagnostic
----- stderr -----
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
");
Ok(())
}
/// Override with exclude patterns
#[test]
fn overrides_exclude() -> anyhow::Result<()> {
let case = CliTest::with_files([
(
"pyproject.toml",
r#"
[tool.ty.rules]
division-by-zero = "error"
[[tool.ty.overrides]]
include = ["tests/**"]
exclude = ["tests/important.py"]
[tool.ty.overrides.rules]
division-by-zero = "warn"
"#,
),
(
"tests/test_main.py",
r#"
y = 4 / 0 # division-by-zero: warn (override applies)
"#,
),
(
"tests/important.py",
r#"
y = 4 / 0 # division-by-zero: error (override excluded)
"#,
),
])?;
assert_cmd_snapshot!(case.command(), @r"
success: false
exit_code: 1
----- stdout -----
error[division-by-zero]: Cannot divide object of type `Literal[4]` by zero
--> tests/important.py:2:5
|
2 | y = 4 / 0 # division-by-zero: error (override excluded)
| ^^^^^
|
info: rule `division-by-zero` was selected in the configuration file
warning[division-by-zero]: Cannot divide object of type `Literal[4]` by zero
--> tests/test_main.py:2:5
|
2 | y = 4 / 0 # division-by-zero: warn (override applies)
| ^^^^^
|
info: rule `division-by-zero` was selected in the configuration file
Found 2 diagnostics
----- stderr -----
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
");
Ok(())
}
/// Override without rules inherits global rules
#[test]
fn overrides_inherit_global() -> anyhow::Result<()> {
let case = CliTest::with_files([
(
"pyproject.toml",
r#"
[tool.ty.rules]
division-by-zero = "warn"
unresolved-reference = "error"
[[tool.ty.overrides]]
include = ["tests/**"]
[tool.ty.overrides.rules]
# Override only division-by-zero, unresolved-reference should inherit from global
division-by-zero = "ignore"
"#,
),
(
"main.py",
r#"
y = 4 / 0 # division-by-zero: warn (global)
prin(y) # unresolved-reference: error (global)
"#,
),
(
"tests/test_main.py",
r#"
y = 4 / 0 # division-by-zero: ignore (overridden)
prin(y) # unresolved-reference: error (inherited from global)
"#,
),
])?;
assert_cmd_snapshot!(case.command(), @r#"
success: false
exit_code: 1
----- stdout -----
warning[division-by-zero]: Cannot divide object of type `Literal[4]` by zero
--> main.py:2:5
|
2 | y = 4 / 0 # division-by-zero: warn (global)
| ^^^^^
3 | prin(y) # unresolved-reference: error (global)
|
info: rule `division-by-zero` was selected in the configuration file
error[unresolved-reference]: Name `prin` used when not defined
--> main.py:3:1
|
2 | y = 4 / 0 # division-by-zero: warn (global)
3 | prin(y) # unresolved-reference: error (global)
| ^^^^
|
info: rule `unresolved-reference` was selected in the configuration file
error[unresolved-reference]: Name `prin` used when not defined
--> tests/test_main.py:3:1
|
2 | y = 4 / 0 # division-by-zero: ignore (overridden)
3 | prin(y) # unresolved-reference: error (inherited from global)
| ^^^^
|
info: rule `unresolved-reference` was selected in the configuration file
Found 3 diagnostics
----- stderr -----
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
"#);
Ok(())
}
/// ty warns about invalid glob patterns in override include patterns
#[test]
fn overrides_invalid_include_glob() -> anyhow::Result<()> {
let case = CliTest::with_files([
(
"pyproject.toml",
r#"
[tool.ty.rules]
division-by-zero = "error"
[[tool.ty.overrides]]
include = ["tests/[invalid"] # Invalid glob: unclosed bracket
[tool.ty.overrides.rules]
division-by-zero = "warn"
"#,
),
(
"test.py",
r#"
y = 4 / 0
"#,
),
])?;
assert_cmd_snapshot!(case.command(), @r#"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
ty failed
Cause: error[invalid-glob]: Invalid include pattern
--> pyproject.toml:6:12
|
5 | [[tool.ty.overrides]]
6 | include = ["tests/[invalid"] # Invalid glob: unclosed bracket
| ^^^^^^^^^^^^^^^^ unclosed character class; missing ']'
7 | [tool.ty.overrides.rules]
8 | division-by-zero = "warn"
|
"#);
Ok(())
}
/// ty warns about invalid glob patterns in override exclude patterns
#[test]
fn overrides_invalid_exclude_glob() -> anyhow::Result<()> {
let case = CliTest::with_files([
(
"pyproject.toml",
r#"
[tool.ty.rules]
division-by-zero = "error"
[[tool.ty.overrides]]
include = ["tests/**"]
exclude = ["***/invalid"] # Invalid glob: triple asterisk
[tool.ty.overrides.rules]
division-by-zero = "warn"
"#,
),
(
"test.py",
r#"
y = 4 / 0
"#,
),
])?;
assert_cmd_snapshot!(case.command(), @r#"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
ty failed
Cause: error[invalid-glob]: Invalid exclude pattern
--> pyproject.toml:7:12
|
5 | [[tool.ty.overrides]]
6 | include = ["tests/**"]
7 | exclude = ["***/invalid"] # Invalid glob: triple asterisk
| ^^^^^^^^^^^^^ Too many stars at position 1
8 | [tool.ty.overrides.rules]
9 | division-by-zero = "warn"
|
"#);
Ok(())
}
/// ty warns when an overrides section has neither include nor exclude
#[test]
fn overrides_missing_include_exclude() -> anyhow::Result<()> {
let case = CliTest::with_files([
(
"pyproject.toml",
r#"
[tool.ty.rules]
division-by-zero = "error"
[[tool.ty.overrides]]
# Missing both include and exclude - should warn
[tool.ty.overrides.rules]
division-by-zero = "warn"
"#,
),
(
"test.py",
r#"
y = 4 / 0
"#,
),
])?;
assert_cmd_snapshot!(case.command(), @r#"
success: true
exit_code: 0
----- stdout -----
warning[unnecessary-overrides-section]: Unnecessary `overrides` section
--> pyproject.toml:5:1
|
3 | division-by-zero = "error"
4 |
5 | [[tool.ty.overrides]]
| ^^^^^^^^^^^^^^^^^^^^^ This overrides section applies to all files
6 | # Missing both include and exclude - should warn
7 | [tool.ty.overrides.rules]
|
info: It has no `include` or `exclude` option restricting the files
info: Restrict the files by adding a pattern to `include` or `exclude`...
info: or remove the `[[overrides]]` section and merge the configuration into the root `[rules]` table if the configuration should apply to all files
warning[division-by-zero]: Cannot divide object of type `Literal[4]` by zero
--> test.py:2:5
|
2 | y = 4 / 0
| ^^^^^
|
info: rule `division-by-zero` was selected in the configuration file
Found 2 diagnostics
----- stderr -----
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
"#);
Ok(())
}
/// ty warns when an overrides section has an empty include array
#[test]
fn overrides_empty_include() -> anyhow::Result<()> {
let case = CliTest::with_files([
(
"pyproject.toml",
r#"
[tool.ty.rules]
division-by-zero = "error"
[[tool.ty.overrides]]
include = [] # Empty include - won't match any files
[tool.ty.overrides.rules]
division-by-zero = "warn"
"#,
),
(
"test.py",
r#"
y = 4 / 0
"#,
),
])?;
assert_cmd_snapshot!(case.command(), @r#"
success: false
exit_code: 1
----- stdout -----
warning[empty-include]: Empty include matches no files
--> pyproject.toml:6:11
|
5 | [[tool.ty.overrides]]
6 | include = [] # Empty include - won't match any files
| ^^ This `include` list is empty
7 | [tool.ty.overrides.rules]
8 | division-by-zero = "warn"
|
info: Remove the `include` option to match all files or add a pattern to match specific files
error[division-by-zero]: Cannot divide object of type `Literal[4]` by zero
--> test.py:2:5
|
2 | y = 4 / 0
| ^^^^^
|
info: rule `division-by-zero` was selected in the configuration file
Found 2 diagnostics
----- stderr -----
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
"#);
Ok(())
}
/// ty warns when an overrides section has no actual overrides
#[test]
fn overrides_no_actual_overrides() -> anyhow::Result<()> {
let case = CliTest::with_files([
(
"pyproject.toml",
r#"
[tool.ty.rules]
division-by-zero = "error"
[[tool.ty.overrides]]
include = ["*.py"] # Has patterns but no rule overrides
# Missing [tool.ty.overrides.rules] section entirely
"#,
),
(
"test.py",
r#"
y = 4 / 0
"#,
),
])?;
assert_cmd_snapshot!(case.command(), @r#"
success: false
exit_code: 1
----- stdout -----
warning[useless-overrides-section]: Useless `overrides` section
--> pyproject.toml:5:1
|
3 | division-by-zero = "error"
4 |
5 | [[tool.ty.overrides]]
| ^^^^^^^^^^^^^^^^^^^^^ This overrides section configures no rules
6 | include = ["*.py"] # Has patterns but no rule overrides
7 | # Missing [tool.ty.overrides.rules] section entirely
|
info: It has no `rules` table
info: Add a `[overrides.rules]` table...
info: or remove the `[[overrides]]` section if there's nothing to override
error[division-by-zero]: Cannot divide object of type `Literal[4]` by zero
--> test.py:2:5
|
2 | y = 4 / 0
| ^^^^^
|
info: rule `division-by-zero` was selected in the configuration file
Found 2 diagnostics
----- stderr -----
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
"#);
Ok(())
}
/// ty warns about unknown rules specified in an overrides section
#[test]
fn overrides_unknown_rules() -> anyhow::Result<()> {
let case = CliTest::with_files([
(
"pyproject.toml",
r#"
[tool.ty.rules]
division-by-zero = "error"
[[tool.ty.overrides]]
include = ["tests/**"]
[tool.ty.overrides.rules]
division-by-zero = "warn"
division-by-zer = "error" # incorrect rule name
"#,
),
(
"main.py",
r#"
y = 4 / 0
"#,
),
(
"tests/test_main.py",
r#"
y = 4 / 0
"#,
),
])?;
assert_cmd_snapshot!(case.command(), @r#"
success: false
exit_code: 1
----- stdout -----
warning[unknown-rule]: Unknown lint rule `division-by-zer`
--> pyproject.toml:10:1
|
8 | [tool.ty.overrides.rules]
9 | division-by-zero = "warn"
10 | division-by-zer = "error" # incorrect rule name
| ^^^^^^^^^^^^^^^
|
error[division-by-zero]: Cannot divide object of type `Literal[4]` by zero
--> main.py:2:5
|
2 | y = 4 / 0
| ^^^^^
|
info: rule `division-by-zero` was selected in the configuration file
warning[division-by-zero]: Cannot divide object of type `Literal[4]` by zero
--> tests/test_main.py:2:5
|
2 | y = 4 / 0
| ^^^^^
|
info: rule `division-by-zero` was selected in the configuration file
Found 3 diagnostics
----- stderr -----
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
"#);
Ok(())
}