pdoc 15.0.1__py3-none-any.whl → 15.0.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pdoc/__init__.py +1 -1
- pdoc/doc.py +5 -2
- pdoc/doc_ast.py +1 -1
- pdoc/doc_types.py +1 -1
- pdoc/docstrings.py +44 -22
- pdoc/extract.py +5 -13
- pdoc/render_helpers.py +6 -6
- pdoc/web.py +2 -0
- {pdoc-15.0.1.dist-info → pdoc-15.0.2.dist-info}/METADATA +1 -1
- {pdoc-15.0.1.dist-info → pdoc-15.0.2.dist-info}/RECORD +14 -14
- {pdoc-15.0.1.dist-info → pdoc-15.0.2.dist-info}/WHEEL +1 -1
- {pdoc-15.0.1.dist-info → pdoc-15.0.2.dist-info}/LICENSE +0 -0
- {pdoc-15.0.1.dist-info → pdoc-15.0.2.dist-info}/entry_points.txt +0 -0
- {pdoc-15.0.1.dist-info → pdoc-15.0.2.dist-info}/top_level.txt +0 -0
pdoc/__init__.py
CHANGED
@@ -481,7 +481,7 @@ You can find an example in [`examples/library-usage`](https://github.com/mitmpro
|
|
481
481
|
from __future__ import annotations
|
482
482
|
|
483
483
|
__docformat__ = "markdown" # explicitly disable rST processing in the examples above.
|
484
|
-
__version__ = "15.0.
|
484
|
+
__version__ = "15.0.2" # this is read from setup.py
|
485
485
|
|
486
486
|
from pathlib import Path
|
487
487
|
from typing import overload
|
pdoc/doc.py
CHANGED
@@ -637,7 +637,7 @@ class Class(Namespace[type]):
|
|
637
637
|
for attr, unresolved_annotation in dynamic_annotations.items():
|
638
638
|
cls_annotations[attr] = unresolved_annotation
|
639
639
|
cls_fullname = (
|
640
|
-
_safe_getattr(cls, "__module__", "") + "." + cls.__qualname__
|
640
|
+
(_safe_getattr(cls, "__module__", "") or "") + "." + cls.__qualname__
|
641
641
|
).lstrip(".")
|
642
642
|
|
643
643
|
new_annotations = {
|
@@ -1095,7 +1095,7 @@ class Variable(Doc[None]):
|
|
1095
1095
|
default = f" = {self.default_value_str}"
|
1096
1096
|
else:
|
1097
1097
|
default = ""
|
1098
|
-
return f
|
1098
|
+
return f"<var {self.qualname.rsplit('.')[-1]}{self.annotation_str}{default}{_docstr(self)}>"
|
1099
1099
|
|
1100
1100
|
@cached_property
|
1101
1101
|
def is_classvar(self) -> bool:
|
@@ -1169,6 +1169,9 @@ class Variable(Doc[None]):
|
|
1169
1169
|
"""The variable's type annotation as a pretty-printed str."""
|
1170
1170
|
if self.annotation is not empty:
|
1171
1171
|
formatted = formatannotation(self.annotation)
|
1172
|
+
# type aliases don't include the module name in their __repr__, so we add it here.
|
1173
|
+
if isinstance(self.annotation, TypeAliasType):
|
1174
|
+
formatted = f"{self.annotation.__module__}.{formatted}"
|
1172
1175
|
return f": {_remove_collections_abc(formatted)}"
|
1173
1176
|
else:
|
1174
1177
|
return ""
|
pdoc/doc_ast.py
CHANGED
@@ -273,7 +273,7 @@ def _parse(
|
|
273
273
|
try:
|
274
274
|
return ast.parse(_dedent(source))
|
275
275
|
except Exception as e:
|
276
|
-
warnings.warn(f"Error parsing source code: {e}\n
|
276
|
+
warnings.warn(f"Error parsing source code: {e}\n===\n{source}\n===")
|
277
277
|
return ast.parse("")
|
278
278
|
|
279
279
|
|
pdoc/doc_types.py
CHANGED
@@ -114,7 +114,7 @@ def safe_eval_type(
|
|
114
114
|
f"Error parsing type annotation {t} for {fullname}: {e}. "
|
115
115
|
f"You are likely attempting to use Python 3.10 syntax (PEP 604 union types) with an older Python "
|
116
116
|
f"release. `X | Y`-style type annotations are invalid syntax on Python {py_ver}, which is what your "
|
117
|
-
f"pdoc instance is using. `from
|
117
|
+
f"pdoc instance is using. `from __future__ import annotations` (PEP 563) postpones evaluation of "
|
118
118
|
f"annotations, which is why your program won't crash right away. However, pdoc needs to evaluate your "
|
119
119
|
f"type annotations and is unable to do so on Python {py_ver}. To fix this issue, either invoke pdoc "
|
120
120
|
f"from Python 3.10+, or switch to `typing.Union[]` syntax."
|
pdoc/docstrings.py
CHANGED
@@ -24,6 +24,13 @@ from textwrap import dedent
|
|
24
24
|
from textwrap import indent
|
25
25
|
import warnings
|
26
26
|
|
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
|
+
|
27
34
|
|
28
35
|
@cache
|
29
36
|
def convert(docstring: str, docformat: str, source_file: Path | None) -> str:
|
@@ -32,39 +39,52 @@ def convert(docstring: str, docformat: str, source_file: Path | None) -> str:
|
|
32
39
|
"""
|
33
40
|
docformat = docformat.lower()
|
34
41
|
|
35
|
-
|
36
|
-
|
42
|
+
try:
|
43
|
+
if any(x in docformat for x in ["google", "numpy", "restructuredtext"]):
|
44
|
+
docstring = rst(docstring, source_file)
|
37
45
|
|
38
|
-
|
39
|
-
|
46
|
+
if "google" in docformat:
|
47
|
+
docstring = google(docstring)
|
40
48
|
|
41
|
-
|
42
|
-
|
49
|
+
if "numpy" in docformat:
|
50
|
+
docstring = numpy(docstring)
|
43
51
|
|
44
|
-
|
45
|
-
|
52
|
+
if source_file is not None and os.environ.get("PDOC_EMBED_IMAGES") != "0":
|
53
|
+
docstring = embed_images(docstring, source_file)
|
54
|
+
|
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
|
46
61
|
|
47
62
|
return docstring
|
48
63
|
|
49
64
|
|
50
65
|
def embed_images(docstring: str, source_file: Path) -> str:
|
66
|
+
def local_image_to_data_uri(href: str) -> str:
|
67
|
+
image_path = source_file.parent / href
|
68
|
+
image_data = image_path.read_bytes()
|
69
|
+
image_mime = mimetypes.guess_type(image_path)[0]
|
70
|
+
image_data_b64 = base64.b64encode(image_data).decode()
|
71
|
+
return f"data:{image_mime};base64,{image_data_b64}"
|
72
|
+
|
51
73
|
def embed_local_image(m: re.Match) -> str:
|
52
|
-
image_path = source_file.parent / m["href"]
|
53
74
|
try:
|
54
|
-
|
55
|
-
image_mime = mimetypes.guess_type(image_path)[0]
|
75
|
+
href = local_image_to_data_uri(m["href"])
|
56
76
|
except Exception:
|
57
77
|
return m[0]
|
58
78
|
else:
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
r"
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
79
|
+
return m["before"] + href + m["after"]
|
80
|
+
|
81
|
+
# TODO: Could probably do more here, e.g. support rST replacements.
|
82
|
+
for regex in [
|
83
|
+
r"(?P<before>!\[\s*.*?\s*]\(\s*)(?P<href>.+?)(?P<after>\s*\))",
|
84
|
+
r"""(?P<before>src=['"])(?P<href>.+?)(?P<after>['"])""",
|
85
|
+
]:
|
86
|
+
docstring = re.sub(regex, embed_local_image, docstring)
|
87
|
+
return docstring
|
68
88
|
|
69
89
|
|
70
90
|
def google(docstring: str) -> str:
|
@@ -178,13 +198,15 @@ def numpy(docstring: str) -> str:
|
|
178
198
|
)
|
179
199
|
contents = sections[0]
|
180
200
|
for heading, content in zip(sections[1::2], sections[2::2]):
|
181
|
-
if content.startswith(" "):
|
201
|
+
if content.startswith(" ") and re.search(r"\n(?![ \n])", content):
|
182
202
|
# If the first line of section content is indented, we consider the section to be finished
|
183
203
|
# on the first non-indented line. We take out the rest - the tail - here.
|
184
204
|
content, tail = re.split(r"\n(?![ \n])", content, maxsplit=1)
|
185
205
|
else:
|
186
206
|
tail = ""
|
187
207
|
|
208
|
+
content = dedent(content)
|
209
|
+
|
188
210
|
if heading in (
|
189
211
|
"Parameters",
|
190
212
|
"Returns",
|
@@ -199,7 +221,7 @@ def numpy(docstring: str) -> str:
|
|
199
221
|
elif heading == "See Also":
|
200
222
|
contents += f"###### {heading}\n{_numpy_seealso(content)}"
|
201
223
|
else:
|
202
|
-
contents += f"###### {heading}\n{
|
224
|
+
contents += f"###### {heading}\n{content}"
|
203
225
|
contents += tail
|
204
226
|
return contents
|
205
227
|
|
pdoc/extract.py
CHANGED
@@ -61,7 +61,7 @@ def walk_specs(specs: Sequence[Path | str]) -> list[str]:
|
|
61
61
|
modspec = importlib.util.find_spec(modname)
|
62
62
|
if modspec is None:
|
63
63
|
raise ModuleNotFoundError(modname)
|
64
|
-
except AnyException:
|
64
|
+
except pdoc.docstrings.AnyException:
|
65
65
|
warnings.warn(
|
66
66
|
f"Cannot find spec for {modname} (from {spec}):\n{traceback.format_exc()}",
|
67
67
|
stacklevel=2,
|
@@ -110,7 +110,7 @@ def parse_spec(spec: Path | str) -> str:
|
|
110
110
|
modspec = importlib.util.find_spec(spec)
|
111
111
|
if modspec is None:
|
112
112
|
raise ModuleNotFoundError
|
113
|
-
except AnyException:
|
113
|
+
except pdoc.docstrings.AnyException:
|
114
114
|
# Module does not exist, use local file.
|
115
115
|
spec = pspec
|
116
116
|
else:
|
@@ -218,18 +218,10 @@ def load_module(module: str) -> types.ModuleType:
|
|
218
218
|
Returns the imported module."""
|
219
219
|
try:
|
220
220
|
return importlib.import_module(module)
|
221
|
-
except AnyException as e:
|
221
|
+
except pdoc.docstrings.AnyException as e:
|
222
222
|
raise RuntimeError(f"Error importing {module}") from e
|
223
223
|
|
224
224
|
|
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
|
-
|
233
225
|
def iter_modules2(module: types.ModuleType) -> dict[str, pkgutil.ModuleInfo]:
|
234
226
|
"""
|
235
227
|
Returns all direct child modules of a given module.
|
@@ -315,7 +307,7 @@ def module_mtime(modulename: str) -> float | None:
|
|
315
307
|
try:
|
316
308
|
with mock_some_common_side_effects():
|
317
309
|
spec = importlib.util.find_spec(modulename)
|
318
|
-
except AnyException:
|
310
|
+
except pdoc.docstrings.AnyException:
|
319
311
|
pass
|
320
312
|
else:
|
321
313
|
if spec is not None and spec.origin is not None:
|
@@ -365,7 +357,7 @@ def invalidate_caches(module_name: str) -> None:
|
|
365
357
|
continue # some funky stuff going on - one example is typing.io, which is a class.
|
366
358
|
with mock_some_common_side_effects():
|
367
359
|
importlib.reload(sys.modules[modname])
|
368
|
-
except AnyException:
|
360
|
+
except pdoc.docstrings.AnyException:
|
369
361
|
warnings.warn(
|
370
362
|
f"Error reloading {modname}:\n{traceback.format_exc()}",
|
371
363
|
stacklevel=2,
|
pdoc/render_helpers.py
CHANGED
@@ -99,7 +99,7 @@ Link pattern used for markdown2's [`link-patterns` extra](https://github.com/tre
|
|
99
99
|
|
100
100
|
|
101
101
|
@cache
|
102
|
-
def highlight(doc: pdoc.doc.Doc) ->
|
102
|
+
def highlight(doc: pdoc.doc.Doc) -> Markup:
|
103
103
|
"""Highlight the source code of a documentation object using pygments."""
|
104
104
|
if isinstance(doc, str): # pragma: no cover
|
105
105
|
warnings.warn(
|
@@ -114,7 +114,7 @@ def highlight(doc: pdoc.doc.Doc) -> str:
|
|
114
114
|
return Markup(pygments.highlight(doc.source, lexer, formatter))
|
115
115
|
|
116
116
|
|
117
|
-
def format_signature(sig: inspect.Signature, colon: bool) ->
|
117
|
+
def format_signature(sig: inspect.Signature, colon: bool) -> Markup:
|
118
118
|
"""Format and highlight a function signature using pygments. Returns HTML."""
|
119
119
|
# First get a list with all params as strings.
|
120
120
|
result = pdoc.doc._PrettySignature._params(sig) # type: ignore
|
@@ -308,7 +308,7 @@ def module_candidates(identifier: str, current_module: str) -> Iterable[str]:
|
|
308
308
|
@pass_context
|
309
309
|
def linkify(
|
310
310
|
context: Context, code: str, namespace: str = "", shorten: bool = True
|
311
|
-
) ->
|
311
|
+
) -> Markup:
|
312
312
|
"""
|
313
313
|
Link all identifiers in a block of text. Identifiers referencing unknown modules or modules that
|
314
314
|
are not rendered at the moment will be ignored.
|
@@ -436,7 +436,7 @@ def linkify(
|
|
436
436
|
|
437
437
|
|
438
438
|
@pass_context
|
439
|
-
def link(context: Context, spec: tuple[str, str], text: str | None = None) ->
|
439
|
+
def link(context: Context, spec: tuple[str, str], text: str | None = None) -> Markup:
|
440
440
|
"""Create a link for a specific `(modulename, qualname)` tuple."""
|
441
441
|
mod: pdoc.doc.Module = context["module"]
|
442
442
|
modulename, qualname = spec
|
@@ -469,7 +469,7 @@ def link(context: Context, spec: tuple[str, str], text: str | None = None) -> st
|
|
469
469
|
return Markup(
|
470
470
|
f'<a href="{relative_link(context["module"].modulename, modulename)}{qualname}">{text or fullname}</a>'
|
471
471
|
)
|
472
|
-
return text or fullname
|
472
|
+
return Markup.escape(text or fullname)
|
473
473
|
|
474
474
|
|
475
475
|
def edit_url(
|
@@ -507,7 +507,7 @@ def root_module_name(all_modules: Mapping[str, pdoc.doc.Module]) -> str | None:
|
|
507
507
|
return None
|
508
508
|
|
509
509
|
|
510
|
-
def minify_css(css: str) ->
|
510
|
+
def minify_css(css: str) -> Markup:
|
511
511
|
"""Do some very basic CSS minification."""
|
512
512
|
css = re.sub(r"[ ]{4}|\n|(?<=[:{}]) | (?=[{}])", "", css)
|
513
513
|
css = re.sub(
|
pdoc/web.py
CHANGED
@@ -14,6 +14,7 @@ from functools import cache
|
|
14
14
|
import http.server
|
15
15
|
import traceback
|
16
16
|
from typing import Mapping
|
17
|
+
import urllib.parse
|
17
18
|
import warnings
|
18
19
|
import webbrowser
|
19
20
|
|
@@ -60,6 +61,7 @@ class DocHandler(http.server.BaseHTTPRequestHandler):
|
|
60
61
|
return "Not Found: Please normalize all module separators to '/'."
|
61
62
|
else:
|
62
63
|
module_name = path.lstrip("/").removesuffix(".html").replace("/", ".")
|
64
|
+
module_name = urllib.parse.unquote(module_name)
|
63
65
|
if module_name not in self.server.all_modules:
|
64
66
|
self.send_response(404)
|
65
67
|
self.send_header("content-type", "text/html")
|
@@ -1,17 +1,17 @@
|
|
1
|
-
pdoc/__init__.py,sha256=
|
1
|
+
pdoc/__init__.py,sha256=jnoeoAPOPSzWTb12xjX2gUW4SV_TUCS1QS6JdnavNOA,21456
|
2
2
|
pdoc/__main__.py,sha256=DOXWKG7I0M-E9uSs8a--9RGJNI266_2VKZpVQR4paj0,8416
|
3
3
|
pdoc/_compat.py,sha256=iXM2kfvS8oRg30EuA-HYWyVt5iorA5JrJHAhUZvsuu4,1447
|
4
|
-
pdoc/doc.py,sha256=
|
5
|
-
pdoc/doc_ast.py,sha256=
|
4
|
+
pdoc/doc.py,sha256=866peOsabjNx-rexUlF41K9GYBYHqEaMv_fQUuF8gD4,50099
|
5
|
+
pdoc/doc_ast.py,sha256=qoWLta30b2XTlwj9fI15IM0687T0dIp9Vk5bB325O60,11345
|
6
6
|
pdoc/doc_pyi.py,sha256=r2QdI8WeUxY6jQ9O4xmL3m1zPVmIpxEAviqLYt_M5gk,5078
|
7
|
-
pdoc/doc_types.py,sha256=
|
8
|
-
pdoc/docstrings.py,sha256=
|
9
|
-
pdoc/extract.py,sha256=
|
7
|
+
pdoc/doc_types.py,sha256=tcZysNBSHk1tAxbr4JSmDARoLkHlxINVW6UYvEtzUvs,8465
|
8
|
+
pdoc/docstrings.py,sha256=m3yzwekXlQxY-_wcVEyLzT6A6hJyY-yp95ooyzx90uA,17187
|
9
|
+
pdoc/extract.py,sha256=1EtgteSdCF61Z5kr4nR3fL9BXwKoJ9FM92aNCPS48nM,14227
|
10
10
|
pdoc/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
11
11
|
pdoc/render.py,sha256=8vXpDlqzRayJdaH0oU6nA6aApFYeGrtxVLOmCD7EbIU,7081
|
12
|
-
pdoc/render_helpers.py,sha256=
|
12
|
+
pdoc/render_helpers.py,sha256=Db-uB28WkWird--4Rtu4klJnP6S7p3LJFsaAXiH4fJQ,20395
|
13
13
|
pdoc/search.py,sha256=RGFaRftEQOg1Mw4FEOmJVRY9DhBncBYSFi5r4MSknTM,7248
|
14
|
-
pdoc/web.py,sha256=
|
14
|
+
pdoc/web.py,sha256=9pRpukVWMEoWbthB1E9Yrg86KoSNmXMeBicno_cVcPQ,6933
|
15
15
|
pdoc/markdown2/LICENSE,sha256=BfcOT5Iu-7wDaKcbIta8wkP-pFncOu4yXeBlMfbeYGI,1116
|
16
16
|
pdoc/markdown2/README.md,sha256=-b2NGwLPzTBnaCGPSqRCzHxSrqArlXxGG5w0c6pOqFk,200
|
17
17
|
pdoc/markdown2/__init__.py,sha256=guvOlezAha8NQBH8TFkEwiP4zFy5tsV2NVYiEOWD2jg,159248
|
@@ -47,9 +47,9 @@ pdoc/templates/resources/info-circle-fill.svg,sha256=kO3AMXfWtacpJPzC8Pvihf46OZd
|
|
47
47
|
pdoc/templates/resources/lightning-fill.svg,sha256=XEyCtbgxeAlwCezdsf7N0NFd5aMjwqyJJDpaFbYYTFA,265
|
48
48
|
pdoc/templates/resources/navtoggle.svg,sha256=WVR0BJIucX0MgwwEawmfX0qYD1i_dSbUhoGnqPef3jw,187
|
49
49
|
pdoc/templates/resources/pdoc-logo.svg,sha256=w5OsMmytDaA2Fr9CobeQQFxBNx4-wFFHtLvkORj0gjk,6989
|
50
|
-
pdoc-15.0.
|
51
|
-
pdoc-15.0.
|
52
|
-
pdoc-15.0.
|
53
|
-
pdoc-15.0.
|
54
|
-
pdoc-15.0.
|
55
|
-
pdoc-15.0.
|
50
|
+
pdoc-15.0.2.dist-info/LICENSE,sha256=LrhIeJ7gKTDPyOX9YVuZGr9mpmyjpkvqH6LjxvE0szM,898
|
51
|
+
pdoc-15.0.2.dist-info/METADATA,sha256=448hBCXQ-y-3rZfozXBq0dbJZG83T24O-pBdooMTsos,6775
|
52
|
+
pdoc-15.0.2.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
|
53
|
+
pdoc-15.0.2.dist-info/entry_points.txt,sha256=-bK-S1ZvmqCWqi1hGnsl5nayWkzXB1BEs-Cynh5QZaI,43
|
54
|
+
pdoc-15.0.2.dist-info/top_level.txt,sha256=rg5eIToBHzwTfZZi1E7NVHgie5joQuSuU1rWV0qKS9k,5
|
55
|
+
pdoc-15.0.2.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|