pdoc 14.6.1__tar.gz → 15.0.0__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 (76) hide show
  1. {pdoc-14.6.1 → pdoc-15.0.0}/CHANGELOG.md +22 -0
  2. {pdoc-14.6.1/pdoc.egg-info → pdoc-15.0.0}/PKG-INFO +5 -17
  3. {pdoc-14.6.1 → pdoc-15.0.0}/README.md +1 -1
  4. {pdoc-14.6.1 → pdoc-15.0.0}/pdoc/__init__.py +1 -1
  5. {pdoc-14.6.1 → pdoc-15.0.0}/pdoc/__main__.py +5 -6
  6. pdoc-15.0.0/pdoc/_compat.py +60 -0
  7. {pdoc-14.6.1 → pdoc-15.0.0}/pdoc/doc.py +15 -5
  8. {pdoc-14.6.1 → pdoc-15.0.0}/pdoc/doc_ast.py +10 -11
  9. {pdoc-14.6.1 → pdoc-15.0.0}/pdoc/doc_pyi.py +1 -2
  10. {pdoc-14.6.1 → pdoc-15.0.0}/pdoc/doc_types.py +1 -1
  11. {pdoc-14.6.1 → pdoc-15.0.0}/pdoc/docstrings.py +1 -2
  12. {pdoc-14.6.1 → pdoc-15.0.0}/pdoc/extract.py +7 -5
  13. {pdoc-14.6.1 → pdoc-15.0.0}/pdoc/render.py +1 -1
  14. {pdoc-14.6.1 → pdoc-15.0.0}/pdoc/render_helpers.py +18 -10
  15. {pdoc-14.6.1 → pdoc-15.0.0}/pdoc/templates/content.css +7 -0
  16. {pdoc-14.6.1 → pdoc-15.0.0}/pdoc/templates/default/module.html.jinja2 +6 -2
  17. {pdoc-14.6.1 → pdoc-15.0.0}/pdoc/web.py +3 -4
  18. {pdoc-14.6.1 → pdoc-15.0.0/pdoc.egg-info}/PKG-INFO +5 -17
  19. pdoc-15.0.0/pdoc.egg-info/requires.txt +3 -0
  20. {pdoc-14.6.1 → pdoc-15.0.0}/pyproject.toml +19 -20
  21. {pdoc-14.6.1 → pdoc-15.0.0}/test/test_doc.py +8 -7
  22. {pdoc-14.6.1 → pdoc-15.0.0}/test/test_doc_types.py +3 -1
  23. {pdoc-14.6.1 → pdoc-15.0.0}/test/test_extract.py +9 -0
  24. {pdoc-14.6.1 → pdoc-15.0.0}/test/test_snapshot.py +5 -10
  25. pdoc-14.6.1/pdoc/_compat.py +0 -148
  26. pdoc-14.6.1/pdoc.egg-info/requires.txt +0 -18
  27. {pdoc-14.6.1 → pdoc-15.0.0}/LICENSE +0 -0
  28. {pdoc-14.6.1 → pdoc-15.0.0}/MANIFEST.in +0 -0
  29. {pdoc-14.6.1 → pdoc-15.0.0}/pdoc/markdown2/LICENSE +0 -0
  30. {pdoc-14.6.1 → pdoc-15.0.0}/pdoc/markdown2/README.md +0 -0
  31. {pdoc-14.6.1 → pdoc-15.0.0}/pdoc/markdown2/__init__.py +0 -0
  32. {pdoc-14.6.1 → pdoc-15.0.0}/pdoc/py.typed +0 -0
  33. {pdoc-14.6.1 → pdoc-15.0.0}/pdoc/search.py +0 -0
  34. {pdoc-14.6.1 → pdoc-15.0.0}/pdoc/templates/README.md +0 -0
  35. {pdoc-14.6.1 → pdoc-15.0.0}/pdoc/templates/build-search-index.js +0 -0
  36. {pdoc-14.6.1 → pdoc-15.0.0}/pdoc/templates/custom.css +0 -0
  37. {pdoc-14.6.1 → pdoc-15.0.0}/pdoc/templates/default/error.html.jinja2 +0 -0
  38. {pdoc-14.6.1 → pdoc-15.0.0}/pdoc/templates/default/frame.html.jinja2 +0 -0
  39. {pdoc-14.6.1 → pdoc-15.0.0}/pdoc/templates/default/index.html.jinja2 +0 -0
  40. {pdoc-14.6.1 → pdoc-15.0.0}/pdoc/templates/deprecated/README.md +0 -0
  41. {pdoc-14.6.1 → pdoc-15.0.0}/pdoc/templates/deprecated/bootstrap-reboot.min.css +0 -0
  42. {pdoc-14.6.1 → pdoc-15.0.0}/pdoc/templates/deprecated/box-arrow-in-left.svg +0 -0
  43. {pdoc-14.6.1 → pdoc-15.0.0}/pdoc/templates/deprecated/elasticlunr.min.js +0 -0
  44. {pdoc-14.6.1 → pdoc-15.0.0}/pdoc/templates/deprecated/favicon.svg +0 -0
  45. {pdoc-14.6.1 → pdoc-15.0.0}/pdoc/templates/deprecated/navtoggle.svg +0 -0
  46. {pdoc-14.6.1 → pdoc-15.0.0}/pdoc/templates/deprecated/pdoc-logo.svg +0 -0
  47. {pdoc-14.6.1 → pdoc-15.0.0}/pdoc/templates/deprecated/resources/favicon.svg +0 -0
  48. {pdoc-14.6.1 → pdoc-15.0.0}/pdoc/templates/layout.css +0 -0
  49. {pdoc-14.6.1 → pdoc-15.0.0}/pdoc/templates/livereload.html.jinja2 +0 -0
  50. {pdoc-14.6.1 → pdoc-15.0.0}/pdoc/templates/math.html.jinja2 +0 -0
  51. {pdoc-14.6.1 → pdoc-15.0.0}/pdoc/templates/mermaid.html.jinja2 +0 -0
  52. {pdoc-14.6.1 → pdoc-15.0.0}/pdoc/templates/resources/bootstrap-reboot.min.css +0 -0
  53. {pdoc-14.6.1 → pdoc-15.0.0}/pdoc/templates/resources/box-arrow-in-left.svg +0 -0
  54. {pdoc-14.6.1 → pdoc-15.0.0}/pdoc/templates/resources/elasticlunr.min.js +0 -0
  55. {pdoc-14.6.1 → pdoc-15.0.0}/pdoc/templates/resources/exclamation-triangle-fill.svg +0 -0
  56. {pdoc-14.6.1 → pdoc-15.0.0}/pdoc/templates/resources/info-circle-fill.svg +0 -0
  57. {pdoc-14.6.1 → pdoc-15.0.0}/pdoc/templates/resources/lightning-fill.svg +0 -0
  58. {pdoc-14.6.1 → pdoc-15.0.0}/pdoc/templates/resources/navtoggle.svg +0 -0
  59. {pdoc-14.6.1 → pdoc-15.0.0}/pdoc/templates/resources/pdoc-logo.svg +0 -0
  60. {pdoc-14.6.1 → pdoc-15.0.0}/pdoc/templates/search.html.jinja2 +0 -0
  61. {pdoc-14.6.1 → pdoc-15.0.0}/pdoc/templates/search.js.jinja2 +0 -0
  62. {pdoc-14.6.1 → pdoc-15.0.0}/pdoc/templates/syntax-highlighting.css +0 -0
  63. {pdoc-14.6.1 → pdoc-15.0.0}/pdoc/templates/theme.css +0 -0
  64. {pdoc-14.6.1 → pdoc-15.0.0}/pdoc.egg-info/SOURCES.txt +0 -0
  65. {pdoc-14.6.1 → pdoc-15.0.0}/pdoc.egg-info/dependency_links.txt +0 -0
  66. {pdoc-14.6.1 → pdoc-15.0.0}/pdoc.egg-info/entry_points.txt +0 -0
  67. {pdoc-14.6.1 → pdoc-15.0.0}/pdoc.egg-info/top_level.txt +0 -0
  68. {pdoc-14.6.1 → pdoc-15.0.0}/setup.cfg +0 -0
  69. {pdoc-14.6.1 → pdoc-15.0.0}/test/test_doc_ast.py +0 -0
  70. {pdoc-14.6.1 → pdoc-15.0.0}/test/test_doc_pyi.py +0 -0
  71. {pdoc-14.6.1 → pdoc-15.0.0}/test/test_docstrings.py +0 -0
  72. {pdoc-14.6.1 → pdoc-15.0.0}/test/test_main.py +0 -0
  73. {pdoc-14.6.1 → pdoc-15.0.0}/test/test_render_helpers.py +0 -0
  74. {pdoc-14.6.1 → pdoc-15.0.0}/test/test_search.py +0 -0
  75. {pdoc-14.6.1 → pdoc-15.0.0}/test/test_smoke.py +0 -0
  76. {pdoc-14.6.1 → pdoc-15.0.0}/test/test_web.py +0 -0
