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 @@
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]
25class Issue226: -26 @Descriptor -27 def size(self): -28 """This is the size""" + @@ -833,8 +832,8 @@
46def func_with_defaults(a=default_obj, b=default_func): -47 """this shouldn't render object or function addresses""" -48 pass +@@ -876,25 +875,25 @@45def func_with_defaults(a=default_obj, b=default_func): +46 """this shouldn't render object or function addresses""" +47 pass
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 +@@ -929,9 +928,9 @@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
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 +@@ -1065,8 +1064,8 @@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
156class _Private: -157 """private class""" -158 -159 pass -160 -161 def _do(self): -162 """private method""" +@@ -1231,9 +1230,9 @@155class _Private: +156 """private class""" +157 +158 pass +159 +160 def _do(self): +161 """private method"""
168class LambdaAttr: -169 # not really supported, but also shouldn't crash. -170 attr = lambda x: 42 # noqa +@@ -1250,7 +1249,7 @@167class LambdaAttr: +168 # not really supported, but also shouldn't crash. +169 attr = lambda x: 42 # noqa
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""" +@@ -1426,8 +1425,8 @@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"""
220 @lru_cache() -221 # comment -222 def foo_commented(self): -223 """no indents""" + @@ -1566,10 +1565,10 @@
235 @lru_cache() -236 def qux_decorated(self): -237 """ -238 two -239 indents -240 """ + @@ -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""" +@@ -1668,9 +1667,9 @@241 @lru_cache( +242 maxsize=42 +243 ) +244 def quux_decorated(self): +245 """multi-line decorator, https://github.com/mitmproxy/pdoc/issues/246"""
253@_protected_decorator -254def fun_with_protected_decorator(): -255 """This function has a protected decorator (name starting with a single `_`).""" +@@ -1703,11 +1702,11 @@252@_protected_decorator +253def fun_with_protected_decorator(): +254 """This function has a protected decorator (name starting with a single `_`)."""
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 +@@ -1727,9 +1726,9 @@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
277 def add_func(b: int) -> int: -278 """This function adds two numbers.""" -279 return a + b + @@ -1770,9 +1769,9 @@
277 def add_func(b: int) -> int: -278 """This function adds two numbers.""" -279 return a + b + @@ -1792,9 +1791,9 @@
277 def add_func(b: int) -> int: -278 """This function adds two numbers.""" -279 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 """ +@@ -1853,9 +1852,9 @@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 """
309class Issue352a(metaclass=Issue352aMeta): -310 def __init__(self): -311 """Issue352.__init__ should be preferred over Meta.__call__.""" +@@ -1871,8 +1870,8 @@308class Issue352a(metaclass=Issue352aMeta): +309 def __init__(self): +310 """Issue352.__init__ should be preferred over Meta.__call__."""
310 def __init__(self): -311 """Issue352.__init__ should be preferred over Meta.__call__.""" + @@ -1893,8 +1892,8 @@
319class Issue352b(metaclass=Issue352bMeta): -320 """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.""" +@@ -1933,8 +1932,8 @@327class CustomCall(metaclass=CustomCallMeta): +328 """A class where the constructor is defined by its metaclass."""
324 def __call__(cls, *args, **kwargs): -325 """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 """ +@@ -2023,8 +2022,8 @@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 """Heading 6
366def repr_not_syntax_highlightable(x=CustomRepr()): -367 """The default value for x fails to highlight with pygments.""" +@@ -2044,10 +2043,10 @@365def repr_not_syntax_highlightable(x=CustomRepr()): +366 """The default value for x fails to highlight with pygments."""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 +@@ -2065,8 +2064,8 @@369class ClassDecorator: +370 """This is a class that wraps a function. It will be documented correctly.""" +371 def __init__(self, f): +372 self.f = fHeading 6
382class SubclassRef: -383 class SubClass: -384 pass -385 -386 def __init__(self, x: "SubClass"): -387 self.x = x +@@ -2120,8 +2119,8 @@381class SubclassRef: +382 class SubClass: +383 pass +384 +385 def __init__(self, x: "SubClass"): +386 self.x = xHeading 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""" +@@ -2210,8 +2209,8 @@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"""Heading 6
398class scheduler(sched.scheduler): -399 """Test for broken links for inherited methods, https://github.com/mitmproxy/pdoc/issues/490""" +@@ -2246,8 +2245,8 @@397class scheduler(sched.scheduler): +398 """Test for broken links for inherited methods, https://github.com/mitmproxy/pdoc/issues/490"""Inherited Members
402class __init__: -403 """https://github.com/mitmproxy/pdoc/issues/519""" + @@ -2267,8 +2266,8 @@Inherited Members
406def dynamically_modify_docstring1(): -407 """this should **not** be the docstring.""" + @@ -2288,8 +2287,8 @@Inherited Members
423@_docstring_modifier -424def dynamically_modify_docstring3(): -425 """This should **not** be the docstring.""" +@@ -2331,9 +2330,9 @@422@_docstring_modifier +423def dynamically_modify_docstring3(): +424 """This should **not** be the docstring."""Inherited Members
428@_docstring_modifier -429def dynamically_modify_docstring4(): -430 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}'")
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 +@@ -271,9 +270,9 @@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 = 3Inherited Members
30class Foo(TypedDict): -31 a: Optional[int] -32 """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 +@@ -362,17 +361,17 @@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 attributeInherited 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 +@@ -416,30 +415,30 @@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 attributeInherited 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}'") +@@ -457,13 +456,13 @@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}'")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!") +@@ -490,13 +489,13 @@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!")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}") +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 @@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}")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"]