From 360b033e045a94bee720d1b483b04494747ea6c2 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Sun, 11 Dec 2022 10:04:06 -0500 Subject: [PATCH] Avoid F821 false positive on annotated global (#1196) --- resources/test/fixtures/pyflakes/F821_6.py | 17 +++++++++++++++++ src/check_ast.rs | 17 +++++++++++++++-- src/pyflakes/mod.rs | 1 + .../ruff__pyflakes__tests__F821_F821_6.py.snap | 6 ++++++ 4 files changed, 39 insertions(+), 2 deletions(-) create mode 100644 resources/test/fixtures/pyflakes/F821_6.py create mode 100644 src/pyflakes/snapshots/ruff__pyflakes__tests__F821_F821_6.py.snap diff --git a/resources/test/fixtures/pyflakes/F821_6.py b/resources/test/fixtures/pyflakes/F821_6.py new file mode 100644 index 0000000000..672fee6450 --- /dev/null +++ b/resources/test/fixtures/pyflakes/F821_6.py @@ -0,0 +1,17 @@ +"""Test: annotated global.""" + + +n: int + + +def f(): + print(n) + + +def g(): + global n + n = 1 + + +g() +f() diff --git a/src/check_ast.rs b/src/check_ast.rs index 48afebedb0..2710f5e939 100644 --- a/src/check_ast.rs +++ b/src/check_ast.rs @@ -1155,7 +1155,13 @@ where // If any global bindings don't already exist in the global scope, add it. let globals = operations::extract_globals(body); for (name, stmt) in operations::extract_globals(body) { - if !self.scopes[GLOBAL_SCOPE_INDEX].values.contains_key(name) { + if self.scopes[GLOBAL_SCOPE_INDEX] + .values + .get(name) + .map_or(true, |index| { + matches!(self.bindings[*index].kind, BindingKind::Annotation) + }) + { let index = self.bindings.len(); self.bindings.push(Binding { kind: BindingKind::Assignment, @@ -1207,7 +1213,13 @@ where // If any global bindings don't already exist in the global scope, add it. let globals = operations::extract_globals(body); for (name, stmt) in &globals { - if !self.scopes[GLOBAL_SCOPE_INDEX].values.contains_key(name) { + if self.scopes[GLOBAL_SCOPE_INDEX] + .values + .get(name) + .map_or(true, |index| { + matches!(self.bindings[*index].kind, BindingKind::Annotation) + }) + { let index = self.bindings.len(); self.bindings.push(Binding { kind: BindingKind::Assignment, @@ -2717,6 +2729,7 @@ impl<'a> Checker<'a> { let mut first_iter = true; let mut in_generator = false; let mut import_starred = false; + for scope_index in self.scope_stack.iter().rev() { let scope = &self.scopes[*scope_index]; diff --git a/src/pyflakes/mod.rs b/src/pyflakes/mod.rs index 77b1f66dcf..b806cfbefd 100644 --- a/src/pyflakes/mod.rs +++ b/src/pyflakes/mod.rs @@ -93,6 +93,7 @@ mod tests { #[test_case(CheckCode::F821, Path::new("F821_3.py"); "F821_3")] #[test_case(CheckCode::F821, Path::new("F821_4.py"); "F821_4")] #[test_case(CheckCode::F821, Path::new("F821_5.py"); "F821_5")] + #[test_case(CheckCode::F821, Path::new("F821_6.py"); "F821_6")] #[test_case(CheckCode::F822, Path::new("F822.py"); "F822")] #[test_case(CheckCode::F823, Path::new("F823.py"); "F823")] #[test_case(CheckCode::F831, Path::new("F831.py"); "F831")] diff --git a/src/pyflakes/snapshots/ruff__pyflakes__tests__F821_F821_6.py.snap b/src/pyflakes/snapshots/ruff__pyflakes__tests__F821_F821_6.py.snap new file mode 100644 index 0000000000..43ccad66f9 --- /dev/null +++ b/src/pyflakes/snapshots/ruff__pyflakes__tests__F821_F821_6.py.snap @@ -0,0 +1,6 @@ +--- +source: src/pyflakes/mod.rs +expression: checks +--- +[] +