diff --git a/pdoc/__main__.py b/pdoc/__main__.py
index 6773bc7d..9aa7204b 100644
--- a/pdoc/__main__.py
+++ b/pdoc/__main__.py
@@ -7,7 +7,6 @@
import sys
import warnings
-from pdoc._compat import BooleanOptionalAction
import pdoc.doc
import pdoc.extract
import pdoc.render
@@ -57,7 +56,7 @@
)
renderopts.add_argument(
"--include-undocumented",
- action=BooleanOptionalAction,
+ action=argparse.BooleanOptionalAction,
default=True,
help="Show classes/functions/variables that do not have a docstring.",
)
diff --git a/pdoc/_compat.py b/pdoc/_compat.py
index 32af1e66..25c3c323 100644
--- a/pdoc/_compat.py
+++ b/pdoc/_compat.py
@@ -1,21 +1,6 @@
# fmt: off
import sys
-if sys.version_info >= (3, 9):
- from functools import cache
-else: # pragma: no cover
- from functools import lru_cache
-
- cache = lru_cache(maxsize=None)
-
-if sys.version_info >= (3, 9):
- from ast import unparse as ast_unparse
-else: # pragma: no cover
- from astunparse import unparse as _unparse
-
- def ast_unparse(t): # type: ignore
- return _unparse(t).strip("\t\n \"'")
-
if sys.version_info >= (3, 12):
from ast import TypeAlias as ast_TypeAlias
else: # pragma: no cover
@@ -34,33 +19,12 @@ class TypeAliasType:
class TypeAlias:
pass
-if sys.version_info >= (3, 9):
- from types import GenericAlias
-else: # pragma: no cover
- from typing import _GenericAlias as GenericAlias
-
if sys.version_info >= (3, 10):
from types import UnionType # type: ignore
else: # pragma: no cover
class UnionType:
pass
-if sys.version_info >= (3, 9):
- removesuffix = str.removesuffix
-else: # pragma: no cover
- def removesuffix(x: str, suffix: str):
- if x.endswith(suffix):
- x = x[: -len(suffix)]
- return x
-
-if sys.version_info >= (3, 9):
- removeprefix = str.removeprefix
-else: # pragma: no cover
- def removeprefix(x: str, prefix: str):
- if x.startswith(prefix):
- x = x[len(prefix):]
- return x
-
if (3, 9) <= sys.version_info < (3, 9, 8) or (3, 10) <= sys.version_info < (3, 10, 1): # pragma: no cover
import inspect
@@ -76,53 +40,6 @@ def formatannotation(annotation) -> str:
else:
from inspect import formatannotation
-if sys.version_info >= (3, 9):
- from argparse import BooleanOptionalAction
-else: # pragma: no cover
- # https://github.com/python/cpython/pull/27672
- from argparse import Action
-
- class BooleanOptionalAction(Action): # pragma: no cover
- def __init__(self,
- option_strings,
- dest,
- default=None,
- type=None,
- choices=None,
- required=False,
- help=None,
- metavar=None):
-
- _option_strings = []
- for option_string in option_strings:
- _option_strings.append(option_string)
-
- if option_string.startswith('--'):
- option_string = '--no-' + option_string[2:]
- _option_strings.append(option_string)
-
- if help is not None and default is not None:
- help += " (default: %(default)s)"
-
- super().__init__(
- option_strings=_option_strings,
- dest=dest,
- nargs=0,
- default=default,
- type=type,
- choices=choices,
- required=required,
- help=help,
- metavar=metavar)
-
- def __call__(self, parser, namespace, values, option_string=None):
- if option_string in self.option_strings:
- setattr(namespace, self.dest, not option_string.startswith('--no-'))
-
- def format_usage(self):
- return ' | '.join(self.option_strings)
-
-
if sys.version_info >= (3, 10):
from typing import is_typeddict
else: # pragma: no cover
@@ -134,15 +51,10 @@ def is_typeddict(tp):
__all__ = [
- "cache",
- "ast_unparse",
"ast_TypeAlias",
"TypeAliasType",
"TypeAlias",
- "GenericAlias",
"UnionType",
- "removesuffix",
"formatannotation",
- "BooleanOptionalAction",
"is_typeddict",
]
diff --git a/pdoc/doc.py b/pdoc/doc.py
index 5f3c881e..51468dd2 100644
--- a/pdoc/doc.py
+++ b/pdoc/doc.py
@@ -23,6 +23,7 @@
from collections.abc import Callable
import dataclasses
import enum
+from functools import cache
from functools import cached_property
from functools import singledispatchmethod
from functools import wraps
@@ -48,7 +49,6 @@
from pdoc import extract
from pdoc._compat import TypeAlias
from pdoc._compat import TypeAliasType
-from pdoc._compat import cache
from pdoc._compat import formatannotation
from pdoc._compat import is_typeddict
from pdoc.doc_types import GenericAlias
diff --git a/pdoc/doc_ast.py b/pdoc/doc_ast.py
index 4031644c..2a6ed237 100644
--- a/pdoc/doc_ast.py
+++ b/pdoc/doc_ast.py
@@ -11,6 +11,7 @@
from collections.abc import Iterator
from dataclasses import dataclass
import inspect
+from functools import cache
from itertools import tee
from itertools import zip_longest
import types
@@ -23,8 +24,6 @@
import pdoc
from ._compat import ast_TypeAlias
-from ._compat import ast_unparse
-from ._compat import cache
if TYPE_CHECKING:
import pdoc.doc_types
@@ -81,7 +80,7 @@ def parse(obj):
@cache
def unparse(tree: ast.AST):
"""`ast.unparse`, but cached."""
- return ast_unparse(tree)
+ return ast.unparse(tree)
@dataclass
diff --git a/pdoc/doc_pyi.py b/pdoc/doc_pyi.py
index f1df53b4..b2b1e90a 100644
--- a/pdoc/doc_pyi.py
+++ b/pdoc/doc_pyi.py
@@ -7,6 +7,7 @@
from __future__ import annotations
import importlib.util
+from functools import cache
from pathlib import Path
import sys
import traceback
@@ -17,7 +18,6 @@
from pdoc import doc
-from ._compat import cache
overload_docstr = typing.overload(lambda: None).__doc__
diff --git a/pdoc/doc_types.py b/pdoc/doc_types.py
index 67d2c44b..8be7df2f 100644
--- a/pdoc/doc_types.py
+++ b/pdoc/doc_types.py
@@ -14,6 +14,7 @@
import sys
import types
from types import BuiltinFunctionType
+from types import GenericAlias
from types import ModuleType
import typing
from typing import TYPE_CHECKING
@@ -24,7 +25,6 @@
import warnings
from . import extract
-from ._compat import GenericAlias
from ._compat import UnionType
from .doc_ast import type_checking_sections
diff --git a/pdoc/docstrings.py b/pdoc/docstrings.py
index a8cee5e5..30a9be0e 100644
--- a/pdoc/docstrings.py
+++ b/pdoc/docstrings.py
@@ -17,13 +17,13 @@
import inspect
import mimetypes
import os
+from functools import cache
from pathlib import Path
import re
from textwrap import dedent
from textwrap import indent
import warnings
-from ._compat import cache
@cache
diff --git a/pdoc/render_helpers.py b/pdoc/render_helpers.py
index b87c30dc..c2ea2647 100644
--- a/pdoc/render_helpers.py
+++ b/pdoc/render_helpers.py
@@ -8,6 +8,7 @@
import inspect
import os
import re
+from functools import cache
from unittest.mock import patch
import warnings
@@ -28,8 +29,6 @@
import pdoc.markdown2
from . import docstrings
-from ._compat import cache
-from ._compat import removesuffix
lexer = pygments.lexers.PythonLexer()
"""
@@ -328,7 +327,7 @@ def linkify_repl(m: re.Match):
plain_text = text.replace(
'.', "."
)
- identifier = removesuffix(plain_text, "()")
+ identifier = plain_text.removesuffix("()")
mod: pdoc.doc.Module = context["module"]
# Check if this is a relative reference. These cannot be local and need to be resolved.
@@ -462,7 +461,7 @@ def link(context: Context, spec: tuple[str, str], text: str | None = None) -> st
if mod.modulename == modulename:
fullname = qualname
else:
- fullname = removesuffix(f"{modulename}.{qualname}", ".")
+ fullname = f"{modulename}.{qualname}".removesuffix(".")
if qualname:
qualname = f"#{qualname}"
diff --git a/test/testdata/demo_long.html b/test/testdata/demo_long.html
index 59cea137..343e6cac 100644
--- a/test/testdata/demo_long.html
+++ b/test/testdata/demo_long.html
@@ -258,260 +258,259 @@ A Second Section
27from dataclasses import dataclass
28from dataclasses import field
29import enum
- 30from functools import cached_property
- 31import os
- 32from typing import ClassVar
- 33from typing import List
- 34from typing import Optional
- 35from typing import Sequence
- 36from typing import TypeVar
- 37from typing import Union
- 38
- 39from pdoc._compat import cache
- 40
- 41FOO_CONSTANT: int = 42
- 42"""
- 43A happy constant. ✨
- 44pdoc documents constants with their type annotation and default value.
- 45"""
- 46
- 47FOO_SINGLETON: "Foo"
- 48"""
- 49This variable is annotated with a type only, but not assigned to a value.
- 50We also haven't defined the associated type (`Foo`) yet,
- 51so the type annotation in the code in the source code is actually a string literal:
- 52
- 53```python
- 54FOO_SINGLETON: "Foo"
- 55```
- 56
- 57Similar to mypy, pdoc resolves
- 58[string forward references](https://mypy.readthedocs.io/en/stable/kinds_of_types.html#class-name-forward-references)
- 59automatically.
- 60"""
- 61
- 62NO_DOCSTRING: int
- 63# this variable has a type annotation but not docstring.
+ 30from functools import cache
+ 31from functools import cached_property
+ 32import os
+ 33from typing import ClassVar
+ 34from typing import List
+ 35from typing import Optional
+ 36from typing import Sequence
+ 37from typing import TypeVar
+ 38from typing import Union
+ 39
+ 40FOO_CONSTANT: int = 42
+ 41"""
+ 42A happy constant. ✨
+ 43pdoc documents constants with their type annotation and default value.
+ 44"""
+ 45
+ 46FOO_SINGLETON: "Foo"
+ 47"""
+ 48This variable is annotated with a type only, but not assigned to a value.
+ 49We also haven't defined the associated type (`Foo`) yet,
+ 50so the type annotation in the code in the source code is actually a string literal:
+ 51
+ 52```python
+ 53FOO_SINGLETON: "Foo"
+ 54```
+ 55
+ 56Similar to mypy, pdoc resolves
+ 57[string forward references](https://mypy.readthedocs.io/en/stable/kinds_of_types.html#class-name-forward-references)
+ 58automatically.
+ 59"""
+ 60
+ 61NO_DOCSTRING: int
+ 62# this variable has a type annotation but not docstring.
+ 63
64
- 65
- 66def a_simple_function(a: str) -> str:
- 67 """
- 68 This is a basic module-level function.
- 69
- 70 For a more complex example, take a look at `a_complex_function`!
- 71 """
- 72 return a.upper()
+ 65def a_simple_function(a: str) -> str:
+ 66 """
+ 67 This is a basic module-level function.
+ 68
+ 69 For a more complex example, take a look at `a_complex_function`!
+ 70 """
+ 71 return a.upper()
+ 72
73
- 74
- 75T = TypeVar("T")
+ 74T = TypeVar("T")
+ 75
76
- 77
- 78def a_complex_function(
- 79 a: str, b: Union["Foo", str], *, c: Optional[T] = None
- 80) -> Optional[T]:
- 81 """
- 82 This is a function with a fairly complex signature,
- 83 involving type annotations with `typing.Union`, a `typing.TypeVar` (~T),
- 84 as well as a keyword-only arguments (*).
- 85 """
- 86 return None
+ 77def a_complex_function(
+ 78 a: str, b: Union["Foo", str], *, c: Optional[T] = None
+ 79) -> Optional[T]:
+ 80 """
+ 81 This is a function with a fairly complex signature,
+ 82 involving type annotations with `typing.Union`, a `typing.TypeVar` (~T),
+ 83 as well as a keyword-only arguments (*).
+ 84 """
+ 85 return None
+ 86
87
- 88
- 89class Foo:
- 90 """
- 91 `Foo` is a basic class without any parent classes (except for the implicit `object` class).
- 92
- 93 You will see in the definition of `Bar` that docstrings are inherited by default.
- 94
- 95 Functions in the current scope can be referenced without prefix: `a_regular_function()`.
- 96 """
- 97
- 98 an_attribute: Union[str, List["int"]]
- 99 """A regular attribute with type annotations"""
-100
-101 a_class_attribute: ClassVar[str] = "lots of foo!"
-102 """An attribute with a ClassVar annotation."""
-103
-104 def __init__(self) -> None:
-105 """
-106 The constructor is currently always listed first as this feels most natural."""
-107 self.a_constructor_only_attribute: int = 42
-108 """This attribute is defined in the constructor only, but still picked up by pdoc's AST traversal."""
-109
-110 self.undocumented_constructor_attribute = 42
-111 a_complex_function("a", "Foo")
-112
-113 def a_regular_function(self) -> "Foo":
-114 """This is a regular method, returning the object itself."""
-115 return self
-116
-117 @property
-118 def a_property(self) -> str:
-119 """This is a `@property` attribute. pdoc will display it as a variable."""
-120 return "true foo"
-121
-122 @cached_property
-123 def a_cached_property(self) -> str:
-124 """This is a `@functools.cached_property` attribute. pdoc will display it as a variable as well."""
-125 return "true foo"
-126
-127 @cache
-128 def a_cached_function(self) -> str:
-129 """This is method with `@cache` decoration."""
-130 return "true foo"
-131
-132 @classmethod
-133 def a_class_method(cls) -> int:
-134 """This is what a `@classmethod` looks like."""
-135 return 24
-136
-137 @classmethod # type: ignore
-138 @property
-139 def a_class_property(cls) -> int:
-140 """This is what a `@classmethod @property` looks like."""
-141 return 24
-142
-143 @staticmethod
-144 def a_static_method():
-145 """This is what a `@staticmethod` looks like."""
-146 print("Hello World")
+ 88class Foo:
+ 89 """
+ 90 `Foo` is a basic class without any parent classes (except for the implicit `object` class).
+ 91
+ 92 You will see in the definition of `Bar` that docstrings are inherited by default.
+ 93
+ 94 Functions in the current scope can be referenced without prefix: `a_regular_function()`.
+ 95 """
+ 96
+ 97 an_attribute: Union[str, List["int"]]
+ 98 """A regular attribute with type annotations"""
+ 99
+100 a_class_attribute: ClassVar[str] = "lots of foo!"
+101 """An attribute with a ClassVar annotation."""
+102
+103 def __init__(self) -> None:
+104 """
+105 The constructor is currently always listed first as this feels most natural."""
+106 self.a_constructor_only_attribute: int = 42
+107 """This attribute is defined in the constructor only, but still picked up by pdoc's AST traversal."""
+108
+109 self.undocumented_constructor_attribute = 42
+110 a_complex_function("a", "Foo")
+111
+112 def a_regular_function(self) -> "Foo":
+113 """This is a regular method, returning the object itself."""
+114 return self
+115
+116 @property
+117 def a_property(self) -> str:
+118 """This is a `@property` attribute. pdoc will display it as a variable."""
+119 return "true foo"
+120
+121 @cached_property
+122 def a_cached_property(self) -> str:
+123 """This is a `@functools.cached_property` attribute. pdoc will display it as a variable as well."""
+124 return "true foo"
+125
+126 @cache
+127 def a_cached_function(self) -> str:
+128 """This is method with `@cache` decoration."""
+129 return "true foo"
+130
+131 @classmethod
+132 def a_class_method(cls) -> int:
+133 """This is what a `@classmethod` looks like."""
+134 return 24
+135
+136 @classmethod # type: ignore
+137 @property
+138 def a_class_property(cls) -> int:
+139 """This is what a `@classmethod @property` looks like."""
+140 return 24
+141
+142 @staticmethod
+143 def a_static_method():
+144 """This is what a `@staticmethod` looks like."""
+145 print("Hello World")
+146
147
-148
-149class Bar(Foo):
-150 bar: str
-151 """A new attribute defined on this subclass."""
-152
-153 class Baz:
-154 """
-155 This class is an attribute of `Bar`.
-156 To not create overwhelmingly complex trees, pdoc flattens the class hierarchy in the documentation
-157 (but not in the navigation).
-158
-159 It should be noted that inner classes are a pattern you most often want to avoid in Python.
-160 Think about moving stuff in a new package instead!
-161
-162 This class has no __init__ method defined, so pdoc will not show a constructor.
-163 """
-164
-165 def wat(self):
-166 """A regular method. Above, you see what happens if a class has no constructor defined and
-167 no constructor docstring."""
+148class Bar(Foo):
+149 bar: str
+150 """A new attribute defined on this subclass."""
+151
+152 class Baz:
+153 """
+154 This class is an attribute of `Bar`.
+155 To not create overwhelmingly complex trees, pdoc flattens the class hierarchy in the documentation
+156 (but not in the navigation).
+157
+158 It should be noted that inner classes are a pattern you most often want to avoid in Python.
+159 Think about moving stuff in a new package instead!
+160
+161 This class has no __init__ method defined, so pdoc will not show a constructor.
+162 """
+163
+164 def wat(self):
+165 """A regular method. Above, you see what happens if a class has no constructor defined and
+166 no constructor docstring."""
+167
168
-169
-170async def i_am_async(self) -> int:
-171 """
-172 This is an example of an async function.
-173
-174 - Knock, knock
-175 - An async function
-176 - Who's there?
-177 """
-178 raise NotImplementedError
+169async def i_am_async(self) -> int:
+170 """
+171 This is an example of an async function.
+172
+173 - Knock, knock
+174 - An async function
+175 - Who's there?
+176 """
+177 raise NotImplementedError
+178
179
-180
-181@cache
-182def fib(n):
-183 """
-184 This is an example of decorated function. Decorators are included in the documentation as well.
-185 This is often useful when documenting web APIs, for example.
-186 """
-187 if n < 2:
-188 return n
-189 return fib(n - 1) + fib(n - 2)
+180@cache
+181def fib(n):
+182 """
+183 This is an example of decorated function. Decorators are included in the documentation as well.
+184 This is often useful when documenting web APIs, for example.
+185 """
+186 if n < 2:
+187 return n
+188 return fib(n - 1) + fib(n - 2)
+189
190
-191
-192def security(test=os.environ):
-193 """
-194 Default values are generally rendered using repr(),
-195 but some special cases -- like os.environ -- are overridden to avoid leaking sensitive data.
-196 """
-197 return False
+191def security(test=os.environ):
+192 """
+193 Default values are generally rendered using repr(),
+194 but some special cases -- like os.environ -- are overridden to avoid leaking sensitive data.
+195 """
+196 return False
+197
198
-199
-200class DoubleInherit(Foo, Bar.Baz, abc.ABC):
-201 """This is an example of a class that inherits from multiple parent classes."""
+199class DoubleInherit(Foo, Bar.Baz, abc.ABC):
+200 """This is an example of a class that inherits from multiple parent classes."""
+201
202
-203
-204CONST_B = "yes"
-205"""A constant without type annotation"""
-206
-207CONST_NO_DOC = "SHOULD NOT APPEAR"
+203CONST_B = "yes"
+204"""A constant without type annotation"""
+205
+206CONST_NO_DOC = "SHOULD NOT APPEAR"
+207
208
-209
-210@dataclass
-211class DataDemo:
-212 """
-213 This is an example for a dataclass.
-214
-215 As usual, you can link to individual properties: `DataDemo.a`.
-216 """
-217
-218 a: int
-219 """Again, we can document individual properties with docstrings."""
-220 a2: Sequence[str]
-221 # This property has a type annotation but is not documented.
-222 a3 = "a3"
-223 # This property has a default value but is not documented.
-224 a4: str = "a4"
-225 # This property has a type annotation and a default value but is not documented.
-226 b: bool = field(repr=False, default=True)
-227 """This property is assigned to `dataclasses.field()`, which works just as well."""
+209@dataclass
+210class DataDemo:
+211 """
+212 This is an example for a dataclass.
+213
+214 As usual, you can link to individual properties: `DataDemo.a`.
+215 """
+216
+217 a: int
+218 """Again, we can document individual properties with docstrings."""
+219 a2: Sequence[str]
+220 # This property has a type annotation but is not documented.
+221 a3 = "a3"
+222 # This property has a default value but is not documented.
+223 a4: str = "a4"
+224 # This property has a type annotation and a default value but is not documented.
+225 b: bool = field(repr=False, default=True)
+226 """This property is assigned to `dataclasses.field()`, which works just as well."""
+227
228
-229
-230@dataclass
-231class DataDemoExtended(DataDemo):
-232 c: str = "42"
-233 """A new attribute."""
+229@dataclass
+230class DataDemoExtended(DataDemo):
+231 c: str = "42"
+232 """A new attribute."""
+233
234
-235
-236class EnumDemo(enum.Enum):
-237 """
-238 This is an example of an Enum.
-239
-240 As usual, you can link to individual properties: `GREEN`.
-241 """
-242
-243 RED = 1
-244 """I am the red."""
-245 GREEN = 2
-246 """I am green."""
-247 BLUE = enum.auto()
+235class EnumDemo(enum.Enum):
+236 """
+237 This is an example of an Enum.
+238
+239 As usual, you can link to individual properties: `GREEN`.
+240 """
+241
+242 RED = 1
+243 """I am the red."""
+244 GREEN = 2
+245 """I am green."""
+246 BLUE = enum.auto()
+247
248
-249
-250def embed_image():
-251 """
-252 This docstring includes an embedded image:
-253
-254 ```
-255 ![pdoc logo](../docs/logo.png)
-256 ```
-257
-258 ![pdoc logo](../../docs/logo.png)
-259 """
+249def embed_image():
+250 """
+251 This docstring includes an embedded image:
+252
+253 ```
+254 ![pdoc logo](../docs/logo.png)
+255 ```
+256
+257 ![pdoc logo](../../docs/logo.png)
+258 """
+259
260
-261
-262def admonitions():
-263 """
-264 pdoc also supports basic reStructuredText admonitions or GitHub's Markdown alerts:
-265
-266 ```
-267 > [!NOTE/WARNING/DANGER]
-268 > Useful information that users should know, even when skimming content.
-269
-270 .. note/warning/danger:: Optional title
-271 Body text
-272 ```
-273
-274 > [!NOTE]
-275 > Hi there!
-276
-277 .. warning:: Be Careful!
-278 This warning has both a title *and* content.
-279
-280 .. danger::
-281 Danger ahead.
-282
-283 """
+261def admonitions():
+262 """
+263 pdoc also supports basic reStructuredText admonitions or GitHub's Markdown alerts:
+264
+265 ```
+266 > [!NOTE/WARNING/DANGER]
+267 > Useful information that users should know, even when skimming content.
+268
+269 .. note/warning/danger:: Optional title
+270 Body text
+271 ```
+272
+273 > [!NOTE]
+274 > Hi there!
+275
+276 .. warning:: Be Careful!
+277 This warning has both a title *and* content.
+278
+279 .. danger::
+280 Danger ahead.
+281
+282 """
@@ -577,13 +576,13 @@
67def a_simple_function(a: str) -> str: -68 """ -69 This is a basic module-level function. -70 -71 For a more complex example, take a look at `a_complex_function`! -72 """ -73 return a.upper() +@@ -605,15 +604,15 @@66def a_simple_function(a: str) -> str: +67 """ +68 This is a basic module-level function. +69 +70 For a more complex example, take a look at `a_complex_function`! +71 """ +72 return a.upper()A Second Section
79def a_complex_function( -80 a: str, b: Union["Foo", str], *, c: Optional[T] = None -81) -> Optional[T]: -82 """ -83 This is a function with a fairly complex signature, -84 involving type annotations with `typing.Union`, a `typing.TypeVar` (~T), -85 as well as a keyword-only arguments (*). -86 """ -87 return None +@@ -635,64 +634,64 @@78def a_complex_function( +79 a: str, b: Union["Foo", str], *, c: Optional[T] = None +80) -> Optional[T]: +81 """ +82 This is a function with a fairly complex signature, +83 involving type annotations with `typing.Union`, a `typing.TypeVar` (~T), +84 as well as a keyword-only arguments (*). +85 """ +86 return NoneA Second Section
90class Foo: - 91 """ - 92 `Foo` is a basic class without any parent classes (except for the implicit `object` class). - 93 - 94 You will see in the definition of `Bar` that docstrings are inherited by default. - 95 - 96 Functions in the current scope can be referenced without prefix: `a_regular_function()`. - 97 """ - 98 - 99 an_attribute: Union[str, List["int"]] -100 """A regular attribute with type annotations""" -101 -102 a_class_attribute: ClassVar[str] = "lots of foo!" -103 """An attribute with a ClassVar annotation.""" -104 -105 def __init__(self) -> None: -106 """ -107 The constructor is currently always listed first as this feels most natural.""" -108 self.a_constructor_only_attribute: int = 42 -109 """This attribute is defined in the constructor only, but still picked up by pdoc's AST traversal.""" -110 -111 self.undocumented_constructor_attribute = 42 -112 a_complex_function("a", "Foo") -113 -114 def a_regular_function(self) -> "Foo": -115 """This is a regular method, returning the object itself.""" -116 return self -117 -118 @property -119 def a_property(self) -> str: -120 """This is a `@property` attribute. pdoc will display it as a variable.""" -121 return "true foo" -122 -123 @cached_property -124 def a_cached_property(self) -> str: -125 """This is a `@functools.cached_property` attribute. pdoc will display it as a variable as well.""" -126 return "true foo" -127 -128 @cache -129 def a_cached_function(self) -> str: -130 """This is method with `@cache` decoration.""" -131 return "true foo" -132 -133 @classmethod -134 def a_class_method(cls) -> int: -135 """This is what a `@classmethod` looks like.""" -136 return 24 -137 -138 @classmethod # type: ignore -139 @property -140 def a_class_property(cls) -> int: -141 """This is what a `@classmethod @property` looks like.""" -142 return 24 -143 -144 @staticmethod -145 def a_static_method(): -146 """This is what a `@staticmethod` looks like.""" -147 print("Hello World") +@@ -714,14 +713,14 @@89class Foo: + 90 """ + 91 `Foo` is a basic class without any parent classes (except for the implicit `object` class). + 92 + 93 You will see in the definition of `Bar` that docstrings are inherited by default. + 94 + 95 Functions in the current scope can be referenced without prefix: `a_regular_function()`. + 96 """ + 97 + 98 an_attribute: Union[str, List["int"]] + 99 """A regular attribute with type annotations""" +100 +101 a_class_attribute: ClassVar[str] = "lots of foo!" +102 """An attribute with a ClassVar annotation.""" +103 +104 def __init__(self) -> None: +105 """ +106 The constructor is currently always listed first as this feels most natural.""" +107 self.a_constructor_only_attribute: int = 42 +108 """This attribute is defined in the constructor only, but still picked up by pdoc's AST traversal.""" +109 +110 self.undocumented_constructor_attribute = 42 +111 a_complex_function("a", "Foo") +112 +113 def a_regular_function(self) -> "Foo": +114 """This is a regular method, returning the object itself.""" +115 return self +116 +117 @property +118 def a_property(self) -> str: +119 """This is a `@property` attribute. pdoc will display it as a variable.""" +120 return "true foo" +121 +122 @cached_property +123 def a_cached_property(self) -> str: +124 """This is a `@functools.cached_property` attribute. pdoc will display it as a variable as well.""" +125 return "true foo" +126 +127 @cache +128 def a_cached_function(self) -> str: +129 """This is method with `@cache` decoration.""" +130 return "true foo" +131 +132 @classmethod +133 def a_class_method(cls) -> int: +134 """This is what a `@classmethod` looks like.""" +135 return 24 +136 +137 @classmethod # type: ignore +138 @property +139 def a_class_property(cls) -> int: +140 """This is what a `@classmethod @property` looks like.""" +141 return 24 +142 +143 @staticmethod +144 def a_static_method(): +145 """This is what a `@staticmethod` looks like.""" +146 print("Hello World")A Second Section
105 def __init__(self) -> None: -106 """ -107 The constructor is currently always listed first as this feels most natural.""" -108 self.a_constructor_only_attribute: int = 42 -109 """This attribute is defined in the constructor only, but still picked up by pdoc's AST traversal.""" -110 -111 self.undocumented_constructor_attribute = 42 -112 a_complex_function("a", "Foo") +@@ -792,9 +791,9 @@104 def __init__(self) -> None: +105 """ +106 The constructor is currently always listed first as this feels most natural.""" +107 self.a_constructor_only_attribute: int = 42 +108 """This attribute is defined in the constructor only, but still picked up by pdoc's AST traversal.""" +109 +110 self.undocumented_constructor_attribute = 42 +111 a_complex_function("a", "Foo")A Second Section
114 def a_regular_function(self) -> "Foo": -115 """This is a regular method, returning the object itself.""" -116 return self +@@ -812,10 +811,10 @@113 def a_regular_function(self) -> "Foo": +114 """This is a regular method, returning the object itself.""" +115 return selfA Second Section
118 @property -119 def a_property(self) -> str: -120 """This is a `@property` attribute. pdoc will display it as a variable.""" -121 return "true foo" +@@ -833,10 +832,10 @@117 @property +118 def a_property(self) -> str: +119 """This is a `@property` attribute. pdoc will display it as a variable.""" +120 return "true foo"A Second Section
123 @cached_property -124 def a_cached_property(self) -> str: -125 """This is a `@functools.cached_property` attribute. pdoc will display it as a variable as well.""" -126 return "true foo" +@@ -857,10 +856,10 @@122 @cached_property +123 def a_cached_property(self) -> str: +124 """This is a `@functools.cached_property` attribute. pdoc will display it as a variable as well.""" +125 return "true foo"A Second Section
128 @cache -129 def a_cached_function(self) -> str: -130 """This is method with `@cache` decoration.""" -131 return "true foo" +@@ -881,10 +880,10 @@127 @cache +128 def a_cached_function(self) -> str: +129 """This is method with `@cache` decoration.""" +130 return "true foo"A Second Section
133 @classmethod -134 def a_class_method(cls) -> int: -135 """This is what a `@classmethod` looks like.""" -136 return 24 +@@ -902,11 +901,11 @@132 @classmethod +133 def a_class_method(cls) -> int: +134 """This is what a `@classmethod` looks like.""" +135 return 24A Second Section
138 @classmethod # type: ignore -139 @property -140 def a_class_property(cls) -> int: -141 """This is what a `@classmethod @property` looks like.""" -142 return 24 +@@ -927,10 +926,10 @@137 @classmethod # type: ignore +138 @property +139 def a_class_property(cls) -> int: +140 """This is what a `@classmethod @property` looks like.""" +141 return 24A Second Section
144 @staticmethod -145 def a_static_method(): -146 """This is what a `@staticmethod` looks like.""" -147 print("Hello World") +@@ -951,25 +950,25 @@143 @staticmethod +144 def a_static_method(): +145 """This is what a `@staticmethod` looks like.""" +146 print("Hello World")A Second Section
150class Bar(Foo): -151 bar: str -152 """A new attribute defined on this subclass.""" -153 -154 class Baz: -155 """ -156 This class is an attribute of `Bar`. -157 To not create overwhelmingly complex trees, pdoc flattens the class hierarchy in the documentation -158 (but not in the navigation). -159 -160 It should be noted that inner classes are a pattern you most often want to avoid in Python. -161 Think about moving stuff in a new package instead! -162 -163 This class has no __init__ method defined, so pdoc will not show a constructor. -164 """ -165 -166 def wat(self): -167 """A regular method. Above, you see what happens if a class has no constructor defined and -168 no constructor docstring.""" +@@ -1026,21 +1025,21 @@149class Bar(Foo): +150 bar: str +151 """A new attribute defined on this subclass.""" +152 +153 class Baz: +154 """ +155 This class is an attribute of `Bar`. +156 To not create overwhelmingly complex trees, pdoc flattens the class hierarchy in the documentation +157 (but not in the navigation). +158 +159 It should be noted that inner classes are a pattern you most often want to avoid in Python. +160 Think about moving stuff in a new package instead! +161 +162 This class has no __init__ method defined, so pdoc will not show a constructor. +163 """ +164 +165 def wat(self): +166 """A regular method. Above, you see what happens if a class has no constructor defined and +167 no constructor docstring."""Inherited Members
154 class Baz: -155 """ -156 This class is an attribute of `Bar`. -157 To not create overwhelmingly complex trees, pdoc flattens the class hierarchy in the documentation -158 (but not in the navigation). -159 -160 It should be noted that inner classes are a pattern you most often want to avoid in Python. -161 Think about moving stuff in a new package instead! -162 -163 This class has no __init__ method defined, so pdoc will not show a constructor. -164 """ -165 -166 def wat(self): -167 """A regular method. Above, you see what happens if a class has no constructor defined and -168 no constructor docstring.""" +@@ -1066,9 +1065,9 @@153 class Baz: +154 """ +155 This class is an attribute of `Bar`. +156 To not create overwhelmingly complex trees, pdoc flattens the class hierarchy in the documentation +157 (but not in the navigation). +158 +159 It should be noted that inner classes are a pattern you most often want to avoid in Python. +160 Think about moving stuff in a new package instead! +161 +162 This class has no __init__ method defined, so pdoc will not show a constructor. +163 """ +164 +165 def wat(self): +166 """A regular method. Above, you see what happens if a class has no constructor defined and +167 no constructor docstring."""Inherited Members
166 def wat(self): -167 """A regular method. Above, you see what happens if a class has no constructor defined and -168 no constructor docstring.""" +@@ -1090,15 +1089,15 @@165 def wat(self): +166 """A regular method. Above, you see what happens if a class has no constructor defined and +167 no constructor docstring."""Inherited Members
171async def i_am_async(self) -> int: -172 """ -173 This is an example of an async function. -174 -175 - Knock, knock -176 - An async function -177 - Who's there? -178 """ -179 raise NotImplementedError +@@ -1125,15 +1124,15 @@170async def i_am_async(self) -> int: +171 """ +172 This is an example of an async function. +173 +174 - Knock, knock +175 - An async function +176 - Who's there? +177 """ +178 raise NotImplementedErrorInherited Members
182@cache -183def fib(n): -184 """ -185 This is an example of decorated function. Decorators are included in the documentation as well. -186 This is often useful when documenting web APIs, for example. -187 """ -188 if n < 2: -189 return n -190 return fib(n - 1) + fib(n - 2) +@@ -1154,12 +1153,12 @@181@cache +182def fib(n): +183 """ +184 This is an example of decorated function. Decorators are included in the documentation as well. +185 This is often useful when documenting web APIs, for example. +186 """ +187 if n < 2: +188 return n +189 return fib(n - 1) + fib(n - 2)Inherited Members
193def security(test=os.environ): -194 """ -195 Default values are generally rendered using repr(), -196 but some special cases -- like os.environ -- are overridden to avoid leaking sensitive data. -197 """ -198 return False +@@ -1180,8 +1179,8 @@192def security(test=os.environ): +193 """ +194 Default values are generally rendered using repr(), +195 but some special cases -- like os.environ -- are overridden to avoid leaking sensitive data. +196 """ +197 return FalseInherited Members
201class DoubleInherit(Foo, Bar.Baz, abc.ABC): -202 """This is an example of a class that inherits from multiple parent classes.""" +@@ -1252,24 +1251,24 @@200class DoubleInherit(Foo, Bar.Baz, abc.ABC): +201 """This is an example of a class that inherits from multiple parent classes."""Inherited Members
211@dataclass -212class DataDemo: -213 """ -214 This is an example for a dataclass. -215 -216 As usual, you can link to individual properties: `DataDemo.a`. -217 """ -218 -219 a: int -220 """Again, we can document individual properties with docstrings.""" -221 a2: Sequence[str] -222 # This property has a type annotation but is not documented. -223 a3 = "a3" -224 # This property has a default value but is not documented. -225 a4: str = "a4" -226 # This property has a type annotation and a default value but is not documented. -227 b: bool = field(repr=False, default=True) -228 """This property is assigned to `dataclasses.field()`, which works just as well.""" +@@ -1366,10 +1365,10 @@210@dataclass +211class DataDemo: +212 """ +213 This is an example for a dataclass. +214 +215 As usual, you can link to individual properties: `DataDemo.a`. +216 """ +217 +218 a: int +219 """Again, we can document individual properties with docstrings.""" +220 a2: Sequence[str] +221 # This property has a type annotation but is not documented. +222 a3 = "a3" +223 # This property has a default value but is not documented. +224 a4: str = "a4" +225 # This property has a type annotation and a default value but is not documented. +226 b: bool = field(repr=False, default=True) +227 """This property is assigned to `dataclasses.field()`, which works just as well."""Inherited Members
231@dataclass -232class DataDemoExtended(DataDemo): -233 c: str = "42" -234 """A new attribute.""" + @@ -1426,18 +1425,18 @@Inherited Members
237class EnumDemo(enum.Enum): -238 """ -239 This is an example of an Enum. -240 -241 As usual, you can link to individual properties: `GREEN`. -242 """ -243 -244 RED = 1 -245 """I am the red.""" -246 GREEN = 2 -247 """I am green.""" -248 BLUE = enum.auto() +@@ -1509,16 +1508,16 @@236class EnumDemo(enum.Enum): +237 """ +238 This is an example of an Enum. +239 +240 As usual, you can link to individual properties: `GREEN`. +241 """ +242 +243 RED = 1 +244 """I am the red.""" +245 GREEN = 2 +246 """I am green.""" +247 BLUE = enum.auto()Inherited Members
251def embed_image(): -252 """ -253 This docstring includes an embedded image: -254 -255 ``` -256 ![pdoc logo](../docs/logo.png) -257 ``` -258 -259 ![pdoc logo](../../docs/logo.png) -260 """ +@@ -1543,28 +1542,28 @@250def embed_image(): +251 """ +252 This docstring includes an embedded image: +253 +254 ``` +255 ![pdoc logo](../docs/logo.png) +256 ``` +257 +258 ![pdoc logo](../../docs/logo.png) +259 """Inherited Members
263def admonitions(): -264 """ -265 pdoc also supports basic reStructuredText admonitions or GitHub's Markdown alerts: -266 -267 ``` -268 > [!NOTE/WARNING/DANGER] -269 > Useful information that users should know, even when skimming content. -270 -271 .. note/warning/danger:: Optional title -272 Body text -273 ``` -274 -275 > [!NOTE] -276 > Hi there! -277 -278 .. warning:: Be Careful! -279 This warning has both a title *and* content. -280 -281 .. danger:: -282 Danger ahead. -283 -284 """ +diff --git a/test/testdata/demo_long.py b/test/testdata/demo_long.py index 537307f6..7b85334e 100644 --- a/test/testdata/demo_long.py +++ b/test/testdata/demo_long.py @@ -27,6 +27,7 @@ from dataclasses import dataclass from dataclasses import field import enum +from functools import cache from functools import cached_property import os from typing import ClassVar @@ -36,8 +37,6 @@ from typing import TypeVar from typing import Union -from pdoc._compat import cache - FOO_CONSTANT: int = 42 """ A happy constant. ✨262def admonitions(): +263 """ +264 pdoc also supports basic reStructuredText admonitions or GitHub's Markdown alerts: +265 +266 ``` +267 > [!NOTE/WARNING/DANGER] +268 > Useful information that users should know, even when skimming content. +269 +270 .. note/warning/danger:: Optional title +271 Body text +272 ``` +273 +274 > [!NOTE] +275 > Hi there! +276 +277 .. warning:: Be Careful! +278 This warning has both a title *and* content. +279 +280 .. danger:: +281 Danger ahead. +282 +283 """