Merge pull request #9251 from tk0miya/9216_support_jinja2-3

Close #9216: Support jinja2-3.0
This commit is contained in:
Takeshi KOMIYA 2021-05-19 23:13:17 +09:00 committed by GitHub
commit c015f97f16
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 29 additions and 17 deletions

View File

@ -4,6 +4,8 @@ Release 4.0.2 (in development)
Dependencies Dependencies
------------ ------------
* #9216: Support jinja2-3.0
Incompatible changes Incompatible changes
-------------------- --------------------

View File

@ -21,8 +21,7 @@ install_requires = [
'sphinxcontrib-htmlhelp', 'sphinxcontrib-htmlhelp',
'sphinxcontrib-serializinghtml', 'sphinxcontrib-serializinghtml',
'sphinxcontrib-qthelp', 'sphinxcontrib-qthelp',
'Jinja2>=2.3,<3.0', 'Jinja2>=2.3',
'MarkupSafe<2.0',
'Pygments>=2.0', 'Pygments>=2.0',
'docutils>=0.14,<0.18', 'docutils>=0.14,<0.18',
'snowballstemmer>=1.1', 'snowballstemmer>=1.1',

View File

@ -12,7 +12,7 @@ from os import path
from pprint import pformat from pprint import pformat
from typing import TYPE_CHECKING, Any, Callable, Dict, Iterator, List, Tuple, Union from typing import TYPE_CHECKING, Any, Callable, Dict, Iterator, List, Tuple, Union
from jinja2 import BaseLoader, FileSystemLoader, TemplateNotFound, contextfunction from jinja2 import BaseLoader, FileSystemLoader, TemplateNotFound
from jinja2.environment import Environment from jinja2.environment import Environment
from jinja2.sandbox import SandboxedEnvironment from jinja2.sandbox import SandboxedEnvironment
from jinja2.utils import open_if_exists from jinja2.utils import open_if_exists
@ -22,6 +22,11 @@ from sphinx.theming import Theme
from sphinx.util import logging from sphinx.util import logging
from sphinx.util.osutil import mtimes_of_files from sphinx.util.osutil import mtimes_of_files
try:
from jinja2.utils import pass_context
except ImportError:
from jinja2 import contextfunction as pass_context
if TYPE_CHECKING: if TYPE_CHECKING:
from sphinx.builders import Builder from sphinx.builders import Builder
@ -101,7 +106,7 @@ class idgen:
next = __next__ # Python 2/Jinja compatibility next = __next__ # Python 2/Jinja compatibility
@contextfunction @pass_context
def warning(context: Dict, message: str, *args: Any, **kwargs: Any) -> str: def warning(context: Dict, message: str, *args: Any, **kwargs: Any) -> str:
if 'pagename' in context: if 'pagename' in context:
filename = context.get('pagename') + context.get('file_suffix', '') filename = context.get('pagename') + context.get('file_suffix', '')
@ -180,9 +185,9 @@ class BuiltinTemplateLoader(TemplateBridge, BaseLoader):
self.environment.filters['toint'] = _toint self.environment.filters['toint'] = _toint
self.environment.filters['todim'] = _todim self.environment.filters['todim'] = _todim
self.environment.filters['slice_index'] = _slice_index self.environment.filters['slice_index'] = _slice_index
self.environment.globals['debug'] = contextfunction(pformat) self.environment.globals['debug'] = pass_context(pformat)
self.environment.globals['warning'] = warning self.environment.globals['warning'] = warning
self.environment.globals['accesskey'] = contextfunction(accesskey) self.environment.globals['accesskey'] = pass_context(accesskey)
self.environment.globals['idgen'] = idgen self.environment.globals['idgen'] = idgen
if use_i18n: if use_i18n:
self.environment.install_gettext_translations(builder.app.translator) self.environment.install_gettext_translations(builder.app.translator)

View File

@ -235,7 +235,7 @@ def save_traceback(app: "Sphinx") -> str:
platform.python_version(), platform.python_version(),
platform.python_implementation(), platform.python_implementation(),
docutils.__version__, docutils.__version_details__, docutils.__version__, docutils.__version_details__,
jinja2.__version__, # type: ignore jinja2.__version__,
last_msgs)).encode()) last_msgs)).encode())
if app is not None: if app is not None:
for ext in app.extensions.values(): for ext in app.extensions.values():

View File

@ -18,11 +18,17 @@ from docutils.parsers.rst import roles
from docutils.parsers.rst.languages import en as english from docutils.parsers.rst.languages import en as english
from docutils.statemachine import StringList from docutils.statemachine import StringList
from docutils.utils import Reporter from docutils.utils import Reporter
from jinja2 import Environment, environmentfilter from jinja2 import Environment
from sphinx.locale import __ from sphinx.locale import __
from sphinx.util import docutils, logging from sphinx.util import docutils, logging
try:
from jinja2.utils import pass_environment
except ImportError:
from jinja2 import environmentfilter as pass_environment
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
docinfo_re = re.compile(':\\w+:.*?') docinfo_re = re.compile(':\\w+:.*?')
@ -51,11 +57,11 @@ def textwidth(text: str, widechars: str = 'WF') -> int:
return sum(charwidth(c, widechars) for c in text) return sum(charwidth(c, widechars) for c in text)
@environmentfilter @pass_environment
def heading(env: Environment, text: str, level: int = 1) -> str: def heading(env: Environment, text: str, level: int = 1) -> str:
"""Create a heading for *level*.""" """Create a heading for *level*."""
assert level <= 3 assert level <= 3
width = textwidth(text, WIDECHARS[env.language]) # type: ignore width = textwidth(text, WIDECHARS[env.language])
sectioning_char = SECTIONING_CHARS[level - 1] sectioning_char = SECTIONING_CHARS[level - 1]
return '%s\n%s' % (text, sectioning_char * width) return '%s\n%s' % (text, sectioning_char * width)

View File

@ -69,18 +69,18 @@ class Tags:
def eval_node(node: Node) -> bool: def eval_node(node: Node) -> bool:
if isinstance(node, nodes.CondExpr): if isinstance(node, nodes.CondExpr):
if eval_node(node.test): # type: ignore if eval_node(node.test):
return eval_node(node.expr1) # type: ignore return eval_node(node.expr1)
else: else:
return eval_node(node.expr2) # type: ignore return eval_node(node.expr2)
elif isinstance(node, nodes.And): elif isinstance(node, nodes.And):
return eval_node(node.left) and eval_node(node.right) # type: ignore return eval_node(node.left) and eval_node(node.right)
elif isinstance(node, nodes.Or): elif isinstance(node, nodes.Or):
return eval_node(node.left) or eval_node(node.right) # type: ignore return eval_node(node.left) or eval_node(node.right)
elif isinstance(node, nodes.Not): elif isinstance(node, nodes.Not):
return not eval_node(node.node) # type: ignore return not eval_node(node.node)
elif isinstance(node, nodes.Name): elif isinstance(node, nodes.Name):
return self.tags.get(node.name, False) # type: ignore return self.tags.get(node.name, False)
else: else:
raise ValueError('invalid node, check parsing') raise ValueError('invalid node, check parsing')