Skip to content

Commit aa63c24

Browse files
danparizherntBre
andauthored
[pycodestyle] Fix E301 to only trigger for functions immediately within a class (#19768)
## Summary Fixes #19752 --------- Co-authored-by: Brent Westbrook <[email protected]>
1 parent 1f46c18 commit aa63c24

File tree

4 files changed

+115
-0
lines changed

4 files changed

+115
-0
lines changed

crates/ruff_linter/resources/test/fixtures/pycodestyle/E30.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -974,3 +974,39 @@ class A:
974974
APPLE = 200
975975

976976
# end
977+
978+
979+
# https://github.com/astral-sh/ruff/issues/19752
980+
class foo:
981+
async def recv(self, *, length=65536):
982+
loop = asyncio.get_event_loop()
983+
def callback():
984+
loop.remove_reader(self._fd)
985+
loop.add_reader(self._fd, callback)
986+
# end
987+
988+
989+
# E301
990+
class Foo:
991+
if True:
992+
print("conditional")
993+
def test():
994+
pass
995+
# end
996+
997+
998+
# Test case for nested class scenario
999+
class Bar:
1000+
def f():
1001+
x = 1
1002+
def g():
1003+
return 1
1004+
return 2
1005+
1006+
def f():
1007+
class Baz:
1008+
x = 1
1009+
def g():
1010+
return 1
1011+
return 2
1012+
# end

crates/ruff_linter/src/rules/pycodestyle/rules/blank_lines.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -836,7 +836,10 @@ impl<'a, 'b> BlankLinesChecker<'a, 'b> {
836836
// Allow groups of one-liners.
837837
&& !(state.follows.is_any_def() && line.last_token != TokenKind::Colon)
838838
&& !state.follows.follows_def_with_dummy_body()
839+
// Only for class scope: we must be inside a class block
839840
&& matches!(state.class_status, Status::Inside(_))
841+
// But NOT inside a function body; nested defs inside methods are handled by E306
842+
&& matches!(state.fn_status, Status::Outside | Status::CommentAfter(_))
840843
// The class/parent method's docstring can directly precede the def.
841844
// Allow following a decorator (if there is an error it will be triggered on the first decorator).
842845
&& !matches!(state.follows, Follows::Docstring | Follows::Decorator)

crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E301_E30.py.snap

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,3 +94,22 @@ help: Add missing blank line
9494
527 | def bar(self, x: int | str) -> int | str:
9595
528 | return x
9696
529 | # end
97+
98+
E301 [*] Expected 1 blank line, found 0
99+
--> E30.py:993:9
100+
|
101+
991 | if True:
102+
992 | print("conditional")
103+
993 | def test():
104+
| ^^^
105+
994 | pass
106+
995 | # end
107+
|
108+
help: Add missing blank line
109+
990 | class Foo:
110+
991 | if True:
111+
992 | print("conditional")
112+
993 +
113+
994 | def test():
114+
995 | pass
115+
996 | # end

crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E306_E30.py.snap

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,3 +208,60 @@ help: Add missing blank line
208208
926 | async def b():
209209
927 | pass
210210
928 | # end
211+
212+
E306 [*] Expected 1 blank line before a nested definition, found 0
213+
--> E30.py:983:9
214+
|
215+
981 | async def recv(self, *, length=65536):
216+
982 | loop = asyncio.get_event_loop()
217+
983 | def callback():
218+
| ^^^
219+
984 | loop.remove_reader(self._fd)
220+
985 | loop.add_reader(self._fd, callback)
221+
|
222+
help: Add missing blank line
223+
980 | class foo:
224+
981 | async def recv(self, *, length=65536):
225+
982 | loop = asyncio.get_event_loop()
226+
983 +
227+
984 | def callback():
228+
985 | loop.remove_reader(self._fd)
229+
986 | loop.add_reader(self._fd, callback)
230+
231+
E306 [*] Expected 1 blank line before a nested definition, found 0
232+
--> E30.py:1002:9
233+
|
234+
1000 | def f():
235+
1001 | x = 1
236+
1002 | def g():
237+
| ^^^
238+
1003 | return 1
239+
1004 | return 2
240+
|
241+
help: Add missing blank line
242+
999 | class Bar:
243+
1000 | def f():
244+
1001 | x = 1
245+
1002 +
246+
1003 | def g():
247+
1004 | return 1
248+
1005 | return 2
249+
250+
E306 [*] Expected 1 blank line before a nested definition, found 0
251+
--> E30.py:1009:13
252+
|
253+
1007 | class Baz:
254+
1008 | x = 1
255+
1009 | def g():
256+
| ^^^
257+
1010 | return 1
258+
1011 | return 2
259+
|
260+
help: Add missing blank line
261+
1006 | def f():
262+
1007 | class Baz:
263+
1008 | x = 1
264+
1009 +
265+
1010 | def g():
266+
1011 | return 1
267+
1012 | return 2

0 commit comments

Comments
 (0)