Skip to content
This repository was archived by the owner on Nov 3, 2023. It is now read-only.

Commit 302bb78

Browse files
cdce8psambhavPierre-Sassoulas
authored
Fix decorator parsing for async functions (#577)
Co-authored-by: Sambhav Kothari <[email protected]> Co-authored-by: Pierre Sassoulas <[email protected]>
1 parent bd294bb commit 302bb78

File tree

4 files changed

+83
-0
lines changed

4 files changed

+83
-0
lines changed

docs/release_notes.rst

+7
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,13 @@ Release Notes
44
**pydocstyle** version numbers follow the
55
`Semantic Versioning <http://semver.org/>`_ specification.
66

7+
6.2.3 - January 8th, 2023
8+
---------------------------
9+
10+
Bug Fixes
11+
12+
* Fix decorator parsing for async function. Resolves some false positives
13+
with async functions and ``overload``. (#577)
714

815
6.2.2 - January 3rd, 2023
916
---------------------------

src/pydocstyle/parser.py

+1
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,7 @@ def parse_decorators(self):
492492
self.current.value,
493493
)
494494
if self.current.kind == tk.NAME and self.current.value in [
495+
'async',
495496
'def',
496497
'class',
497498
]:

src/tests/test_decorators.py

+15
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,21 @@ def some_method(self):
130130
assert 'first_decorator' == decorators[0].name
131131
assert '' == decorators[0].arguments
132132

133+
def test_parse_async_function_decorator(self):
134+
"""Decorators for async functions are also accumulated."""
135+
code = textwrap.dedent("""\
136+
@first_decorator
137+
async def some_method(self):
138+
pass
139+
""")
140+
141+
module = checker.parse(io.StringIO(code), 'dummy.py')
142+
decorators = module.children[0].decorators
143+
144+
assert 1 == len(decorators)
145+
assert 'first_decorator' == decorators[0].name
146+
assert '' == decorators[0].arguments
147+
133148
def test_parse_method_nested_decorator(self):
134149
"""Method decorators are accumulated for nested methods."""
135150
code = textwrap.dedent("""\

src/tests/test_integration.py

+60
Original file line numberDiff line numberDiff line change
@@ -621,6 +621,36 @@ def overloaded_func(a):
621621
assert 'D103' not in out
622622

623623

624+
def test_overload_async_function(env):
625+
"""Async functions decorated with @overload trigger D418 error."""
626+
with env.open('example.py', 'wt') as example:
627+
example.write(textwrap.dedent('''\
628+
from typing import overload
629+
630+
631+
@overload
632+
async def overloaded_func(a: int) -> str:
633+
...
634+
635+
636+
@overload
637+
async def overloaded_func(a: str) -> str:
638+
"""Foo bar documentation."""
639+
...
640+
641+
642+
async def overloaded_func(a):
643+
"""Foo bar documentation."""
644+
return str(a)
645+
646+
'''))
647+
env.write_config(ignore="D100")
648+
out, err, code = env.invoke()
649+
assert code == 1
650+
assert 'D418' in out
651+
assert 'D103' not in out
652+
653+
624654
def test_overload_method(env):
625655
"""Methods decorated with @overload trigger D418 error."""
626656
with env.open('example.py', 'wt') as example:
@@ -714,6 +744,36 @@ def overloaded_func(a):
714744
assert code == 0
715745

716746

747+
def test_overload_async_function_valid(env):
748+
"""Valid case for overload decorated async functions.
749+
750+
This shouldn't throw any errors.
751+
"""
752+
with env.open('example.py', 'wt') as example:
753+
example.write(textwrap.dedent('''\
754+
from typing import overload
755+
756+
757+
@overload
758+
async def overloaded_func(a: int) -> str:
759+
...
760+
761+
762+
@overload
763+
async def overloaded_func(a: str) -> str:
764+
...
765+
766+
767+
async def overloaded_func(a):
768+
"""Foo bar documentation."""
769+
return str(a)
770+
771+
'''))
772+
env.write_config(ignore="D100")
773+
out, err, code = env.invoke()
774+
assert code == 0
775+
776+
717777
def test_overload_nested_function(env):
718778
"""Nested functions decorated with @overload trigger D418 error."""
719779
with env.open('example.py', 'wt') as example:

0 commit comments

Comments
 (0)