[syntax-errors] Store to or delete __debug__ (#16984)

Summary
--

Detect setting or deleting `__debug__`. Assigning to `__debug__` was a
`SyntaxError` on the earliest version I tested (3.8). Deleting
`__debug__` was made a `SyntaxError` in [BPO 45000], which said it was
resolved in Python 3.10. However, `del __debug__` was also a runtime
error (`NameError`) when I tested in Python 3.9.6, so I thought it was
worth including 3.9 in this check.

I don't think it was ever a *good* idea to try `del __debug__`, so I
think there's also an argument for not making this version-dependent at
all. That would only simplify the implementation very slightly, though.

[BPO 45000]: https://github.com/python/cpython/issues/89163

Test Plan
--

New inline tests. This also required adding a `PythonVersion` field to
the `TestContext` that could be taken from the inline `ParseOptions` and
making the version field on the options accessible.
This commit is contained in:
Brent Westbrook 2025-03-29 12:07:20 -04:00 committed by GitHub
parent 8396d7cd63
commit a0819f0c51
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
28 changed files with 1372 additions and 7 deletions

View file

@ -551,6 +551,7 @@ impl SemanticSyntaxContext for Checker<'_> {
| SemanticSyntaxErrorKind::DuplicateTypeParameter | SemanticSyntaxErrorKind::DuplicateTypeParameter
| SemanticSyntaxErrorKind::MultipleCaseAssignment(_) | SemanticSyntaxErrorKind::MultipleCaseAssignment(_)
| SemanticSyntaxErrorKind::IrrefutableCasePattern(_) | SemanticSyntaxErrorKind::IrrefutableCasePattern(_)
| SemanticSyntaxErrorKind::WriteToDebug(_)
if self.settings.preview.is_enabled() => if self.settings.preview.is_enabled() =>
{ {
self.semantic_errors.borrow_mut().push(error); self.semantic_errors.borrow_mut().push(error);
@ -558,7 +559,8 @@ impl SemanticSyntaxContext for Checker<'_> {
SemanticSyntaxErrorKind::ReboundComprehensionVariable SemanticSyntaxErrorKind::ReboundComprehensionVariable
| SemanticSyntaxErrorKind::DuplicateTypeParameter | SemanticSyntaxErrorKind::DuplicateTypeParameter
| SemanticSyntaxErrorKind::MultipleCaseAssignment(_) | SemanticSyntaxErrorKind::MultipleCaseAssignment(_)
| SemanticSyntaxErrorKind::IrrefutableCasePattern(_) => {} | SemanticSyntaxErrorKind::IrrefutableCasePattern(_)
| SemanticSyntaxErrorKind::WriteToDebug(_) => {}
} }
} }
} }

View file

@ -0,0 +1,2 @@
class __debug__: ... # class name
class C[__debug__]: ... # type parameter name

View file

@ -0,0 +1,3 @@
def __debug__(): ... # function name
def f[__debug__](): ... # type parameter name
def f(__debug__): ... # parameter name

View file

@ -0,0 +1,4 @@
import __debug__
import debug as __debug__
from x import __debug__
from x import debug as __debug__

View file

@ -0,0 +1,2 @@
match x:
case __debug__: ...

View file

@ -0,0 +1,2 @@
try: ...
except Exception as __debug__: ...

View file

@ -0,0 +1,2 @@
type __debug__ = list[int] # visited as an Expr but still flagged
type Debug[__debug__] = str

View file

@ -0,0 +1 @@
with open("foo.txt") as __debug__: ...

View file

@ -0,0 +1,2 @@
# parse_options: {"target-version": "3.9"}
del __debug__

View file

@ -0,0 +1,4 @@
del __debug__
del x, y, __debug__, z
__debug__ = 1
x, y, __debug__, z = 1, 2, 3, 4

View file

@ -0,0 +1,3 @@
import __debug__ as debug
from __debug__ import Some
from x import __debug__ as debug

View file

@ -0,0 +1,2 @@
# parse_options: {"target-version": "3.8"}
del __debug__

View file

@ -0,0 +1,2 @@
if __debug__: ...
x = __debug__

View file

