Ignore globals when checking local variable names (#800)

This commit is contained in:
Charlie Marsh 2022-11-17 17:19:01 -05:00 committed by GitHub
parent 801c76037f
commit 66ae4db6cd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 42 additions and 35 deletions

View file

@ -1,8 +1,12 @@
import collections import collections
from collections import namedtuple from collections import namedtuple
GLOBAL: str = "foo"
def f(): def f():
global GLOBAL
GLOBAL = "bar"
lower = 0 lower = 0
Camel = 0 Camel = 0
CONSTANT = 0 CONSTANT = 0

View file

@ -79,8 +79,10 @@ pub enum BindingKind {
Annotation, Annotation,
Argument, Argument,
Assignment, Assignment,
// TODO(charlie): This seems to be a catch-all.
Binding, Binding,
LoopVar, LoopVar,
Global,
Builtin, Builtin,
ClassDefinition, ClassDefinition,
Definition, Definition,

View file

@ -19,8 +19,7 @@ use crate::ast::helpers::{
use crate::ast::operations::extract_all_names; use crate::ast::operations::extract_all_names;
use crate::ast::relocate::relocate_expr; use crate::ast::relocate::relocate_expr;
use crate::ast::types::{ use crate::ast::types::{
Binding, BindingContext, BindingKind, ClassScope, FunctionScope, ImportKind, Range, Scope, Binding, BindingContext, BindingKind, ClassScope, ImportKind, Range, Scope, ScopeKind,
ScopeKind,
}; };
use crate::ast::visitor::{walk_excepthandler, Visitor}; use crate::ast::visitor::{walk_excepthandler, Visitor};
use crate::ast::{helpers, operations, visitor}; use crate::ast::{helpers, operations, visitor};
@ -216,23 +215,20 @@ where
match &stmt.node { match &stmt.node {
StmtKind::Global { names } | StmtKind::Nonlocal { names } => { StmtKind::Global { names } | StmtKind::Nonlocal { names } => {
let global_scope_id = self.scopes[GLOBAL_SCOPE_INDEX].id; let global_scope_id = self.scopes[GLOBAL_SCOPE_INDEX].id;
let scope =
let current_scope = self.current_scope(); &mut self.scopes[*(self.scope_stack.last().expect("No current scope found."))];
let current_scope_id = current_scope.id; if scope.id != global_scope_id {
if current_scope_id != global_scope_id {
for name in names { for name in names {
for scope in self.scopes.iter_mut().skip(GLOBAL_SCOPE_INDEX + 1) {
scope.values.insert( scope.values.insert(
name, name,
Binding { Binding {
kind: BindingKind::Assignment, kind: BindingKind::Global,
used: Some((global_scope_id, Range::from_located(stmt))), used: Some((global_scope_id, Range::from_located(stmt))),
range: Range::from_located(stmt), range: Range::from_located(stmt),
}, },
); );
} }
} }
}
if self.settings.enabled.contains(&CheckCode::E741) { if self.settings.enabled.contains(&CheckCode::E741) {
let location = Range::from_located(stmt); let location = Range::from_located(stmt);
@ -732,10 +728,8 @@ where
)); ));
} }
let scope = &mut self.scopes[*(self let scope = &mut self.scopes
.scope_stack [*(self.scope_stack.last().expect("No current scope found."))];
.last_mut()
.expect("No current scope found."))];
scope.import_starred = true; scope.import_starred = true;
} else { } else {
if let Some(asname) = &alias.node.asname { if let Some(asname) = &alias.node.asname {
@ -1452,15 +1446,10 @@ where
if let ExprKind::Name { id, ctx } = &func.node { if let ExprKind::Name { id, ctx } = &func.node {
if id == "locals" && matches!(ctx, ExprContext::Load) { if id == "locals" && matches!(ctx, ExprContext::Load) {
let scope = &mut self.scopes[*(self let scope = &mut self.scopes
.scope_stack [*(self.scope_stack.last().expect("No current scope found."))];
.last_mut() if let ScopeKind::Function(inner) = &mut scope.kind {
.expect("No current scope found."))]; inner.uses_locals = true;
if matches!(
scope.kind,
ScopeKind::Function(FunctionScope { uses_locals: false })
) {
scope.kind = ScopeKind::Function(FunctionScope { uses_locals: true });
} }
} }
} }
@ -2243,9 +2232,18 @@ impl<'a> Checker<'a> {
if self.settings.enabled.contains(&CheckCode::N806) { if self.settings.enabled.contains(&CheckCode::N806) {
if matches!(self.current_scope().kind, ScopeKind::Function(..)) { if matches!(self.current_scope().kind, ScopeKind::Function(..)) {
// Ignore globals.
if !self
.current_scope()
.values
.get(id)
.map(|binding| matches!(binding.kind, BindingKind::Global))
.unwrap_or(false)
{
pep8_naming::plugins::non_lowercase_variable_in_function(self, expr, parent, id) pep8_naming::plugins::non_lowercase_variable_in_function(self, expr, parent, id)
} }
} }
}
if self.settings.enabled.contains(&CheckCode::N815) { if self.settings.enabled.contains(&CheckCode::N815) {
if matches!(self.current_scope().kind, ScopeKind::Class(..)) { if matches!(self.current_scope().kind, ScopeKind::Class(..)) {

View file

@ -55,7 +55,10 @@ pub fn unused_variables(scope: &Scope, dummy_variable_rgx: &Regex) -> Vec<Check>
if matches!( if matches!(
scope.kind, scope.kind,
ScopeKind::Function(FunctionScope { uses_locals: true }) ScopeKind::Function(FunctionScope {
uses_locals: true,
..
})
) { ) {
return checks; return checks;
} }

View file

@ -5,19 +5,19 @@ expression: checks
- kind: - kind:
NonLowercaseVariableInFunction: Camel NonLowercaseVariableInFunction: Camel
location: location:
row: 7 row: 11
column: 4 column: 4
end_location: end_location:
row: 7 row: 11
column: 9 column: 9
fix: ~ fix: ~
- kind: - kind:
NonLowercaseVariableInFunction: CONSTANT NonLowercaseVariableInFunction: CONSTANT
location: location:
row: 8 row: 12
column: 4 column: 4
end_location: end_location:
row: 8 row: 12
column: 12 column: 12
fix: ~ fix: ~