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

Commit 2f9f337

Browse files
committed
Raise ParseError on fstring docstrings as they are not valid docstrings
1 parent afd0030 commit 2f9f337

File tree

5 files changed

+41
-30
lines changed

5 files changed

+41
-30
lines changed

src/pydocstyle/checker.py

+21-2
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,8 @@
2626
from .utils import (
2727
common_prefix_length,
2828
is_blank,
29-
is_fstring,
3029
log,
3130
pairwise,
32-
safe_literal_eval,
3331
strip_non_alphanumeric,
3432
)
3533
from .wordlists import IMPERATIVE_BLACKLIST, IMPERATIVE_VERBS, stem
@@ -46,6 +44,27 @@ def decorator(f):
4644
return decorator
4745

4846

47+
FSTRING_REGEX = re(r'^([rR]?)[fF]')
48+
49+
50+
def is_fstring(docstring):
51+
"""Return True if docstring is an f-string."""
52+
return FSTRING_REGEX.match(str(docstring))
53+
54+
55+
def safe_literal_eval(string):
56+
"""Safely evaluate a literal even if it is an fstring."""
57+
try:
58+
return ast.literal_eval(string)
59+
except ValueError as error:
60+
# If the docstring is a fstring, it is
61+
# not considered a valid docstring. See
62+
# https://bugs.python.org/issue28739
63+
raise ParseError(
64+
info="f-strings are not valid as docstrings."
65+
) from error
66+
67+
4968
class ConventionChecker:
5069
"""Checker for PEP 257, NumPy and Google conventions.
5170

src/pydocstyle/parser.py

+5-1
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,12 @@
3030
class ParseError(Exception):
3131
"""An error parsing contents of a Python file."""
3232

33+
def __init__(self, info=""):
34+
"""Initialize the error with a more specific message."""
35+
self.info = info
36+
3337
def __str__(self):
34-
return "Cannot parse file."
38+
return f"Cannot parse file. {self.info}".strip()
3539

3640

3741
class UnexpectedTokenError(ParseError):

src/pydocstyle/utils.py

-22
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
"""General shared utilities."""
2-
import ast
32
import logging
43
import re
54
from itertools import tee, zip_longest
@@ -47,24 +46,3 @@ def common_prefix_length(a: str, b: str) -> int:
4746
def strip_non_alphanumeric(string: str) -> str:
4847
"""Strip string from any non-alphanumeric characters."""
4948
return NON_ALPHANUMERIC_STRIP_RE.sub('', string)
50-
51-
52-
FSTRING_REGEX = re.compile(r'^([rR]?)[fF]')
53-
54-
55-
def is_fstring(docstring):
56-
"""Return True if docstring is an f-string."""
57-
return FSTRING_REGEX.match(str(docstring))
58-
59-
60-
def safe_literal_eval(string):
61-
"""Safely evaluate a literal even if it is an fstring."""
62-
try:
63-
return ast.literal_eval(string)
64-
except ValueError:
65-
# In case we hit a value error due to an fstring
66-
# we do a literal eval by subtituting the fstring
67-
# with a normal string.
68-
# We keep the first captured group if any. This includes
69-
# the raw identifiers (r/R) and replace f/F with a blank.
70-
return ast.literal_eval(FSTRING_REGEX.sub(r"\1", string))

src/tests/test_cases/fstrings.py

-5
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,3 @@ def fstring_with_other_errors(arg=1, missing_arg=2):
5050
@D303
5151
def fstring_with_blank_doc_string():
5252
f""" """
53-
54-
55-
@expect("D103: Missing docstring in public function")
56-
def fstring_with_ignores(): # noqa: D303
57-
f""" """

src/tests/test_integration.py

+15
Original file line numberDiff line numberDiff line change
@@ -571,6 +571,21 @@ def foo():
571571
assert code == 0
572572

573573

574+
def test_fstring_excluded(env):
575+
"""Test excluding D303 fstring error."""
576+
with env.open('example.py', 'wt') as example:
577+
example.write(textwrap.dedent("""\
578+
def foo(): # noqa: D303
579+
f'''Test'''
580+
"""))
581+
582+
env.write_config(add_ignore="D100")
583+
out, err, code = env.invoke()
584+
assert code == 1
585+
assert out == ""
586+
assert "f-strings are not valid as docstrings." in err
587+
588+
574589
def test_empty_select_with_added_error(env):
575590
"""Test excluding all errors but one."""
576591
with env.open('example.py', 'wt') as example:

0 commit comments

Comments
 (0)