mirror of https://github.com/astral-sh/ruff
Treat bare function annotations as locals per PEP 526 (F821)
This commit is contained in:
parent
416e2267da
commit
321499ef62
|
|
@ -0,0 +1,27 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing import Callable
|
||||||
|
|
||||||
|
|
||||||
|
def demonstrate_bare_local_annotation():
|
||||||
|
x: int
|
||||||
|
print(x)
|
||||||
|
|
||||||
|
demonstrate_bare_local_annotation()
|
||||||
|
|
||||||
|
|
||||||
|
def make_closure_pair() -> tuple[Callable[[], int], Callable[[int], None]]:
|
||||||
|
x: int
|
||||||
|
|
||||||
|
def get_value() -> int:
|
||||||
|
return x
|
||||||
|
|
||||||
|
def set_value(new_value: int) -> None:
|
||||||
|
nonlocal x
|
||||||
|
x = new_value
|
||||||
|
|
||||||
|
return get_value, set_value
|
||||||
|
|
||||||
|
get_value, set_value = make_closure_pair()
|
||||||
|
set_value(123)
|
||||||
|
print(get_value())
|
||||||
|
|
@ -167,6 +167,7 @@ mod tests {
|
||||||
#[test_case(Rule::UndefinedName, Path::new("F821_31.py"))]
|
#[test_case(Rule::UndefinedName, Path::new("F821_31.py"))]
|
||||||
#[test_case(Rule::UndefinedName, Path::new("F821_32.pyi"))]
|
#[test_case(Rule::UndefinedName, Path::new("F821_32.pyi"))]
|
||||||
#[test_case(Rule::UndefinedName, Path::new("F821_33.py"))]
|
#[test_case(Rule::UndefinedName, Path::new("F821_33.py"))]
|
||||||
|
#[test_case(Rule::UndefinedName, Path::new("F821_34.py"))]
|
||||||
#[test_case(Rule::UndefinedExport, Path::new("F822_0.py"))]
|
#[test_case(Rule::UndefinedExport, Path::new("F822_0.py"))]
|
||||||
#[test_case(Rule::UndefinedExport, Path::new("F822_0.pyi"))]
|
#[test_case(Rule::UndefinedExport, Path::new("F822_0.pyi"))]
|
||||||
#[test_case(Rule::UndefinedExport, Path::new("F822_1.py"))]
|
#[test_case(Rule::UndefinedExport, Path::new("F822_1.py"))]
|
||||||
|
|
@ -3663,7 +3664,7 @@ lambda: fu
|
||||||
name: str
|
name: str
|
||||||
print(name)
|
print(name)
|
||||||
",
|
",
|
||||||
&[Rule::UndefinedName],
|
&[],
|
||||||
);
|
);
|
||||||
flakes(
|
flakes(
|
||||||
r"
|
r"
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff_linter/src/rules/pyflakes/mod.rs
|
||||||
|
---
|
||||||
|
|
||||||
|
|
@ -475,9 +475,19 @@ impl<'a> SemanticModel<'a> {
|
||||||
// The `name` in `print(name)` should be treated as unresolved, but the `name` in
|
// The `name` in `print(name)` should be treated as unresolved, but the `name` in
|
||||||
// `name: str` should be treated as used.
|
// `name: str` should be treated as used.
|
||||||
//
|
//
|
||||||
// Stub files are an exception. In a stub file, it _is_ considered valid to
|
// There are two exceptions to this rule:
|
||||||
// resolve to a type annotation.
|
// 1. Stub files. In a stub file, it _is_ considered valid to resolve to a
|
||||||
BindingKind::Annotation if !self.in_stub_file() => continue,
|
// type annotation.
|
||||||
|
// 2. Bare annotations inside functions. Per PEP 526, these create local
|
||||||
|
// variables.
|
||||||
|
BindingKind::Annotation
|
||||||
|
if !self.in_stub_file()
|
||||||
|
&& !self.scopes[self.bindings[binding_id].scope]
|
||||||
|
.kind
|
||||||
|
.is_function() =>
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// If it's a deletion, don't treat it as resolved, since the name is now
|
// If it's a deletion, don't treat it as resolved, since the name is now
|
||||||
// unbound. For example, given:
|
// unbound. For example, given:
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue