pdoc 14.5.1__tar.gz → 14.6.1__tar.gz

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.
Files changed (75) hide show
  1. {pdoc-14.5.1 → pdoc-14.6.1}/CHANGELOG.md +32 -3
  2. pdoc-14.6.1/LICENSE +5 -0
  3. {pdoc-14.5.1/pdoc.egg-info → pdoc-14.6.1}/PKG-INFO +2 -2
  4. {pdoc-14.5.1 → pdoc-14.6.1}/pdoc/__init__.py +7 -1
  5. {pdoc-14.5.1 → pdoc-14.6.1}/pdoc/__main__.py +2 -2
  6. {pdoc-14.5.1 → pdoc-14.6.1}/pdoc/_compat.py +11 -0
  7. {pdoc-14.5.1 → pdoc-14.6.1}/pdoc/doc.py +40 -16
  8. {pdoc-14.5.1 → pdoc-14.6.1}/pdoc/doc_ast.py +2 -2
  9. {pdoc-14.5.1 → pdoc-14.6.1}/pdoc/doc_pyi.py +22 -6
  10. {pdoc-14.5.1 → pdoc-14.6.1}/pdoc/docstrings.py +1 -1
  11. {pdoc-14.5.1 → pdoc-14.6.1}/pdoc/extract.py +1 -1
  12. {pdoc-14.5.1 → pdoc-14.6.1}/pdoc/markdown2/__init__.py +1667 -765
  13. {pdoc-14.5.1 → pdoc-14.6.1}/pdoc/render_helpers.py +76 -38
  14. {pdoc-14.5.1 → pdoc-14.6.1}/pdoc/templates/content.css +10 -6
  15. {pdoc-14.5.1 → pdoc-14.6.1}/pdoc/templates/default/module.html.jinja2 +1 -1
  16. {pdoc-14.5.1 → pdoc-14.6.1/pdoc.egg-info}/PKG-INFO +2 -2
  17. {pdoc-14.5.1 → pdoc-14.6.1}/pyproject.toml +5 -6
  18. {pdoc-14.5.1 → pdoc-14.6.1}/test/test_doc_types.py +3 -1
  19. {pdoc-14.5.1 → pdoc-14.6.1}/test/test_extract.py +3 -0
  20. {pdoc-14.5.1 → pdoc-14.6.1}/test/test_render_helpers.py +13 -0
  21. {pdoc-14.5.1 → pdoc-14.6.1}/test/test_snapshot.py +2 -1
  22. pdoc-14.5.1/LICENSE +0 -24
  23. {pdoc-14.5.1 → pdoc-14.6.1}/MANIFEST.in +0 -0
  24. {pdoc-14.5.1 → pdoc-14.6.1}/README.md +0 -0
  25. {pdoc-14.5.1 → pdoc-14.6.1}/pdoc/doc_types.py +0 -0
  26. {pdoc-14.5.1 → pdoc-14.6.1}/pdoc/markdown2/LICENSE +0 -0
  27. {pdoc-14.5.1 → pdoc-14.6.1}/pdoc/markdown2/README.md +0 -0
  28. {pdoc-14.5.1 → pdoc-14.6.1}/pdoc/py.typed +0 -0
  29. {pdoc-14.5.1 → pdoc-14.6.1}/pdoc/render.py +0 -0
  30. {pdoc-14.5.1 → pdoc-14.6.1}/pdoc/search.py +0 -0
  31. {pdoc-14.5.1 → pdoc-14.6.1}/pdoc/templates/README.md +0 -0
  32. {pdoc-14.5.1 → pdoc-14.6.1}/pdoc/templates/build-search-index.js +0 -0
  33. {pdoc-14.5.1 → pdoc-14.6.1}/pdoc/templates/custom.css +0 -0
  34. {pdoc-14.5.1 → pdoc-14.6.1}/pdoc/templates/default/error.html.jinja2 +0 -0
  35. {pdoc-14.5.1 → pdoc-14.6.1}/pdoc/templates/default/frame.html.jinja2 +0 -0
  36. {pdoc-14.5.1 → pdoc-14.6.1}/pdoc/templates/default/index.html.jinja2 +0 -0
  37. {pdoc-14.5.1 → pdoc-14.6.1}/pdoc/templates/deprecated/README.md +0 -0
  38. {pdoc-14.5.1 → pdoc-14.6.1}/pdoc/templates/deprecated/bootstrap-reboot.min.css +0 -0
  39. {pdoc-14.5.1 → pdoc-14.6.1}/pdoc/templates/deprecated/box-arrow-in-left.svg +0 -0
  40. {pdoc-14.5.1 → pdoc-14.6.1}/pdoc/templates/deprecated/elasticlunr.min.js +0 -0
  41. {pdoc-14.5.1 → pdoc-14.6.1}/pdoc/templates/deprecated/favicon.svg +0 -0
  42. {pdoc-14.5.1 → pdoc-14.6.1}/pdoc/templates/deprecated/navtoggle.svg +0 -0
  43. {pdoc-14.5.1 → pdoc-14.6.1}/pdoc/templates/deprecated/pdoc-logo.svg +0 -0
  44. {pdoc-14.5.1 → pdoc-14.6.1}/pdoc/templates/deprecated/resources/favicon.svg +0 -0
  45. {pdoc-14.5.1 → pdoc-14.6.1}/pdoc/templates/layout.css +0 -0
  46. {pdoc-14.5.1 → pdoc-14.6.1}/pdoc/templates/livereload.html.jinja2 +0 -0
  47. {pdoc-14.5.1 → pdoc-14.6.1}/pdoc/templates/math.html.jinja2 +0 -0
  48. {pdoc-14.5.1 → pdoc-14.6.1}/pdoc/templates/mermaid.html.jinja2 +0 -0
  49. {pdoc-14.5.1 → pdoc-14.6.1}/pdoc/templates/resources/bootstrap-reboot.min.css +0 -0
  50. {pdoc-14.5.1 → pdoc-14.6.1}/pdoc/templates/resources/box-arrow-in-left.svg +0 -0
  51. {pdoc-14.5.1 → pdoc-14.6.1}/pdoc/templates/resources/elasticlunr.min.js +0 -0
  52. {pdoc-14.5.1 → pdoc-14.6.1}/pdoc/templates/resources/exclamation-triangle-fill.svg +0 -0
  53. {pdoc-14.5.1 → pdoc-14.6.1}/pdoc/templates/resources/info-circle-fill.svg +0 -0
  54. {pdoc-14.5.1 → pdoc-14.6.1}/pdoc/templates/resources/lightning-fill.svg +0 -0
  55. {pdoc-14.5.1 → pdoc-14.6.1}/pdoc/templates/resources/navtoggle.svg +0 -0
  56. {pdoc-14.5.1 → pdoc-14.6.1}/pdoc/templates/resources/pdoc-logo.svg +0 -0
  57. {pdoc-14.5.1 → pdoc-14.6.1}/pdoc/templates/search.html.jinja2 +0 -0
  58. {pdoc-14.5.1 → pdoc-14.6.1}/pdoc/templates/search.js.jinja2 +0 -0
  59. {pdoc-14.5.1 → pdoc-14.6.1}/pdoc/templates/syntax-highlighting.css +0 -0
  60. {pdoc-14.5.1 → pdoc-14.6.1}/pdoc/templates/theme.css +0 -0
  61. {pdoc-14.5.1 → pdoc-14.6.1}/pdoc/web.py +0 -0
  62. {pdoc-14.5.1 → pdoc-14.6.1}/pdoc.egg-info/SOURCES.txt +0 -0
  63. {pdoc-14.5.1 → pdoc-14.6.1}/pdoc.egg-info/dependency_links.txt +0 -0
  64. {pdoc-14.5.1 → pdoc-14.6.1}/pdoc.egg-info/entry_points.txt +0 -0
  65. {pdoc-14.5.1 → pdoc-14.6.1}/pdoc.egg-info/requires.txt +0 -0
  66. {pdoc-14.5.1 → pdoc-14.6.1}/pdoc.egg-info/top_level.txt +0 -0
  67. {pdoc-14.5.1 → pdoc-14.6.1}/setup.cfg +0 -0
  68. {pdoc-14.5.1 → pdoc-14.6.1}/test/test_doc.py +0 -0
  69. {pdoc-14.5.1 → pdoc-14.6.1}/test/test_doc_ast.py +0 -0
  70. {pdoc-14.5.1 → pdoc-14.6.1}/test/test_doc_pyi.py +0 -0
  71. {pdoc-14.5.1 → pdoc-14.6.1}/test/test_docstrings.py +0 -0
  72. {pdoc-14.5.1 → pdoc-14.6.1}/test/test_main.py +0 -0
  73. {pdoc-14.5.1 → pdoc-14.6.1}/test/test_search.py +0 -0
  74. {pdoc-14.5.1 → pdoc-14.6.1}/test/test_smoke.py +0 -0
  75. {pdoc-14.5.1 → pdoc-14.6.1}/test/test_web.py +0 -0
