mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-15 16:10:38 +00:00
Improve handling of __qualname__
, __module__
, and __class__
(#4512)
This commit is contained in:
parent
9e21414294
commit
6aa9900c03
3 changed files with 75 additions and 8 deletions
|
@ -4841,13 +4841,6 @@ impl<'a> Checker<'a> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allow "__module__" and "__qualname__" in class scopes.
|
|
||||||
if (id == "__module__" || id == "__qualname__")
|
|
||||||
&& matches!(self.ctx.scope().kind, ScopeKind::Class(..))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Avoid flagging if `NameError` is handled.
|
// Avoid flagging if `NameError` is handled.
|
||||||
if self
|
if self
|
||||||
.ctx
|
.ctx
|
||||||
|
|
|
@ -473,6 +473,16 @@ mod tests {
|
||||||
"#,
|
"#,
|
||||||
&[Rule::UndefinedName],
|
&[Rule::UndefinedName],
|
||||||
);
|
);
|
||||||
|
flakes(
|
||||||
|
r#"
|
||||||
|
def f():
|
||||||
|
__qualname__ = 1
|
||||||
|
|
||||||
|
class Foo:
|
||||||
|
__qualname__
|
||||||
|
"#,
|
||||||
|
&[Rule::UnusedVariable],
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -1151,6 +1161,40 @@ mod tests {
|
||||||
"#,
|
"#,
|
||||||
&[],
|
&[],
|
||||||
);
|
);
|
||||||
|
flakes(
|
||||||
|
r#"
|
||||||
|
class Test(object):
|
||||||
|
print(__class__.__name__)
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.x = 1
|
||||||
|
|
||||||
|
t = Test()
|
||||||
|
"#,
|
||||||
|
&[Rule::UndefinedName],
|
||||||
|
);
|
||||||
|
flakes(
|
||||||
|
r#"
|
||||||
|
class Test(object):
|
||||||
|
X = [__class__ for _ in range(10)]
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.x = 1
|
||||||
|
|
||||||
|
t = Test()
|
||||||
|
"#,
|
||||||
|
&[Rule::UndefinedName],
|
||||||
|
);
|
||||||
|
flakes(
|
||||||
|
r#"
|
||||||
|
def f(self):
|
||||||
|
print(__class__.__name__)
|
||||||
|
self.x = 1
|
||||||
|
|
||||||
|
f()
|
||||||
|
"#,
|
||||||
|
&[Rule::UndefinedName],
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// See: <https://github.com/PyCQA/pyflakes/blob/04ecb0c324ef3b61124e2f80f9e1af6c3a4c7b26/pyflakes/test/test_imports.py>
|
/// See: <https://github.com/PyCQA/pyflakes/blob/04ecb0c324ef3b61124e2f80f9e1af6c3a4c7b26/pyflakes/test/test_imports.py>
|
||||||
|
|
|
@ -126,11 +126,19 @@ impl<'a> Context<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut seen_function = false;
|
||||||
let mut import_starred = false;
|
let mut import_starred = false;
|
||||||
for (index, scope_id) in self.scopes.ancestor_ids(self.scope_id).enumerate() {
|
for (index, scope_id) in self.scopes.ancestor_ids(self.scope_id).enumerate() {
|
||||||
let scope = &self.scopes[scope_id];
|
let scope = &self.scopes[scope_id];
|
||||||
if scope.kind.is_class() {
|
if scope.kind.is_class() {
|
||||||
if symbol == "__class__" {
|
// Allow usages of `__class__` within methods, e.g.:
|
||||||
|
//
|
||||||
|
// ```python
|
||||||
|
// class Foo:
|
||||||
|
// def __init__(self):
|
||||||
|
// print(__class__)
|
||||||
|
// ```
|
||||||
|
if seen_function && matches!(symbol, "__class__") {
|
||||||
return ResolvedReference::ImplicitGlobal;
|
return ResolvedReference::ImplicitGlobal;
|
||||||
}
|
}
|
||||||
if index > 0 {
|
if index > 0 {
|
||||||
|
@ -162,6 +170,28 @@ impl<'a> Context<'a> {
|
||||||
return ResolvedReference::Resolved(scope_id, *binding_id);
|
return ResolvedReference::Resolved(scope_id, *binding_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Allow usages of `__module__` and `__qualname__` within class scopes, e.g.:
|
||||||
|
//
|
||||||
|
// ```python
|
||||||
|
// class Foo:
|
||||||
|
// print(__qualname__)
|
||||||
|
// ```
|
||||||
|
//
|
||||||
|
// Intentionally defer this check to _after_ the standard `scope.get` logic, so that
|
||||||
|
// we properly attribute reads to overridden class members, e.g.:
|
||||||
|
//
|
||||||
|
// ```python
|
||||||
|
// class Foo:
|
||||||
|
// __qualname__ = "Bar"
|
||||||
|
// print(__qualname__)
|
||||||
|
// ```
|
||||||
|
if index == 0 && scope.kind.is_class() {
|
||||||
|
if matches!(symbol, "__module__" | "__qualname__") {
|
||||||
|
return ResolvedReference::ImplicitGlobal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
seen_function |= scope.kind.is_function();
|
||||||
import_starred = import_starred || scope.uses_star_imports();
|
import_starred = import_starred || scope.uses_star_imports();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue