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

Commit

Permalink
Add support for PEP701
Browse files Browse the repository at this point in the history
* fstrings are broken into several distinct token in py3.12, reattach
  them together as a singular string to preserve previous behavior.

Closes: #646
Signed-off-by: Alfred Wingate <parona@protonmail.com>
  • Loading branch information
parona-source committed Nov 2, 2023
1 parent f78f194 commit 5d25894
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 0 deletions.
8 changes: 8 additions & 0 deletions docs/release_notes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@ Release Notes
**pydocstyle** version numbers follow the
`Semantic Versioning <http://semver.org/>`_ specification.


Current development version
---------------------------

Bug Fixes

* Add support for PEP-701 fixing fstring parsing in python3.12 (#656).

6.3.0 - January 17th, 2023
--------------------------

Expand Down
22 changes: 22 additions & 0 deletions src/pydocstyle/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -463,6 +463,7 @@ def leapfrog(self, kind, value=None):
return
self.stream.move()


def parse_docstring(self):
"""Parse a single docstring and return its value."""
self.log.debug("parsing docstring, token is %s", self.current)
Expand All @@ -479,6 +480,27 @@ def parse_docstring(self):
)
self.stream.move()
return docstring
if (sys.version_info.major, sys.version_info.minor) >= (
3,
12,
) and self.current.kind == tk.FSTRING_START:
def fstring(string):
"""Recursively parse fstring tokens to output it as one string."""
while self.current.kind != tk.FSTRING_END:
self.stream.move()
string += self.current.value
if self.current.kind == tk.FSTRING_START:
string = fstring(string)
self.stream.move()
string += self.current.value
return string
# Reattach fstring tokens together into a string to deal with PEP 701 in python3.12
start = self.current.start[0]
string = fstring(self.current.value)
end = self.current.end[0]
docstring = Docstring(string, start, end)
self.stream.move()
return docstring
return None

def parse_decorators(self):
Expand Down
29 changes: 29 additions & 0 deletions src/tests/parser_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,35 @@ def do_something(pos_param0, pos_param1, kw_param0="default"):
assert str(function) == 'in public function `do_something`'


def test_nested_fstring():
"""Test parsing fstring with nested fstrings."""
parser = Parser()
code = CodeSnippet("""\
def do_something(pos_param0, pos_param1, kw_param0="default"):
f\"""Do something. {f"This is a nested fstring."}\"""
return None
""")
module = parser.parse(code, 'file_path')
assert module.is_public
assert module.dunder_all is None

function, = module.children
assert function.name == 'do_something'
assert function.decorators == []
assert function.children == []
assert function.docstring == 'f"""Do something. {f"This is a nested fstring."}"""'
assert function.docstring.start == 2
assert function.docstring.end == 2
assert function.kind == 'function'
assert function.parent == module
assert function.start == 1
assert function.end == 3
assert function.error_lineno == 2
assert function.source == code.getvalue()
assert function.is_public
assert str(function) == 'in public function `do_something`'


def test_decorated_function():
"""Test parsing of a simple function with a decorator."""
parser = Parser()
Expand Down

0 comments on commit 5d25894

Please sign in to comment.