[ty] disable division-by-zero by default (#18220)
Some checks are pending
CI / Determine changes (push) Waiting to run
CI / cargo fmt (push) Waiting to run
CI / cargo clippy (push) Blocked by required conditions
CI / cargo test (linux) (push) Blocked by required conditions
CI / cargo test (linux, release) (push) Blocked by required conditions
CI / cargo test (windows) (push) Blocked by required conditions
CI / cargo test (wasm) (push) Blocked by required conditions
CI / cargo build (release) (push) Waiting to run
CI / cargo build (msrv) (push) Blocked by required conditions
CI / cargo fuzz build (push) Blocked by required conditions
CI / fuzz parser (push) Blocked by required conditions
CI / test scripts (push) Blocked by required conditions
CI / ecosystem (push) Blocked by required conditions
CI / Fuzz for new ty panics (push) Blocked by required conditions
CI / cargo shear (push) Blocked by required conditions
CI / python package (push) Waiting to run
CI / pre-commit (push) Waiting to run
CI / mkdocs (push) Waiting to run
CI / formatter instabilities and black similarity (push) Blocked by required conditions
CI / test ruff-lsp (push) Blocked by required conditions
CI / check playground (push) Blocked by required conditions
CI / benchmarks (push) Blocked by required conditions
[ty Playground] Release / publish (push) Waiting to run

## Summary

I think `division-by-zero` is a low-value diagnostic in general; most
real division-by-zero errors (especially those that are less obvious to
the human eye) will occur on values typed as `int`, in which case we
don't issue the diagnostic anyway. Mypy and pyright do not emit this
diagnostic.

Currently the diagnostic is prone to false positives because a) we do
not silence it in unreachable code, and b) we do not implement narrowing
of literals from inequality checks. We will probably fix (a) regardless,
but (b) is low priority apart from division-by-zero.

I think we have many more important things to do and should not allow
false positives on a low-value diagnostic to be a distraction. Not
opposed to re-enabling this diagnostic in future when we can prioritize
reducing its false positives.

References https://github.com/astral-sh/ty/issues/443

## Test Plan

Existing tests.
This commit is contained in:
Carl Meyer 2025-05-20 14:47:56 -04:00 committed by GitHub
parent 7917269d9a
commit d098118e37
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 43 additions and 85 deletions

View file

@ -5,3 +5,4 @@
[rules]
possibly-unresolved-reference = "warn"
unused-ignore-comment = "warn"
division-by-zero = "warn"

View file

@ -176,29 +176,6 @@ class B(A): ...
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L195)
</details>
## `division-by-zero`
**Default level**: error
<details>
<summary>detects division by zero</summary>
### What it does
It detects division by zero.
### Why is this bad?
Dividing by zero raises a `ZeroDivisionError` at runtime.
### Examples
```python
5 / 0
```
### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20division-by-zero)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L221)
</details>
## `duplicate-base`
**Default level**: error
@ -1743,6 +1720,29 @@ a = 20 / 0 # ty: ignore[division-by-zero]
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Fsuppression.rs#L40)
</details>
## `division-by-zero`
**Default level**: ignore
<details>
<summary>detects division by zero</summary>
### What it does
It detects division by zero.
### Why is this bad?
Dividing by zero raises a `ZeroDivisionError` at runtime.
### Examples
```python
5 / 0
```
### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20division-by-zero)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L221)
</details>
## `possibly-unresolved-reference`
**Default level**: ignore

View file

