Skip to content

Commit

Permalink
Improve Support for type statements (#651)
Browse files Browse the repository at this point in the history
  • Loading branch information
mhils committed Dec 13, 2023
1 parent c4418ff commit dc5a058
Show file tree
Hide file tree
Showing 10 changed files with 434 additions and 280 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

- pdoc now documents PyO3 or pybind11 submodules that are not picked up by Python's builtin pkgutil module.
([#633](https://github.com/mitmproxy/pdoc/issues/633), @mhils)
- pdoc now supports Python 3.12's `type` statements and has improved `TypeAlias` rendering.
([#651](https://github.com/mitmproxy/pdoc/pull/651), @mhils)
- Add support for `code-block` ReST directives
([#624](https://github.com/mitmproxy/pdoc/pull/624), @JCGoran)
- If a variable's value meets certain entropy criteria and matches an environment variable value,
Expand Down
21 changes: 21 additions & 0 deletions pdoc/_compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,24 @@
def ast_unparse(t): # type: ignore
return _unparse(t).strip("\t\n \"'")

if sys.version_info >= (3, 12):
from ast import TypeAlias as ast_TypeAlias
else: # pragma: no cover
class ast_TypeAlias:
pass

if sys.version_info >= (3, 12):
from typing import TypeAliasType
else: # pragma: no cover
class TypeAliasType:
"""Placeholder class for TypeAliasType"""

if sys.version_info >= (3, 10):
from typing import TypeAlias
else: # pragma: no cover
class TypeAlias:
pass

if sys.version_info >= (3, 9):
from types import GenericAlias
else: # pragma: no cover
Expand Down Expand Up @@ -108,6 +126,9 @@ def format_usage(self):
__all__ = [
"cache",
"ast_unparse",
"ast_TypeAlias",
"TypeAliasType",
"TypeAlias",
"GenericAlias",
"UnionType",
"removesuffix",
Expand Down
16 changes: 13 additions & 3 deletions pdoc/doc.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,15 +44,16 @@
from pdoc import doc_ast
from pdoc import doc_pyi
from pdoc import extract
from pdoc._compat import TypeAlias
from pdoc._compat import TypeAliasType
from pdoc._compat import cache
from pdoc._compat import formatannotation
from pdoc.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 formatannotation


def _include_fullname_in_traceback(f):
"""
Expand Down Expand Up @@ -1089,6 +1090,11 @@ def is_typevar(self) -> bool:
else:
return False

@cached_property
def is_type_alias_type(self) -> bool:
"""`True` if the variable is a `typing.TypeAliasType`, `False` otherwise."""
return isinstance(self.default_value, TypeAliasType)

@cached_property
def is_enum_member(self) -> bool:
"""`True` if the variable is an enum member, `False` otherwise."""
Expand All @@ -1102,6 +1108,10 @@ def default_value_str(self) -> str:
"""The variable's default value as a pretty-printed str."""
if self.default_value is empty:
return ""
if isinstance(self.default_value, TypeAliasType):
return formatannotation(self.default_value.__value__)
elif self.annotation == TypeAlias:
return formatannotation(self.default_value)

# This is not perfect, but a solid attempt at preventing accidental leakage of secrets.
# If you have input on how to improve the heuristic, please send a pull request!
Expand Down
9 changes: 8 additions & 1 deletion pdoc/doc_ast.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

import pdoc

from ._compat import ast_TypeAlias
from ._compat import ast_unparse
from ._compat import cache

Expand Down Expand Up @@ -115,7 +116,11 @@ def _walk_tree(
func_docstrings = {}
annotations = {}
for a, b in _pairwise_longest(_nodes(tree)):
if isinstance(a, ast.AnnAssign) and isinstance(a.target, ast.Name) and a.simple:
if isinstance(a, ast_TypeAlias):
name = a.name.id
elif (
isinstance(a, ast.AnnAssign) and isinstance(a.target, ast.Name) and a.simple
):
name = a.target.id
annotations[name] = unparse(a.annotation)
elif (
Expand Down Expand Up @@ -183,6 +188,8 @@ def sort_by_source(
name = a.target.id
elif isinstance(a, (ast.FunctionDef, ast.AsyncFunctionDef, ast.ClassDef)):
name = a.name
elif isinstance(a, ast_TypeAlias):
name = a.name.id
else:
continue

Expand Down
1 change: 1 addition & 0 deletions pdoc/templates/default/module.html.jinja2
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ See https://pdoc.dev/docs/pdoc/render_helpers.html#DefaultMacroExtension for an
{% endif %}
{% enddefaultmacro %}
{% defaultmacro variable(var) -%}
{%- if var.is_type_alias_type %}<span class="def">type</span> {% endif -%}
<span class="name">{{ var.name }}</span>{{ annotation(var) }}{{ default_value(var) }}
{% enddefaultmacro %}
{% defaultmacro submodule(mod) -%}
Expand Down
459 changes: 234 additions & 225 deletions test/testdata/flavors_rst.html

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions test/testdata/flavors_rst.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ def admonitions():
.. versionchanged:: 2.5
The *spam* parameter.
.. code-block::
This is a code block.
.. deprecated:: 3.1
Use :func:`spam` instead.
Expand Down
Loading

0 comments on commit dc5a058

Please sign in to comment.