@ -34,6 +34,10 @@ impl ParseOptions {
self.target_version = target_version; self.target_version = target_version;
self self
} }
pub fn target_version(&self) -> PythonVersion {
self.target_version
}
} }
impl From<Mode> for ParseOptions { impl From<Mode> for ParseOptions {

View file

@ -9,7 +9,8 @@ use std::fmt::Display;
use ruff_python_ast::{ use ruff_python_ast::{
self as ast, self as ast,
visitor::{walk_expr, Visitor}, visitor::{walk_expr, Visitor},
Expr, IrrefutablePatternKind, Pattern, PythonVersion, Stmt, StmtExpr, StmtImportFrom, Expr, ExprContext, IrrefutablePatternKind, Pattern, PythonVersion, Stmt, StmtExpr,
StmtImportFrom,
}; };
use ruff_text_size::{Ranged, TextRange}; use ruff_text_size::{Ranged, TextRange};
use rustc_hash::FxHashSet; use rustc_hash::FxHashSet;
@ -74,6 +75,105 @@ impl SemanticSyntaxChecker {
} }
_ => {} _ => {}
} }
Self::debug_shadowing(stmt, ctx);
}
/// Check for [`SemanticSyntaxErrorKind::WriteToDebug`] in `stmt`.
fn debug_shadowing<Ctx: SemanticSyntaxContext>(stmt: &ast::Stmt, ctx: &Ctx) {
match stmt {
Stmt::FunctionDef(ast::StmtFunctionDef {
name,
type_params,
parameters,
..
}) => {
// test_err debug_shadow_function
// def __debug__(): ... # function name
// def f[__debug__](): ... # type parameter name
// def f(__debug__): ... # parameter name
Self::check_identifier(name, ctx);
if let Some(type_params) = type_params {
for type_param in type_params.iter() {
Self::check_identifier(type_param.name(), ctx);
}
}
for parameter in parameters {
Self::check_identifier(parameter.name(), ctx);
}
}
Stmt::ClassDef(ast::StmtClassDef {
name, type_params, ..
}) => {
// test_err debug_shadow_class
// class __debug__: ... # class name
// class C[__debug__]: ... # type parameter name
Self::check_identifier(name, ctx);
if let Some(type_params) = type_params {
for type_param in type_params.iter() {
Self::check_identifier(type_param.name(), ctx);
}
}
}
Stmt::TypeAlias(ast::StmtTypeAlias {
type_params: Some(type_params),
..
}) => {
// test_err debug_shadow_type_alias
// type __debug__ = list[int] # visited as an Expr but still flagged
// type Debug[__debug__] = str
for type_param in type_params.iter() {
Self::check_identifier(type_param.name(), ctx);
}
}
Stmt::Import(ast::StmtImport { names, .. })
| Stmt::ImportFrom(ast::StmtImportFrom { names, .. }) => {
// test_err debug_shadow_import
// import __debug__
// import debug as __debug__
// from x import __debug__
// from x import debug as __debug__
// test_ok debug_rename_import
// import __debug__ as debug
// from __debug__ import Some
// from x import __debug__ as debug
for name in names {
match &name.asname {
Some(asname) => Self::check_identifier(asname, ctx),
None => Self::check_identifier(&name.name, ctx),
}
}
}
Stmt::Try(ast::StmtTry { handlers, .. }) => {
// test_err debug_shadow_try
// try: ...
// except Exception as __debug__: ...
for handler in handlers
.iter()
.filter_map(ast::ExceptHandler::as_except_handler)
{
if let Some(name) = &handler.name {
Self::check_identifier(name, ctx);
}
}
}
// test_err debug_shadow_with
// with open("foo.txt") as __debug__: ...
_ => {}
}
}
/// Check if `ident` is equal to `__debug__` and emit a
/// [`SemanticSyntaxErrorKind::WriteToDebug`] if so.
fn check_identifier<Ctx: SemanticSyntaxContext>(ident: &ast::Identifier, ctx: &Ctx) {
if ident.id == "__debug__" {
Self::add_error(
ctx,
SemanticSyntaxErrorKind::WriteToDebug(WriteToDebugKind::Store),
ident.range,
);
}
} }
fn duplicate_type_parameter_name<Ctx: SemanticSyntaxContext>( fn duplicate_type_parameter_name<Ctx: SemanticSyntaxContext>(
@ -207,6 +307,51 @@ impl SemanticSyntaxChecker {
Self::check_generator_expr(key, generators, ctx); Self::check_generator_expr(key, generators, ctx);
Self::check_generator_expr(value, generators, ctx); Self::check_generator_expr(value, generators, ctx);
} }
Expr::Name(ast::ExprName {
range,
id,
ctx: expr_ctx,
}) => {
// test_err write_to_debug_expr
// del __debug__
// del x, y, __debug__, z
// __debug__ = 1
// x, y, __debug__, z = 1, 2, 3, 4
// test_err del_debug_py39
// # parse_options: {"target-version": "3.9"}
// del __debug__
// test_ok del_debug_py38
// # parse_options: {"target-version": "3.8"}
// del __debug__
// test_ok read_from_debug
// if __debug__: ...
// x = __debug__
if id == "__debug__" {
match expr_ctx {
ExprContext::Store => Self::add_error(
ctx,
SemanticSyntaxErrorKind::WriteToDebug(WriteToDebugKind::Store),
*range,
),
ExprContext::Del => {
let version = ctx.python_version();
if version >= PythonVersion::PY39 {
Self::add_error(
ctx,
SemanticSyntaxErrorKind::WriteToDebug(
WriteToDebugKind::Delete(version),
),
*range,
);
}
}
_ => {}
};
}
}
_ => {} _ => {}
} }
} }
@ -292,6 +437,12 @@ impl Display for SemanticSyntaxError {
f.write_str("wildcard makes remaining patterns unreachable") f.write_str("wildcard makes remaining patterns unreachable")
} }
}, },
SemanticSyntaxErrorKind::WriteToDebug(kind) => match kind {
WriteToDebugKind::Store => f.write_str("cannot assign to `__debug__`"),
WriteToDebugKind::Delete(python_version) => {
write!(f, "cannot delete `__debug__` on Python {python_version} (syntax was removed in 3.9)")
}
},
} }
} }
} }
@ -370,6 +521,30 @@ pub enum SemanticSyntaxErrorKind {
/// ///
/// [Python reference]: https://docs.python.org/3/reference/compound_stmts.html#irrefutable-case-blocks /// [Python reference]: https://docs.python.org/3/reference/compound_stmts.html#irrefutable-case-blocks
IrrefutableCasePattern(IrrefutablePatternKind), IrrefutableCasePattern(IrrefutablePatternKind),
/// Represents a write to `__debug__`. This includes simple assignments and deletions as well
/// other kinds of statements that can introduce bindings, such as type parameters in functions,
/// classes, and aliases, `match` arms, and imports, among others.
///
/// ## Examples
///
/// ```python
/// del __debug__
/// __debug__ = False
/// def f(__debug__): ...
/// class C[__debug__]: ...
/// ```
///
/// See [BPO 45000] for more information.
///
/// [BPO 45000]: https://github.com/python/cpython/issues/89163
WriteToDebug(WriteToDebugKind),
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum WriteToDebugKind {
Store,
Delete(PythonVersion),
} }
/// Searches for the first named expression (`x := y`) rebinding one of the `iteration_variables` in /// Searches for the first named expression (`x := y`) rebinding one of the `iteration_variables` in
@ -480,6 +655,10 @@ impl<'a, Ctx: SemanticSyntaxContext> MultipleCaseAssignmentVisitor<'a, Ctx> {
ident.range(), ident.range(),
); );
} }
// test_err debug_shadow_match
// match x:
// case __debug__: ...
SemanticSyntaxChecker::check_identifier(ident, self.ctx);
} }
} }