@ -387,22 +387,11 @@ fn configuration_rule_severity() -> anyhow::Result<()> {
"#,
)?;
// Assert that there's an `unresolved-reference` diagnostic (error)
// and a `division-by-zero` diagnostic (error).
assert_cmd_snapshot!(case.command(), @r"
// Assert that there's an `unresolved-reference` diagnostic (error).
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
--> test.py:2:5
|
2 | y = 4 / 0
| ^^^^^
3 |
4 | for a in range(0, int(y)):
|
info: rule `division-by-zero` is enabled by default
error[unresolved-reference]: Name `prin` used when not defined
--> test.py:7:1
|
@ -413,17 +402,17 @@ fn configuration_rule_severity() -> anyhow::Result<()> {
|
info: rule `unresolved-reference` is enabled by default
Found 2 diagnostics
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" # demote to warn
division-by-zero = "warn" # promote to warn
unresolved-reference = "ignore"
"#,
)?;
@ -468,9 +457,9 @@ fn cli_rule_severity() -> anyhow::Result<()> {
"#,
)?;
// Assert that there's an `unresolved-reference` diagnostic (error),
// a `division-by-zero` (error) and a unresolved-import (error) diagnostic by default.
assert_cmd_snapshot!(case.command(), @r"
// 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 -----
@ -485,18 +474,6 @@ fn cli_rule_severity() -> anyhow::Result<()> {
info: make sure your Python environment is properly configured: https://github.com/astral-sh/ty/blob/main/docs/README.md#python-environment
info: rule `unresolved-import` is enabled by default
error[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` is enabled by default
error[unresolved-reference]: Name `prin` used when not defined
--> test.py:9:1
|
@ -507,11 +484,11 @@ fn cli_rule_severity() -> anyhow::Result<()> {
|
info: rule `unresolved-reference` is enabled by default
Found 3 diagnostics
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
@ -575,22 +552,11 @@ fn cli_rule_severity_precedence() -> anyhow::Result<()> {
"#,
)?;
// Assert that there's a `unresolved-reference` diagnostic (error)
// and a `division-by-zero` (error) by default.
assert_cmd_snapshot!(case.command(), @r"
// Assert that there's a `unresolved-reference` diagnostic (error) by default.
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
--> test.py:2:5
|
2 | y = 4 / 0
| ^^^^^
3 |
4 | for a in range(0, int(y)):
|
info: rule `division-by-zero` is enabled by default
error[unresolved-reference]: Name `prin` used when not defined
--> test.py:7:1
|
@ -601,11 +567,11 @@ fn cli_rule_severity_precedence() -> anyhow::Result<()> {
|
info: rule `unresolved-reference` is enabled by default
Found 2 diagnostics
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
@ -614,7 +580,6 @@ fn cli_rule_severity_precedence() -> anyhow::Result<()> {
.arg("unresolved-reference")
.arg("--warn")
.arg("division-by-zero")
// Override the error severity with warning
.arg("--ignore")
.arg("unresolved-reference"),
@r"
@ -1103,18 +1068,10 @@ fn check_specific_paths() -> anyhow::Result<()> {
assert_cmd_snapshot!(
case.command(),
@r"
@r###"
success: false
exit_code: 1
----- stdout -----
error[division-by-zero]: Cannot divide object of type `Literal[4]` by zero
--> project/main.py:2:5
|
2 | y = 4 / 0 # error: division-by-zero
| ^^^^^
|
info: rule `division-by-zero` is enabled by default
error[unresolved-import]: Cannot resolve imported module `main2`
--> project/other.py:2:6
|
@ -1135,11 +1092,11 @@ fn check_specific_paths() -> anyhow::Result<()> {
info: make sure your Python environment is properly configured: https://github.com/astral-sh/ty/blob/main/docs/README.md#python-environment
info: rule `unresolved-import` is enabled by default
Found 3 diagnostics
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.
"
"###
);
// Now check only the `tests` and `other.py` files.

View file

@ -232,7 +232,7 @@ declare_lint! {
pub(crate) static DIVISION_BY_ZERO = {
summary: "detects division by zero",
status: LintStatus::preview("1.0.0"),
default_level: Level::Error,
default_level: Level::Ignore,
}
}

2
ty.schema.json generated
View file

@ -293,7 +293,7 @@
"division-by-zero": {
"title": "detects division by zero",
"description": "## What it does\nIt detects division by zero.\n\n## Why is this bad?\nDividing by zero raises a `ZeroDivisionError` at runtime.\n\n## Examples\n```python\n5 / 0\n```",
"default": "error",
"default": "ignore",
"oneOf": [
{
"$ref": "#/definitions/Level"