Skip to content

Commit fd74e2e

Browse files
tobiscodeTobias Köhneautofix-ci[bot]
authored
add descriptive error message if re.split fails in numpy (#784)
* add descriptive error message if re.split fails in numpy * move error catching from numpy() to convert(), reusing AnyException * [autofix.ci] apply automated fixes * add error-raising test for docstring.convert * fix test_smoke after moving AnyException * change test_convert_exception to use monkeypatch to raise error --------- Co-authored-by: Tobias Köhne <[email protected]> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
1 parent 6a825e8 commit fd74e2e

File tree

4 files changed

+42
-22
lines changed

4 files changed

+42
-22
lines changed

pdoc/docstrings.py

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,13 @@
2424
from textwrap import indent
2525
import warnings
2626

27+
AnyException = (SystemExit, GeneratorExit, Exception)
28+
"""BaseException, but excluding KeyboardInterrupt.
29+
30+
Modules may raise SystemExit on import (which we want to catch),
31+
but we don't want to catch a user's KeyboardInterrupt.
32+
"""
33+
2734

2835
@cache
2936
def convert(docstring: str, docformat: str, source_file: Path | None) -> str:
@@ -32,17 +39,25 @@ def convert(docstring: str, docformat: str, source_file: Path | None) -> str:
3239
"""
3340
docformat = docformat.lower()
3441

35-
if any(x in docformat for x in ["google", "numpy", "restructuredtext"]):
36-
docstring = rst(docstring, source_file)
42+
try:
43+
if any(x in docformat for x in ["google", "numpy", "restructuredtext"]):
44+
docstring = rst(docstring, source_file)
45+
46+
if "google" in docformat:
47+
docstring = google(docstring)
3748

38-
if "google" in docformat:
39-
docstring = google(docstring)
49+
if "numpy" in docformat:
50+
docstring = numpy(docstring)
4051

41-
if "numpy" in docformat:
42-
docstring = numpy(docstring)
52+
if source_file is not None and os.environ.get("PDOC_EMBED_IMAGES") != "0":
53+
docstring = embed_images(docstring, source_file)
4354

44-
if source_file is not None and os.environ.get("PDOC_EMBED_IMAGES") != "0":
45-
docstring = embed_images(docstring, source_file)
55+
except AnyException as e:
56+
raise RuntimeError(
57+
'Docstring processing failed for docstring=\n"""\n'
58+
+ docstring
59+
+ f'\n"""\n{source_file=}\n{docformat=}'
60+
) from e
4661

4762
return docstring
4863

pdoc/extract.py

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ def walk_specs(specs: Sequence[Path | str]) -> list[str]:
6161
modspec = importlib.util.find_spec(modname)
6262
if modspec is None:
6363
raise ModuleNotFoundError(modname)
64-
except AnyException:
64+
except pdoc.docstrings.AnyException:
6565
warnings.warn(
6666
f"Cannot find spec for {modname} (from {spec}):\n{traceback.format_exc()}",
6767
stacklevel=2,
@@ -110,7 +110,7 @@ def parse_spec(spec: Path | str) -> str:
110110
modspec = importlib.util.find_spec(spec)
111111
if modspec is None:
112112
raise ModuleNotFoundError
113-
except AnyException:
113+
except pdoc.docstrings.AnyException:
114114
# Module does not exist, use local file.
115115
spec = pspec
116116
else:
@@ -218,18 +218,10 @@ def load_module(module: str) -> types.ModuleType:
218218
Returns the imported module."""
219219
try:
220220
return importlib.import_module(module)
221-
except AnyException as e:
221+
except pdoc.docstrings.AnyException as e:
222222
raise RuntimeError(f"Error importing {module}") from e
223223

224224

225-
AnyException = (SystemExit, GeneratorExit, Exception)
226-
"""BaseException, but excluding KeyboardInterrupt.
227-
228-
Modules may raise SystemExit on import (which we want to catch),
229-
but we don't want to catch a user's KeyboardInterrupt.
230-
"""
231-
232-
233225
def iter_modules2(module: types.ModuleType) -> dict[str, pkgutil.ModuleInfo]:
234226
"""
235227
Returns all direct child modules of a given module.
@@ -315,7 +307,7 @@ def module_mtime(modulename: str) -> float | None:
315307
try:
316308
with mock_some_common_side_effects():
317309
spec = importlib.util.find_spec(modulename)
318-
except AnyException:
310+
except pdoc.docstrings.AnyException:
319311
pass
320312
else:
321313
if spec is not None and spec.origin is not None:
@@ -365,7 +357,7 @@ def invalidate_caches(module_name: str) -> None:
365357
continue # some funky stuff going on - one example is typing.io, which is a class.
366358
with mock_some_common_side_effects():
367359
importlib.reload(sys.modules[modname])
368-
except AnyException:
360+
except pdoc.docstrings.AnyException:
369361
warnings.warn(
370362
f"Error reloading {modname}:\n{traceback.format_exc()}",
371363
stacklevel=2,

test/test_docstrings.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,19 @@ def test_rst_extract_options_fuzz(s):
3737
assert not s or content or options
3838

3939

40+
def test_convert_exception(monkeypatch):
41+
def raise_(*_):
42+
raise Exception
43+
44+
monkeypatch.setattr(docstrings, "rst", raise_)
45+
with pytest.raises(RuntimeError, match="Docstring processing failed"):
46+
docstrings.convert(
47+
"Valid minimal docstring without in- or output.",
48+
"numpy",
49+
None,
50+
)
51+
52+
4053
def test_rst_extract_options():
4154
content = (
4255
":alpha: beta\n"

test/test_smoke.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ def test_smoke(module):
2222
try:
2323
with pdoc.extract.mock_some_common_side_effects():
2424
importlib.import_module(module)
25-
except pdoc.extract.AnyException:
25+
except pdoc.docstrings.AnyException:
2626
pass
2727
else:
2828
try:

0 commit comments

Comments
 (0)