@@ -4,9 +4,38 @@
4
4
 
5
5
  ## Unreleased: pdoc next
6
6
 
7
- - **Security:** Documentation generated with math mode (`pdoc --math`) does not include scripts
8
- from polyfill.io anymore. See https://sansec.io/research/polyfill-supply-chain-attack for details.
9
- Users who produce documentation with math mode should update immediately. All other users are unaffected.
7
+
8
+ ## 2024-08-27: pdoc 14.6.1
9
+
10
+ - Fix a bug where entire modules would be excluded by `--no-include-undocumented`.
11
+ To exclude modules, see https://pdoc.dev/docs/pdoc.html#exclude-submodules-from-being-documented.
12
+ ([#728](https://github.com/mitmproxy/pdoc/pull/728), @mhils)
13
+ - Fix a bug where pdoc would crash when importing pyi files.
14
+ ([#732](https://github.com/mitmproxy/pdoc/pull/732), @mhils)
15
+ - Fix a bug where subclasses of TypedDict subclasses would not render correctly.
16
+ ([#729](https://github.com/mitmproxy/pdoc/pull/729), @mhils)
17
+
18
+ ## 2024-07-24: pdoc 14.6.0
19
+
20
+ - If `example.data.Data` is also exposed as `example.Data`, pdoc now links to `example.Data` in documentation.
21
+ ([#670](https://github.com/mitmproxy/pdoc/pull/670), @nathanthorpe, @mhils)
22
+ - Add support for [GitHub Markdown Alerts](https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax#alerts).
23
+ ([#718](https://github.com/mitmproxy/pdoc/pull/718), @mhils)
24
+ - Improve rendering of enums on Python 3.12+.
25
+ ([#708](https://github.com/mitmproxy/pdoc/pull/708), @mhils)
26
+ - Fix a bug where hyperlinks would get parsed as docstring references.
27
+ ([#709](https://github.com/mitmproxy/pdoc/pull/709), @mhils)
28
+ - Fix a TypeError when trying to parse modules that implement `__dir__` incorrectly.
29
+ ([#710](https://github.com/mitmproxy/pdoc/pull/710), @mhils)
30
+ - Fix a bug where a combination of `@dataclass` and `ctypes.Structure` would crash pdoc.
31
+ ([#711](https://github.com/mitmproxy/pdoc/pull/711), @mhils)
32
+ - Update bundled version of markdown2.
33
+ ([#717](https://github.com/mitmproxy/pdoc/pull/717), @mhils)
34
+
35
+ ## 2024-06-25: pdoc 14.5.1
36
+
37
+ - **[CVE-2024-38526](https://github.com/mitmproxy/pdoc/security/advisories/GHSA-5vgj-ggm4-fg62):** Documentation generated with math mode (`pdoc --math`) does not include scripts
38
+ from polyfill.io anymore. Users who produce documentation with math mode should update immediately. All other users are unaffected.
10
39
  ([#703](https://github.com/mitmproxy/pdoc/pull/703), @adhintz)
11
40
 
12
41
  ## 2024-05-16: pdoc 14.5.0
pdoc-14.6.1/LICENSE ADDED
@@ -0,0 +1,5 @@
1
+ Copyright 2024 Maximilian Hils
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so.
4
+
5
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pdoc
3
- Version: 14.5.1
3
+ Version: 14.6.1
4
4
  Summary: API Documentation for Python Projects
5
5
  Author-email: Maximilian Hils <pdoc@maximilianhils.com>
6
- License: Unlicense
6
+ License: MIT-0
7
7
  Project-URL: Homepage, https://pdoc.dev
8
8
  Project-URL: Source, https://github.com/mitmproxy/pdoc/
9
9
  Project-URL: Documentation, https://pdoc.dev/docs/pdoc.html
@@ -194,11 +194,17 @@ In general, we recommend keeping the following conventions:
194
194
  - If you want to document a special `__dunder__` method, the recommended way to do so is
195
195
  to not document the dunder method specifically, but to add some usage examples in the class documentation.
196
196
 
197
+ > [!NOTE]
198
+ > Hiding an item only removes it from documentation.
199
+ > It is still displayed in the source code when clicking the "View Source" button.
200
+
197
201
  As a last resort, you can override pdoc's behavior with a custom module template (see
198
202
  [*How can I edit pdoc's HTML template?*](#edit-pdocs-html-template)).
199
203
  You can find an example at
200
204
  [`examples/custom-template/module.html.jinja2`](https://github.com/mitmproxy/pdoc/blob/main/examples/custom-template/module.html.jinja2).
201
205
 
206
+ Hiding an item only removes it from documentation. It is still displayed in the source code when clicking the "View Source" button.
207
+
202
208
  ## ...exclude submodules from being documented?
203
209
 
204
210
  If you would like to exclude specific submodules from the documentation, the recommended way is to specify `__all__` as
@@ -475,7 +481,7 @@ You can find an example in [`examples/library-usage`](https://github.com/mitmpro
475
481
  from __future__ import annotations
476
482
 
477
483
  __docformat__ = "markdown" # explicitly disable rST processing in the examples above.
478
- __version__ = "14.5.1" # this is read from setup.py
484
+ __version__ = "14.6.1" # this is read from setup.py
479
485
 
480
486
  from pathlib import Path
481
487
  from typing import overload
@@ -265,12 +265,12 @@ def get_dev_version() -> str:
265
265
 
266
266
  def _nicer_showwarning(message, category, filename, lineno, file=None, line=None):
267
267
  """A replacement for `warnings.showwarning` that renders warnings in a more visually pleasing way."""
268
- if category == UserWarning:
268
+ if category is UserWarning:
269
269
  print(
270
270
  f"{yellow}Warn:{default} {message} {gray}({filename}:{lineno}){default}",
271
271
  file=sys.stderr,
272
272
  )
273
- elif category == RuntimeWarning:
273
+ elif category is RuntimeWarning:
274
274
  print(
275
275
  f"{yellow}Warn:{default} {message}",
276
276
  file=sys.stderr,
@@ -123,6 +123,16 @@ else: # pragma: no cover
123
123
  return ' | '.join(self.option_strings)
124
124
 
125
125
 
126
+ if sys.version_info >= (3, 10):
127
+ from typing import is_typeddict
128
+ else: # pragma: no cover
129
+ def is_typeddict(tp):
130
+ try:
131
+ return tp.__orig_bases__[-1].__name__ == "TypedDict"
132
+ except Exception:
133
+ return False
134
+
135
+
126
136
  __all__ = [
127
137
  "cache",
128
138
  "ast_unparse",
@@ -134,4 +144,5 @@ __all__ = [
134
144
  "removesuffix",
135
145
  "formatannotation",
136
146
  "BooleanOptionalAction",
147
+ "is_typeddict",
137
148
  ]
@@ -37,6 +37,7 @@ import types
37
37
  from typing import Any
38
38
  from typing import ClassVar
39
39
  from typing import Generic
40
+ from typing import TypedDict
40
41
  from typing import TypeVar
41
42
  from typing import Union
42
43
  from typing import get_origin
@@ -49,6 +50,7 @@ from pdoc._compat import TypeAlias
49
50
  from pdoc._compat import TypeAliasType
50
51
  from pdoc._compat import cache
51
52
  from pdoc._compat import formatannotation
53
+ from pdoc._compat import is_typeddict
52
54
  from pdoc.doc_types import GenericAlias
53
55
  from pdoc.doc_types import NonUserDefinedCallables
54
56
  from pdoc.doc_types import empty
@@ -587,15 +589,21 @@ class Class(Namespace[type]):
587
589
  if doc == dict.__doc__:
588
590
  # Don't display default docstring for dict subclasses (primarily TypedDict).
589
591
  return ""
590
- is_dataclass_with_default_docstring = (
591
- dataclasses.is_dataclass(self.obj)
592
- # from https://github.com/python/cpython/blob/3.10/Lib/dataclasses.py
593
- and doc
594
- == self.obj.__name__
595
- + str(inspect.signature(self.obj)).replace(" -> None", "")
596
- )
597
- if is_dataclass_with_default_docstring:
592
+ if doc in _Enum_default_docstrings:
593
+ # Don't display default docstring for enum subclasses.
598
594
  return ""
595
+ if dataclasses.is_dataclass(self.obj) and doc.startswith(self.obj.__name__):
596
+ try:
597
+ sig = inspect.signature(self.obj)
598
+ except Exception:
599
+ pass
600
+ else:
601
+ # from https://github.com/python/cpython/blob/3.10/Lib/dataclasses.py
602
+ is_dataclass_with_default_docstring = doc == self.obj.__name__ + str(
603
+ sig
604
+ ).replace(" -> None", "")
605
+ if is_dataclass_with_default_docstring:
606
+ return ""
599
607
  return doc
600
608
 
601
609
  @cached_property
@@ -649,14 +657,21 @@ class Class(Namespace[type]):
649
657
  @cached_property
650
658
  def _bases(self) -> tuple[type, ...]:
651
659
  orig_bases = _safe_getattr(self.obj, "__orig_bases__", ())
652
- old_python_typeddict_workaround = (
653
- sys.version_info < (3, 12)
654
- and orig_bases
655
- and _safe_getattr(orig_bases[-1], "__name__", None) == "TypedDict"
656
- )
657
- if old_python_typeddict_workaround: # pragma: no cover
658
- # TypedDicts on Python <3.12 have a botched __mro__. We need to fix it.
659
- return (self.obj, *orig_bases[:-1])
660
+
661
+ if is_typeddict(self.obj):
662
+ if sys.version_info < (3, 12): # pragma: no cover
663
+ # TypedDicts on Python <3.12 have a botched __mro__. We need to fix it.
664
+ return (self.obj, *orig_bases[:-1])
665
+ else:
666
+ # TypedDict on Python >=3.12 removes intermediate classes from __mro__,
667
+ # so we use orig_bases to recover the full mro.
668
+ while orig_bases and orig_bases[-1] is not TypedDict:
669
+ parent_bases = _safe_getattr(orig_bases[-1], "__orig_bases__", ())
670
+ if (
671
+ len(parent_bases) != 1 or parent_bases in orig_bases
672
+ ): # sanity check that things look right
673
+ break # pragma: no cover
674
+ orig_bases = (*orig_bases, parent_bases[0])
660
675
 
661
676
  # __mro__ and __orig_bases__ differ between Python versions and special cases like TypedDict/NamedTuple.
662
677
  # This here is a pragmatic approximation of what we want.
@@ -1306,6 +1321,15 @@ def _safe_getdoc(obj: Any) -> str:
1306
1321
  return doc.strip()
1307
1322
 
1308
1323
 
1324
+ _Enum_default_docstrings = tuple(
1325
+ {
1326
+ _safe_getdoc(enum.Enum),
1327
+ _safe_getdoc(enum.IntEnum),
1328
+ _safe_getdoc(_safe_getattr(enum, "StrEnum", enum.Enum)),
1329
+ }
1330
+ )
1331
+
1332
+
1309
1333
  def _remove_memory_addresses(x: str) -> str:
1310
1334
  """Remove memory addresses from repr() output"""
1311
1335
  return re.sub(r" at 0x[0-9a-fA-F]+(?=>)", "", x)
@@ -245,7 +245,7 @@ def _parse_class(source: str) -> ast.ClassDef:
245
245
  t = tree.body[0]
246
246
  assert isinstance(t, ast.ClassDef)
247
247
  return t
248
- return ast.ClassDef(body=[], decorator_list=[])
248
+ return ast.ClassDef(body=[], decorator_list=[]) # type: ignore
249
249
 
250
250
 
251
251
  @cache
@@ -265,7 +265,7 @@ def _parse_function(source: str) -> ast.FunctionDef | ast.AsyncFunctionDef:
265
265
  # we have a lambda function,
266
266
  # to simplify the API return the ast.FunctionDef stub.
267
267
  pass
268
- return ast.FunctionDef(body=[], decorator_list=[])
268
+ return ast.FunctionDef(body=[], decorator_list=[]) # type: ignore
269
269
 
270
270
 
271
271
  def _parse(
@@ -6,6 +6,7 @@ This makes it possible to add type hints for native modules such as modules writ
6
6
 
7
7
  from __future__ import annotations
8
8
 
9
+ import importlib.util
9
10
  from pathlib import Path
10
11
  import sys
11
12
  import traceback
@@ -45,13 +46,28 @@ def find_stub_file(module_name: str) -> Path | None:
45
46
 
46
47
 
47
48
  def _import_stub_file(module_name: str, stub_file: Path) -> types.ModuleType:
48
- """Import the type stub outside of the normal import machinery."""
49
- code = compile(stub_file.read_text(), str(stub_file), "exec")
50
- m = types.ModuleType(module_name)
51
- m.__file__ = str(stub_file)
52
- eval(code, m.__dict__, m.__dict__)
49
+ """
50
+ Import the type stub outside of the normal import machinery.
53
51
 
54
- return m
52
+ Note that currently, for objects imported by the stub file, the _original_ module
53
+ is used and not the corresponding stub file.
54
+ """
55
+ sys.path_hooks.append(
56
+ importlib.machinery.FileFinder.path_hook(
57
+ (importlib.machinery.SourceFileLoader, [".pyi"])
58
+ )
59
+ )
60
+ try:
61
+ loader = importlib.machinery.SourceFileLoader(module_name, str(stub_file))
62
+ spec = importlib.util.spec_from_file_location(
63
+ module_name, stub_file, loader=loader
64
+ )
65
+ assert spec is not None
66
+ m = importlib.util.module_from_spec(spec)
67
+ loader.exec_module(m)
68
+ return m
69
+ finally:
70
+ sys.path_hooks.pop()
55
71
 
56
72
 
57
73
  def _prepare_module(ns: doc.Namespace) -> None:
@@ -427,7 +427,7 @@ def _rst_admonitions(contents: str, source_file: Path | None) -> str:
427
427
  else:
428
428
  heading = ""
429
429
  return (
430
- f'{ind}<div class="pdoc-alert pdoc-alert-{type}" markdown="1">\n'
430
+ f'{ind}<div class="alert {type}" markdown="1">\n'
431
431
  f"{heading}"
432
432
  f"{indent(contents, ind)}\n"
433
433
  f"{ind}</div>\n"
@@ -253,7 +253,7 @@ def iter_modules2(module: types.ModuleType) -> dict[str, pkgutil.ModuleInfo]:
253
253
  # This is a hacky workaround to register them.
254
254
  members = dir(module) if mod_all is None else mod_all
255
255
  for name in members:
256
- if name in submodules or name == "__main__":
256
+ if name in submodules or name == "__main__" or not isinstance(name, str):
257
257
  continue
258
258
  member = getattr(module, name, None)
259
259
  is_wild_child_module = (