@@ -5,6 +5,28 @@
5
5
  ## Unreleased: pdoc next
6
6
 
7
7
 
8
+ ## 2024-10-11: pdoc 15.0.0
9
+
10
+ - Remove support for Python 3.8, which has reached end-of-life on 2024-10-07.
11
+ ([#747](https://github.com/mitmproxy/pdoc/pull/747), @mhils)
12
+ - Inherited members are now hidden by default if the base class is not part of the documentation.
13
+ Please make yourself heard in https://github.com/mitmproxy/pdoc/issues/715 if you relied on the old behavior.
14
+ ([#748](https://github.com/mitmproxy/pdoc/pull/748), @mhils)
15
+ - Python 3.13: `@deprecated` decorators are now rendered with visual emphasis.
16
+ ([#750](https://github.com/mitmproxy/pdoc/pull/750), @mhils)
17
+ - Improve mocking of `sys.stdin`, `sys.stdout`, and `sys.stderr` to fix runtime errors with some packages.
18
+ ([#751](https://github.com/mitmproxy/pdoc/pull/751), @mhils)
19
+
20
+ ## 2024-09-11: pdoc 14.7.0
21
+
22
+ - Do not shorten `current_module.func` to `func` in docstrings when linking.
23
+ This prevents logical errors in code examples with imports.
24
+ ([#740](https://github.com/mitmproxy/pdoc/pull/740), @mhils)
25
+ - Add support for Python 3.13.
26
+ ([#730](https://github.com/mitmproxy/pdoc/pull/730), @mhils)
27
+ - pdoc now strips `collections.abc.` from type annotations to make them more concise.
28
+ ([#736](https://github.com/mitmproxy/pdoc/pull/736), @mhils)
29
+
8
30
  ## 2024-08-27: pdoc 14.6.1
9
31
 
10
32
  - Fix a bug where entire modules would be excluded by `--no-include-undocumented`.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pdoc
3
- Version: 14.6.1
3
+ Version: 15.0.0
4
4
  Summary: API Documentation for Python Projects
5
5
  Author-email: Maximilian Hils <pdoc@maximilianhils.com>
6
6
  License: MIT-0
@@ -16,30 +16,18 @@ Classifier: Development Status :: 5 - Production/Stable
16
16
  Classifier: Environment :: Console
17
17
  Classifier: Intended Audience :: Developers
18
18
  Classifier: Operating System :: OS Independent
19
- Classifier: Programming Language :: Python :: 3.8
20
19
  Classifier: Programming Language :: Python :: 3.9
21
20
  Classifier: Programming Language :: Python :: 3.10
22
21
  Classifier: Programming Language :: Python :: 3.11
23
22
  Classifier: Programming Language :: Python :: 3.12
23
+ Classifier: Programming Language :: Python :: 3.13
24
24
  Classifier: Typing :: Typed
25
- Requires-Python: >=3.8
25
+ Requires-Python: >=3.9
26
26
  Description-Content-Type: text/markdown
27
27
  License-File: LICENSE
28
28
  Requires-Dist: Jinja2>=2.11.0
29
29
  Requires-Dist: pygments>=2.12.0
30
- Requires-Dist: MarkupSafe
31
- Requires-Dist: astunparse; python_version < "3.9"
32
- Provides-Extra: dev
33
- Requires-Dist: tox; extra == "dev"
34
- Requires-Dist: ruff; extra == "dev"
35
- Requires-Dist: mypy; extra == "dev"
36
- Requires-Dist: types-pygments; extra == "dev"
37
- Requires-Dist: pytest; extra == "dev"
38
- Requires-Dist: pytest-cov; extra == "dev"
39
- Requires-Dist: pytest-timeout; extra == "dev"
40
- Requires-Dist: hypothesis; extra == "dev"
41
- Requires-Dist: pygments>=2.14.0; extra == "dev"
42
- Requires-Dist: pdoc-pyo3-sample-library==1.0.11; extra == "dev"
30
+ Requires-Dist: MarkupSafe>=1.1.1
43
31
 
44
32
  <p align="center">
45
33
  <a href="https://pdoc.dev/"><img alt="pdoc" src="https://pdoc.dev/logo.svg" width="200" height="100" /></a>
@@ -64,7 +52,7 @@ API Documentation for Python Projects.
64
52
  pip install pdoc
65
53
  ```
66
54
 
67
- pdoc is compatible with Python 3.8 and newer.
55
+ pdoc is compatible with Python 3.9 and newer.
68
56
 
69
57
 
70
58
  # Usage
@@ -21,7 +21,7 @@ API Documentation for Python Projects.
21
21
  pip install pdoc
22
22
  ```
23
23
 
24
- pdoc is compatible with Python 3.8 and newer.
24
+ pdoc is compatible with Python 3.9 and newer.
25
25
 
26
26
 
27
27
  # Usage
@@ -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__ = "14.6.1" # this is read from setup.py
484
+ __version__ = "15.0.0" # this is read from setup.py
485
485
 
486
486
  from pathlib import Path
487
487
  from typing import overload
@@ -7,7 +7,6 @@ import subprocess
7
7
  import sys
8
8
  import warnings
9
9
 
10
- from pdoc._compat import BooleanOptionalAction
11
10
  import pdoc.doc
12
11
  import pdoc.extract
13
12
  import pdoc.render
@@ -57,7 +56,7 @@ renderopts.add_argument(
57
56
  )
58
57
  renderopts.add_argument(
59
58
  "--include-undocumented",
60
- action=BooleanOptionalAction,
59
+ action=argparse.BooleanOptionalAction,
61
60
  default=True,
62
61
  help="Show classes/functions/variables that do not have a docstring.",
63
62
  )
@@ -98,25 +97,25 @@ renderopts.add_argument(
98
97
  )
99
98
  renderopts.add_argument(
100
99
  "--math",
101
- action=BooleanOptionalAction,
100
+ action=argparse.BooleanOptionalAction,
102
101
  default=False,
103
102
  help="Include MathJax from a CDN to enable math formula rendering.",
104
103
  )
105
104
  renderopts.add_argument(
106
105
  "--mermaid",
107
- action=BooleanOptionalAction,
106
+ action=argparse.BooleanOptionalAction,
108
107
  default=False,
109
108
  help="Include Mermaid.js from a CDN to enable Mermaid diagram rendering.",
110
109
  )
111
110
  renderopts.add_argument(
112
111
  "--search",
113
- action=BooleanOptionalAction,
112
+ action=argparse.BooleanOptionalAction,
114
113
  default=True,
115
114
  help="Enable search functionality if multiple modules are documented.",
116
115
  )
117
116
  renderopts.add_argument(
118
117
  "--show-source",
119
- action=BooleanOptionalAction,
118
+ action=argparse.BooleanOptionalAction,
120
119
  default=True,
121
120
  help='Display "View Source" buttons.',
122
121
  )
@@ -0,0 +1,60 @@
1
+ # fmt: off
2
+ import sys
3
+
4
+ if sys.version_info >= (3, 12):
5
+ from ast import TypeAlias as ast_TypeAlias
6
+ else: # pragma: no cover
7
+ class ast_TypeAlias:
8
+ pass
9
+
10
+ if sys.version_info >= (3, 12):
11
+ from typing import TypeAliasType
12
+ else: # pragma: no cover
13
+ class TypeAliasType:
14
+ """Placeholder class for TypeAliasType"""
15
+
16
+ if sys.version_info >= (3, 10):
17
+ from typing import TypeAlias
18
+ else: # pragma: no cover
19
+ class TypeAlias:
20
+ pass
21
+
22
+ if sys.version_info >= (3, 10):
23
+ from types import UnionType # type: ignore
24
+ else: # pragma: no cover
25
+ class UnionType:
26
+ pass
27
+
28
+
29
+ if (3, 9) <= sys.version_info < (3, 9, 8) or (3, 10) <= sys.version_info < (3, 10, 1): # pragma: no cover
30
+ import inspect
31
+ import types
32
+
33
+ def formatannotation(annotation) -> str:
34
+ """
35
+ https://github.com/python/cpython/pull/29212
36
+ """
37
+ if isinstance(annotation, types.GenericAlias):
38
+ return str(annotation)
39
+ return inspect.formatannotation(annotation)
40
+ else:
41
+ from inspect import formatannotation
42
+
43
+ if sys.version_info >= (3, 10):
44
+ from typing import is_typeddict
45
+ else: # pragma: no cover
46
+ def is_typeddict(tp):
47
+ try:
48
+ return tp.__orig_bases__[-1].__name__ == "TypedDict"
49
+ except Exception:
50
+ return False
51
+
52
+
53
+ __all__ = [
54
+ "ast_TypeAlias",
55
+ "TypeAliasType",
56
+ "TypeAlias",
57
+ "UnionType",
58
+ "formatannotation",
59
+ "is_typeddict",
60
+ ]
@@ -23,6 +23,7 @@ from abc import abstractmethod
23
23
  from collections.abc import Callable
24
24
  import dataclasses
25
25
  import enum
26
+ from functools import cache
26
27
  from functools import cached_property
27
28
  from functools import singledispatchmethod
28
29
  from functools import wraps
@@ -48,7 +49,6 @@ from pdoc import doc_pyi
48
49
  from pdoc import extract
49
50
  from pdoc._compat import TypeAlias
50
51
  from pdoc._compat import TypeAliasType
51
- from pdoc._compat import cache
52
52
  from pdoc._compat import formatannotation
53
53
  from pdoc._compat import is_typeddict
54
54
  from pdoc.doc_types import GenericAlias
@@ -1132,9 +1132,11 @@ class Variable(Doc[None]):
1132
1132
  if self.default_value is empty:
1133
1133
  return ""
1134
1134
  if isinstance(self.default_value, TypeAliasType):
1135
- return formatannotation(self.default_value.__value__)
1135
+ formatted = formatannotation(self.default_value.__value__)
1136
+ return _remove_collections_abc(formatted)
1136
1137
  elif self.annotation == TypeAlias:
1137
- return formatannotation(self.default_value)
1138
+ formatted = formatannotation(self.default_value)
1139
+ return _remove_collections_abc(formatted)
1138
1140
 
1139
1141
  # This is not perfect, but a solid attempt at preventing accidental leakage of secrets.
1140
1142
  # If you have input on how to improve the heuristic, please send a pull request!
@@ -1166,7 +1168,8 @@ class Variable(Doc[None]):
1166
1168
  def annotation_str(self) -> str:
1167
1169
  """The variable's type annotation as a pretty-printed str."""
1168
1170
  if self.annotation is not empty:
1169
- return f": {formatannotation(self.annotation)}"
1171
+ formatted = formatannotation(self.annotation)
1172
+ return f": {_remove_collections_abc(formatted)}"
1170
1173
  else:
1171
1174
  return ""
1172
1175
 
@@ -1202,6 +1205,7 @@ class _PrettySignature(inspect.Signature):
1202
1205
  for param in self.parameters.values():
1203
1206
  formatted = str(param)
1204
1207
  formatted = _remove_memory_addresses(formatted)
1208
+ formatted = _remove_collections_abc(formatted)
1205
1209
 
1206
1210
  kind = param.kind
1207
1211
 
@@ -1238,7 +1242,8 @@ class _PrettySignature(inspect.Signature):
1238
1242
 
1239
1243
  def _return_annotation_str(self) -> str:
1240
1244
  if self.return_annotation is not empty:
1241
- return formatannotation(self.return_annotation)
1245
+ formatted = formatannotation(self.return_annotation)
1246
+ return _remove_collections_abc(formatted)
1242
1247
  else:
1243
1248
  return ""
1244
1249
 
@@ -1333,3 +1338,8 @@ _Enum_default_docstrings = tuple(
1333
1338
  def _remove_memory_addresses(x: str) -> str:
1334
1339
  """Remove memory addresses from repr() output"""
1335
1340
  return re.sub(r" at 0x[0-9a-fA-F]+(?=>)", "", x)
1341
+
1342
+
1343
+ def _remove_collections_abc(x: str) -> str:
1344
+ """Remove 'collections.abc' from type signatures."""
1345
+ return re.sub(r"(?!\.)\bcollections\.abc\.", "", x)
@@ -10,6 +10,7 @@ import ast
10
10
  from collections.abc import Iterable
11
11
  from collections.abc import Iterator
12
12
  from dataclasses import dataclass
13
+ from functools import cache
13
14
  import inspect
14
15
  from itertools import tee
15
16
  from itertools import zip_longest
@@ -23,8 +24,6 @@ import warnings
23
24
  import pdoc
24
25
 
25
26
  from ._compat import ast_TypeAlias
26
- from ._compat import ast_unparse
27
- from ._compat import cache
28
27
 
29
28
  if TYPE_CHECKING:
30
29
  import pdoc.doc_types
@@ -81,7 +80,7 @@ def parse(obj):
81
80
  @cache
82
81
  def unparse(tree: ast.AST):
83
82
  """`ast.unparse`, but cached."""
84
- return ast_unparse(tree)
83
+ return ast.unparse(tree)
85
84
 
86
85
 
87
86
  @dataclass
@@ -240,12 +239,11 @@ def _parse_class(source: str) -> ast.ClassDef:
240
239
  Returns an empty ast.ClassDef if source is empty.
241
240
  """
242
241
  tree = _parse(source)
243
- assert len(tree.body) <= 1
244
- if tree.body:
242
+ if tree.body and len(tree.body) == 1:
245
243
  t = tree.body[0]
246
- assert isinstance(t, ast.ClassDef)
247
- return t
248
- return ast.ClassDef(body=[], decorator_list=[]) # type: ignore
244
+ if isinstance(t, ast.ClassDef):
245
+ return t
246
+ return ast.ClassDef(name="PdocStub", body=[], decorator_list=[]) # type: ignore
249
247
 
250
248
 
251
249
  @cache
@@ -256,8 +254,7 @@ def _parse_function(source: str) -> ast.FunctionDef | ast.AsyncFunctionDef:
256
254
  Returns an empty ast.FunctionDef if source is empty.
257
255
  """
258
256
  tree = _parse(source)
259
- assert len(tree.body) <= 1
260
- if tree.body:
257
+ if tree.body and len(tree.body) == 1:
261
258
  t = tree.body[0]
262
259
  if isinstance(t, (ast.FunctionDef, ast.AsyncFunctionDef)):
263
260
  return t
@@ -265,7 +262,9 @@ def _parse_function(source: str) -> ast.FunctionDef | ast.AsyncFunctionDef:
265
262
  # we have a lambda function,
266
263
  # to simplify the API return the ast.FunctionDef stub.
267
264
  pass
268
- return ast.FunctionDef(body=[], decorator_list=[]) # type: ignore
265
+ return ast.FunctionDef(
266
+ name="pdoc_stub", args=ast.arguments(), body=[], decorator_list=[]
267
+ ) # type: ignore
269
268
 
270
269
 
271
270
  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
+ from functools import cache
9
10
  import importlib.util
10
11
  from pathlib import Path
11
12
  import sys
@@ -17,8 +18,6 @@ import warnings
17
18
 
18
19
  from pdoc import doc
19
20
 
20
- from ._compat import cache
21
-
22
21
  overload_docstr = typing.overload(lambda: None).__doc__
23
22
 
24
23
 
@@ -14,6 +14,7 @@ import operator
14
14
  import sys
15
15
  import types
16
16
  from types import BuiltinFunctionType
17
+ from types import GenericAlias
17
18
  from types import ModuleType
18
19
  import typing
19
20
  from typing import TYPE_CHECKING
@@ -24,7 +25,6 @@ from typing import get_origin
24
25
  import warnings
25
26
 
26
27
  from . import extract
27
- from ._compat import GenericAlias
28
28
  from ._compat import UnionType
29
29
  from .doc_ast import type_checking_sections
30
30
 
@@ -14,6 +14,7 @@ accompanied by matching snapshot tests in `test/testdata/`.
14
14
  from __future__ import annotations
15
15
 
16
16
  import base64
17
+ from functools import cache
17
18
  import inspect
18
19
  import mimetypes
19
20
  import os
@@ -23,8 +24,6 @@ from textwrap import dedent
23
24
  from textwrap import indent
24
25
  import warnings
25
26
 
26
- from ._compat import cache
27
-
28
27
 
29
28
  @cache
30
29
  def convert(docstring: str, docformat: str, source_file: Path | None) -> str:
@@ -201,11 +201,13 @@ def mock_some_common_side_effects():
201
201
 
202
202
  Note that this function must not be used for security purposes, it's easily bypassable.
203
203
  """
204
- with patch("subprocess.Popen", new=_PdocDefusedPopen), patch(
205
- "os.startfile", new=_noop, create=True
206
- ), patch("sys.stdout", new=io.StringIO()), patch(
207
- "sys.stderr", new=io.StringIO()
208
- ), patch("sys.stdin", new=io.StringIO()):
204
+ with (
205
+ patch("subprocess.Popen", new=_PdocDefusedPopen),
206
+ patch("os.startfile", new=_noop, create=True),
207
+ patch("sys.stdout", new=io.TextIOWrapper(io.BytesIO())),
208
+ patch("sys.stderr", new=io.TextIOWrapper(io.BytesIO())),
209
+ patch("sys.stdin", new=io.TextIOWrapper(io.BytesIO())),
210
+ ):
209
211
  yield
210
212
 
211
213
 
@@ -177,7 +177,7 @@ _default_searchpath = [
177
177
 
178
178
  env = Environment(
179
179
  loader=FileSystemLoader(_default_searchpath),
180
- extensions=[DefaultMacroExtension],
180
+ extensions=["jinja2.ext.loopcontrols", DefaultMacroExtension],
181
181
  autoescape=True,
182
182
  trim_blocks=True,
183
183
  lstrip_blocks=True,
@@ -4,6 +4,7 @@ from collections.abc import Collection
4
4
  from collections.abc import Iterable
5
5
  from collections.abc import Mapping
6
6
  from contextlib import contextmanager
7
+ from functools import cache
7
8
  import html
8
9
  import inspect
9
10
  import os
@@ -28,8 +29,6 @@ from markupsafe import Markup
28
29
  import pdoc.markdown2
29
30
 
30
31
  from . import docstrings
31
- from ._compat import cache
32
- from ._compat import removesuffix
33
32
 
34
33
  lexer = pygments.lexers.PythonLexer()
35
34
  """
@@ -307,11 +306,17 @@ def module_candidates(identifier: str, current_module: str) -> Iterable[str]:
307
306
 
308
307
 
309
308
  @pass_context
310
- def linkify(context: Context, code: str, namespace: str = "") -> str:
309
+ def linkify(
310
+ context: Context, code: str, namespace: str = "", shorten: bool = True
311
+ ) -> str:
311
312
  """
312
313
  Link all identifiers in a block of text. Identifiers referencing unknown modules or modules that
313
314
  are not rendered at the moment will be ignored.
314
315
  A piece of text is considered to be an identifier if it either contains a `.` or is surrounded by `<code>` tags.
316
+
317
+ If `shorten` is True, replace identifiers with short forms where possible.
318
+ For example, replace "current_module.Foo" with "Foo". This is useful for annotations
319
+ (which are verbose), but undesired for docstrings (where we want to preserve intent).
315
320
  """
316
321
 
317
322
  def linkify_repl(m: re.Match):
@@ -322,7 +327,7 @@ def linkify(context: Context, code: str, namespace: str = "") -> str:
322
327
  plain_text = text.replace(
323
328
  '</span><span class="o">.</span><span class="n">', "."
324
329
  )
325
- identifier = removesuffix(plain_text, "()")
330
+ identifier = plain_text.removesuffix("()")
326
331
  mod: pdoc.doc.Module = context["module"]
327
332
 
328
333
  # Check if this is a relative reference. These cannot be local and need to be resolved.
@@ -381,12 +386,15 @@ def linkify(context: Context, code: str, namespace: str = "") -> str:
381
386
  and (target_object is doc.obj or target_object is None)
382
387
  and context["is_public"](doc).strip()
383
388
  ):
384
- if module == mod:
385
- url_text = qualname
389
+ if shorten:
390
+ if module == mod:
391
+ url_text = qualname
392
+ else:
393
+ url_text = doc.fullname
394
+ if plain_text.endswith("()"):
395
+ url_text += "()"
386
396
  else:
387
- url_text = doc.fullname
388
- if plain_text.endswith("()"):
389
- url_text += "()"
397
+ url_text = plain_text
390
398
  return f'<a href="{relative_link(context["module"].modulename, doc.modulename)}#{qualname}">{url_text}</a>'
391
399
 
392
400
  # No matches found.
@@ -453,7 +461,7 @@ def link(context: Context, spec: tuple[str, str], text: str | None = None) -> st
453
461
  if mod.modulename == modulename:
454
462
  fullname = qualname
455
463
  else:
456
- fullname = removesuffix(f"{modulename}.{qualname}", ".")
464
+ fullname = f"{modulename}.{qualname}".removesuffix(".")
457
465
 
458
466
  if qualname:
459
467
  qualname = f"#{qualname}"
@@ -308,6 +308,13 @@ This makes sure that the pdoc styling doesn't leak to the rest of the page when
308
308
  margin-left: 2rem;
309
309
  }
310
310
 
311
+ .pdoc .decorator-deprecated {
312
+ color: #842029;
313
+ }
314
+ .pdoc .decorator-deprecated ~ span {
315
+ filter: grayscale(1) opacity(0.8);
316
+ }
317
+
311
318
  .pdoc .name {
312
319
  color: var(--name);
313
320
  font-weight: bold;
@@ -162,7 +162,7 @@ See https://pdoc.dev/docs/pdoc/render_helpers.html#DefaultMacroExtension for an
162
162
  {% enddefaultmacro %}
163
163
  {% defaultmacro decorators(doc) %}
164
164
  {% for d in doc.decorators if not d.startswith("@_") %}
165
- <div class="decorator">{{ d }}</div>
165
+ <div class="decorator decorator-{{ d[1:].partition("(")[0] }}">{{ d }}</div>
166
166
  {% endfor %}
167
167
  {% enddefaultmacro %}
168
168
  {% defaultmacro function(fn) -%}
@@ -209,7 +209,7 @@ See https://pdoc.dev/docs/pdoc/render_helpers.html#DefaultMacroExtension for an
209
209
  {% enddefaultmacro %}
210
210
  {% defaultmacro docstring(var) %}
211
211
  {% if var.docstring %}
212
- <div class="docstring">{{ var.docstring | replace("@public", "") | to_markdown | to_html | linkify(namespace=var.qualname) }}</div>
212
+ <div class="docstring">{{ var.docstring | replace("@public", "") | to_markdown | to_html | linkify(namespace=var.qualname, shorten=False) }}</div>
213
213
  {% endif %}
214
214
  {% enddefaultmacro %}
215
215
  {% defaultmacro nav_members(members) %}
@@ -266,6 +266,10 @@ See https://pdoc.dev/docs/pdoc/render_helpers.html#DefaultMacroExtension for an
266
266
  {# fmt: off #}
267
267
  {% defaultmacro inherited(cls) %}
268
268
  {% for base, members in cls.inherited_members.items() %}
269
+ {% if base[0] not in all_modules %}
270
+ {# hide inherited members from modules that are not in the documentation, https://github.com/mitmproxy/pdoc/issues/715 #}
271
+ {% continue %}
272
+ {% endif %}
269
273
  {% set m = None %}{# workaround for https://github.com/pallets/jinja/issues/1427 #}
270
274
  {% set member_html %}
271
275
  {% for m in members if is_public(m) | trim %}
@@ -10,6 +10,7 @@ from __future__ import annotations
10
10
 
11
11
  from collections.abc import Iterable
12
12
  from collections.abc import Iterator
13
+ from functools import cache
13
14
  import http.server
14
15
  import traceback
15
16
  from typing import Mapping
@@ -19,8 +20,6 @@ import webbrowser
19
20
  from pdoc import doc
20
21
  from pdoc import extract
21
22
  from pdoc import render
22
- from pdoc._compat import cache
23
- from pdoc._compat import removesuffix
24
23
 
25
24
 
26
25
  class DocHandler(http.server.BaseHTTPRequestHandler):
@@ -52,7 +51,7 @@ class DocHandler(http.server.BaseHTTPRequestHandler):
52
51
  self.send_header("content-type", "application/javascript")
53
52
  self.end_headers()
54
53
  return self.server.render_search_index()
55
- elif "." in removesuffix(path, ".html"):
54
+ elif "." in path.removesuffix(".html"):
56
55
  # See https://github.com/mitmproxy/pdoc/issues/615: All module separators should be normalized to "/".
57
56
  # We could redirect here, but that would create the impression of a working link, which will fall apart
58
57
  # when pdoc prerenders to static HTML. So we rather fail early.
@@ -60,7 +59,7 @@ class DocHandler(http.server.BaseHTTPRequestHandler):
60
59
  self.end_headers()
61
60
  return "Not Found: Please normalize all module separators to '/'."
62
61
  else:
63
- module_name = removesuffix(path.lstrip("/"), ".html").replace("/", ".")
62
+ module_name = path.lstrip("/").removesuffix(".html").replace("/", ".")
64
63
  if module_name not in self.server.all_modules:
65
64
  self.send_response(404)
66
65
  self.send_header("content-type", "text/html")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pdoc
3
- Version: 14.6.1
3
+ Version: 15.0.0
4
4
  Summary: API Documentation for Python Projects
5
5
  Author-email: Maximilian Hils <pdoc@maximilianhils.com>
6
6
  License: MIT-0
@@ -16,30 +16,18 @@ Classifier: Development Status :: 5 - Production/Stable
16
16
  Classifier: Environment :: Console
17
17
  Classifier: Intended Audience :: Developers
18
18
  Classifier: Operating System :: OS Independent
19
- Classifier: Programming Language :: Python :: 3.8
20
19
  Classifier: Programming Language :: Python :: 3.9
21
20
  Classifier: Programming Language :: Python :: 3.10
22
21
  Classifier: Programming Language :: Python :: 3.11
23
22
  Classifier: Programming Language :: Python :: 3.12
23
+ Classifier: Programming Language :: Python :: 3.13
24
24
  Classifier: Typing :: Typed
25
- Requires-Python: >=3.8
25
+ Requires-Python: >=3.9
26
26
  Description-Content-Type: text/markdown
27
27
  License-File: LICENSE
28
28
  Requires-Dist: Jinja2>=2.11.0
29
29
  Requires-Dist: pygments>=2.12.0
30
- Requires-Dist: MarkupSafe
31
- Requires-Dist: astunparse; python_version < "3.9"
32
- Provides-Extra: dev
33
- Requires-Dist: tox; extra == "dev"
34
- Requires-Dist: ruff; extra == "dev"
35
- Requires-Dist: mypy; extra == "dev"
36
- Requires-Dist: types-pygments; extra == "dev"
37
- Requires-Dist: pytest; extra == "dev"
38
- Requires-Dist: pytest-cov; extra == "dev"
39
- Requires-Dist: pytest-timeout; extra == "dev"
40
- Requires-Dist: hypothesis; extra == "dev"
41
- Requires-Dist: pygments>=2.14.0; extra == "dev"
42
- Requires-Dist: pdoc-pyo3-sample-library==1.0.11; extra == "dev"
30
+ Requires-Dist: MarkupSafe>=1.1.1
43
31
 
44
32
  <p align="center">
45
33
  <a href="https://pdoc.dev/"><img alt="pdoc" src="https://pdoc.dev/logo.svg" width="200" height="100" /></a>
@@ -64,7 +52,7 @@ API Documentation for Python Projects.
64
52
  pip install pdoc
65
53
  ```
66
54
 
67
- pdoc is compatible with Python 3.8 and newer.
55
+ pdoc is compatible with Python 3.9 and newer.
68
56
 
69
57
 
70
58
  # Usage
@@ -0,0 +1,3 @@
1
+ Jinja2>=2.11.0
2
+ pygments>=2.12.0
3
+ MarkupSafe>=1.1.1
@@ -2,7 +2,7 @@
2
2
  name = "pdoc"
3
3
  description = "API Documentation for Python Projects"
4
4
  readme = "README.md"
5
- requires-python = ">=3.8"
5
+ requires-python = ">=3.9"
6
6
  license = { text="MIT-0" }
7
7
  authors = [{name = "Maximilian Hils", email = "pdoc@maximilianhils.com"}]
8
8
  dynamic = ["version"]
@@ -10,8 +10,7 @@ dynamic = ["version"]
10
10
  dependencies = [
11
11
  "Jinja2 >= 2.11.0",
12
12
  "pygments >= 2.12.0",
13
- "MarkupSafe",
14
- "astunparse; python_version<'3.9'",
13
+ "MarkupSafe >= 1.1.1",
15
14
  ]
16
15
 
17
16
  classifiers = [
@@ -23,11 +22,11 @@ classifiers = [
23
22
  "Environment :: Console",
24
23
  "Intended Audience :: Developers",
25
24
  "Operating System :: OS Independent",
26
- "Programming Language :: Python :: 3.8",
27
25
  "Programming Language :: Python :: 3.9",
28
26
  "Programming Language :: Python :: 3.10",
29
27
  "Programming Language :: Python :: 3.11",
30
28
  "Programming Language :: Python :: 3.12",
29
+ "Programming Language :: Python :: 3.13",
31
30
  "Typing :: Typed",
32
31
  ]
33
32
 
@@ -40,18 +39,18 @@ Issues = "https://github.com/mitmproxy/pdoc/issues"
40
39
  [project.scripts]
41
40
  pdoc = "pdoc.__main__:cli"
42
41
 
43
- [project.optional-dependencies]
44
- dev = [
45
- "tox",
46
- "ruff",
47
- "mypy",
48
- "types-pygments",
49
- "pytest",
50
- "pytest-cov",
51
- "pytest-timeout",
52
- "hypothesis",
53
- "pygments >= 2.14.0",
54
- "pdoc-pyo3-sample-library==1.0.11",
42
+ [tool.uv]
43
+ dev-dependencies = [
44
+ "tox>=4.21.2",
45
+ "tox-uv>=1.13.0",
46
+ "ruff>=0.6.9",
47
+ "mypy>=1.11.2",
48
+ "types-pygments>=2.18.0.20240506",
49
+ "pytest>=8.3.3",
50
+ "pytest-cov>=5.0.0",
51
+ "pytest-timeout>=2.3.1",
52
+ "hypothesis>=6.113.0",
53
+ "pdoc-pyo3-sample-library>=1.0.11",
55
54
  ]
56
55
 
57
56
  [build-system]
@@ -109,17 +108,17 @@ isort = { force-single-line = true, force-sort-within-sections = true }
109
108
  legacy_tox_ini = """
110
109
  [tox]
111
110
  envlist = lint, py
112
- skipsdist = True
113
111
  toxworkdir = {env:TOX_WORK_DIR:.tox}
112
+ runner = uv-venv-lock-runner
114
113
 
115
114
  [testenv]
116
- deps =
117
- -r requirements-dev.txt
118
- -e .
119
115
  commands =
120
116
  pdoc --version
121
117
  pytest --cov=pdoc --cov-report term-missing {posargs:-m "not slow"}
122
118
 
119
+ [testenv:old-dependencies]
120
+ uv_resolution = lowest
121
+
123
122
  [testenv:lint]
124
123
  commands =
125
124
  ruff check . {posargs}
@@ -1,7 +1,6 @@
1
1
  import builtins
2
2
  import dataclasses
3
3
  from pathlib import Path
4
- import sys
5
4
  import types
6
5
  from unittest.mock import patch
7
6
 
@@ -120,13 +119,15 @@ def test_builtin_source():
120
119
  assert m.source_lines is None
121
120
 
122
121
 
123
- @pytest.mark.skipif(sys.version_info < (3, 9), reason="3.9+ only")
124
122
  def test_raising_getdoc():
125
- class Foo:
126
- @classmethod
127
- @property
128
- def __doc__(self):
129
- raise RuntimeError
123
+ class FooMeta(type):
124
+ def __getattribute__(cls, name):
125
+ if name == "__doc__":
126
+ raise RuntimeError
127
+ return super().__getattribute__(name)
128
+
129
+ class Foo(metaclass=FooMeta):
130
+ pass
130
131
 
131
132
  x = Class(Foo.__module__, Foo.__qualname__, Foo, (Foo.__module__, Foo.__qualname__))
132
133
  with pytest.warns(UserWarning, match="inspect.getdoc(.+) raised an exception"):
@@ -50,7 +50,9 @@ def test_eval_fail_import_nonexistent(monkeypatch):
50
50
  lambda _: "import typing\nif typing.TYPE_CHECKING:\n\timport nonexistent_module",
51
51
  )
52
52
  a = types.ModuleType("a")
53
- with pytest.warns(UserWarning, match="No module named 'nonexistent_module'"):
53
+ with pytest.warns(
54
+ UserWarning, match="No module named 'nonexistent_module'|Import of xyz failed"
55
+ ):
54
56
  assert safe_eval_type("xyz", a.__dict__, None, a, "a") == "xyz"
55
57
 
56
58
 
@@ -5,6 +5,7 @@ import sys
5
5
  import pytest
6
6
 
7
7
  from pdoc.extract import invalidate_caches
8
+ from pdoc.extract import mock_some_common_side_effects
8
9
  from pdoc.extract import module_mtime
9
10
  from pdoc.extract import parse_spec
10
11
  from pdoc.extract import walk_specs
@@ -137,3 +138,11 @@ def test_invalidate_caches(monkeypatch):
137
138
  monkeypatch.setattr(importlib, "reload", raise_)
138
139
  with pytest.warns(UserWarning, match="Error reloading"):
139
140
  invalidate_caches("pdoc.render_helpers")
141
+
142
+
143
+ def test_mock_sideeffects():
144
+ """https://github.com/mitmproxy/pdoc/issues/745"""
145
+ with mock_some_common_side_effects():
146
+ import sys
147
+
148
+ sys.stdout.reconfigure(encoding="utf-8")
@@ -96,8 +96,9 @@ class Snapshot:
96
96
 
97
97
  snapshots = [
98
98
  Snapshot("ast_parsing"),
99
+ Snapshot("collections_abc", min_version=(3, 9)),
99
100
  Snapshot("demo", min_version=(3, 9)),
100
- Snapshot("enums", min_version=(3, 12)),
101
+ Snapshot("enums", min_version=(3, 13)),
101
102
  Snapshot("flavors_google"),
102
103
  Snapshot("flavors_numpy"),
103
104
  Snapshot("flavors_rst"),
@@ -135,16 +136,9 @@ snapshots = [
135
136
  with_output_directory=True,
136
137
  ),
137
138
  Snapshot("misc"),
138
- Snapshot(
139
- "misc_py39",
140
- min_version=(3, 9),
141
- ),
142
139
  Snapshot("misc_py310", min_version=(3, 10)),
143
- Snapshot("misc_py311", min_version=(3, 11)),
144
- Snapshot(
145
- "misc_py312",
146
- min_version=(3, 12),
147
- ),
140
+ Snapshot("misc_py312", min_version=(3, 12)),
141
+ Snapshot("misc_py313", min_version=(3, 13)),
148
142
  Snapshot("math_demo", render_options={"math": True}),
149
143
  Snapshot("math_misc", render_options={"math": True}),
150
144
  Snapshot("mermaid_demo", render_options={"mermaid": True}, min_version=(3, 9)),
@@ -164,6 +158,7 @@ snapshots = [
164
158
  Snapshot("pyo3_sample_library", specs=["pdoc_pyo3_sample_library"]),
165
159
  Snapshot("top_level_reimports", ["top_level_reimports"]),
166
160
  Snapshot("type_checking_imports", ["type_checking_imports.main"]),
161
+ Snapshot("typed_dict", min_version=(3, 13)),
167
162
  Snapshot("type_stubs", ["type_stubs"], min_version=(3, 10)),
168
163
  Snapshot(
169
164
  "visibility",
@@ -1,148 +0,0 @@
1
- # fmt: off
2
- import sys
3
-
4
- if sys.version_info >= (3, 9):
5
- from functools import cache
6
- else: # pragma: no cover
7
- from functools import lru_cache
8
-
9
- cache = lru_cache(maxsize=None)
10
-
11
- if sys.version_info >= (3, 9):
12
- from ast import unparse as ast_unparse
13
- else: # pragma: no cover
14
- from astunparse import unparse as _unparse
15
-
16
- def ast_unparse(t): # type: ignore
17
- return _unparse(t).strip("\t\n \"'")
18
-
19
- if sys.version_info >= (3, 12):
20
- from ast import TypeAlias as ast_TypeAlias
21
- else: # pragma: no cover
22
- class ast_TypeAlias:
23
- pass
24
-
25
- if sys.version_info >= (3, 12):
26
- from typing import TypeAliasType
27
- else: # pragma: no cover
28
- class TypeAliasType:
29
- """Placeholder class for TypeAliasType"""
30
-
31
- if sys.version_info >= (3, 10):
32
- from typing import TypeAlias
33
- else: # pragma: no cover
34
- class TypeAlias:
35
- pass
36
-
37
- if sys.version_info >= (3, 9):
38
- from types import GenericAlias
39
- else: # pragma: no cover
40
- from typing import _GenericAlias as GenericAlias
41
-
42
- if sys.version_info >= (3, 10):
43
- from types import UnionType # type: ignore
44
- else: # pragma: no cover
45
- class UnionType:
46
- pass
47
-
48
- if sys.version_info >= (3, 9):
49
- removesuffix = str.removesuffix
50
- else: # pragma: no cover
51
- def removesuffix(x: str, suffix: str):
52
- if x.endswith(suffix):
53
- x = x[: -len(suffix)]
54
- return x
55
-
56
- if sys.version_info >= (3, 9):
57
- removeprefix = str.removeprefix
58
- else: # pragma: no cover
59
- def removeprefix(x: str, prefix: str):
60
- if x.startswith(prefix):
61
- x = x[len(prefix):]
62
- return x
63
-
64
-
65
- if (3, 9) <= sys.version_info < (3, 9, 8) or (3, 10) <= sys.version_info < (3, 10, 1): # pragma: no cover
66
- import inspect
67
- import types
68
-
69
- def formatannotation(annotation) -> str:
70
- """
71
- https://github.com/python/cpython/pull/29212
72
- """
73
- if isinstance(annotation, types.GenericAlias):
74
- return str(annotation)
75
- return inspect.formatannotation(annotation)
76
- else:
77
- from inspect import formatannotation
78
-
79
- if sys.version_info >= (3, 9):
80
- from argparse import BooleanOptionalAction
81
- else: # pragma: no cover
82
- # https://github.com/python/cpython/pull/27672
83
- from argparse import Action
84
-
85
- class BooleanOptionalAction(Action): # pragma: no cover
86
- def __init__(self,
87
- option_strings,
88
- dest,
89
- default=None,
90
- type=None,
91
- choices=None,
92
- required=False,
93
- help=None,
94
- metavar=None):
95
-
96
- _option_strings = []
97
- for option_string in option_strings:
98
- _option_strings.append(option_string)
99
-
100
- if option_string.startswith('--'):
101
- option_string = '--no-' + option_string[2:]
102
- _option_strings.append(option_string)
103
-
104
- if help is not None and default is not None:
105
- help += " (default: %(default)s)"
106
-
107
- super().__init__(
108
- option_strings=_option_strings,
109
- dest=dest,
110
- nargs=0,
111
- default=default,
112
- type=type,
113
- choices=choices,
114
- required=required,
115
- help=help,
116
- metavar=metavar)
117
-
118
- def __call__(self, parser, namespace, values, option_string=None):
119
- if option_string in self.option_strings:
120
- setattr(namespace, self.dest, not option_string.startswith('--no-'))
121
-
122
- def format_usage(self):
123
- return ' | '.join(self.option_strings)
124
-
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
-
136
- __all__ = [
137
- "cache",
138
- "ast_unparse",
139
- "ast_TypeAlias",
140
- "TypeAliasType",
141
- "TypeAlias",
142
- "GenericAlias",
143
- "UnionType",
144
- "removesuffix",
145
- "formatannotation",
146
- "BooleanOptionalAction",
147
- "is_typeddict",
148
- ]
@@ -1,18 +0,0 @@
1
- Jinja2>=2.11.0
2
- pygments>=2.12.0
3
- MarkupSafe
4
-
5
- [:python_version < "3.9"]
6
- astunparse
7
-
8
- [dev]
9
- tox
10
- ruff
11
- mypy
12
- types-pygments
13
- pytest
14
- pytest-cov
15
- pytest-timeout
16
- hypothesis
17
- pygments>=2.14.0
18
- pdoc-pyo3-sample-library==1.0.11
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes