mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Fix #7535: sphinx-autogen: crashes when custom template uses inheritance
This commit is contained in:
parent
fd0a55223f
commit
b15e3f6639
1
CHANGES
1
CHANGES
@ -30,6 +30,7 @@ Features added
|
|||||||
caption to the toctree
|
caption to the toctree
|
||||||
* #248, #6040: autosummary: Add ``:recursive:`` option to autosummary directive
|
* #248, #6040: autosummary: Add ``:recursive:`` option to autosummary directive
|
||||||
to generate stub files recursively
|
to generate stub files recursively
|
||||||
|
* #7535: sphinx-autogen: crashes when custom template uses inheritance
|
||||||
* #7481: html theme: Add right margin to footnote/citation labels
|
* #7481: html theme: Add right margin to footnote/citation labels
|
||||||
* #7482: html theme: CSS spacing for code blocks with captions and line numbers
|
* #7482: html theme: CSS spacing for code blocks with captions and line numbers
|
||||||
* #7443: html theme: Add new options :confval:`globaltoc_collapse` and
|
* #7443: html theme: Add new options :confval:`globaltoc_collapse` and
|
||||||
|
@ -25,25 +25,27 @@ import pydoc
|
|||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
import warnings
|
import warnings
|
||||||
|
from os import path
|
||||||
from typing import Any, Callable, Dict, List, NamedTuple, Set, Tuple
|
from typing import Any, Callable, Dict, List, NamedTuple, Set, Tuple
|
||||||
|
|
||||||
from jinja2 import BaseLoader, FileSystemLoader, TemplateNotFound
|
from jinja2 import TemplateNotFound
|
||||||
from jinja2.sandbox import SandboxedEnvironment
|
from jinja2.sandbox import SandboxedEnvironment
|
||||||
|
|
||||||
import sphinx.locale
|
import sphinx.locale
|
||||||
from sphinx import __display_version__
|
from sphinx import __display_version__
|
||||||
from sphinx import package_dir
|
from sphinx import package_dir
|
||||||
from sphinx.builders import Builder
|
from sphinx.builders import Builder
|
||||||
|
from sphinx.config import Config
|
||||||
from sphinx.deprecation import RemovedInSphinx40Warning, RemovedInSphinx50Warning
|
from sphinx.deprecation import RemovedInSphinx40Warning, RemovedInSphinx50Warning
|
||||||
from sphinx.ext.autodoc import Documenter
|
from sphinx.ext.autodoc import Documenter
|
||||||
from sphinx.ext.autosummary import import_by_name, get_documenter
|
from sphinx.ext.autosummary import import_by_name, get_documenter
|
||||||
from sphinx.jinja2glue import BuiltinTemplateLoader
|
|
||||||
from sphinx.locale import __
|
from sphinx.locale import __
|
||||||
from sphinx.registry import SphinxComponentRegistry
|
from sphinx.registry import SphinxComponentRegistry
|
||||||
from sphinx.util import logging
|
from sphinx.util import logging
|
||||||
from sphinx.util import rst
|
from sphinx.util import rst
|
||||||
from sphinx.util.inspect import safe_getattr
|
from sphinx.util.inspect import safe_getattr
|
||||||
from sphinx.util.osutil import ensuredir
|
from sphinx.util.osutil import ensuredir
|
||||||
|
from sphinx.util.template import SphinxTemplateLoader
|
||||||
|
|
||||||
if False:
|
if False:
|
||||||
# For type annotation
|
# For type annotation
|
||||||
@ -59,6 +61,7 @@ class DummyApplication:
|
|||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
self.registry = SphinxComponentRegistry()
|
self.registry = SphinxComponentRegistry()
|
||||||
self.messagelog = [] # type: List[str]
|
self.messagelog = [] # type: List[str]
|
||||||
|
self.translator = None
|
||||||
self.verbosity = 0
|
self.verbosity = 0
|
||||||
self._warncount = 0
|
self._warncount = 0
|
||||||
self.warningiserror = False
|
self.warningiserror = False
|
||||||
@ -67,6 +70,21 @@ class DummyApplication:
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class DummyBuilder:
|
||||||
|
"""Dummy builder class for sphinx-autogen command."""
|
||||||
|
|
||||||
|
def __init__(self, app: DummyApplication, template_path: str) -> None:
|
||||||
|
if template_path:
|
||||||
|
templates_path = [path.abspath(template_path)]
|
||||||
|
else:
|
||||||
|
templates_path = []
|
||||||
|
|
||||||
|
self.app = app
|
||||||
|
self.srcdir = "/"
|
||||||
|
self.config = Config(overrides={'templates_path': templates_path})
|
||||||
|
self.config.init_values()
|
||||||
|
|
||||||
|
|
||||||
AutosummaryEntry = NamedTuple('AutosummaryEntry', [('name', str),
|
AutosummaryEntry = NamedTuple('AutosummaryEntry', [('name', str),
|
||||||
('path', str),
|
('path', str),
|
||||||
('template', str),
|
('template', str),
|
||||||
@ -110,16 +128,10 @@ class AutosummaryRenderer:
|
|||||||
"""A helper class for rendering."""
|
"""A helper class for rendering."""
|
||||||
|
|
||||||
def __init__(self, builder: Builder, template_dir: str) -> None:
|
def __init__(self, builder: Builder, template_dir: str) -> None:
|
||||||
loader = None # type: BaseLoader
|
system_templates_path = [os.path.join(package_dir, 'ext', 'autosummary', 'templates')]
|
||||||
template_dirs = [os.path.join(package_dir, 'ext', 'autosummary', 'templates')]
|
loader = SphinxTemplateLoader(builder.srcdir,
|
||||||
if builder is None:
|
builder.config.templates_path,
|
||||||
if template_dir:
|
system_templates_path)
|
||||||
template_dirs.insert(0, template_dir)
|
|
||||||
loader = FileSystemLoader(template_dirs)
|
|
||||||
else:
|
|
||||||
# allow the user to override the templates
|
|
||||||
loader = BuiltinTemplateLoader()
|
|
||||||
loader.init(builder, dirs=template_dirs)
|
|
||||||
|
|
||||||
self.env = SandboxedEnvironment(loader=loader)
|
self.env = SandboxedEnvironment(loader=loader)
|
||||||
self.env.filters['escape'] = rst.escape
|
self.env.filters['escape'] = rst.escape
|
||||||
@ -514,9 +526,9 @@ def main(argv: List[str] = sys.argv[1:]) -> None:
|
|||||||
logging.setup(app, sys.stdout, sys.stderr) # type: ignore
|
logging.setup(app, sys.stdout, sys.stderr) # type: ignore
|
||||||
setup_documenters(app)
|
setup_documenters(app)
|
||||||
args = get_parser().parse_args(argv)
|
args = get_parser().parse_args(argv)
|
||||||
|
builder = DummyBuilder(app, args.templates)
|
||||||
generate_autosummary_docs(args.source_file, args.output_dir,
|
generate_autosummary_docs(args.source_file, args.output_dir,
|
||||||
'.' + args.suffix,
|
'.' + args.suffix, builder=builder, # type: ignore
|
||||||
template_dir=args.templates,
|
|
||||||
imported_members=args.imported_members,
|
imported_members=args.imported_members,
|
||||||
app=app)
|
app=app)
|
||||||
|
|
||||||
|
@ -10,8 +10,11 @@
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
from functools import partial
|
from functools import partial
|
||||||
from typing import Dict, List, Union
|
from os import path
|
||||||
|
from typing import Callable, Dict, List, Tuple, Union
|
||||||
|
|
||||||
|
from jinja2 import TemplateNotFound
|
||||||
|
from jinja2.environment import Environment
|
||||||
from jinja2.loaders import BaseLoader
|
from jinja2.loaders import BaseLoader
|
||||||
from jinja2.sandbox import SandboxedEnvironment
|
from jinja2.sandbox import SandboxedEnvironment
|
||||||
|
|
||||||
@ -94,3 +97,36 @@ class ReSTRenderer(SphinxRenderer):
|
|||||||
self.env.filters['e'] = rst.escape
|
self.env.filters['e'] = rst.escape
|
||||||
self.env.filters['escape'] = rst.escape
|
self.env.filters['escape'] = rst.escape
|
||||||
self.env.filters['heading'] = rst.heading
|
self.env.filters['heading'] = rst.heading
|
||||||
|
|
||||||
|
|
||||||
|
class SphinxTemplateLoader(BaseLoader):
|
||||||
|
"""A loader supporting template inheritance"""
|
||||||
|
|
||||||
|
def __init__(self, confdir: str, templates_paths: List[str],
|
||||||
|
system_templates_paths: List[str]) -> None:
|
||||||
|
self.loaders = []
|
||||||
|
self.sysloaders = []
|
||||||
|
|
||||||
|
for templates_path in templates_paths:
|
||||||
|
loader = SphinxFileSystemLoader(path.join(confdir, templates_path))
|
||||||
|
self.loaders.append(loader)
|
||||||
|
|
||||||
|
for templates_path in system_templates_paths:
|
||||||
|
loader = SphinxFileSystemLoader(templates_path)
|
||||||
|
self.loaders.append(loader)
|
||||||
|
self.sysloaders.append(loader)
|
||||||
|
|
||||||
|
def get_source(self, environment: Environment, template: str) -> Tuple[str, str, Callable]:
|
||||||
|
if template.startswith('!'):
|
||||||
|
# search a template from ``system_templates_paths``
|
||||||
|
loaders = self.sysloaders
|
||||||
|
template = template[1:]
|
||||||
|
else:
|
||||||
|
loaders = self.loaders
|
||||||
|
|
||||||
|
for loader in loaders:
|
||||||
|
try:
|
||||||
|
return loader.get_source(environment, template)
|
||||||
|
except TemplateNotFound:
|
||||||
|
pass
|
||||||
|
raise TemplateNotFound(template)
|
||||||
|
Loading…
Reference in New Issue
Block a user