Skip to content

Commit c833f0c

Browse files
committed
allow normal dotted names
1 parent a0adf85 commit c833f0c

File tree

3 files changed

+104
-3
lines changed

3 files changed

+104
-3
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# parse_options: { "target-version": "3.8" }
2+
@buttons.clicked.connect
3+
def spam(): ...

crates/ruff_python_parser/src/parser/statement.rs

+22-3
Original file line numberDiff line numberDiff line change
@@ -2527,11 +2527,25 @@ impl<'src> Parser<'src> {
25272527
fn try_parse_old_decorators(&mut self) -> Option<ParsedExpr> {
25282528
let errors = self.errors.len();
25292529
let start = self.node_start();
2530-
let name = self.parse_name();
2531-
if name.ctx.is_invalid() {
2530+
// initial identifier
2531+
let ident = self.parse_identifier();
2532+
if !ident.is_valid() {
25322533
return None;
25332534
}
2534-
let name = Expr::from(name);
2535+
let mut name = Expr::from(ast::ExprName {
2536+
range: self.node_range(start),
2537+
id: ident.id,
2538+
ctx: ExprContext::Load,
2539+
});
2540+
// ("." identifier)*
2541+
while self.at(TokenKind::Dot) {
2542+
let attr = self.parse_attribute_expression(name, start);
2543+
if !attr.attr.is_valid() {
2544+
return None;
2545+
}
2546+
name = Expr::from(attr);
2547+
}
2548+
// ["(" [argument_list [","]] ")"] NEWLINE
25352549
let parsed = match self.current_token_kind() {
25362550
TokenKind::Lpar => Some(Expr::Call(self.parse_call_expression(name, start)).into()),
25372551
TokenKind::Newline => Some(name.into()),
@@ -2561,6 +2575,11 @@ impl<'src> Parser<'src> {
25612575
// before 3.9 but avoid false positives on examples like the `@_` "identity function hack"
25622576
// or the "eval hack" called out in the PEP.
25632577

2578+
// test_ok decorator_expression_dotted_ident_before_py39
2579+
// # parse_options: { "target-version": "3.8" }
2580+
// @buttons.clicked.connect
2581+
// def spam(): ...
2582+
25642583
// test_ok decorator_expression_identity_hack_before_py39
25652584
// # parse_options: { "target-version": "3.8" }
25662585
// def _(x): return x
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
---
2+
source: crates/ruff_python_parser/tests/fixtures.rs
3+
input_file: crates/ruff_python_parser/resources/inline/ok/decorator_expression_dotted_ident_before_py39.py
4+
---
5+
## AST
6+
7+
```
8+
Module(
9+
ModModule {
10+
range: 0..86,
11+
body: [
12+
FunctionDef(
13+
StmtFunctionDef {
14+
range: 45..85,
15+
is_async: false,
16+
decorator_list: [
17+
Decorator {
18+
range: 45..69,
19+
expression: Attribute(
20+
ExprAttribute {
21+
range: 46..69,
22+
value: Attribute(
23+
ExprAttribute {
24+
range: 46..61,
25+
value: Name(
26+
ExprName {
27+
range: 46..53,
28+
id: Name("buttons"),
29+
ctx: Load,
30+
},
31+
),
32+
attr: Identifier {
33+
id: Name("clicked"),
34+
range: 54..61,
35+
},
36+
ctx: Load,
37+
},
38+
),
39+
attr: Identifier {
40+
id: Name("connect"),
41+
range: 62..69,
42+
},
43+
ctx: Load,
44+
},
45+
),
46+
},
47+
],
48+
name: Identifier {
49+
id: Name("spam"),
50+
range: 74..78,
51+
},
52+
type_params: None,
53+
parameters: Parameters {
54+
range: 78..80,
55+
posonlyargs: [],
56+
args: [],
57+
vararg: None,
58+
kwonlyargs: [],
59+
kwarg: None,
60+
},
61+
returns: None,
62+
body: [
63+
Expr(
64+
StmtExpr {
65+
range: 82..85,
66+
value: EllipsisLiteral(
67+
ExprEllipsisLiteral {
68+
range: 82..85,
69+
},
70+
),
71+
},
72+
),
73+
],
74+
},
75+
),
76+
],
77+
},
78+
)
79+
```

0 commit comments

Comments
 (0)