View file

@ -42,7 +42,7 @@ fn test_valid_syntax(input_path: &Path) {
let options = extract_options(&source).unwrap_or_else(|| { let options = extract_options(&source).unwrap_or_else(|| {
ParseOptions::from(Mode::Module).with_target_version(PythonVersion::latest()) ParseOptions::from(Mode::Module).with_target_version(PythonVersion::latest())
}); });
let parsed = parse_unchecked(&source, options); let parsed = parse_unchecked(&source, options.clone());
if parsed.has_syntax_errors() { if parsed.has_syntax_errors() {
let line_index = LineIndex::from_source_text(&source); let line_index = LineIndex::from_source_text(&source);
@ -88,7 +88,9 @@ fn test_valid_syntax(input_path: &Path) {
let parsed = parsed.try_into_module().expect("Parsed with Mode::Module"); let parsed = parsed.try_into_module().expect("Parsed with Mode::Module");
let mut visitor = SemanticSyntaxCheckerVisitor::new(TestContext::default()); let mut visitor = SemanticSyntaxCheckerVisitor::new(
TestContext::default().with_python_version(options.target_version()),
);
for stmt in parsed.suite() { for stmt in parsed.suite() {
visitor.visit_stmt(stmt); visitor.visit_stmt(stmt);
@ -134,7 +136,7 @@ fn test_invalid_syntax(input_path: &Path) {
let options = extract_options(&source).unwrap_or_else(|| { let options = extract_options(&source).unwrap_or_else(|| {
ParseOptions::from(Mode::Module).with_target_version(PythonVersion::latest()) ParseOptions::from(Mode::Module).with_target_version(PythonVersion::latest())
}); });
let parsed = parse_unchecked(&source, options); let parsed = parse_unchecked(&source, options.clone());
validate_tokens(parsed.tokens(), source.text_len(), input_path); validate_tokens(parsed.tokens(), source.text_len(), input_path);
validate_ast(parsed.syntax(), source.text_len(), input_path); validate_ast(parsed.syntax(), source.text_len(), input_path);
@ -182,7 +184,9 @@ fn test_invalid_syntax(input_path: &Path) {
let parsed = parsed.try_into_module().expect("Parsed with Mode::Module"); let parsed = parsed.try_into_module().expect("Parsed with Mode::Module");
let mut visitor = SemanticSyntaxCheckerVisitor::new(TestContext::default()); let mut visitor = SemanticSyntaxCheckerVisitor::new(
TestContext::default().with_python_version(options.target_version()),
);
for stmt in parsed.suite() { for stmt in parsed.suite() {
visitor.visit_stmt(stmt); visitor.visit_stmt(stmt);
@ -461,6 +465,15 @@ impl<'ast> SourceOrderVisitor<'ast> for ValidateAstVisitor<'ast> {
#[derive(Debug, Default)] #[derive(Debug, Default)]
struct TestContext { struct TestContext {
diagnostics: RefCell<Vec<SemanticSyntaxError>>, diagnostics: RefCell<Vec<SemanticSyntaxError>>,
python_version: PythonVersion,
}
impl TestContext {
#[must_use]
fn with_python_version(mut self, python_version: PythonVersion) -> Self {
self.python_version = python_version;
self
}
} }
impl SemanticSyntaxContext for TestContext { impl SemanticSyntaxContext for TestContext {
@ -469,7 +482,7 @@ impl SemanticSyntaxContext for TestContext {
} }
fn python_version(&self) -> PythonVersion { fn python_version(&self) -> PythonVersion {
PythonVersion::default() self.python_version
} }
fn report_semantic_error(&self, error: SemanticSyntaxError) { fn report_semantic_error(&self, error: SemanticSyntaxError) {

View file

@ -0,0 +1,94 @@
---
source: crates/ruff_python_parser/tests/fixtures.rs
input_file: crates/ruff_python_parser/resources/inline/err/debug_shadow_class.py
---
## AST
```
Module(
ModModule {
range: 0..82,
body: [
ClassDef(
StmtClassDef {
range: 0..20,
decorator_list: [],
name: Identifier {
id: Name("__debug__"),
range: 6..15,
},
type_params: None,
arguments: None,
body: [
Expr(
StmtExpr {
range: 17..20,
value: EllipsisLiteral(
ExprEllipsisLiteral {
range: 17..20,
},
),
},
),
],
},
),
ClassDef(
StmtClassDef {
range: 35..58,
decorator_list: [],
name: Identifier {
id: Name("C"),
range: 41..42,
},
type_params: Some(
TypeParams {
range: 42..53,
type_params: [
TypeVar(
TypeParamTypeVar {
range: 43..52,
name: Identifier {
id: Name("__debug__"),
range: 43..52,
},
bound: None,
default: None,
},
),
],
},
),
arguments: None,
body: [
Expr(
StmtExpr {
range: 55..58,
value: EllipsisLiteral(
ExprEllipsisLiteral {
range: 55..58,
},
),
},
),
],
},
),
],
},
)
```
## Semantic Syntax Errors
|
1 | class __debug__: ... # class name
| ^^^^^^^^^ Syntax Error: cannot assign to `__debug__`
2 | class C[__debug__]: ... # type parameter name
|
|
1 | class __debug__: ... # class name
2 | class C[__debug__]: ... # type parameter name
| ^^^^^^^^^ Syntax Error: cannot assign to `__debug__`
|

View file

@ -0,0 +1,168 @@
---
source: crates/ruff_python_parser/tests/fixtures.rs
input_file: crates/ruff_python_parser/resources/inline/err/debug_shadow_function.py
---
## AST
```
Module(
ModModule {
range: 0..125,
body: [
FunctionDef(
StmtFunctionDef {
range: 0..20,
is_async: false,
decorator_list: [],
name: Identifier {
id: Name("__debug__"),
range: 4..13,
},
type_params: None,
parameters: Parameters {
range: 13..15,
posonlyargs: [],
args: [],
vararg: None,
kwonlyargs: [],
kwarg: None,
},
returns: None,
body: [
Expr(
StmtExpr {
range: 17..20,
value: EllipsisLiteral(
ExprEllipsisLiteral {
range: 17..20,
},
),
},
),
],
},
),
FunctionDef(
StmtFunctionDef {
range: 38..61,
is_async: false,
decorator_list: [],
name: Identifier {
id: Name("f"),
range: 42..43,
},
type_params: Some(
TypeParams {
range: 43..54,
type_params: [
TypeVar(
TypeParamTypeVar {
range: 44..53,
name: Identifier {
id: Name("__debug__"),
range: 44..53,
},
bound: None,
default: None,
},
),
],
},
),
parameters: Parameters {
range: 54..56,
posonlyargs: [],
args: [],
vararg: None,
kwonlyargs: [],
kwarg: None,
},
returns: None,
body: [
Expr(
StmtExpr {
range: 58..61,
value: EllipsisLiteral(
ExprEllipsisLiteral {
range: 58..61,
},
),
},
),
],
},
),
FunctionDef(
StmtFunctionDef {
range: 85..106,
is_async: false,
decorator_list: [],
name: Identifier {
id: Name("f"),
range: 89..90,
},
type_params: None,
parameters: Parameters {
range: 90..101,
posonlyargs: [],
args: [
ParameterWithDefault {
range: 91..100,
parameter: Parameter {
range: 91..100,
name: Identifier {
id: Name("__debug__"),
range: 91..100,
},
annotation: None,
},
default: None,
},
],
vararg: None,
kwonlyargs: [],
kwarg: None,
},
returns: None,
body: [
Expr(
StmtExpr {
range: 103..106,
value: EllipsisLiteral(
ExprEllipsisLiteral {
range: 103..106,
},
),
},
),
],
},
),
],
},
)
```
## Semantic Syntax Errors
|
1 | def __debug__(): ... # function name
| ^^^^^^^^^ Syntax Error: cannot assign to `__debug__`
2 | def f[__debug__](): ... # type parameter name
3 | def f(__debug__): ... # parameter name
|
|
1 | def __debug__(): ... # function name
2 | def f[__debug__](): ... # type parameter name
| ^^^^^^^^^ Syntax Error: cannot assign to `__debug__`
3 | def f(__debug__): ... # parameter name
|
|
1 | def __debug__(): ... # function name
2 | def f[__debug__](): ... # type parameter name
3 | def f(__debug__): ... # parameter name
| ^^^^^^^^^ Syntax Error: cannot assign to `__debug__`
|

View file

@ -0,0 +1,133 @@
---
source: crates/ruff_python_parser/tests/fixtures.rs
input_file: crates/ruff_python_parser/resources/inline/err/debug_shadow_import.py
---
## AST
```
Module(
ModModule {
range: 0..100,
body: [
Import(
StmtImport {
range: 0..16,
names: [
Alias {
range: 7..16,
name: Identifier {
id: Name("__debug__"),
range: 7..16,
},
asname: None,
},
],
},
),
Import(
StmtImport {
range: 17..42,
names: [
Alias {
range: 24..42,
name: Identifier {
id: Name("debug"),
range: 24..29,
},
asname: Some(
Identifier {
id: Name("__debug__"),
range: 33..42,
},
),
},
],
},
),
ImportFrom(
StmtImportFrom {
range: 43..66,
module: Some(
Identifier {
id: Name("x"),
range: 48..49,
},
),
names: [
Alias {
range: 57..66,
name: Identifier {
id: Name("__debug__"),
range: 57..66,
},
asname: None,
},
],
level: 0,
},
),
ImportFrom(
StmtImportFrom {
range: 67..99,
module: Some(
Identifier {
id: Name("x"),
range: 72..73,
},
),
names: [
Alias {
range: 81..99,
name: Identifier {
id: Name("debug"),
range: 81..86,
},
asname: Some(
Identifier {
id: Name("__debug__"),
range: 90..99,
},
),
},
],
level: 0,
},
),
],
},
)
```
## Semantic Syntax Errors
|
1 | import __debug__
| ^^^^^^^^^ Syntax Error: cannot assign to `__debug__`
2 | import debug as __debug__
3 | from x import __debug__
|
|
1 | import __debug__
2 | import debug as __debug__
| ^^^^^^^^^ Syntax Error: cannot assign to `__debug__`
3 | from x import __debug__
4 | from x import debug as __debug__
|
|
1 | import __debug__
2 | import debug as __debug__
3 | from x import __debug__
| ^^^^^^^^^ Syntax Error: cannot assign to `__debug__`
4 | from x import debug as __debug__
|
|
2 | import debug as __debug__
3 | from x import __debug__
4 | from x import debug as __debug__
| ^^^^^^^^^ Syntax Error: cannot assign to `__debug__`
|

View file

@ -0,0 +1,64 @@
---
source: crates/ruff_python_parser/tests/fixtures.rs
input_file: crates/ruff_python_parser/resources/inline/err/debug_shadow_match.py
---
## AST
```
Module(
ModModule {
range: 0..33,
body: [
Match(
StmtMatch {
range: 0..32,
subject: Name(
ExprName {
range: 6..7,
id: Name("x"),
ctx: Load,
},
),
cases: [
MatchCase {
range: 13..32,
pattern: MatchAs(
PatternMatchAs {
range: 18..27,
pattern: None,
name: Some(
Identifier {
id: Name("__debug__"),
range: 18..27,
},
),
},
),
guard: None,
body: [
Expr(
StmtExpr {
range: 29..32,
value: EllipsisLiteral(
ExprEllipsisLiteral {
range: 29..32,
},
),
},
),
],
},
],
},
),
],
},
)
```
## Semantic Syntax Errors
|
1 | match x:
2 | case __debug__: ...
| ^^^^^^^^^ Syntax Error: cannot assign to `__debug__`
|

View file

@ -0,0 +1,76 @@
---
source: crates/ruff_python_parser/tests/fixtures.rs
input_file: crates/ruff_python_parser/resources/inline/err/debug_shadow_try.py
---
## AST
```
Module(
ModModule {
range: 0..44,
body: [
Try(
StmtTry {
range: 0..43,
body: [
Expr(
StmtExpr {
range: 5..8,
value: EllipsisLiteral(
ExprEllipsisLiteral {
range: 5..8,
},
),
},
),
],
handlers: [
ExceptHandler(
ExceptHandlerExceptHandler {
range: 9..43,
type_: Some(
Name(
ExprName {
range: 16..25,
id: Name("Exception"),
ctx: Load,
},
),
),
name: Some(
Identifier {
id: Name("__debug__"),
range: 29..38,
},
),
body: [
Expr(
StmtExpr {
range: 40..43,
value: EllipsisLiteral(
ExprEllipsisLiteral {
range: 40..43,
},
),
},
),
],
},
),
],
orelse: [],
finalbody: [],
is_star: false,
},
),
],
},
)
```
## Semantic Syntax Errors
|
1 | try: ...
2 | except Exception as __debug__: ...
| ^^^^^^^^^ Syntax Error: cannot assign to `__debug__`
|

View file

@ -0,0 +1,99 @@
---
source: crates/ruff_python_parser/tests/fixtures.rs
input_file: crates/ruff_python_parser/resources/inline/err/debug_shadow_type_alias.py
---
## AST
```
Module(
ModModule {
range: 0..95,
body: [
TypeAlias(
StmtTypeAlias {
range: 0..26,
name: Name(
ExprName {
range: 5..14,
id: Name("__debug__"),
ctx: Store,
},
),
type_params: None,
value: Subscript(
ExprSubscript {
range: 17..26,
value: Name(
ExprName {
range: 17..21,
id: Name("list"),
ctx: Load,
},
),
slice: Name(
ExprName {
range: 22..25,
id: Name("int"),
ctx: Load,
},
),
ctx: Load,
},
),
},
),
TypeAlias(
StmtTypeAlias {
range: 67..94,
name: Name(
ExprName {
range: 72..77,
id: Name("Debug"),
ctx: Store,
},
),
type_params: Some(
TypeParams {
range: 77..88,
type_params: [
TypeVar(
TypeParamTypeVar {
range: 78..87,
name: Identifier {
id: Name("__debug__"),
range: 78..87,
},
bound: None,
default: None,
},
),
],
},
),
value: Name(
ExprName {
range: 91..94,
id: Name("str"),
ctx: Load,
},
),
},
),
],
},
)
```
## Semantic Syntax Errors
|
1 | type __debug__ = list[int] # visited as an Expr but still flagged
| ^^^^^^^^^ Syntax Error: cannot assign to `__debug__`
2 | type Debug[__debug__] = str
|
|
1 | type __debug__ = list[int] # visited as an Expr but still flagged
2 | type Debug[__debug__] = str
| ^^^^^^^^^ Syntax Error: cannot assign to `__debug__`
|

View file

@ -0,0 +1,89 @@
---
source: crates/ruff_python_parser/tests/fixtures.rs
input_file: crates/ruff_python_parser/resources/inline/err/debug_shadow_with.py
---
## AST
```
Module(
ModModule {
range: 0..39,
body: [
With(
StmtWith {
range: 0..38,
is_async: false,
items: [
WithItem {
range: 5..33,
context_expr: Call(
ExprCall {
range: 5..20,
func: Name(
ExprName {
range: 5..9,
id: Name("open"),
ctx: Load,
},
),
arguments: Arguments {
range: 9..20,
args: [
StringLiteral(
ExprStringLiteral {
range: 10..19,
value: StringLiteralValue {
inner: Single(
StringLiteral {
range: 10..19,
value: "foo.txt",
flags: StringLiteralFlags {
quote_style: Double,
prefix: Empty,
triple_quoted: false,
},
},
),
},
},
),
],
keywords: [],
},
},
),
optional_vars: Some(
Name(
ExprName {
range: 24..33,
id: Name("__debug__"),
ctx: Store,
},
),
),
},
],
body: [
Expr(
StmtExpr {
range: 35..38,
value: EllipsisLiteral(
ExprEllipsisLiteral {
range: 35..38,
},
),
},
),
],
},
),
],
},
)
```
## Semantic Syntax Errors
|
1 | with open("foo.txt") as __debug__: ...
| ^^^^^^^^^ Syntax Error: cannot assign to `__debug__`
|

View file

@ -0,0 +1,36 @@
---
source: crates/ruff_python_parser/tests/fixtures.rs
input_file: crates/ruff_python_parser/resources/inline/err/del_debug_py39.py
---
## AST
```
Module(
ModModule {
range: 0..57,
body: [
Delete(
StmtDelete {
range: 43..56,
targets: [
Name(
ExprName {
range: 47..56,
id: Name("__debug__"),
ctx: Del,
},
),
],
},
),
],
},
)
```
## Semantic Syntax Errors
|
1 | # parse_options: {"target-version": "3.9"}
2 | del __debug__
| ^^^^^^^^^ Syntax Error: cannot delete `__debug__` on Python 3.9 (syntax was removed in 3.9)
|

View file

@ -0,0 +1,205 @@
---
source: crates/ruff_python_parser/tests/fixtures.rs
input_file: crates/ruff_python_parser/resources/inline/err/write_to_debug_expr.py
---
## AST
```
Module(
ModModule {
range: 0..83,
body: [
Delete(
StmtDelete {
range: 0..13,
targets: [
Name(
ExprName {
range: 4..13,
id: Name("__debug__"),
ctx: Del,
},
),
],
},
),
Delete(
StmtDelete {
range: 14..36,
targets: [
Name(
ExprName {
range: 18..19,
id: Name("x"),
ctx: Del,
},
),
Name(
ExprName {
range: 21..22,
id: Name("y"),
ctx: Del,
},
),
Name(
ExprName {
range: 24..33,
id: Name("__debug__"),
ctx: Del,
},
),
Name(
ExprName {
range: 35..36,
id: Name("z"),
ctx: Del,
},
),
],
},
),
Assign(
StmtAssign {
range: 37..50,
targets: [
Name(
ExprName {
range: 37..46,
id: Name("__debug__"),
ctx: Store,
},
),
],
value: NumberLiteral(
ExprNumberLiteral {
range: 49..50,
value: Int(
1,
),
},
),
},
),
Assign(
StmtAssign {
range: 51..82,
targets: [
Tuple(
ExprTuple {
range: 51..69,
elts: [
Name(
ExprName {
range: 51..52,
id: Name("x"),
ctx: Store,
},
),
Name(
ExprName {
range: 54..55,
id: Name("y"),
ctx: Store,
},
),
Name(
ExprName {
range: 57..66,
id: Name("__debug__"),
ctx: Store,
},
),
Name(
ExprName {
range: 68..69,
id: Name("z"),
ctx: Store,
},
),
],
ctx: Store,
parenthesized: false,
},
),
],
value: Tuple(
ExprTuple {
range: 72..82,
elts: [
NumberLiteral(
ExprNumberLiteral {
range: 72..73,
value: Int(
1,
),
},
),
NumberLiteral(
ExprNumberLiteral {
range: 75..76,
value: Int(
2,
),
},
),
NumberLiteral(
ExprNumberLiteral {
range: 78..79,
value: Int(
3,
),
},
),
NumberLiteral(
ExprNumberLiteral {
range: 81..82,
value: Int(
4,
),
},
),
],
ctx: Load,
parenthesized: false,
},
),
},
),
],
},
)
```
## Semantic Syntax Errors
|
1 | del __debug__
| ^^^^^^^^^ Syntax Error: cannot delete `__debug__` on Python 3.13 (syntax was removed in 3.9)
2 | del x, y, __debug__, z
3 | __debug__ = 1
|
|
1 | del __debug__
2 | del x, y, __debug__, z
| ^^^^^^^^^ Syntax Error: cannot delete `__debug__` on Python 3.13 (syntax was removed in 3.9)
3 | __debug__ = 1
4 | x, y, __debug__, z = 1, 2, 3, 4
|
|
1 | del __debug__
2 | del x, y, __debug__, z
3 | __debug__ = 1
| ^^^^^^^^^ Syntax Error: cannot assign to `__debug__`
4 | x, y, __debug__, z = 1, 2, 3, 4
|
|
2 | del x, y, __debug__, z
3 | __debug__ = 1
4 | x, y, __debug__, z = 1, 2, 3, 4
| ^^^^^^^^^ Syntax Error: cannot assign to `__debug__`
|

View file

@ -0,0 +1,84 @@
---
source: crates/ruff_python_parser/tests/fixtures.rs
input_file: crates/ruff_python_parser/resources/inline/ok/debug_rename_import.py
---
## AST
```
Module(
ModModule {
range: 0..86,
body: [
Import(
StmtImport {
range: 0..25,
names: [
Alias {
range: 7..25,
name: Identifier {
id: Name("__debug__"),
range: 7..16,
},
asname: Some(
Identifier {
id: Name("debug"),
range: 20..25,
},
),
},
],
},
),
ImportFrom(
StmtImportFrom {
range: 26..52,
module: Some(
Identifier {
id: Name("__debug__"),
range: 31..40,
},
),
names: [
Alias {
range: 48..52,
name: Identifier {
id: Name("Some"),
range: 48..52,
},
asname: None,
},
],
level: 0,
},
),
ImportFrom(
StmtImportFrom {
range: 53..85,
module: Some(
Identifier {
id: Name("x"),
range: 58..59,
},
),
names: [
Alias {
range: 67..85,
name: Identifier {
id: Name("__debug__"),
range: 67..76,
},
asname: Some(
Identifier {
id: Name("debug"),
range: 80..85,
},
),
},
],
level: 0,
},
),
],
},
)
```

View file

@ -0,0 +1,29 @@
---
source: crates/ruff_python_parser/tests/fixtures.rs
input_file: crates/ruff_python_parser/resources/inline/ok/del_debug_py38.py
---
## AST
```
Module(
ModModule {
range: 0..57,
body: [
Delete(
StmtDelete {
range: 43..56,
targets: [
Name(
ExprName {
range: 47..56,
id: Name("__debug__"),
ctx: Del,
},
),
],
},
),
],
},
)
```

View file

@ -0,0 +1,61 @@
---
source: crates/ruff_python_parser/tests/fixtures.rs
input_file: crates/ruff_python_parser/resources/inline/ok/read_from_debug.py
---
## AST
```
Module(
ModModule {
range: 0..32,
body: [
If(
StmtIf {
range: 0..17,
test: Name(
ExprName {
range: 3..12,
id: Name("__debug__"),
ctx: Load,
},
),
body: [
Expr(
StmtExpr {
range: 14..17,
value: EllipsisLiteral(
ExprEllipsisLiteral {
range: 14..17,
},
),
},
),
],
elif_else_clauses: [],
},
),
Assign(
StmtAssign {
range: 18..31,
targets: [
Name(
ExprName {
range: 18..19,
id: Name("x"),
ctx: Store,
},
),
],
value: Name(
ExprName {
range: 22..31,
id: Name("__debug__"),
ctx: Load,
},
),
},
),
],
},
)
```