[ty] Ignore possibly-unresolved-reference by default (#17934)

This commit is contained in:
Micha Reiser 2025-05-08 17:44:56 +02:00 committed by GitHub
parent 067a8ac574
commit d608eae126
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 97 additions and 72 deletions

6
.github/mypy-primer-ty.toml vendored Normal file
View file

@ -0,0 +1,6 @@
#:schema ../ty.schema.json
# Configuration overrides for the mypy primer run
# Enable off-by-default rules.
[rules]
possibly-unresolved-reference = "warn"

View file

@ -50,6 +50,10 @@ jobs:
run: | run: |
cd ruff cd ruff
echo "Enabling mypy primer specific configuration overloads (see .github/mypy-primer-ty.toml)"
mkdir -p ~/.config/ty
cp .github/mypy-primer-ty.toml ~/.config/ty/ty.toml
PRIMER_SELECTOR="$(paste -s -d'|' crates/ty_python_semantic/resources/primer/good.txt)" PRIMER_SELECTOR="$(paste -s -d'|' crates/ty_python_semantic/resources/primer/good.txt)"
echo "new commit" echo "new commit"

View file

@ -1394,33 +1394,6 @@ or `ImportError` at runtime.
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L822) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L822)
</details> </details>
## `possibly-unresolved-reference`
**Default level**: warn
<details>
<summary>detects references to possibly undefined names</summary>
### What it does
Checks for references to names that are possibly not defined.
### Why is this bad?
Using an undefined variable will raise a `NameError` at runtime.
### Example
```python
for i in range(0):
x = i
print(x) # NameError: name 'x' is not defined
```
### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20possibly-unresolved-reference)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L836)
</details>
## `redundant-cast` ## `redundant-cast`
**Default level**: warn **Default level**: warn
@ -1552,3 +1525,30 @@ a = 20 / 2
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Fsuppression.rs#L15) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Fsuppression.rs#L15)
</details> </details>
## `possibly-unresolved-reference`
**Default level**: ignore
<details>
<summary>detects references to possibly undefined names</summary>
### What it does
Checks for references to names that are possibly not defined.
### Why is this bad?
Using an undefined variable will raise a `NameError` at runtime.
### Example
```python
for i in range(0):
x = i
print(x) # NameError: name 'x' is not defined
```
### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20possibly-unresolved-reference)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L836)
</details>

View file

