Skip to content

Commit 693f957

Browse files
authored
[pylint] - implement global-at-module-level (W0604) (#8058)
## Summary Implements [`global-at-module-level`/`W0604`](https://pylint.pycqa.org/en/latest/user_guide/messages/warning/global-at-module-level.html) See #970 ## Test Plan `cargo test` and manually
1 parent a85ed30 commit 693f957

File tree

8 files changed

+73
-0
lines changed

8 files changed

+73
-0
lines changed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
global price # W0604
2+
3+
price = 25
4+
5+
if True:
6+
global X # W0604
7+
8+
def no_error():
9+
global price
10+
price = 30

crates/ruff_linter/src/checkers/ast/analyze/statement.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ use crate::settings::types::PythonVersion;
2121
pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
2222
match stmt {
2323
Stmt::Global(ast::StmtGlobal { names, range: _ }) => {
24+
if checker.enabled(Rule::GlobalAtModuleLevel) {
25+
pylint::rules::global_at_module_level(checker, stmt);
26+
}
2427
if checker.enabled(Rule::AmbiguousVariableName) {
2528
checker.diagnostics.extend(names.iter().filter_map(|name| {
2629
pycodestyle::rules::ambiguous_variable_name(name, name.range())

crates/ruff_linter/src/codes.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
264264
(Pylint, "W0131") => (RuleGroup::Stable, rules::pylint::rules::NamedExprWithoutContext),
265265
(Pylint, "W0406") => (RuleGroup::Stable, rules::pylint::rules::ImportSelf),
266266
(Pylint, "W0602") => (RuleGroup::Stable, rules::pylint::rules::GlobalVariableNotAssigned),
267+
(Pylint, "W0604") => (RuleGroup::Preview, rules::pylint::rules::GlobalAtModuleLevel),
267268
(Pylint, "W0603") => (RuleGroup::Stable, rules::pylint::rules::GlobalStatement),
268269
(Pylint, "W0711") => (RuleGroup::Stable, rules::pylint::rules::BinaryOpException),
269270
(Pylint, "W1508") => (RuleGroup::Stable, rules::pylint::rules::InvalidEnvvarDefault),

crates/ruff_linter/src/rules/pylint/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ mod tests {
138138
#[test_case(Rule::NoSelfUse, Path::new("no_self_use.py"))]
139139
#[test_case(Rule::MisplacedBareRaise, Path::new("misplaced_bare_raise.py"))]
140140
#[test_case(Rule::LiteralMembership, Path::new("literal_membership.py"))]
141+
#[test_case(Rule::GlobalAtModuleLevel, Path::new("global_at_module_level.py"))]
141142
fn rules(rule_code: Rule, path: &Path) -> Result<()> {
142143
let snapshot = format!("{}_{}", rule_code.noqa_code(), path.to_string_lossy());
143144
let diagnostics = test_path(
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
use ruff_diagnostics::{Diagnostic, Violation};
2+
use ruff_macros::{derive_message_formats, violation};
3+
use ruff_python_ast::Stmt;
4+
use ruff_text_size::Ranged;
5+
6+
use crate::checkers::ast::Checker;
7+
8+
/// ## What it does
9+
/// Checks for uses of the `global` keyword at the module level.
10+
///
11+
/// ## Why is this bad?
12+
/// The `global` keyword is used within functions to indicate that a name
13+
/// refers to a global variable, rather than a local variable.
14+
///
15+
/// At the module level, all names are global by default, so the `global`
16+
/// keyword is redundant.
17+
#[violation]
18+
pub struct GlobalAtModuleLevel;
19+
20+
impl Violation for GlobalAtModuleLevel {
21+
#[derive_message_formats]
22+
fn message(&self) -> String {
23+
format!("`global` at module level is redundant")
24+
}
25+
}
26+
27+
/// PLW0604
28+
pub(crate) fn global_at_module_level(checker: &mut Checker, stmt: &Stmt) {
29+
if checker.semantic().current_scope().kind.is_module() {
30+
checker
31+
.diagnostics
32+
.push(Diagnostic::new(GlobalAtModuleLevel, stmt.range()));
33+
}
34+
}

crates/ruff_linter/src/rules/pylint/rules/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ pub(crate) use comparison_with_itself::*;
1414
pub(crate) use continue_in_finally::*;
1515
pub(crate) use duplicate_bases::*;
1616
pub(crate) use eq_without_hash::*;
17+
pub(crate) use global_at_module_level::*;
1718
pub(crate) use global_statement::*;
1819
pub(crate) use global_variable_not_assigned::*;
1920
pub(crate) use import_self::*;
@@ -78,6 +79,7 @@ mod comparison_with_itself;
7879
mod continue_in_finally;
7980
mod duplicate_bases;
8081
mod eq_without_hash;
82+
mod global_at_module_level;
8183
mod global_statement;
8284
mod global_variable_not_assigned;
8385
mod import_self;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
---
2+
source: crates/ruff_linter/src/rules/pylint/mod.rs
3+
---
4+
global_at_module_level.py:1:1: PLW0604 `global` at module level is redundant
5+
|
6+
1 | global price # W0604
7+
| ^^^^^^^^^^^^ PLW0604
8+
2 |
9+
3 | price = 25
10+
|
11+
12+
global_at_module_level.py:6:5: PLW0604 `global` at module level is redundant
13+
|
14+
5 | if True:
15+
6 | global X # W0604
16+
| ^^^^^^^^ PLW0604
17+
7 |
18+
8 | def no_error():
19+
|
20+
21+

ruff.schema.json

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)