-
Notifications
You must be signed in to change notification settings - Fork 215
Open
Labels
enhancementNew feature or requestNew feature or request
Description
Describe the feature you'd like to request
Goals
- Create a custom role which extends
docutils.parsers.rst.roles.code_role. - Pass static type checking (
mypy) - Pass runtime type checking (
beartype)
Below is a minimized example of my work towards supporting MyST for substitution-code within https://github.com/adamtheturtle/sphinx-substitution-extensions.
Requirements
beartype==0.19.0myst-parser==4.0.0types-docutils==0.21.0.20241128
Files
Layout as described in
https://www.sphinx-doc.org/en/master/usage/configuration.html#confval-extensions.
<project directory>/
├── conf.py
└── sphinxext/
└── extname.py
# conf.py
import sys
from pathlib import Path
# Path configured as per
# https://www.sphinx-doc.org/en/master/usage/configuration.html#confval-extensions
sys.path.append(str(Path('sphinxext').resolve()))
extensions = [
"myst_parser",
"extname",
]# sphinxext/extname.py
from typing import Any
from beartype import beartype
from docutils.nodes import Node, system_message
from docutils.parsers.rst.roles import code_role
from docutils.parsers.rst.states import Inliner
# Typed version of the example from https://docutils.sourceforge.io/docs/howto/rst-roles.html#define-the-role-function
@beartype
def role_fn(
name: str,
rawtext: str,
text: str,
lineno: int,
# This is an `Inliner`, so it can be passed through directly to `code_role`.
inliner: Inliner,
options: dict[Any, Any] = {},
content: list[str] = [],
) -> tuple[list[Node], list[system_message]]:
print("Custom logic")
# Type stubs for `code_role` are at
# https://github.com/python/typeshed/blob/57d7c4334b64856fda6f6e8f992b101ddafe2f57/stubs/docutils/docutils/parsers/rst/roles.pyi#L103
#
# Importantly, they require that `inliner` is an `Inliner`.
return code_role(
role=name,
rawtext=rawtext,
text=text,
lineno=lineno,
inliner=inliner,
options=options,
content=content,
)
@beartype
def setup(app):
app.add_role(name="my-role", role=role_fn)Command
sphinx-build -M html . build/Error
beartype.roar.BeartypeCallHintParamViolation: Function extname.role_fn() parameter inliner=<myst_parser.mocking.MockInliner object at 0x10826e120> violates type hint <class 'docutils.parsers.rst.states.Inliner'>, as <class "myst_parser.mocking.MockInliner"> <myst_parser.mocking.MockInliner object at 0x10826e120> not instance of <class "docutils.parsers.rst.states.Inliner">.
Describe the solution you'd like
Modify MockInliner as per https://beartype.readthedocs.io/en/latest/faq/#mock-types to define a new __class__ property which returns Inliner.
Describe alternatives you've considered
My workaround is to have role_fn hint inliner as inliner: Inliner | MockInliner, and then to create a new Inliner object as needed for code_role:
if isinstance(inliner, MockInliner):
new_inliner = Inliner()
new_inliner.document = inliner_document
inliner = new_inliner
Another alternative is to contribute to types-docutils to have code_role take a Protocol of just what is needed from Inliner, so it supports MockInliner, too.
Metadata
Metadata
Assignees
Labels
enhancementNew feature or requestNew feature or request