@ -369,12 +369,12 @@ fn configuration_rule_severity() -> anyhow::Result<()> {
for a in range(0, int(y)): for a in range(0, int(y)):
x = a x = a
print(x) # possibly-unresolved-reference prin(x) # unresolved-reference
"#, "#,
)?; )?;
// Assert that there's a possibly unresolved reference diagnostic // Assert that there's an `unresolved-reference` diagnostic (error)
// and that division-by-zero has a severity of error by default. // and a `division-by-zero` diagnostic (error).
assert_cmd_snapshot!(case.command(), @r" assert_cmd_snapshot!(case.command(), @r"
success: false success: false
exit_code: 1 exit_code: 1
@ -389,15 +389,15 @@ fn configuration_rule_severity() -> anyhow::Result<()> {
| |
info: `lint:division-by-zero` is enabled by default info: `lint:division-by-zero` is enabled by default
warning: lint:possibly-unresolved-reference: Name `x` used when possibly not defined warning: lint:unresolved-reference: Name `prin` used when not defined
--> test.py:7:7 --> test.py:7:1
| |
5 | x = a 5 | x = a
6 | 6 |
7 | print(x) # possibly-unresolved-reference 7 | prin(x) # unresolved-reference
| ^ | ^^^^
| |
info: `lint:possibly-unresolved-reference` is enabled by default info: `lint:unresolved-reference` is enabled by default
Found 2 diagnostics Found 2 diagnostics
@ -409,7 +409,7 @@ fn configuration_rule_severity() -> anyhow::Result<()> {
r#" r#"
[tool.ty.rules] [tool.ty.rules]
division-by-zero = "warn" # demote to warn division-by-zero = "warn" # demote to warn
possibly-unresolved-reference = "ignore" unresolved-reference = "ignore"
"#, "#,
)?; )?;
@ -448,12 +448,12 @@ fn cli_rule_severity() -> anyhow::Result<()> {
for a in range(0, int(y)): for a in range(0, int(y)):
x = a x = a
print(x) # possibly-unresolved-reference prin(x) # unresolved-reference
"#, "#,
)?; )?;
// Assert that there's a possibly unresolved reference diagnostic // Assert that there's an `unresolved-reference` diagnostic (error),
// and that division-by-zero has a severity of error by default. // a `division-by-zero` (error) and a unresolved-import (error) diagnostic by default.
assert_cmd_snapshot!(case.command(), @r" assert_cmd_snapshot!(case.command(), @r"
success: false success: false
exit_code: 1 exit_code: 1
@ -480,15 +480,15 @@ fn cli_rule_severity() -> anyhow::Result<()> {
| |
info: `lint:division-by-zero` is enabled by default info: `lint:division-by-zero` is enabled by default
warning: lint:possibly-unresolved-reference: Name `x` used when possibly not defined warning: lint:unresolved-reference: Name `prin` used when not defined
--> test.py:9:7 --> test.py:9:1
| |
7 | x = a 7 | x = a
8 | 8 |
9 | print(x) # possibly-unresolved-reference 9 | prin(x) # unresolved-reference
| ^ | ^^^^
| |
info: `lint:possibly-unresolved-reference` is enabled by default info: `lint:unresolved-reference` is enabled by default
Found 3 diagnostics Found 3 diagnostics
@ -499,7 +499,7 @@ fn cli_rule_severity() -> anyhow::Result<()> {
case case
.command() .command()
.arg("--ignore") .arg("--ignore")
.arg("possibly-unresolved-reference") .arg("unresolved-reference")
.arg("--warn") .arg("--warn")
.arg("division-by-zero") .arg("division-by-zero")
.arg("--warn") .arg("--warn")
@ -551,12 +551,12 @@ fn cli_rule_severity_precedence() -> anyhow::Result<()> {
for a in range(0, int(y)): for a in range(0, int(y)):
x = a x = a
print(x) # possibly-unresolved-reference prin(x) # unresolved-reference
"#, "#,
)?; )?;
// Assert that there's a possibly unresolved reference diagnostic // Assert that there's a `unresolved-reference` diagnostic (error)
// and that division-by-zero has a severity of error by default. // and a `division-by-zero` (error) by default.
assert_cmd_snapshot!(case.command(), @r" assert_cmd_snapshot!(case.command(), @r"
success: false success: false
exit_code: 1 exit_code: 1
@ -571,15 +571,15 @@ fn cli_rule_severity_precedence() -> anyhow::Result<()> {
| |
info: `lint:division-by-zero` is enabled by default info: `lint:division-by-zero` is enabled by default
warning: lint:possibly-unresolved-reference: Name `x` used when possibly not defined warning: lint:unresolved-reference: Name `prin` used when not defined
--> test.py:7:7 --> test.py:7:1
| |
5 | x = a 5 | x = a
6 | 6 |
7 | print(x) # possibly-unresolved-reference 7 | prin(x) # unresolved-reference
| ^ | ^^^^
| |
info: `lint:possibly-unresolved-reference` is enabled by default info: `lint:unresolved-reference` is enabled by default
Found 2 diagnostics Found 2 diagnostics
@ -590,12 +590,12 @@ fn cli_rule_severity_precedence() -> anyhow::Result<()> {
case case
.command() .command()
.arg("--error") .arg("--error")
.arg("possibly-unresolved-reference") .arg("unresolved-reference")
.arg("--warn") .arg("--warn")
.arg("division-by-zero") .arg("division-by-zero")
// Override the error severity with warning // Override the error severity with warning
.arg("--ignore") .arg("--ignore")
.arg("possibly-unresolved-reference"), .arg("unresolved-reference"),
@r" @r"
success: true success: true
exit_code: 0 exit_code: 0
@ -951,7 +951,7 @@ fn user_configuration() -> anyhow::Result<()> {
for a in range(0, int(y)): for a in range(0, int(y)):
x = a x = a
print(x) prin(x)
"#, "#,
), ),
])?; ])?;
@ -979,15 +979,15 @@ fn user_configuration() -> anyhow::Result<()> {
| |
info: `lint:division-by-zero` was selected in the configuration file info: `lint:division-by-zero` was selected in the configuration file
warning: lint:possibly-unresolved-reference: Name `x` used when possibly not defined warning: lint:unresolved-reference: Name `prin` used when not defined
--> main.py:7:7 --> main.py:7:1
| |
5 | x = a 5 | x = a
6 | 6 |
7 | print(x) 7 | prin(x)
| ^ | ^^^^
| |
info: `lint:possibly-unresolved-reference` is enabled by default info: `lint:unresolved-reference` is enabled by default
Found 2 diagnostics Found 2 diagnostics
@ -995,7 +995,7 @@ fn user_configuration() -> anyhow::Result<()> {
" "
); );
// The user-level configuration promotes `possibly-unresolved-reference` to an error. // The user-level configuration sets the severity for `unresolved-reference` to error.
// Changing the level for `division-by-zero` has no effect, because the project-level configuration // Changing the level for `division-by-zero` has no effect, because the project-level configuration
// has higher precedence. // has higher precedence.
case.write_file( case.write_file(
@ -1003,7 +1003,7 @@ fn user_configuration() -> anyhow::Result<()> {
r#" r#"
[rules] [rules]
division-by-zero = "error" division-by-zero = "error"
possibly-unresolved-reference = "error" unresolved-reference = "error"
"#, "#,
)?; )?;
@ -1023,15 +1023,15 @@ fn user_configuration() -> anyhow::Result<()> {
| |
info: `lint:division-by-zero` was selected in the configuration file info: `lint:division-by-zero` was selected in the configuration file
error: lint:possibly-unresolved-reference: Name `x` used when possibly not defined error: lint:unresolved-reference: Name `prin` used when not defined
--> main.py:7:7 --> main.py:7:1
| |
5 | x = a 5 | x = a
6 | 6 |
7 | print(x) 7 | prin(x)
| ^ | ^^^^
| |
info: `lint:possibly-unresolved-reference` was selected in the configuration file info: `lint:unresolved-reference` was selected in the configuration file
Found 2 diagnostics Found 2 diagnostics

View file

@ -59,7 +59,7 @@ info: revealed-type: Revealed type
``` ```
``` ```
warning: lint:possibly-unresolved-reference: Name `x` used when possibly not defined info: lint:possibly-unresolved-reference: Name `x` used when possibly not defined
--> src/mdtest_snippet.py:16:17 --> src/mdtest_snippet.py:16:17
| |
14 | # revealed: Unknown 14 | # revealed: Unknown

View file

@ -475,12 +475,26 @@ impl RuleSelection {
/// Creates a new rule selection from all known lints in the registry that are enabled /// Creates a new rule selection from all known lints in the registry that are enabled
/// according to their default severity. /// according to their default severity.
pub fn from_registry(registry: &LintRegistry) -> Self { pub fn from_registry(registry: &LintRegistry) -> Self {
Self::from_registry_with_default(registry, None)
}
/// Creates a new rule selection from all known lints in the registry, including lints that are default by default.
/// Lints that are disabled by default use the `default_severity`.
pub fn all(registry: &LintRegistry, default_severity: Severity) -> Self {
Self::from_registry_with_default(registry, Some(default_severity))
}
fn from_registry_with_default(
registry: &LintRegistry,
default_severity: Option<Severity>,
) -> Self {
let lints = registry let lints = registry
.lints() .lints()
.iter() .iter()
.filter_map(|lint| { .filter_map(|lint| {
Severity::try_from(lint.default_level()) Severity::try_from(lint.default_level())
.ok() .ok()
.or(default_severity)
.map(|severity| (*lint, (severity, LintSource::Default))) .map(|severity| (*lint, (severity, LintSource::Default)))
}) })
.collect(); .collect();

View file

@ -851,7 +851,7 @@ declare_lint! {
pub(crate) static POSSIBLY_UNRESOLVED_REFERENCE = { pub(crate) static POSSIBLY_UNRESOLVED_REFERENCE = {
summary: "detects references to possibly undefined names", summary: "detects references to possibly undefined names",
status: LintStatus::preview("1.0.0"), status: LintStatus::preview("1.0.0"),
default_level: Level::Warn, default_level: Level::Ignore,
} }
} }

View file

@ -1,4 +1,5 @@
use camino::{Utf8Component, Utf8PathBuf}; use camino::{Utf8Component, Utf8PathBuf};
use ruff_db::diagnostic::Severity;
use ruff_db::files::{File, Files}; use ruff_db::files::{File, Files};
use ruff_db::system::{ use ruff_db::system::{
CaseSensitivity, DbWithWritableSystem, InMemorySystem, OsSystem, System, SystemPath, CaseSensitivity, DbWithWritableSystem, InMemorySystem, OsSystem, System, SystemPath,
@ -25,7 +26,7 @@ pub(crate) struct Db {
impl Db { impl Db {
pub(crate) fn setup() -> Self { pub(crate) fn setup() -> Self {
let rule_selection = RuleSelection::from_registry(default_lint_registry()); let rule_selection = RuleSelection::all(default_lint_registry(), Severity::Info);
Self { Self {
system: MdtestSystem::in_memory(), system: MdtestSystem::in_memory(),

View file

@ -653,7 +653,7 @@
"possibly-unresolved-reference": { "possibly-unresolved-reference": {
"title": "detects references to possibly undefined names", "title": "detects references to possibly undefined names",
"description": "## What it does\nChecks for references to names that are possibly not defined.\n\n## Why is this bad?\nUsing an undefined variable will raise a `NameError` at runtime.\n\n## Example\n\n```python\nfor i in range(0):\n x = i\n\nprint(x) # NameError: name 'x' is not defined\n```", "description": "## What it does\nChecks for references to names that are possibly not defined.\n\n## Why is this bad?\nUsing an undefined variable will raise a `NameError` at runtime.\n\n## Example\n\n```python\nfor i in range(0):\n x = i\n\nprint(x) # NameError: name 'x' is not defined\n```",
"default": "warn", "default": "ignore",
"oneOf": [ "oneOf": [
{ {
"$ref": "#/definitions/Level" "$ref": "#/definitions/Level"