Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix type_annotation_transforms for Sphinx 6 #181

Merged
merged 7 commits into from
Jan 3, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Fix type_annotation_transforms to work with Sphinx 6
Instead of intercepting the call to `ast.parse`, we now parse,
transform, and then unparse.

This also drops support for Python 3.7, since Sphinx 6 also drops
Python 3.7 support.
  • Loading branch information
jbms committed Jan 2, 2023
commit a78cb008d08de247015b4da9bb9cb2ef259dca2b
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ jobs:
- 'windows-latest'
- 'macos-latest'
python-version:
- '3.7'
- '3.8'
- '3.9'
- '3.10'
- '3.11'
node-version:
- '16.x'
runs-on: ${{ matrix.os }}
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ def run(self):
],
"sphinx_immaterial.apidoc.cpp.cppreference_data": ["*.xml"],
},
python_requires=">=3.7",
python_requires=">=3.8",
2bndy5 marked this conversation as resolved.
Show resolved Hide resolved
install_requires=REQUIREMENTS,
use_scm_version={
# It would be nice to include the commit hash in the version, but that
Expand Down
46 changes: 34 additions & 12 deletions sphinx_immaterial/apidoc/python/type_annotation_transforms.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"""Optional type annotation transformations."""

import ast
import functools
import re
import sys
Expand All @@ -19,9 +20,32 @@
import sphinx.application
import sphinx.domains.python
import sphinx.environment
from sphinx.pycode.ast import ast
import sphinx.util.logging

# `ast.unparse` added in Python 3.9
if sys.version_info >= (3, 9):
from ast import unparse as ast_unparse
else:
from sphinx.pycode.ast import unparse as ast_unparse
from sphinx.pycode.ast import _UnparseVisitor

def _monkey_patch_sphinx_ast_unparse():
"""Monkey patch Sphinx's `ast_unparse`.

This adds support for some additional ast nodes that we require.
"""

def visit_Module(self: _UnparseVisitor, node: ast.Module) -> str:
return "\n".join(self.visit(el) for el in node.body)

def visit_Expr(self: _UnparseVisitor, node: ast.Expr) -> str:
return self.visit(node.value)

_UnparseVisitor.visit_Module = visit_Module # type: ignore[assignment]
_UnparseVisitor.visit_Expr = visit_Expr # type: ignore[assignment]

_monkey_patch_sphinx_ast_unparse()

logger = sphinx.util.logging.getLogger(__name__)

PEP585_ALIASES = {
Expand Down Expand Up @@ -230,19 +254,17 @@ def _parse_annotation(annotation: str, env: sphinx.environment.BuildEnvironment)
transformer_config = getattr(env, _CONFIG_ATTR, None)
if transformer_config is None or not transformer_config.transform:
return orig_parse_annotation(annotation, env)
try:
orig_ast_parse = sphinx.domains.python.ast_parse

def ast_parse(annotation: str) -> ast.AST:
tree = orig_ast_parse(annotation)
transformer = TypeAnnotationTransformer()
transformer.config = cast(TypeTransformConfig, transformer_config)
return ast.fix_missing_locations(transformer.visit(tree))

sphinx.domains.python.ast_parse = ast_parse # type: ignore
try:
tree = ast.parse(annotation, type_comments=True)
except SyntaxError:
return orig_parse_annotation(annotation, env)
finally:
sphinx.domains.python.ast_parse = orig_ast_parse

transformer = TypeAnnotationTransformer()
transformer.config = cast(TypeTransformConfig, transformer_config)
tree = ast.fix_missing_locations(transformer.visit(tree))
annotation = ast_unparse(tree)
return orig_parse_annotation(annotation, env)

sphinx.domains.python._parse_annotation = _parse_annotation

Expand Down