[`pycodestyle`] Fix `E301` to only trigger for functions immediately within a class (#19768)

## Summary

Fixes #19752

---------

Co-authored-by: Brent Westbrook <brentrwestbrook@gmail.com>
This commit is contained in:
Dan Parizher 2025-09-16 11:00:07 -04:00 committed by GitHub
parent 1f46c18921
commit aa63c24b8f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 115 additions and 0 deletions

View File

@ -974,3 +974,39 @@ BANANA = 100
APPLE = 200
# end
# https://github.com/astral-sh/ruff/issues/19752
class foo:
async def recv(self, *, length=65536):
loop = asyncio.get_event_loop()
def callback():
loop.remove_reader(self._fd)
loop.add_reader(self._fd, callback)
# end
# E301
class Foo:
if True:
print("conditional")
def test():
pass
# end
# Test case for nested class scenario
class Bar:
def f():
x = 1
def g():
return 1
return 2
def f():
class Baz:
x = 1
def g():
return 1
return 2
# end

View File

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

View File

@ -94,3 +94,22 @@ help: Add missing blank line
527 | def bar(self, x: int | str) -> int | str:
528 | return x
529 | # end
E301 [*] Expected 1 blank line, found 0
--> E30.py:993:9
|
991 | if True:
992 | print("conditional")
993 | def test():
| ^^^
994 | pass
995 | # end
|
help: Add missing blank line
990 | class Foo:
991 | if True:
992 | print("conditional")
993 +
994 | def test():
995 | pass
996 | # end

View File

@ -208,3 +208,60 @@ help: Add missing blank line
926 | async def b():
927 | pass
928 | # end
E306 [*] Expected 1 blank line before a nested definition, found 0
--> E30.py:983:9
|
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)
|
help: Add missing blank line
980 | class foo:
981 | async def recv(self, *, length=65536):
982 | loop = asyncio.get_event_loop()
983 +
984 | def callback():
985 | loop.remove_reader(self._fd)
986 | loop.add_reader(self._fd, callback)
E306 [*] Expected 1 blank line before a nested definition, found 0
--> E30.py:1002:9
|
1000 | def f():
1001 | x = 1
1002 | def g():
| ^^^
1003 | return 1
1004 | return 2
|
help: Add missing blank line
999 | class Bar:
1000 | def f():
1001 | x = 1
1002 +
1003 | def g():
1004 | return 1
1005 | return 2
E306 [*] Expected 1 blank line before a nested definition, found 0
--> E30.py:1009:13
|
1007 | class Baz:
1008 | x = 1
1009 | def g():
| ^^^
1010 | return 1
1011 | return 2
|
help: Add missing blank line
1006 | def f():
1007 | class Baz:
1008 | x = 1
1009 +
1010 | def g():
1011 | return 1
1012 | return 2