- {name: '3.9', python: '3.9', os: ubuntu-latest, tox: py39}
- {name: '3.8', python: '3.8', os: ubuntu-latest, tox: py38}
- {name: '3.7', python: '3.7', os: ubuntu-latest, tox: py37}
- - {name: '3.6', python: '3.6', os: ubuntu-latest, tox: py36}
- {name: 'PyPy', python: 'pypy-3.7', os: ubuntu-latest, tox: pypy37}
- {name: Typing, python: '3.10', os: ubuntu-latest, tox: typing}
steps:
rev: v2.29.0
hooks:
- id: pyupgrade
- args: ["--py36-plus"]
+ args: ["--py37-plus"]
- repo: https://github.com/asottile/reorder_python_imports
rev: v2.6.0
hooks:
{% set comments = get_latest_comments() %}
-My tracebacks look weird. What's happening?
--------------------------------------------
-
-Jinja can rewrite tracebacks so they show the template lines numbers and
-source rather than the underlying compiled code, but this requires
-special Python support. CPython <3.7 requires ``ctypes``, and PyPy
-requires transparent proxy support.
-
-If you are using Google App Engine, ``ctypes`` is not available. You can
-make it available in development, but not in production.
-
-.. code-block:: python
-
- import os
- if os.environ.get('SERVER_SOFTWARE', '').startswith('Dev'):
- from google.appengine.tools.devappserver2.python import sandbox
- sandbox._WHITE_LIST_C_MODULES += ['_ctypes', 'gestalt']
-
-Credit for this snippet goes to `Thomas Johansson
-<https://stackoverflow.com/questions/3086091/debug-jinja2-in-google-app-engine/3694434#3694434>`_
My Macros are overridden by something
-------------------------------------
------------
We recommend using the latest version of Python. Jinja supports Python
-3.6 and newer. We also recommend using a `virtual environment`_ in order
+3.7 and newer. We also recommend using a `virtual environment`_ in order
to isolate your project dependencies from other projects and the system.
.. _virtual environment: https://packaging.python.org/tutorials/installing-packages/#creating-virtual-environments
packages = find:
package_dir = = src
include_package_data = true
-python_requires = >= 3.6
+python_requires = >= 3.7
# Dependencies are in setup.py for GitHub's dependency graph.
[options.packages.find]
[mypy]
files = src/jinja2
-python_version = 3.6
+python_version = 3.7
disallow_subclassing_any = True
disallow_untyped_calls = True
disallow_untyped_defs = True
else:
exported_names = sorted(exported)
- self.writeline("from __future__ import generator_stop") # Python < 3.7
self.writeline("from jinja2.runtime import " + ", ".join(exported_names))
# if we want a deferred initialization we cannot move the
-import platform
import sys
import typing as t
from types import CodeType
# Assign tb_next in reverse to avoid circular references.
for tb in reversed(stack):
- tb_next = tb_set_next(tb, tb_next)
+ tb.tb_next = tb_next
+ tb_next = tb
return exc_value.with_traceback(tb_next)
data[name] = value
return data
-
-
-if sys.version_info >= (3, 7):
- # tb_next is directly assignable as of Python 3.7
- def tb_set_next(
- tb: TracebackType, tb_next: t.Optional[TracebackType]
- ) -> TracebackType:
- tb.tb_next = tb_next
- return tb
-
-
-elif platform.python_implementation() == "PyPy":
- # PyPy might have special support, and won't work with ctypes.
- try:
- import tputil # type: ignore
- except ImportError:
- # Without tproxy support, use the original traceback.
- def tb_set_next(
- tb: TracebackType, tb_next: t.Optional[TracebackType]
- ) -> TracebackType:
- return tb
-
- else:
- # With tproxy support, create a proxy around the traceback that
- # returns the new tb_next.
- def tb_set_next(
- tb: TracebackType, tb_next: t.Optional[TracebackType]
- ) -> TracebackType:
- def controller(op): # type: ignore
- if op.opname == "__getattribute__" and op.args[0] == "tb_next":
- return tb_next
-
- return op.delegate()
-
- return tputil.make_proxy(controller, obj=tb) # type: ignore
-
-
-else:
- # Use ctypes to assign tb_next at the C level since it's read-only
- # from Python.
- import ctypes
-
- class _CTraceback(ctypes.Structure):
- _fields_ = [
- # Extra PyObject slots when compiled with Py_TRACE_REFS.
- ("PyObject_HEAD", ctypes.c_byte * object().__sizeof__()),
- # Only care about tb_next as an object, not a traceback.
- ("tb_next", ctypes.py_object),
- ]
-
- def tb_set_next(
- tb: TracebackType, tb_next: t.Optional[TracebackType]
- ) -> TracebackType:
- c_tb = _CTraceback.from_address(id(tb))
-
- # Clear out the old tb_next.
- if tb.tb_next is not None:
- c_tb_next = ctypes.py_object(tb.tb_next)
- c_tb.tb_next = ctypes.py_object()
- ctypes.pythonapi.Py_DecRef(c_tb_next)
-
- # Assign the new tb_next.
- if tb_next is not None:
- c_tb_next = ctypes.py_object(tb_next)
- ctypes.pythonapi.Py_IncRef(c_tb_next)
- c_tb.tb_next = c_tb_next
-
- return tb
options.
"""
import os
-import sys
import typing
import typing as t
import weakref
close = False
- if sys.version_info < (3, 7):
- loop = asyncio.get_event_loop()
- else:
- try:
- loop = asyncio.get_running_loop()
- except RuntimeError:
- loop = asyncio.new_event_loop()
- close = True
+ try:
+ loop = asyncio.get_running_loop()
+ except RuntimeError:
+ loop = asyncio.new_event_loop()
+ close = True
try:
return loop.run_until_complete(self.render_async(*args, **kwargs))
async def to_list() -> t.List[str]:
return [x async for x in self.generate_async(*args, **kwargs)]
- if sys.version_info < (3, 7):
- loop = asyncio.get_event_loop()
- out = loop.run_until_complete(to_list())
- else:
- out = asyncio.run(to_list())
-
- yield from out
+ yield from asyncio.run(to_list())
return
ctx = self.new_context(dict(*args, **kwargs))
import asyncio
-import sys
import pytest
from jinja2.nativetypes import NativeEnvironment
-if sys.version_info < (3, 7):
-
- def run(coro):
- loop = asyncio.get_event_loop()
- return loop.run_until_complete(coro)
-
-
-else:
-
- def run(coro):
- return asyncio.run(coro)
-
-
def test_basic_async():
t = Template(
"{% for item in [1, 2, 3] %}[{{ item }}]{% endfor %}", enable_async=True
async def func():
return await t.render_async()
- rv = run(func())
+ rv = asyncio.run(func())
assert rv == "[1][2][3]"
async def func():
return await t.render_async(async_func=async_func, normal_func=normal_func)
- rv = run(func())
+ rv = asyncio.run(func())
assert rv == "65"
return 23
rv = t.render(async_func=async_func, normal_func=normal_func)
-
assert rv == "65"
async def func():
return await t.render_async(async_func=async_func)
- rv = run(func())
+ rv = asyncio.run(func())
assert rv == "[42][42]"
async def func():
return await t.render_async()
- rv = run(func())
+ rv = asyncio.run(func())
assert rv == "<Test><Test>"
test_env_async.from_string('{% from "foo" import bar, with with context %}')
def test_exports(self, test_env_async):
- m = run(
- test_env_async.from_string(
- """
+ coro = test_env_async.from_string(
+ """
{% macro toplevel() %}...{% endmacro %}
{% macro __private() %}...{% endmacro %}
{% set variable = 42 %}
{% for item in [1] %}
{% macro notthere() %}{% endmacro %}
{% endfor %}
- """
- )._get_default_module_async()
- )
- assert run(m.toplevel()) == "..."
+ """
+ )._get_default_module_async()
+ m = asyncio.run(coro)
+ assert asyncio.run(m.toplevel()) == "..."
assert not hasattr(m, "__missing")
assert m.variable == 42
assert not hasattr(m, "notthere")
actual = await t.render_async()
assert actual == "Bar"
- run(_test())
+ asyncio.run(_test())
def test_chainable_undefined_aiter():
rv = await t.render_async(a={})
assert rv == ""
- run(_test())
+ asyncio.run(_test())
@pytest.fixture
rv = await t.render_async(x=23)
assert rv == 23
- run(_test())
+ asyncio.run(_test())
def test_native_list_async(async_native_env):
rv = await t.render_async(x=list(range(3)))
assert rv == [0, 1, 2]
- run(_test())
+ asyncio.run(_test())
+++ /dev/null
-import pytest
-
-from jinja2 import Template
-
-
-# Python < 3.7
-def test_generator_stop():
- class X:
- def __getattr__(self, name):
- raise StopIteration()
-
- t = Template("a{{ bad.bar() }}b")
- with pytest.raises(RuntimeError):
- t.render(bad=X())
[tox]
envlist =
- py{311,310,39,38,37,36,py37}
+ py3{11,10,9,8,7},pypy3{8,7}
style
typing
docs