diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 4f6d6f9d..e93a6694 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -6,5 +6,6 @@ updates: interval: "monthly" - package-ecosystem: pip directory: "/" + open-pull-requests-limit: 9 schedule: interval: "monthly" diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index fca54573..3e483175 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -34,8 +34,6 @@ jobs: py: 3.9.16 - os: ubuntu-latest py: 3.8.16 - - os: ubuntu-latest - py: 3.7.15 uses: mhils/workflows/.github/workflows/python-tox.yml@main with: cmd: tox -e py -- -vvv ${{ matrix.args }} diff --git a/CHANGELOG.md b/CHANGELOG.md index b58e7ee3..25780152 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,9 @@ + - Remove support for Python 3.7, which has reached end-of-life on 2023-06-27. + ([#569](https://github.com/mitmproxy/pdoc/pull/569), @mhils) + ## 2023-04-24: pdoc 13.1.1 diff --git a/README.md b/README.md index 598960f7..f0bb38cf 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ API Documentation for Python Projects. pip install pdoc ``` -pdoc is compatible with Python 3.7 and newer. +pdoc is compatible with Python 3.8 and newer. # Usage diff --git a/docs/make.py b/docs/make.py index d724ebdb..4eb640d4 100755 --- a/docs/make.py +++ b/docs/make.py @@ -1,13 +1,13 @@ #!/usr/bin/env python3 +from pathlib import Path import shutil import textwrap -from pathlib import Path -import pygments.formatters.html -import pygments.lexers.python from jinja2 import Environment from jinja2 import FileSystemLoader from markupsafe import Markup +import pygments.formatters.html +import pygments.lexers.python import pdoc.render diff --git a/examples/mkdocs/make.py b/examples/mkdocs/make.py index d21b1c4e..c6ea777d 100644 --- a/examples/mkdocs/make.py +++ b/examples/mkdocs/make.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 -import shutil from pathlib import Path +import shutil from pdoc import pdoc from pdoc import render diff --git a/pdoc/__init__.py b/pdoc/__init__.py index 4bf9c2a0..405ecac3 100644 --- a/pdoc/__init__.py +++ b/pdoc/__init__.py @@ -195,7 +195,7 @@ class GoldenRetriever(Dog): You can find an example at [`examples/custom-template/module.html.jinja2`](https://github.com/mitmproxy/pdoc/blob/main/examples/custom-template/module.html.jinja2). -### ...exclude submodules from being documented? +## ...exclude submodules from being documented? If you would like to exclude specific submodules from the documentation, the recommended way is to specify `__all__` as shown in the previous section. Alternatively, you can pass negative regular expression `!patterns` as part of the @@ -466,7 +466,9 @@ def bark(self, loud: bool) -> None: from pathlib import Path from typing import overload -from pdoc import doc, extract, render +from pdoc import doc +from pdoc import extract +from pdoc import render @overload diff --git a/pdoc/__main__.py b/pdoc/__main__.py index 7b56a6fb..c35adad6 100644 --- a/pdoc/__main__.py +++ b/pdoc/__main__.py @@ -1,17 +1,17 @@ from __future__ import annotations import argparse +from pathlib import Path import platform import subprocess import sys import warnings -from pathlib import Path +from pdoc._compat import BooleanOptionalAction import pdoc.doc import pdoc.extract import pdoc.render import pdoc.web -from pdoc._compat import BooleanOptionalAction if sys.stdout.isatty(): # pragma: no cover red = "\x1b[31m" diff --git a/pdoc/_compat.py b/pdoc/_compat.py index 312ae065..a7ccf3d1 100644 --- a/pdoc/_compat.py +++ b/pdoc/_compat.py @@ -102,28 +102,6 @@ def __get__(self, instance, owner=None): __class_getitem__ = classmethod(GenericAlias) # ✂ end ✂ -if sys.version_info >= (3, 8): - from typing import Literal, get_origin -else: # pragma: no cover - from typing import Generic - - # There is no Literal on 3.7, so we just make one up. It should not be used anyways! - - try: - from typing_extensions import Literal - except ImportError: - class Literal: - pass - - # get_origin is adapted from - # https://github.com/python/cpython/blob/863eb7170b3017399fb2b786a1e3feb6457e54c2/Lib/typing.py#L1474-L1515 - # with Annotations removed (not present in 3.7) - def get_origin(tp): # type: ignore - if isinstance(tp, GenericAlias): - return tp.__origin__ - if tp is Generic: - return Generic - return None if (3, 9) <= sys.version_info < (3, 9, 8) or (3, 10) <= sys.version_info < (3, 10, 1): # pragma: no cover import inspect @@ -145,7 +123,9 @@ def formatannotation(annotation) -> str: class singledispatchmethod: pass # pragma: no cover -if True: +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 @@ -197,8 +177,6 @@ def format_usage(self): "UnionType", "removesuffix", "cached_property", - "get_origin", - "Literal", "formatannotation", "singledispatchmethod", "BooleanOptionalAction", diff --git a/pdoc/doc.py b/pdoc/doc.py index b1bcef42..063a3f94 100644 --- a/pdoc/doc.py +++ b/pdoc/doc.py @@ -17,42 +17,43 @@ """ from __future__ import annotations +from abc import ABCMeta +from abc import abstractmethod +from collections.abc import Callable import dataclasses import enum +from functools import wraps import inspect import os +from pathlib import Path import pkgutil import re import sys import textwrap import traceback import types -import warnings -from abc import ABCMeta -from abc import abstractmethod -from collections.abc import Callable -from functools import wraps -from pathlib import Path from typing import Any from typing import ClassVar from typing import Generic from typing import TypeVar from typing import Union +from typing import get_origin +import warnings -from ._compat import cache -from ._compat import cached_property -from ._compat import formatannotation -from ._compat import get_origin -from ._compat import singledispatchmethod from pdoc import doc_ast from pdoc import doc_pyi from pdoc import extract -from pdoc.doc_types import empty from pdoc.doc_types import GenericAlias from pdoc.doc_types import NonUserDefinedCallables +from pdoc.doc_types import empty from pdoc.doc_types import resolve_annotations from pdoc.doc_types import safe_eval_type +from ._compat import cache +from ._compat import cached_property +from ._compat import formatannotation +from ._compat import singledispatchmethod + def _include_fullname_in_traceback(f): """ diff --git a/pdoc/doc_ast.py b/pdoc/doc_ast.py index 81299ca4..9266149a 100644 --- a/pdoc/doc_ast.py +++ b/pdoc/doc_ast.py @@ -6,19 +6,20 @@ from __future__ import annotations import ast -import inspect -import types -import warnings from collections.abc import Iterable from collections.abc import Iterator from dataclasses import dataclass +import inspect from itertools import tee from itertools import zip_longest +import types from typing import Any -from typing import overload from typing import TypeVar +from typing import overload +import warnings import pdoc + from ._compat import ast_unparse from ._compat import cache @@ -135,11 +136,6 @@ def _walk_tree( and isinstance(b.value.value, str) ): var_docstrings[name] = inspect.cleandoc(b.value.value).strip() - elif isinstance(b, ast.Expr) and isinstance( - b.value, ast.Str - ): # pragma: no cover - # Python <= 3.7 - var_docstrings[name] = inspect.cleandoc(b.value.s).strip() return AstInfo( var_docstrings, func_docstrings, @@ -339,8 +335,7 @@ def _init_nodes(tree: ast.FunctionDef) -> Iterator[ast.AST]: yield ast.Assign( [ast.Name(a.targets[0].attr)], value=a.value, - # not available on Python 3.7 - type_comment=getattr(a, "type_comment", None), + type_comment=a.type_comment, ) elif ( isinstance(a, ast.Expr) @@ -348,11 +343,6 @@ def _init_nodes(tree: ast.FunctionDef) -> Iterator[ast.AST]: and isinstance(a.value.value, str) ): yield a - elif isinstance(a, ast.Expr) and isinstance( - a.value, ast.Str - ): # pragma: no cover - # Python <= 3.7 - yield a else: yield ast.Pass() diff --git a/pdoc/doc_pyi.py b/pdoc/doc_pyi.py index 6de73ecf..2c8b10af 100644 --- a/pdoc/doc_pyi.py +++ b/pdoc/doc_pyi.py @@ -5,16 +5,17 @@ """ from __future__ import annotations +from pathlib import Path import sys import traceback import types -import warnings -from pathlib import Path from unittest import mock +import warnings -from ._compat import cache from pdoc import doc +from ._compat import cache + @cache def find_stub_file(module_name: str) -> Path | None: diff --git a/pdoc/doc_types.py b/pdoc/doc_types.py index f1589e79..25e07fc6 100644 --- a/pdoc/doc_types.py +++ b/pdoc/doc_types.py @@ -12,18 +12,18 @@ import operator import sys import types -import typing -import warnings from types import BuiltinFunctionType from types import ModuleType -from typing import _GenericAlias # type: ignore -from typing import Any +import typing from typing import TYPE_CHECKING +from typing import Any +from typing import Literal +from typing import _GenericAlias # type: ignore +from typing import get_origin +import warnings from . import extract from ._compat import GenericAlias -from ._compat import get_origin -from ._compat import Literal from ._compat import UnionType from .doc_ast import type_checking_sections diff --git a/pdoc/docstrings.py b/pdoc/docstrings.py index 4daa6b5b..3d3196d3 100644 --- a/pdoc/docstrings.py +++ b/pdoc/docstrings.py @@ -16,11 +16,11 @@ import inspect import mimetypes import os -import re -import warnings from pathlib import Path +import re from textwrap import dedent from textwrap import indent +import warnings from ._compat import cache diff --git a/pdoc/extract.py b/pdoc/extract.py index 28d60538..2f32dd04 100644 --- a/pdoc/extract.py +++ b/pdoc/extract.py @@ -5,10 +5,15 @@ """ from __future__ import annotations +from collections.abc import Iterable +from collections.abc import Iterator +from collections.abc import Sequence +from contextlib import contextmanager import importlib.util import io import linecache import os +from pathlib import Path import pkgutil import platform import re @@ -17,13 +22,8 @@ import sys import traceback import types -import warnings -from collections.abc import Iterable -from collections.abc import Iterator -from collections.abc import Sequence -from contextlib import contextmanager -from pathlib import Path from unittest.mock import patch +import warnings import pdoc.doc_ast import pdoc.docstrings diff --git a/pdoc/render.py b/pdoc/render.py index 349fbc5f..34c95328 100644 --- a/pdoc/render.py +++ b/pdoc/render.py @@ -1,11 +1,12 @@ from __future__ import annotations import os -import types -import warnings from pathlib import Path +import types +from typing import Literal from typing import Mapping from typing import cast +import warnings import jinja2 from jinja2 import Environment @@ -13,7 +14,6 @@ import pdoc.doc import pdoc.docstrings -from pdoc._compat import Literal from pdoc.render_helpers import DefaultMacroExtension from pdoc.render_helpers import defuse_unsafe_reprs from pdoc.render_helpers import edit_url diff --git a/pdoc/render_helpers.py b/pdoc/render_helpers.py index e51271ce..b3672ca5 100644 --- a/pdoc/render_helpers.py +++ b/pdoc/render_helpers.py @@ -1,20 +1,20 @@ from __future__ import annotations -import html -import inspect -import os -import re -import warnings from collections.abc import Collection from collections.abc import Iterable from collections.abc import Mapping from contextlib import contextmanager +import html +import inspect +import os +import re from unittest.mock import patch +import warnings -import pygments.formatters -import pygments.lexers from jinja2 import ext from jinja2 import nodes +import pygments.formatters +import pygments.lexers try: # Jinja2 >= 3.0 @@ -28,7 +28,8 @@ import pdoc.markdown2 from . import docstrings -from ._compat import cache, removesuffix +from ._compat import cache +from ._compat import removesuffix lexer = pygments.lexers.PythonLexer() """ diff --git a/pdoc/search.py b/pdoc/search.py index a606a6be..08e8b936 100644 --- a/pdoc/search.py +++ b/pdoc/search.py @@ -38,14 +38,14 @@ """ from __future__ import annotations +from collections.abc import Callable +from collections.abc import Mapping import html import json +from pathlib import Path import shutil import subprocess import textwrap -from collections.abc import Callable -from collections.abc import Mapping -from pathlib import Path import pdoc.doc from pdoc.render_helpers import format_signature diff --git a/pdoc/web.py b/pdoc/web.py index bb810b11..80d4a2d3 100644 --- a/pdoc/web.py +++ b/pdoc/web.py @@ -7,13 +7,13 @@ """ from __future__ import annotations +from collections.abc import Iterable +from collections.abc import Iterator import http.server import traceback +from typing import Mapping import warnings import webbrowser -from collections.abc import Iterable -from collections.abc import Iterator -from typing import Mapping from pdoc import doc from pdoc import extract diff --git a/pyproject.toml b/pyproject.toml index e2166de0..77f959e2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -2,7 +2,7 @@ name = "pdoc" description = "API Documentation for Python Projects" readme = "README.md" -requires-python = ">=3.7" +requires-python = ">=3.8" license = { text="Unlicense" } authors = [{name = "Maximilian Hils", email = "pdoc@maximilianhils.com"}] dynamic = ["version"] @@ -23,7 +23,6 @@ classifiers = [ "Environment :: Console", "Intended Audience :: Developers", "Operating System :: OS Independent", - "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", @@ -102,6 +101,11 @@ ignore_missing_imports = true [tool.ruff] line-length = 140 +select = ["E", "F", "I"] + +[tool.ruff.isort] +force-single-line = true +force-sort-within-sections = true [tool.tox] legacy_tox_ini = """ diff --git a/requirements-dev.txt b/requirements-dev.txt index a9d0270d..02bead55 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -4,13 +4,13 @@ # # pip-compile --all-extras --allow-unsafe --output-file=requirements-dev.txt --resolver=backtracking pyproject.toml # -attrs==22.2.0 +attrs==23.1.0 # via # hypothesis # pytest black==23.3.0 # via pdoc (pyproject.toml) -cachetools==5.3.0 +cachetools==5.3.1 # via tox chardet==5.1.0 # via tox @@ -18,15 +18,15 @@ click==8.1.3 # via black colorama==0.4.6 # via tox -coverage[toml]==7.2.2 +coverage[toml]==7.2.7 # via pytest-cov distlib==0.3.6 # via virtualenv -filelock==3.9.0 +filelock==3.12.0 # via # tox # virtualenv -hypothesis==6.68.2 +hypothesis==6.75.9 # via pdoc (pyproject.toml) iniconfig==2.0.0 # via pytest @@ -36,13 +36,13 @@ markupsafe==2.1.2 # via # jinja2 # pdoc (pyproject.toml) -mypy==1.0.1 +mypy==1.3.0 # via pdoc (pyproject.toml) mypy-extensions==1.0.0 # via # black # mypy -packaging==23.0 +packaging==23.1 # via # black # pyproject-api @@ -50,7 +50,7 @@ packaging==23.0 # tox pathspec==0.11.1 # via black -platformdirs==3.5.0 +platformdirs==3.5.1 # via # black # tox @@ -59,34 +59,34 @@ pluggy==1.0.0 # via # pytest # tox -pygments==2.14.0 +pygments==2.15.1 # via pdoc (pyproject.toml) -pyproject-api==1.5.0 +pyproject-api==1.5.1 # via tox pytest==7.3.1 # via # pdoc (pyproject.toml) # pytest-cov # pytest-timeout -pytest-cov==4.0.0 +pytest-cov==4.1.0 # via pdoc (pyproject.toml) pytest-timeout==2.1.0 # via pdoc (pyproject.toml) -ruff==0.0.263 +ruff==0.0.270 # via pdoc (pyproject.toml) sortedcontainers==2.4.0 # via hypothesis -tox==4.4.5 +tox==4.5.2 # via pdoc (pyproject.toml) -types-docutils==0.19.1.6 +types-docutils==0.20.0.1 # via # types-pygments # types-setuptools -types-pygments==2.14.0.5 +types-pygments==2.15.0.1 # via pdoc (pyproject.toml) -types-setuptools==67.7.0.0 +types-setuptools==67.8.0.0 # via types-pygments -typing-extensions==4.5.0 +typing-extensions==4.6.2 # via mypy -virtualenv==20.20.0 +virtualenv==20.23.0 # via tox diff --git a/test/freeze-requirements.sh b/test/freeze-requirements.sh index ebb8d4d0..9690eedb 100644 --- a/test/freeze-requirements.sh +++ b/test/freeze-requirements.sh @@ -3,7 +3,7 @@ set -ex cd -- "$(dirname -- "$0")" rm -rf freeze-venv -python3.7 -m venv freeze-venv +python3.8 -m venv freeze-venv freeze-venv/bin/python -m pip install -U pip freeze-venv/bin/pip install -e ..[dev] freeze-venv/bin/pip freeze --all --exclude-editable > ../requirements-dev.txt diff --git a/test/test_doc.py b/test/test_doc.py index 446baf1e..fe0c032e 100644 --- a/test/test_doc.py +++ b/test/test_doc.py @@ -1,8 +1,8 @@ import builtins import dataclasses +from pathlib import Path import sys import types -from pathlib import Path from unittest.mock import patch import pytest diff --git a/test/test_doc_pyi.py b/test/test_doc_pyi.py index f98b0e35..32df70a9 100644 --- a/test/test_doc_pyi.py +++ b/test/test_doc_pyi.py @@ -1,5 +1,5 @@ -import types from pathlib import Path +import types import pytest diff --git a/test/test_docstrings.py b/test/test_docstrings.py index c29b2499..f9a2f247 100644 --- a/test/test_docstrings.py +++ b/test/test_docstrings.py @@ -1,10 +1,9 @@ -import pytest from hypothesis import given from hypothesis.strategies import text +import pytest from pdoc import docstrings - # The important tests are in test_snapshot.py (and, by extension, testdata/) # only some fuzzing here. diff --git a/test/test_extract.py b/test/test_extract.py index 0ecd1501..bc2f91cf 100644 --- a/test/test_extract.py +++ b/test/test_extract.py @@ -1,6 +1,6 @@ import importlib -import sys from pathlib import Path +import sys import pytest diff --git a/test/test_main.py b/test/test_main.py index 38d9c013..3a679a10 100644 --- a/test/test_main.py +++ b/test/test_main.py @@ -1,7 +1,7 @@ -import warnings from pathlib import Path from unittest.mock import call from unittest.mock import patch +import warnings import pytest diff --git a/test/test_search.py b/test/test_search.py index 2507d5d2..d2d42ce6 100644 --- a/test/test_search.py +++ b/test/test_search.py @@ -1,7 +1,7 @@ import json +from pathlib import Path import shutil import subprocess -from pathlib import Path from pdoc import search diff --git a/test/test_snapshot.py b/test/test_snapshot.py index b9d3aba7..2194d13c 100755 --- a/test/test_snapshot.py +++ b/test/test_snapshot.py @@ -1,13 +1,13 @@ #!/usr/bin/env python3 from __future__ import annotations +from contextlib import ExitStack import os +from pathlib import Path import shutil import sys import tempfile import warnings -from contextlib import ExitStack -from pathlib import Path import pytest diff --git a/test/test_web.py b/test/test_web.py index 566e2ed8..da8fbc7e 100644 --- a/test/test_web.py +++ b/test/test_web.py @@ -1,14 +1,13 @@ import io +from pathlib import Path import socket import threading -from pathlib import Path import pytest from pdoc.web import DocHandler from pdoc.web import DocServer - here = Path(__file__).parent diff --git a/test/testdata/demo_long.html b/test/testdata/demo_long.html index c4a87f48..ae4d195f 100644 --- a/test/testdata/demo_long.html +++ b/test/testdata/demo_long.html @@ -236,10 +236,10 @@

A Second Section

23from __future__ import annotations 24 25import abc - 26import enum - 27import os - 28from dataclasses import dataclass - 29from dataclasses import field + 26from dataclasses import dataclass + 27from dataclasses import field + 28import enum + 29import os 30from typing import ClassVar 31from typing import List 32from typing import Optional diff --git a/test/testdata/demo_long.py b/test/testdata/demo_long.py index 3b5752ea..b2c2b03e 100644 --- a/test/testdata/demo_long.py +++ b/test/testdata/demo_long.py @@ -23,10 +23,10 @@ from __future__ import annotations import abc -import enum -import os from dataclasses import dataclass from dataclasses import field +import enum +import os from typing import ClassVar from typing import List from typing import Optional diff --git a/test/testdata/misc.html b/test/testdata/misc.html index 51ed95c6..bd3d4a2c 100644 --- a/test/testdata/misc.html +++ b/test/testdata/misc.html @@ -300,476 +300,475 @@

  1import abc
-  2import sched
-  3from functools import lru_cache
+  2from functools import lru_cache
+  3import sched
   4from typing import Generic
   5from typing import TypeVar
   6
   7from pdoc._compat import cached_property
   8
-  9
- 10# https://github.com/mitmproxy/pdoc/issues/226
+  9# https://github.com/mitmproxy/pdoc/issues/226
+ 10
  11
- 12
- 13class Descriptor:
- 14    def __init__(self, func):
- 15        self.__doc__ = func.__doc__
- 16
- 17    def __get__(self, instance, owner):
- 18        return self if instance is None else getattr(instance, "_x", 0)
- 19
- 20    def __set__(self, instance, value):
- 21        instance._x = value
+ 12class Descriptor:
+ 13    def __init__(self, func):
+ 14        self.__doc__ = func.__doc__
+ 15
+ 16    def __get__(self, instance, owner):
+ 17        return self if instance is None else getattr(instance, "_x", 0)
+ 18
+ 19    def __set__(self, instance, value):
+ 20        instance._x = value
+ 21
  22
- 23
- 24class Issue226:
- 25    @Descriptor
- 26    def size(self):
- 27        """This is the size"""
+ 23class Issue226:
+ 24    @Descriptor
+ 25    def size(self):
+ 26        """This is the size"""
+ 27
  28
- 29
- 30# Testing function and object default values
+ 29# Testing function and object default values
+ 30
  31
- 32
- 33def default_func():
- 34    pass
+ 32def default_func():
+ 33    pass
+ 34
  35
- 36
- 37default_obj = object()
- 38
- 39var_with_default_obj = default_obj
- 40"""this shouldn't render the object address"""
- 41var_with_default_func = default_func
- 42"""this just renders like a normal function"""
+ 36default_obj = object()
+ 37
+ 38var_with_default_obj = default_obj
+ 39"""this shouldn't render the object address"""
+ 40var_with_default_func = default_func
+ 41"""this just renders like a normal function"""
+ 42
  43
- 44
- 45def func_with_defaults(a=default_obj, b=default_func):
- 46    """this shouldn't render object or function addresses"""
- 47    pass
+ 44def func_with_defaults(a=default_obj, b=default_func):
+ 45    """this shouldn't render object or function addresses"""
+ 46    pass
+ 47
  48
- 49
- 50# Testing classmethod links in code
- 51class ClassmethodLink:
- 52    """
- 53    You can either do
- 54
- 55    >>> ClassmethodLink.bar()
- 56    42
- 57
- 58    or
- 59
- 60    ```python
- 61    ClassmethodLink.bar()
- 62    ```
- 63
- 64    neither will be linked.
- 65    """
- 66
- 67    @classmethod
- 68    def bar(cls):
- 69        return 42
+ 49# Testing classmethod links in code
+ 50class ClassmethodLink:
+ 51    """
+ 52    You can either do
+ 53
+ 54    >>> ClassmethodLink.bar()
+ 55    42
+ 56
+ 57    or
+ 58
+ 59    ```python
+ 60    ClassmethodLink.bar()
+ 61    ```
+ 62
+ 63    neither will be linked.
+ 64    """
+ 65
+ 66    @classmethod
+ 67    def bar(cls):
+ 68        return 42
+ 69
  70
- 71
- 72# Testing generic bases
- 73
- 74T = TypeVar("T")
+ 71# Testing generic bases
+ 72
+ 73T = TypeVar("T")
+ 74
  75
- 76
- 77class GenericParent(Generic[T]):
- 78    pass
+ 76class GenericParent(Generic[T]):
+ 77    pass
+ 78
  79
- 80
- 81class NonGenericChild(GenericParent[str]):
- 82    pass
+ 80class NonGenericChild(GenericParent[str]):
+ 81    pass
+ 82
  83
- 84
- 85# Testing docstring inheritance
+ 84# Testing docstring inheritance
+ 85
  86
- 87
- 88class Base:
- 89    def __init__(self):
- 90        """init"""
- 91        super().__init__()
- 92
- 93    def foo(self):
- 94        """foo"""
- 95        pass
- 96
- 97    @classmethod
- 98    def bar(cls):
- 99        """bar"""
-100        pass
-101
-102    @staticmethod
-103    def baz():
-104        """baz"""
-105        pass
-106
-107    @property
-108    def qux(self):
-109        """qux"""
-110        return
-111
-112    @cached_property
-113    def quux(self):
-114        """quux"""
-115        return
-116
-117    quuux: int = 42
-118    """quuux"""
+ 87class Base:
+ 88    def __init__(self):
+ 89        """init"""
+ 90        super().__init__()
+ 91
+ 92    def foo(self):
+ 93        """foo"""
+ 94        pass
+ 95
+ 96    @classmethod
+ 97    def bar(cls):
+ 98        """bar"""
+ 99        pass
+100
+101    @staticmethod
+102    def baz():
+103        """baz"""
+104        pass
+105
+106    @property
+107    def qux(self):
+108        """qux"""
+109        return
+110
+111    @cached_property
+112    def quux(self):
+113        """quux"""
+114        return
+115
+116    quuux: int = 42
+117    """quuux"""
+118
 119
-120
-121class Child(Base):
-122    def __init__(self):
-123        super().__init__()
-124
-125    def foo(self):
-126        pass
-127
-128    @classmethod
-129    def bar(cls):
-130        pass
-131
-132    @staticmethod
-133    def baz():
-134        pass
-135
-136    @property
-137    def qux(self):
-138        return
-139
-140    @cached_property
-141    def quux(self):
-142        return
-143
-144    quuux: int = 42
+120class Child(Base):
+121    def __init__(self):
+122        super().__init__()
+123
+124    def foo(self):
+125        pass
+126
+127    @classmethod
+128    def bar(cls):
+129        pass
+130
+131    @staticmethod
+132    def baz():
+133        pass
+134
+135    @property
+136    def qux(self):
+137        return
+138
+139    @cached_property
+140    def quux(self):
+141        return
+142
+143    quuux: int = 42
+144
 145
-146
-147# Testing that an attribute that is only annotated does not trigger a "submodule not found" warning.
-148
-149only_annotated: int
+146# Testing that an attribute that is only annotated does not trigger a "submodule not found" warning.
+147
+148only_annotated: int
+149
 150
-151
-152# Testing that a private class in __all__ is displayed
+151# Testing that a private class in __all__ is displayed
+152
 153
-154
-155class _Private:
-156    """private class"""
-157
-158    pass
-159
-160    def _do(self):
-161        """private method"""
+154class _Private:
+155    """private class"""
+156
+157    pass
+158
+159    def _do(self):
+160        """private method"""
+161
 162
-163
-164# Testing a class attribute that is a lambda (which generates quirky sources)
+163# Testing a class attribute that is a lambda (which generates quirky sources)
+164
 165
-166
-167class LambdaAttr:
-168    # not really supported, but also shouldn't crash.
-169    attr = lambda x: 42  # noqa
+166class LambdaAttr:
+167    # not really supported, but also shouldn't crash.
+168    attr = lambda x: 42  # noqa
+169
 170
-171
-172# Testing different docstring annotations
-173# fmt: off
+171# Testing different docstring annotations
+172# fmt: off
+173
 174
-175
-176def foo():
-177    """no indents"""
+175def foo():
+176    """no indents"""
+177
 178
-179
-180def bar():
-181    """no
-182indents"""
+179def bar():
+180    """no
+181indents"""
+182
 183
-184
-185def baz():
-186    """one
-187    indent"""
+184def baz():
+185    """one
+186    indent"""
+187
 188
-189
-190def qux():
-191    """
-192    two
-193    indents
-194    """
+189def qux():
+190    """
+191    two
+192    indents
+193    """
+194
 195
-196
-197class Indented:
-198    def foo(self):
-199        """no indents"""
-200
-201    def bar(self):
-202        """no
-203indents"""
-204
-205    def baz(self):
-206        """one
-207        indent"""
-208
-209    def qux(self):
-210        """
-211        two
-212        indents
-213        """
-214
-215    @lru_cache()
-216    def foo_decorated(self):
-217        """no indents"""
-218
-219    @lru_cache()
-220    # comment
-221    def foo_commented(self):
-222        """no indents"""
-223
-224    @lru_cache()
-225    def bar_decorated(self):
-226        """no
-227indents"""
-228
-229    @lru_cache()
-230    def baz_decorated(self):
-231        """one
-232        indent"""
-233
-234    @lru_cache()
-235    def qux_decorated(self):
-236        """
-237        two
-238        indents
-239        """
-240
-241    @lru_cache(
-242        maxsize=42
-243    )
-244    def quux_decorated(self):
-245        """multi-line decorator, https://github.com/mitmproxy/pdoc/issues/246"""
+196class Indented:
+197    def foo(self):
+198        """no indents"""
+199
+200    def bar(self):
+201        """no
+202indents"""
+203
+204    def baz(self):
+205        """one
+206        indent"""
+207
+208    def qux(self):
+209        """
+210        two
+211        indents
+212        """
+213
+214    @lru_cache()
+215    def foo_decorated(self):
+216        """no indents"""
+217
+218    @lru_cache()
+219    # comment
+220    def foo_commented(self):
+221        """no indents"""
+222
+223    @lru_cache()
+224    def bar_decorated(self):
+225        """no
+226indents"""
+227
+228    @lru_cache()
+229    def baz_decorated(self):
+230        """one
+231        indent"""
+232
+233    @lru_cache()
+234    def qux_decorated(self):
+235        """
+236        two
+237        indents
+238        """
+239
+240    @lru_cache(
+241        maxsize=42
+242    )
+243    def quux_decorated(self):
+244        """multi-line decorator, https://github.com/mitmproxy/pdoc/issues/246"""
+245
 246
-247
-248def _protected_decorator(f):
-249    return f
+247def _protected_decorator(f):
+248    return f
+249
 250
-251
-252@_protected_decorator
-253def fun_with_protected_decorator():
-254    """This function has a protected decorator (name starting with a single `_`)."""
+251@_protected_decorator
+252def fun_with_protected_decorator():
+253    """This function has a protected decorator (name starting with a single `_`)."""
+254
 255
-256
-257class UnhashableDataDescriptor:
-258    def __get__(self):
-259        pass
-260    __hash__ = None  # type: ignore
+256class UnhashableDataDescriptor:
+257    def __get__(self):
+258        pass
+259    __hash__ = None  # type: ignore
+260
 261
-262
-263unhashable = UnhashableDataDescriptor()
+262unhashable = UnhashableDataDescriptor()
+263
 264
-265
-266class AbstractClass(metaclass=abc.ABCMeta):
-267    """This class shouldn't show a constructor as it's abstract."""
-268    @abc.abstractmethod
-269    def foo(self):
-270        pass
+265class AbstractClass(metaclass=abc.ABCMeta):
+266    """This class shouldn't show a constructor as it's abstract."""
+267    @abc.abstractmethod
+268    def foo(self):
+269        pass
+270
 271
-272
-273# Adapted from https://github.com/mitmproxy/pdoc/issues/320
-274
-275def make_adder(a: int):
-276    def add_func(b: int) -> int:
-277        """This function adds two numbers."""
-278        return a + b
-279    return add_func
+272# Adapted from https://github.com/mitmproxy/pdoc/issues/320
+273
+274def make_adder(a: int):
+275    def add_func(b: int) -> int:
+276        """This function adds two numbers."""
+277        return a + b
+278    return add_func
+279
 280
-281
-282add_four = make_adder(4)
-283add_five = make_adder(5)
-284"""This function adds five."""
-285add_six = make_adder(6)
-286add_six.__doc__ = "This function adds six."
+281add_four = make_adder(4)
+282add_five = make_adder(5)
+283"""This function adds five."""
+284add_six = make_adder(6)
+285add_six.__doc__ = "This function adds six."
+286
 287
-288
-289# Adapted from https://github.com/mitmproxy/pdoc/issues/335
-290def linkify_links():
-291    """
-292    This docstring contains links that are also identifiers:
-293
-294    - [`linkify_links`](https://example.com/)
-295    - [misc.linkify_links](https://example.com/)
-296    - [`linkify_links()`](https://example.com/)
-297    - [misc.linkify_links()](https://example.com/)
-298    - [link in target](https://example.com/misc.linkify_links)
-299    - [explicit linking](#AbstractClass.foo)
-300    """
+288# Adapted from https://github.com/mitmproxy/pdoc/issues/335
+289def linkify_links():
+290    """
+291    This docstring contains links that are also identifiers:
+292
+293    - [`linkify_links`](https://example.com/)
+294    - [misc.linkify_links](https://example.com/)
+295    - [`linkify_links()`](https://example.com/)
+296    - [misc.linkify_links()](https://example.com/)
+297    - [link in target](https://example.com/misc.linkify_links)
+298    - [explicit linking](#AbstractClass.foo)
+299    """
+300
 301
-302
-303class Issue352aMeta(type):
-304    def __call__(cls, *args, **kwargs):
-305        """Meta.__call__"""
+302class Issue352aMeta(type):
+303    def __call__(cls, *args, **kwargs):
+304        """Meta.__call__"""
+305
 306
-307
-308class Issue352a(metaclass=Issue352aMeta):
-309    def __init__(self):
-310        """Issue352.__init__ should be preferred over Meta.__call__."""
+307class Issue352a(metaclass=Issue352aMeta):
+308    def __init__(self):
+309        """Issue352.__init__ should be preferred over Meta.__call__."""
+310
 311
-312
-313class Issue352bMeta(type):
-314    def __call__(cls, *args, **kwargs):
-315        pass
+312class Issue352bMeta(type):
+313    def __call__(cls, *args, **kwargs):
+314        pass
+315
 316
-317
-318class Issue352b(metaclass=Issue352bMeta):
-319    """No docstrings for the constructor here."""
+317class Issue352b(metaclass=Issue352bMeta):
+318    """No docstrings for the constructor here."""
+319
 320
-321
-322class CustomCallMeta(type):
-323    def __call__(cls, *args, **kwargs):
-324        """Custom docstring in metaclass.`__call__`"""
+321class CustomCallMeta(type):
+322    def __call__(cls, *args, **kwargs):
+323        """Custom docstring in metaclass.`__call__`"""
+324
 325
-326
-327class CustomCall(metaclass=CustomCallMeta):
-328    """A class where the constructor is defined by its metaclass."""
+326class CustomCall(metaclass=CustomCallMeta):
+327    """A class where the constructor is defined by its metaclass."""
+328
 329
-330
-331class Headings:
-332    """
-333    # Heading 1
-334
-335    Here is some text.
-336
-337    ## Heading 2
-338
-339    Here is some text.
-340
-341    ### Heading 3
-342
-343    Here is some text.
-344
-345    #### Heading 4
-346
-347    Here is some text.
-348
-349    ##### Heading 5
-350
-351    Here is some text.
-352
-353    ###### Heading 6
-354
-355    Here is some text.
-356
-357    """
+330class Headings:
+331    """
+332    # Heading 1
+333
+334    Here is some text.
+335
+336    ## Heading 2
+337
+338    Here is some text.
+339
+340    ### Heading 3
+341
+342    Here is some text.
+343
+344    #### Heading 4
+345
+346    Here is some text.
+347
+348    ##### Heading 5
+349
+350    Here is some text.
+351
+352    ###### Heading 6
+353
+354    Here is some text.
+355
+356    """
+357
 358
-359
-360class CustomRepr:
-361    def __repr__(self):
-362        return "°<script>alert(1)</script>"
+359class CustomRepr:
+360    def __repr__(self):
+361        return "°<script>alert(1)</script>"
+362
 363
-364
-365def repr_not_syntax_highlightable(x=CustomRepr()):
-366    """The default value for x fails to highlight with pygments."""
+364def repr_not_syntax_highlightable(x=CustomRepr()):
+365    """The default value for x fails to highlight with pygments."""
+366
 367
-368
-369class ClassDecorator:
-370    """This is a class that wraps a function. It will be documented correctly."""
-371    def __init__(self, f):
-372        self.f = f
+368class ClassDecorator:
+369    """This is a class that wraps a function. It will be documented correctly."""
+370    def __init__(self, f):
+371        self.f = f
+372
 373
-374
-375@ClassDecorator
-376def another_decorated_function(arg: str) -> str:
-377    """This is another decorated function. It will not be documented correctly."""
-378    raise NotImplementedError
+374@ClassDecorator
+375def another_decorated_function(arg: str) -> str:
+376    """This is another decorated function. It will not be documented correctly."""
+377    raise NotImplementedError
+378
 379
-380
-381class SubclassRef:
-382    class SubClass:
-383        pass
-384
-385    def __init__(self, x: "SubClass"):
-386        self.x = x
+380class SubclassRef:
+381    class SubClass:
+382        pass
+383
+384    def __init__(self, x: "SubClass"):
+385        self.x = x
+386
 387
-388
-389class ClassAsAttribute:
-390    static_attr_to_class = ClassDecorator
-391    """this is a static attribute that point to a Class (not an instance)"""
-392
-393    static_attr_to_instance = ClassDecorator(None)
-394    """this is a static attribute that point to an instance"""
+388class ClassAsAttribute:
+389    static_attr_to_class = ClassDecorator
+390    """this is a static attribute that point to a Class (not an instance)"""
+391
+392    static_attr_to_instance = ClassDecorator(None)
+393    """this is a static attribute that point to an instance"""
+394
 395
-396
-397class scheduler(sched.scheduler):
-398    """Test for broken links for inherited methods, https://github.com/mitmproxy/pdoc/issues/490"""
+396class scheduler(sched.scheduler):
+397    """Test for broken links for inherited methods, https://github.com/mitmproxy/pdoc/issues/490"""
+398
 399
-400
-401class __init__:
-402    """https://github.com/mitmproxy/pdoc/issues/519"""
+400class __init__:
+401    """https://github.com/mitmproxy/pdoc/issues/519"""
+402
 403
-404
-405def dynamically_modify_docstring1():
-406    """this should **not** be the docstring."""
+404def dynamically_modify_docstring1():
+405    """this should **not** be the docstring."""
+406
 407
-408
-409def dynamically_modify_docstring2():
-410    pass
+408def dynamically_modify_docstring2():
+409    pass
+410
 411
-412
-413dynamically_modify_docstring1.__doc__ = "https://github.com/mitmproxy/pdoc/issues/536"
-414dynamically_modify_docstring2.__doc__ = "https://github.com/mitmproxy/pdoc/issues/536"
+412dynamically_modify_docstring1.__doc__ = "https://github.com/mitmproxy/pdoc/issues/536"
+413dynamically_modify_docstring2.__doc__ = "https://github.com/mitmproxy/pdoc/issues/536"
+414
 415
-416
-417def _docstring_modifier(fn):
-418    fn.__doc__ = "https://github.com/mitmproxy/pdoc/issues/536"
-419    return fn
+416def _docstring_modifier(fn):
+417    fn.__doc__ = "https://github.com/mitmproxy/pdoc/issues/536"
+418    return fn
+419
 420
-421
-422@_docstring_modifier
-423def dynamically_modify_docstring3():
-424    """This should **not** be the docstring."""
+421@_docstring_modifier
+422def dynamically_modify_docstring3():
+423    """This should **not** be the docstring."""
+424
 425
-426
-427@_docstring_modifier
-428def dynamically_modify_docstring4():
-429    pass
+426@_docstring_modifier
+427def dynamically_modify_docstring4():
+428    pass
+429
 430
-431
-432__all__ = [
-433    "Issue226",
-434    "var_with_default_obj",
-435    "var_with_default_func",
-436    "func_with_defaults",
-437    "ClassmethodLink",
-438    "GenericParent",
-439    "NonGenericChild",
-440    "Child",
-441    "only_annotated",
-442    "_Private",
-443    "LambdaAttr",
-444    "foo",
-445    "bar",
-446    "baz",
-447    "qux",
-448    "Indented",
-449    "fun_with_protected_decorator",
-450    "unhashable",
-451    "AbstractClass",
-452    "add_four",
-453    "add_five",
-454    "add_six",
-455    "linkify_links",
-456    "Issue352a",
-457    "Issue352b",
-458    "CustomCall",
-459    "Headings",
-460    "repr_not_syntax_highlightable",
-461    "ClassDecorator",
-462    "another_decorated_function",
-463    "SubclassRef",
-464    "ClassAsAttribute",
-465    "scheduler",
-466    "__init__",
-467    "dynamically_modify_docstring1",
-468    "dynamically_modify_docstring2",
-469    "dynamically_modify_docstring3",
-470    "dynamically_modify_docstring4",
-471]
+431__all__ = [
+432    "Issue226",
+433    "var_with_default_obj",
+434    "var_with_default_func",
+435    "func_with_defaults",
+436    "ClassmethodLink",
+437    "GenericParent",
+438    "NonGenericChild",
+439    "Child",
+440    "only_annotated",
+441    "_Private",
+442    "LambdaAttr",
+443    "foo",
+444    "bar",
+445    "baz",
+446    "qux",
+447    "Indented",
+448    "fun_with_protected_decorator",
+449    "unhashable",
+450    "AbstractClass",
+451    "add_four",
+452    "add_five",
+453    "add_six",
+454    "linkify_links",
+455    "Issue352a",
+456    "Issue352b",
+457    "CustomCall",
+458    "Headings",
+459    "repr_not_syntax_highlightable",
+460    "ClassDecorator",
+461    "another_decorated_function",
+462    "SubclassRef",
+463    "ClassAsAttribute",
+464    "scheduler",
+465    "__init__",
+466    "dynamically_modify_docstring1",
+467    "dynamically_modify_docstring2",
+468    "dynamically_modify_docstring3",
+469    "dynamically_modify_docstring4",
+470]
 
@@ -785,10 +784,10 @@

-
25class Issue226:
-26    @Descriptor
-27    def size(self):
-28        """This is the size"""
+            
24class Issue226:
+25    @Descriptor
+26    def size(self):
+27        """This is the size"""
 
@@ -833,8 +832,8 @@

-
34def default_func():
-35    pass
+            
33def default_func():
+34    pass
 
@@ -854,9 +853,9 @@

-
46def func_with_defaults(a=default_obj, b=default_func):
-47    """this shouldn't render object or function addresses"""
-48    pass
+            
45def func_with_defaults(a=default_obj, b=default_func):
+46    """this shouldn't render object or function addresses"""
+47    pass
 
@@ -876,25 +875,25 @@

-
52class ClassmethodLink:
-53    """
-54    You can either do
-55
-56    >>> ClassmethodLink.bar()
-57    42
-58
-59    or
-60
-61    ```python
-62    ClassmethodLink.bar()
-63    ```
-64
-65    neither will be linked.
-66    """
-67
-68    @classmethod
-69    def bar(cls):
-70        return 42
+            
51class ClassmethodLink:
+52    """
+53    You can either do
+54
+55    >>> ClassmethodLink.bar()
+56    42
+57
+58    or
+59
+60    ```python
+61    ClassmethodLink.bar()
+62    ```
+63
+64    neither will be linked.
+65    """
+66
+67    @classmethod
+68    def bar(cls):
+69        return 42
 
@@ -929,9 +928,9 @@

-
68    @classmethod
-69    def bar(cls):
-70        return 42
+            
67    @classmethod
+68    def bar(cls):
+69        return 42
 
@@ -950,8 +949,8 @@

-
78class GenericParent(Generic[T]):
-79    pass
+            
77class GenericParent(Generic[T]):
+78    pass
 
@@ -988,8 +987,8 @@

-
82class NonGenericChild(GenericParent[str]):
-83    pass
+            
81class NonGenericChild(GenericParent[str]):
+82    pass
 
@@ -1026,30 +1025,30 @@

-
122class Child(Base):
-123    def __init__(self):
-124        super().__init__()
-125
-126    def foo(self):
-127        pass
-128
-129    @classmethod
-130    def bar(cls):
-131        pass
-132
-133    @staticmethod
-134    def baz():
-135        pass
-136
-137    @property
-138    def qux(self):
-139        return
-140
-141    @cached_property
-142    def quux(self):
-143        return
-144
-145    quuux: int = 42
+            
121class Child(Base):
+122    def __init__(self):
+123        super().__init__()
+124
+125    def foo(self):
+126        pass
+127
+128    @classmethod
+129    def bar(cls):
+130        pass
+131
+132    @staticmethod
+133    def baz():
+134        pass
+135
+136    @property
+137    def qux(self):
+138        return
+139
+140    @cached_property
+141    def quux(self):
+142        return
+143
+144    quuux: int = 42
 
@@ -1065,8 +1064,8 @@

-
123    def __init__(self):
-124        super().__init__()
+            
122    def __init__(self):
+123        super().__init__()
 
@@ -1086,8 +1085,8 @@

-
126    def foo(self):
-127        pass
+            
125    def foo(self):
+126        pass
 
@@ -1108,9 +1107,9 @@

-
129    @classmethod
-130    def bar(cls):
-131        pass
+            
128    @classmethod
+129    def bar(cls):
+130        pass
 
@@ -1131,9 +1130,9 @@

-
133    @staticmethod
-134    def baz():
-135        pass
+            
132    @staticmethod
+133    def baz():
+134        pass
 
@@ -1205,13 +1204,13 @@

-
156class _Private:
-157    """private class"""
-158
-159    pass
-160
-161    def _do(self):
-162        """private method"""
+            
155class _Private:
+156    """private class"""
+157
+158    pass
+159
+160    def _do(self):
+161        """private method"""
 
@@ -1231,9 +1230,9 @@

-
168class LambdaAttr:
-169    # not really supported, but also shouldn't crash.
-170    attr = lambda x: 42  # noqa
+            
167class LambdaAttr:
+168    # not really supported, but also shouldn't crash.
+169    attr = lambda x: 42  # noqa
 
@@ -1250,7 +1249,7 @@

-
170    attr = lambda x: 42  # noqa
+            
169    attr = lambda x: 42  # noqa
 
@@ -1269,8 +1268,8 @@

-
177def foo():
-178    """no indents"""
+            
176def foo():
+177    """no indents"""
 
@@ -1290,9 +1289,9 @@

-
181def bar():
-182    """no
-183indents"""
+            
180def bar():
+181    """no
+182indents"""
 
@@ -1313,9 +1312,9 @@

-
186def baz():
-187    """one
-188    indent"""
+            
185def baz():
+186    """one
+187    indent"""
 
@@ -1336,11 +1335,11 @@

-
191def qux():
-192    """
-193    two
-194    indents
-195    """
+            
190def qux():
+191    """
+192    two
+193    indents
+194    """
 
@@ -1361,55 +1360,55 @@

-
198class Indented:
-199    def foo(self):
-200        """no indents"""
-201
-202    def bar(self):
-203        """no
-204indents"""
-205
-206    def baz(self):
-207        """one
-208        indent"""
-209
-210    def qux(self):
-211        """
-212        two
-213        indents
-214        """
-215
-216    @lru_cache()
-217    def foo_decorated(self):
-218        """no indents"""
-219
-220    @lru_cache()
-221    # comment
-222    def foo_commented(self):
-223        """no indents"""
-224
-225    @lru_cache()
-226    def bar_decorated(self):
-227        """no
-228indents"""
-229
-230    @lru_cache()
-231    def baz_decorated(self):
-232        """one
-233        indent"""
-234
-235    @lru_cache()
-236    def qux_decorated(self):
-237        """
-238        two
-239        indents
-240        """
-241
-242    @lru_cache(
-243        maxsize=42
-244    )
-245    def quux_decorated(self):
-246        """multi-line decorator, https://github.com/mitmproxy/pdoc/issues/246"""
+            
197class Indented:
+198    def foo(self):
+199        """no indents"""
+200
+201    def bar(self):
+202        """no
+203indents"""
+204
+205    def baz(self):
+206        """one
+207        indent"""
+208
+209    def qux(self):
+210        """
+211        two
+212        indents
+213        """
+214
+215    @lru_cache()
+216    def foo_decorated(self):
+217        """no indents"""
+218
+219    @lru_cache()
+220    # comment
+221    def foo_commented(self):
+222        """no indents"""
+223
+224    @lru_cache()
+225    def bar_decorated(self):
+226        """no
+227indents"""
+228
+229    @lru_cache()
+230    def baz_decorated(self):
+231        """one
+232        indent"""
+233
+234    @lru_cache()
+235    def qux_decorated(self):
+236        """
+237        two
+238        indents
+239        """
+240
+241    @lru_cache(
+242        maxsize=42
+243    )
+244    def quux_decorated(self):
+245        """multi-line decorator, https://github.com/mitmproxy/pdoc/issues/246"""
 
@@ -1426,8 +1425,8 @@

-
199    def foo(self):
-200        """no indents"""
+            
198    def foo(self):
+199        """no indents"""
 
@@ -1447,9 +1446,9 @@

-
202    def bar(self):
-203        """no
-204indents"""
+            
201    def bar(self):
+202        """no
+203indents"""
 
@@ -1470,9 +1469,9 @@

-
206    def baz(self):
-207        """one
-208        indent"""
+            
205    def baz(self):
+206        """one
+207        indent"""
 
@@ -1493,11 +1492,11 @@

-
210    def qux(self):
-211        """
-212        two
-213        indents
-214        """
+            
209    def qux(self):
+210        """
+211        two
+212        indents
+213        """
 
@@ -1519,9 +1518,9 @@

-
216    @lru_cache()
-217    def foo_decorated(self):
-218        """no indents"""
+            
215    @lru_cache()
+216    def foo_decorated(self):
+217        """no indents"""
 
@@ -1542,10 +1541,10 @@

-
220    @lru_cache()
-221    # comment
-222    def foo_commented(self):
-223        """no indents"""
+            
219    @lru_cache()
+220    # comment
+221    def foo_commented(self):
+222        """no indents"""
 
@@ -1566,10 +1565,10 @@

-
225    @lru_cache()
-226    def bar_decorated(self):
-227        """no
-228indents"""
+            
224    @lru_cache()
+225    def bar_decorated(self):
+226        """no
+227indents"""
 
@@ -1591,10 +1590,10 @@

-
230    @lru_cache()
-231    def baz_decorated(self):
-232        """one
-233        indent"""
+            
229    @lru_cache()
+230    def baz_decorated(self):
+231        """one
+232        indent"""
 
@@ -1616,12 +1615,12 @@

-
235    @lru_cache()
-236    def qux_decorated(self):
-237        """
-238        two
-239        indents
-240        """
+            
234    @lru_cache()
+235    def qux_decorated(self):
+236        """
+237        two
+238        indents
+239        """
 
@@ -1643,11 +1642,11 @@

-
242    @lru_cache(
-243        maxsize=42
-244    )
-245    def quux_decorated(self):
-246        """multi-line decorator, https://github.com/mitmproxy/pdoc/issues/246"""
+            
241    @lru_cache(
+242        maxsize=42
+243    )
+244    def quux_decorated(self):
+245        """multi-line decorator, https://github.com/mitmproxy/pdoc/issues/246"""
 
@@ -1668,9 +1667,9 @@

-
253@_protected_decorator
-254def fun_with_protected_decorator():
-255    """This function has a protected decorator (name starting with a single `_`)."""
+            
252@_protected_decorator
+253def fun_with_protected_decorator():
+254    """This function has a protected decorator (name starting with a single `_`)."""
 
@@ -1703,11 +1702,11 @@

-
267class AbstractClass(metaclass=abc.ABCMeta):
-268    """This class shouldn't show a constructor as it's abstract."""
-269    @abc.abstractmethod
-270    def foo(self):
-271        pass
+            
266class AbstractClass(metaclass=abc.ABCMeta):
+267    """This class shouldn't show a constructor as it's abstract."""
+268    @abc.abstractmethod
+269    def foo(self):
+270        pass
 
@@ -1727,9 +1726,9 @@

-
269    @abc.abstractmethod
-270    def foo(self):
-271        pass
+            
268    @abc.abstractmethod
+269    def foo(self):
+270        pass
 
@@ -1748,9 +1747,9 @@

-
277    def add_func(b: int) -> int:
-278        """This function adds two numbers."""
-279        return a + b
+            
276    def add_func(b: int) -> int:
+277        """This function adds two numbers."""
+278        return a + b
 
@@ -1770,9 +1769,9 @@

-
277    def add_func(b: int) -> int:
-278        """This function adds two numbers."""
-279        return a + b
+            
276    def add_func(b: int) -> int:
+277        """This function adds two numbers."""
+278        return a + b
 
@@ -1792,9 +1791,9 @@

-
277    def add_func(b: int) -> int:
-278        """This function adds two numbers."""
-279        return a + b
+            
276    def add_func(b: int) -> int:
+277        """This function adds two numbers."""
+278        return a + b
 
@@ -1814,17 +1813,17 @@

-
291def linkify_links():
-292    """
-293    This docstring contains links that are also identifiers:
-294
-295    - [`linkify_links`](https://example.com/)
-296    - [misc.linkify_links](https://example.com/)
-297    - [`linkify_links()`](https://example.com/)
-298    - [misc.linkify_links()](https://example.com/)
-299    - [link in target](https://example.com/misc.linkify_links)
-300    - [explicit linking](#AbstractClass.foo)
-301    """
+            
290def linkify_links():
+291    """
+292    This docstring contains links that are also identifiers:
+293
+294    - [`linkify_links`](https://example.com/)
+295    - [misc.linkify_links](https://example.com/)
+296    - [`linkify_links()`](https://example.com/)
+297    - [misc.linkify_links()](https://example.com/)
+298    - [link in target](https://example.com/misc.linkify_links)
+299    - [explicit linking](#AbstractClass.foo)
+300    """
 
@@ -1853,9 +1852,9 @@

-
309class Issue352a(metaclass=Issue352aMeta):
-310    def __init__(self):
-311        """Issue352.__init__ should be preferred over Meta.__call__."""
+            
308class Issue352a(metaclass=Issue352aMeta):
+309    def __init__(self):
+310        """Issue352.__init__ should be preferred over Meta.__call__."""
 
@@ -1871,8 +1870,8 @@

-
310    def __init__(self):
-311        """Issue352.__init__ should be preferred over Meta.__call__."""
+            
309    def __init__(self):
+310        """Issue352.__init__ should be preferred over Meta.__call__."""
 
@@ -1893,8 +1892,8 @@

-
319class Issue352b(metaclass=Issue352bMeta):
-320    """No docstrings for the constructor here."""
+            
318class Issue352b(metaclass=Issue352bMeta):
+319    """No docstrings for the constructor here."""
 
@@ -1914,8 +1913,8 @@

-
328class CustomCall(metaclass=CustomCallMeta):
-329    """A class where the constructor is defined by its metaclass."""
+            
327class CustomCall(metaclass=CustomCallMeta):
+328    """A class where the constructor is defined by its metaclass."""
 
@@ -1933,8 +1932,8 @@

-
324    def __call__(cls, *args, **kwargs):
-325        """Custom docstring in metaclass.`__call__`"""
+            
323    def __call__(cls, *args, **kwargs):
+324        """Custom docstring in metaclass.`__call__`"""
 
@@ -1955,33 +1954,33 @@

-
332class Headings:
-333    """
-334    # Heading 1
-335
-336    Here is some text.
-337
-338    ## Heading 2
-339
-340    Here is some text.
-341
-342    ### Heading 3
-343
-344    Here is some text.
-345
-346    #### Heading 4
-347
-348    Here is some text.
-349
-350    ##### Heading 5
-351
-352    Here is some text.
-353
-354    ###### Heading 6
-355
-356    Here is some text.
-357
-358    """
+            
331class Headings:
+332    """
+333    # Heading 1
+334
+335    Here is some text.
+336
+337    ## Heading 2
+338
+339    Here is some text.
+340
+341    ### Heading 3
+342
+343    Here is some text.
+344
+345    #### Heading 4
+346
+347    Here is some text.
+348
+349    ##### Heading 5
+350
+351    Here is some text.
+352
+353    ###### Heading 6
+354
+355    Here is some text.
+356
+357    """
 
@@ -2023,8 +2022,8 @@
Heading 6
-
366def repr_not_syntax_highlightable(x=CustomRepr()):
-367    """The default value for x fails to highlight with pygments."""
+            
365def repr_not_syntax_highlightable(x=CustomRepr()):
+366    """The default value for x fails to highlight with pygments."""
 
@@ -2044,10 +2043,10 @@
Heading 6
-
370class ClassDecorator:
-371    """This is a class that wraps a function. It will be documented correctly."""
-372    def __init__(self, f):
-373        self.f = f
+            
369class ClassDecorator:
+370    """This is a class that wraps a function. It will be documented correctly."""
+371    def __init__(self, f):
+372        self.f = f
 
@@ -2065,8 +2064,8 @@
Heading 6
-
372    def __init__(self, f):
-373        self.f = f
+            
371    def __init__(self, f):
+372        self.f = f
 
@@ -2099,12 +2098,12 @@
Heading 6
-
382class SubclassRef:
-383    class SubClass:
-384        pass
-385
-386    def __init__(self, x: "SubClass"):
-387        self.x = x
+            
381class SubclassRef:
+382    class SubClass:
+383        pass
+384
+385    def __init__(self, x: "SubClass"):
+386        self.x = x
 
@@ -2120,8 +2119,8 @@
Heading 6
-
386    def __init__(self, x: "SubClass"):
-387        self.x = x
+            
385    def __init__(self, x: "SubClass"):
+386        self.x = x
 
@@ -2140,8 +2139,8 @@
Heading 6
-
383    class SubClass:
-384        pass
+            
382    class SubClass:
+383        pass
 
@@ -2159,12 +2158,12 @@
Heading 6
-
390class ClassAsAttribute:
-391    static_attr_to_class = ClassDecorator
-392    """this is a static attribute that point to a Class (not an instance)"""
-393
-394    static_attr_to_instance = ClassDecorator(None)
-395    """this is a static attribute that point to an instance"""
+            
389class ClassAsAttribute:
+390    static_attr_to_class = ClassDecorator
+391    """this is a static attribute that point to a Class (not an instance)"""
+392
+393    static_attr_to_instance = ClassDecorator(None)
+394    """this is a static attribute that point to an instance"""
 
@@ -2210,8 +2209,8 @@
Heading 6
-
398class scheduler(sched.scheduler):
-399    """Test for broken links for inherited methods, https://github.com/mitmproxy/pdoc/issues/490"""
+            
397class scheduler(sched.scheduler):
+398    """Test for broken links for inherited methods, https://github.com/mitmproxy/pdoc/issues/490"""
 
@@ -2246,8 +2245,8 @@
Inherited Members
-
402class __init__:
-403    """https://github.com/mitmproxy/pdoc/issues/519"""
+            
401class __init__:
+402    """https://github.com/mitmproxy/pdoc/issues/519"""
 
@@ -2267,8 +2266,8 @@
Inherited Members
-
406def dynamically_modify_docstring1():
-407    """this should **not** be the docstring."""
+            
405def dynamically_modify_docstring1():
+406    """this should **not** be the docstring."""
 
@@ -2288,8 +2287,8 @@
Inherited Members
-
410def dynamically_modify_docstring2():
-411    pass
+            
409def dynamically_modify_docstring2():
+410    pass
 
@@ -2309,9 +2308,9 @@
Inherited Members
-
423@_docstring_modifier
-424def dynamically_modify_docstring3():
-425    """This should **not** be the docstring."""
+            
422@_docstring_modifier
+423def dynamically_modify_docstring3():
+424    """This should **not** be the docstring."""
 
@@ -2331,9 +2330,9 @@
Inherited Members
-
428@_docstring_modifier
-429def dynamically_modify_docstring4():
-430    pass
+            
427@_docstring_modifier
+428def dynamically_modify_docstring4():
+429    pass
 
diff --git a/test/testdata/misc.py b/test/testdata/misc.py index fc4ef7e8..f42a8a9c 100644 --- a/test/testdata/misc.py +++ b/test/testdata/misc.py @@ -1,12 +1,11 @@ import abc -import sched from functools import lru_cache +import sched from typing import Generic from typing import TypeVar from pdoc._compat import cached_property - # https://github.com/mitmproxy/pdoc/issues/226 diff --git a/test/testdata/misc_py39.html b/test/testdata/misc_py39.html index 2eedbbb6..08d4a8a5 100644 --- a/test/testdata/misc_py39.html +++ b/test/testdata/misc_py39.html @@ -111,74 +111,73 @@

9from typing import TypedDict 10from typing import Union 11 -12 -13# Testing a typing.NamedTuple -14# we do not care very much about collections.namedtuple, -15# the typing version is superior for documentation and a drop-in replacement. +12# Testing a typing.NamedTuple +13# we do not care very much about collections.namedtuple, +14# the typing version is superior for documentation and a drop-in replacement. +15 16 -17 -18class NamedTupleExample(NamedTuple): -19 """ -20 An example for a typing.NamedTuple. -21 """ -22 -23 name: str -24 """Name of our example tuple.""" -25 id: int = 3 +17class NamedTupleExample(NamedTuple): +18 """ +19 An example for a typing.NamedTuple. +20 """ +21 +22 name: str +23 """Name of our example tuple.""" +24 id: int = 3 +25 26 -27 -28# Testing some edge cases in our inlined implementation of ForwardRef._evaluate in _eval_type. -29class Foo(TypedDict): -30 a: Optional[int] -31 """First attribute.""" +27# Testing some edge cases in our inlined implementation of ForwardRef._evaluate in _eval_type. +28class Foo(TypedDict): +29 a: Optional[int] +30 """First attribute.""" +31 32 -33 -34class Bar(Foo, total=False): -35 """A TypedDict subclass. TypedDict botches the MRO, so things aren't perfect here.""" -36 -37 b: int -38 """Second attribute.""" -39 c: str -40 # undocumented attribute +33class Bar(Foo, total=False): +34 """A TypedDict subclass. TypedDict botches the MRO, so things aren't perfect here.""" +35 +36 b: int +37 """Second attribute.""" +38 c: str +39 # undocumented attribute +40 41 -42 -43class BarWorkaround(Foo, TypedDict, total=False): -44 """ -45 A TypedDict subclass with the workaround to also inherit from TypedDict. -46 -47 See https://github.com/sphinx-doc/sphinx/pull/10806. -48 """ -49 -50 b: int -51 """Second attribute.""" -52 c: str -53 # undocumented attribute +42class BarWorkaround(Foo, TypedDict, total=False): +43 """ +44 A TypedDict subclass with the workaround to also inherit from TypedDict. +45 +46 See https://github.com/sphinx-doc/sphinx/pull/10806. +47 """ +48 +49 b: int +50 """Second attribute.""" +51 c: str +52 # undocumented attribute +53 54 -55 -56class SingleDispatchMethodExample: -57 @functools.singledispatchmethod -58 def fancymethod(self, str_or_int: Union[str, int]): -59 """A fancy method which is capable of handling either `str` or `int`. -60 -61 :param str_or_int: string or integer to handle -62 """ -63 raise NotImplementedError(f"{type(str_or_int)=} not implemented!") -64 -65 @fancymethod.register -66 def fancymethod_handle_str(self, str_to_handle: str): -67 """Fancy method handles a string. -68 -69 :param str_to_handle: string which will be handled -70 """ -71 print(f"{type(str_to_handle)} = '{str_to_handle}") -72 -73 @fancymethod.register -74 def _fancymethod_handle_int(self, int_to_handle: int): -75 """Fancy method handles int (not shown in doc). -76 -77 :param int_to_handle: int which will be handled -78 """ -79 print(f"{type(int_to_handle)} = '{int_to_handle:x}'") +55class SingleDispatchMethodExample: +56 @functools.singledispatchmethod +57 def fancymethod(self, str_or_int: Union[str, int]): +58 """A fancy method which is capable of handling either `str` or `int`. +59 +60 :param str_or_int: string or integer to handle +61 """ +62 raise NotImplementedError(f"{type(str_or_int)=} not implemented!") +63 +64 @fancymethod.register +65 def fancymethod_handle_str(self, str_to_handle: str): +66 """Fancy method handles a string. +67 +68 :param str_to_handle: string which will be handled +69 """ +70 print(f"{type(str_to_handle)} = '{str_to_handle}") +71 +72 @fancymethod.register +73 def _fancymethod_handle_int(self, int_to_handle: int): +74 """Fancy method handles int (not shown in doc). +75 +76 :param int_to_handle: int which will be handled +77 """ +78 print(f"{type(int_to_handle)} = '{int_to_handle:x}'")

@@ -194,14 +193,14 @@

-
19class NamedTupleExample(NamedTuple):
-20    """
-21    An example for a typing.NamedTuple.
-22    """
-23
-24    name: str
-25    """Name of our example tuple."""
-26    id: int = 3
+            
18class NamedTupleExample(NamedTuple):
+19    """
+20    An example for a typing.NamedTuple.
+21    """
+22
+23    name: str
+24    """Name of our example tuple."""
+25    id: int = 3
 
@@ -271,9 +270,9 @@
Inherited Members
-
30class Foo(TypedDict):
-31    a: Optional[int]
-32    """First attribute."""
+            
29class Foo(TypedDict):
+30    a: Optional[int]
+31    """First attribute."""
 
@@ -304,13 +303,13 @@
Inherited Members
-
35class Bar(Foo, total=False):
-36    """A TypedDict subclass. TypedDict botches the MRO, so things aren't perfect here."""
-37
-38    b: int
-39    """Second attribute."""
-40    c: str
-41    # undocumented attribute
+            
34class Bar(Foo, total=False):
+35    """A TypedDict subclass. TypedDict botches the MRO, so things aren't perfect here."""
+36
+37    b: int
+38    """Second attribute."""
+39    c: str
+40    # undocumented attribute
 
@@ -362,17 +361,17 @@
Inherited Members
-
44class BarWorkaround(Foo, TypedDict, total=False):
-45    """
-46    A TypedDict subclass with the workaround to also inherit from TypedDict.
-47
-48    See https://github.com/sphinx-doc/sphinx/pull/10806.
-49    """
-50
-51    b: int
-52    """Second attribute."""
-53    c: str
-54    # undocumented attribute
+            
43class BarWorkaround(Foo, TypedDict, total=False):
+44    """
+45    A TypedDict subclass with the workaround to also inherit from TypedDict.
+46
+47    See https://github.com/sphinx-doc/sphinx/pull/10806.
+48    """
+49
+50    b: int
+51    """Second attribute."""
+52    c: str
+53    # undocumented attribute
 
@@ -416,30 +415,30 @@
Inherited Members
-
57class SingleDispatchMethodExample:
-58    @functools.singledispatchmethod
-59    def fancymethod(self, str_or_int: Union[str, int]):
-60        """A fancy method which is capable of handling either `str` or `int`.
-61
-62        :param str_or_int: string or integer to handle
-63        """
-64        raise NotImplementedError(f"{type(str_or_int)=} not implemented!")
-65
-66    @fancymethod.register
-67    def fancymethod_handle_str(self, str_to_handle: str):
-68        """Fancy method handles a string.
-69
-70        :param str_to_handle: string which will be handled
-71        """
-72        print(f"{type(str_to_handle)} = '{str_to_handle}")
-73
-74    @fancymethod.register
-75    def _fancymethod_handle_int(self, int_to_handle: int):
-76        """Fancy method handles int (not shown in doc).
-77
-78        :param int_to_handle: int which will be handled
-79        """
-80        print(f"{type(int_to_handle)} = '{int_to_handle:x}'")
+            
56class SingleDispatchMethodExample:
+57    @functools.singledispatchmethod
+58    def fancymethod(self, str_or_int: Union[str, int]):
+59        """A fancy method which is capable of handling either `str` or `int`.
+60
+61        :param str_or_int: string or integer to handle
+62        """
+63        raise NotImplementedError(f"{type(str_or_int)=} not implemented!")
+64
+65    @fancymethod.register
+66    def fancymethod_handle_str(self, str_to_handle: str):
+67        """Fancy method handles a string.
+68
+69        :param str_to_handle: string which will be handled
+70        """
+71        print(f"{type(str_to_handle)} = '{str_to_handle}")
+72
+73    @fancymethod.register
+74    def _fancymethod_handle_int(self, int_to_handle: int):
+75        """Fancy method handles int (not shown in doc).
+76
+77        :param int_to_handle: int which will be handled
+78        """
+79        print(f"{type(int_to_handle)} = '{int_to_handle:x}'")
 
@@ -457,13 +456,13 @@
Inherited Members
-
58    @functools.singledispatchmethod
-59    def fancymethod(self, str_or_int: Union[str, int]):
-60        """A fancy method which is capable of handling either `str` or `int`.
-61
-62        :param str_or_int: string or integer to handle
-63        """
-64        raise NotImplementedError(f"{type(str_or_int)=} not implemented!")
+            
57    @functools.singledispatchmethod
+58    def fancymethod(self, str_or_int: Union[str, int]):
+59        """A fancy method which is capable of handling either `str` or `int`.
+60
+61        :param str_or_int: string or integer to handle
+62        """
+63        raise NotImplementedError(f"{type(str_or_int)=} not implemented!")
 
@@ -490,13 +489,13 @@
Parameters
-
66    @fancymethod.register
-67    def fancymethod_handle_str(self, str_to_handle: str):
-68        """Fancy method handles a string.
-69
-70        :param str_to_handle: string which will be handled
-71        """
-72        print(f"{type(str_to_handle)} = '{str_to_handle}")
+            
65    @fancymethod.register
+66    def fancymethod_handle_str(self, str_to_handle: str):
+67        """Fancy method handles a string.
+68
+69        :param str_to_handle: string which will be handled
+70        """
+71        print(f"{type(str_to_handle)} = '{str_to_handle}")
 
diff --git a/test/testdata/misc_py39.py b/test/testdata/misc_py39.py index 8e3ae9e0..49186868 100644 --- a/test/testdata/misc_py39.py +++ b/test/testdata/misc_py39.py @@ -9,7 +9,6 @@ from typing import TypedDict from typing import Union - # Testing a typing.NamedTuple # we do not care very much about collections.namedtuple, # the typing version is superior for documentation and a drop-in replacement. diff --git a/test/testdata/top_level_reimports.html b/test/testdata/top_level_reimports.html index df0fbcc6..5e67b91a 100644 --- a/test/testdata/top_level_reimports.html +++ b/test/testdata/top_level_reimports.html @@ -83,8 +83,8 @@

7 - `top_level_reimports._internal.baz()` 8""" 9from ._internal import Bar -10from ._internal import baz -11from ._internal import Foo +10from ._internal import Foo +11from ._internal import baz 12 13__all__ = ["Foo", "Bar", "baz"]

diff --git a/test/testdata/top_level_reimports/__init__.py b/test/testdata/top_level_reimports/__init__.py index fe220493..c3c058b7 100644 --- a/test/testdata/top_level_reimports/__init__.py +++ b/test/testdata/top_level_reimports/__init__.py @@ -7,7 +7,7 @@ - `top_level_reimports._internal.baz()` """ from ._internal import Bar -from ._internal import baz from ._internal import Foo +from ._internal import baz __all__ = ["Foo", "Bar", "baz"] diff --git a/test/testdata/type_stub.pyi b/test/testdata/type_stub.pyi index 072990df..b15e297b 100644 --- a/test/testdata/type_stub.pyi +++ b/test/testdata/type_stub.pyi @@ -1,4 +1,5 @@ -from typing import Any, Iterable +from typing import Any +from typing import Iterable def func(x: str, y: Any, z: "Iterable[str]") -> int: ...