Update upstream source from tag 'upstream/3.0.3'
Update to upstream version '3.0.3'
with Debian dir c5effc9e732ea93b64c585df82836429d457b66a
Piotr Ożarowski
2 years ago
0 | 0 | .. currentmodule:: jinja2 |
1 | ||
2 | Version 3.0.3 | |
3 | ------------- | |
4 | ||
5 | Released 2021-11-09 | |
6 | ||
7 | - Fix traceback rewriting internals for Python 3.10 and 3.11. | |
8 | :issue:`1535` | |
9 | - Fix how the native environment treats leading and trailing spaces | |
10 | when parsing values on Python 3.10. :pr:`1537` | |
11 | - Improve async performance by avoiding checks for common types. | |
12 | :issue:`1514` | |
13 | - Revert change to ``hash(Node)`` behavior. Nodes are hashed by id | |
14 | again :issue:`1521` | |
15 | - ``PackageLoader`` works when the package is a single module file. | |
16 | :issue:`1512` | |
17 | ||
18 | ||
19 | Version 3.0.2 | |
20 | ------------- | |
21 | ||
22 | Released 2021-10-04 | |
23 | ||
24 | - Fix a loop scoping bug that caused assignments in nested loops | |
25 | to still be referenced outside of it. :issue:`1427` | |
26 | - Make ``compile_templates`` deterministic for filter and import | |
27 | names. :issue:`1452, 1453` | |
28 | - Revert an unintended change that caused ``Undefined`` to act like | |
29 | ``StrictUndefined`` for the ``in`` operator. :issue:`1448` | |
30 | - Imported macros have access to the current template globals in async | |
31 | environments. :issue:`1494` | |
32 | - ``PackageLoader`` will not include a current directory (.) path | |
33 | segment. This allows loading templates from the root of a zip | |
34 | import. :issue:`1467` | |
35 | ||
1 | 36 | |
2 | 37 | Version 3.0.1 |
3 | 38 | ------------- |
389 | 424 | possible. For more information and a discussion see :issue:`641` |
390 | 425 | - Resolved an issue where ``block scoped`` would not take advantage of |
391 | 426 | the new scoping rules. In some more exotic cases a variable |
392 | overriden in a local scope would not make it into a block. | |
427 | overridden in a local scope would not make it into a block. | |
393 | 428 | - Change the code generation of the ``with`` statement to be in line |
394 | 429 | with the new scoping rules. This resolves some unlikely bugs in edge |
395 | 430 | cases. This also introduces a new internal ``With`` node that can be |
0 | 0 | Metadata-Version: 2.1 |
1 | 1 | Name: Jinja2 |
2 | Version: 3.0.1 | |
2 | Version: 3.0.3 | |
3 | 3 | Summary: A very fast and expressive template engine. |
4 | 4 | Home-page: https://palletsprojects.com/p/jinja/ |
5 | 5 | Author: Armin Ronacher |
14 | 14 | Project-URL: Issue Tracker, https://github.com/pallets/jinja/issues/ |
15 | 15 | Project-URL: Twitter, https://twitter.com/PalletsTeam |
16 | 16 | Project-URL: Chat, https://discord.gg/pallets |
17 | Description: Jinja | |
18 | ===== | |
19 | ||
20 | Jinja is a fast, expressive, extensible templating engine. Special | |
21 | placeholders in the template allow writing code similar to Python | |
22 | syntax. Then the template is passed data to render the final document. | |
23 | ||
24 | It includes: | |
25 | ||
26 | - Template inheritance and inclusion. | |
27 | - Define and import macros within templates. | |
28 | - HTML templates can use autoescaping to prevent XSS from untrusted | |
29 | user input. | |
30 | - A sandboxed environment can safely render untrusted templates. | |
31 | - AsyncIO support for generating templates and calling async | |
32 | functions. | |
33 | - I18N support with Babel. | |
34 | - Templates are compiled to optimized Python code just-in-time and | |
35 | cached, or can be compiled ahead-of-time. | |
36 | - Exceptions point to the correct line in templates to make debugging | |
37 | easier. | |
38 | - Extensible filters, tests, functions, and even syntax. | |
39 | ||
40 | Jinja's philosophy is that while application logic belongs in Python if | |
41 | possible, it shouldn't make the template designer's job difficult by | |
42 | restricting functionality too much. | |
43 | ||
44 | ||
45 | Installing | |
46 | ---------- | |
47 | ||
48 | Install and update using `pip`_: | |
49 | ||
50 | .. code-block:: text | |
51 | ||
52 | $ pip install -U Jinja2 | |
53 | ||
54 | .. _pip: https://pip.pypa.io/en/stable/quickstart/ | |
55 | ||
56 | ||
57 | In A Nutshell | |
58 | ------------- | |
59 | ||
60 | .. code-block:: jinja | |
61 | ||
62 | {% extends "base.html" %} | |
63 | {% block title %}Members{% endblock %} | |
64 | {% block content %} | |
65 | <ul> | |
66 | {% for user in users %} | |
67 | <li><a href="{{ user.url }}">{{ user.username }}</a></li> | |
68 | {% endfor %} | |
69 | </ul> | |
70 | {% endblock %} | |
71 | ||
72 | ||
73 | Donate | |
74 | ------ | |
75 | ||
76 | The Pallets organization develops and supports Jinja and other popular | |
77 | packages. In order to grow the community of contributors and users, and | |
78 | allow the maintainers to devote more time to the projects, `please | |
79 | donate today`_. | |
80 | ||
81 | .. _please donate today: https://palletsprojects.com/donate | |
82 | ||
83 | ||
84 | Links | |
85 | ----- | |
86 | ||
87 | - Documentation: https://jinja.palletsprojects.com/ | |
88 | - Changes: https://jinja.palletsprojects.com/changes/ | |
89 | - PyPI Releases: https://pypi.org/project/Jinja2/ | |
90 | - Source Code: https://github.com/pallets/jinja/ | |
91 | - Issue Tracker: https://github.com/pallets/jinja/issues/ | |
92 | - Website: https://palletsprojects.com/p/jinja/ | |
93 | - Twitter: https://twitter.com/PalletsTeam | |
94 | - Chat: https://discord.gg/pallets | |
95 | ||
96 | 17 | Platform: UNKNOWN |
97 | 18 | Classifier: Development Status :: 5 - Production/Stable |
98 | 19 | Classifier: Environment :: Web Environment |
105 | 26 | Requires-Python: >=3.6 |
106 | 27 | Description-Content-Type: text/x-rst |
107 | 28 | Provides-Extra: i18n |
29 | License-File: LICENSE.rst | |
30 | ||
31 | Jinja | |
32 | ===== | |
33 | ||
34 | Jinja is a fast, expressive, extensible templating engine. Special | |
35 | placeholders in the template allow writing code similar to Python | |
36 | syntax. Then the template is passed data to render the final document. | |
37 | ||
38 | It includes: | |
39 | ||
40 | - Template inheritance and inclusion. | |
41 | - Define and import macros within templates. | |
42 | - HTML templates can use autoescaping to prevent XSS from untrusted | |
43 | user input. | |
44 | - A sandboxed environment can safely render untrusted templates. | |
45 | - AsyncIO support for generating templates and calling async | |
46 | functions. | |
47 | - I18N support with Babel. | |
48 | - Templates are compiled to optimized Python code just-in-time and | |
49 | cached, or can be compiled ahead-of-time. | |
50 | - Exceptions point to the correct line in templates to make debugging | |
51 | easier. | |
52 | - Extensible filters, tests, functions, and even syntax. | |
53 | ||
54 | Jinja's philosophy is that while application logic belongs in Python if | |
55 | possible, it shouldn't make the template designer's job difficult by | |
56 | restricting functionality too much. | |
57 | ||
58 | ||
59 | Installing | |
60 | ---------- | |
61 | ||
62 | Install and update using `pip`_: | |
63 | ||
64 | .. code-block:: text | |
65 | ||
66 | $ pip install -U Jinja2 | |
67 | ||
68 | .. _pip: https://pip.pypa.io/en/stable/getting-started/ | |
69 | ||
70 | ||
71 | In A Nutshell | |
72 | ------------- | |
73 | ||
74 | .. code-block:: jinja | |
75 | ||
76 | {% extends "base.html" %} | |
77 | {% block title %}Members{% endblock %} | |
78 | {% block content %} | |
79 | <ul> | |
80 | {% for user in users %} | |
81 | <li><a href="{{ user.url }}">{{ user.username }}</a></li> | |
82 | {% endfor %} | |
83 | </ul> | |
84 | {% endblock %} | |
85 | ||
86 | ||
87 | Donate | |
88 | ------ | |
89 | ||
90 | The Pallets organization develops and supports Jinja and other popular | |
91 | packages. In order to grow the community of contributors and users, and | |
92 | allow the maintainers to devote more time to the projects, `please | |
93 | donate today`_. | |
94 | ||
95 | .. _please donate today: https://palletsprojects.com/donate | |
96 | ||
97 | ||
98 | Links | |
99 | ----- | |
100 | ||
101 | - Documentation: https://jinja.palletsprojects.com/ | |
102 | - Changes: https://jinja.palletsprojects.com/changes/ | |
103 | - PyPI Releases: https://pypi.org/project/Jinja2/ | |
104 | - Source Code: https://github.com/pallets/jinja/ | |
105 | - Issue Tracker: https://github.com/pallets/jinja/issues/ | |
106 | - Website: https://palletsprojects.com/p/jinja/ | |
107 | - Twitter: https://twitter.com/PalletsTeam | |
108 | - Chat: https://discord.gg/pallets | |
109 | ||
110 |
34 | 34 | |
35 | 35 | $ pip install -U Jinja2 |
36 | 36 | |
37 | .. _pip: https://pip.pypa.io/en/stable/quickstart/ | |
37 | .. _pip: https://pip.pypa.io/en/stable/getting-started/ | |
38 | 38 | |
39 | 39 | |
40 | 40 | In A Nutshell |
37 | 37 | ] |
38 | 38 | } |
39 | 39 | html_sidebars = { |
40 | "index": ["project.html", "localtoc.html", "searchbox.html"], | |
41 | "**": ["localtoc.html", "relations.html", "searchbox.html"], | |
40 | "index": ["project.html", "localtoc.html", "searchbox.html", "ethicalads.html"], | |
41 | "**": ["localtoc.html", "relations.html", "searchbox.html", "ethicalads.html"], | |
42 | 42 | } |
43 | singlehtml_sidebars = {"index": ["project.html", "localtoc.html"]} | |
43 | singlehtml_sidebars = {"index": ["project.html", "localtoc.html", "ethicalads.html"]} | |
44 | 44 | html_static_path = ["_static"] |
45 | 45 | html_favicon = "_static/jinja-logo-sidebar.png" |
46 | 46 | html_logo = "_static/jinja-logo-sidebar.png" |
122 | 122 | :ref:`the template documentation <i18n-in-templates>`. |
123 | 123 | |
124 | 124 | .. _gettext: https://docs.python.org/3/library/gettext.html |
125 | .. _Babel: http://babel.pocoo.org/ | |
125 | .. _Babel: https://babel.pocoo.org/ | |
126 | 126 | |
127 | 127 | |
128 | 128 | Whitespace Trimming |
59 | 59 | |
60 | 60 | - `Babel`_ provides translation support in templates. |
61 | 61 | |
62 | .. _Babel: http://babel.pocoo.org/ | |
62 | .. _Babel: https://babel.pocoo.org/ |
20 | 20 | echo.may add the Sphinx directory to PATH. |
21 | 21 | echo. |
22 | 22 | echo.If you don't have Sphinx installed, grab it from |
23 | echo.http://sphinx-doc.org/ | |
23 | echo.https://www.sphinx-doc.org/ | |
24 | 24 | exit /b 1 |
25 | 25 | ) |
26 | 26 |
586 | 586 | Template Objects |
587 | 587 | ~~~~~~~~~~~~~~~~ |
588 | 588 | |
589 | .. versionchanged:: 2.4 | |
590 | ||
591 | If a template object was passed in the template context, you can | |
592 | extend from that object as well. Assuming the calling code passes | |
593 | a layout template as `layout_template` to the environment, this | |
594 | code works:: | |
595 | ||
596 | {% extends layout_template %} | |
597 | ||
598 | Previously, the `layout_template` variable had to be a string with | |
599 | the layout template's filename for this to work. | |
589 | ``extends``, ``include``, and ``import`` can take a template object | |
590 | instead of the name of a template to load. This could be useful in some | |
591 | advanced situations, since you can use Python code to load a template | |
592 | first and pass it in to ``render``. | |
593 | ||
594 | .. code-block:: python | |
595 | ||
596 | if debug_mode: | |
597 | layout = env.get_template("debug_layout.html") | |
598 | else: | |
599 | layout = env.get_template("layout.html") | |
600 | ||
601 | user_detail = env.get_template("user/detail.html", layout=layout) | |
602 | ||
603 | .. code-block:: jinja | |
604 | ||
605 | {% extends layout %} | |
606 | ||
607 | Note how ``extends`` is passed the variable with the template object | |
608 | that was passed to ``render``, instead of a string. | |
600 | 609 | |
601 | 610 | |
602 | 611 | HTML Escaping |
913 | 922 | `arguments` |
914 | 923 | A tuple of the names of arguments the macro accepts. |
915 | 924 | |
916 | `defaults` | |
917 | A tuple of default values. | |
918 | ||
919 | 925 | `catch_kwargs` |
920 | 926 | This is `true` if the macro accepts extra keyword arguments (i.e.: accesses |
921 | 927 | the special `kwargs` variable). |
1337 | 1343 | ``{{ '=' * 80 }}`` would print a bar of 80 equal signs. |
1338 | 1344 | |
1339 | 1345 | ``**`` |
1340 | Raise the left operand to the power of the right operand. ``{{ 2**3 }}`` | |
1341 | would return ``8``. | |
1346 | Raise the left operand to the power of the right operand. | |
1347 | ``{{ 2**3 }}`` would return ``8``. | |
1348 | ||
1349 | Unlike Python, chained pow is evaluated left to right. | |
1350 | ``{{ 3**3**3 }}`` is evaluated as ``(3**3)**3`` in Jinja, but would | |
1351 | be evaluated as ``3**(3**3)`` in Python. Use parentheses in Jinja | |
1352 | to be explicit about what order you want. It is usually preferable | |
1353 | to do extended math in Python and pass the results to ``render`` | |
1354 | rather than doing it in the template. | |
1355 | ||
1356 | This behavior may be changed in the future to match Python, if it's | |
1357 | possible to introduce an upgrade path. | |
1358 | ||
1342 | 1359 | |
1343 | 1360 | Comparisons |
1344 | 1361 | ~~~~~~~~~~~ |
0 | 0 | # |
1 | # This file is autogenerated by pip-compile | |
1 | # This file is autogenerated by pip-compile with python 3.10 | |
2 | 2 | # To update, run: |
3 | 3 | # |
4 | 4 | # pip-compile requirements/dev.in |
5 | 5 | # |
6 | 6 | alabaster==0.7.12 |
7 | 7 | # via sphinx |
8 | appdirs==1.4.4 | |
9 | # via virtualenv | |
10 | 8 | attrs==21.2.0 |
11 | 9 | # via pytest |
12 | 10 | babel==2.9.1 |
13 | 11 | # via sphinx |
14 | certifi==2020.12.5 | |
12 | backports.entry-points-selectable==1.1.0 | |
13 | # via virtualenv | |
14 | certifi==2021.10.8 | |
15 | 15 | # via requests |
16 | cfgv==3.2.0 | |
16 | cfgv==3.3.1 | |
17 | 17 | # via pre-commit |
18 | chardet==4.0.0 | |
18 | charset-normalizer==2.0.7 | |
19 | 19 | # via requests |
20 | click==8.0.0 | |
20 | click==8.0.3 | |
21 | 21 | # via pip-tools |
22 | distlib==0.3.1 | |
22 | distlib==0.3.3 | |
23 | 23 | # via virtualenv |
24 | 24 | docutils==0.17.1 |
25 | 25 | # via sphinx |
26 | filelock==3.0.12 | |
26 | filelock==3.3.2 | |
27 | 27 | # via |
28 | 28 | # tox |
29 | 29 | # virtualenv |
30 | identify==2.2.4 | |
30 | identify==2.3.3 | |
31 | 31 | # via pre-commit |
32 | idna==2.10 | |
32 | idna==3.3 | |
33 | 33 | # via requests |
34 | 34 | imagesize==1.2.0 |
35 | 35 | # via sphinx |
36 | 36 | iniconfig==1.1.1 |
37 | 37 | # via pytest |
38 | jinja2==3.0.0 | |
38 | jinja2==3.0.2 | |
39 | 39 | # via sphinx |
40 | markupsafe==2.0.0 | |
40 | markupsafe==2.0.1 | |
41 | 41 | # via jinja2 |
42 | mypy==0.910 | |
43 | # via -r requirements/typing.in | |
42 | 44 | mypy-extensions==0.4.3 |
43 | 45 | # via mypy |
44 | mypy==0.812 | |
45 | # via -r requirements/typing.in | |
46 | 46 | nodeenv==1.6.0 |
47 | 47 | # via pre-commit |
48 | packaging==20.9 | |
48 | packaging==21.2 | |
49 | 49 | # via |
50 | 50 | # pallets-sphinx-themes |
51 | 51 | # pytest |
52 | 52 | # sphinx |
53 | 53 | # tox |
54 | pallets-sphinx-themes==2.0.0 | |
54 | pallets-sphinx-themes==2.0.1 | |
55 | 55 | # via -r requirements/docs.in |
56 | pep517==0.10.0 | |
56 | pep517==0.12.0 | |
57 | 57 | # via pip-tools |
58 | pip-tools==6.1.0 | |
58 | pip-tools==6.4.0 | |
59 | 59 | # via -r requirements/dev.in |
60 | pluggy==0.13.1 | |
60 | platformdirs==2.4.0 | |
61 | # via virtualenv | |
62 | pluggy==1.0.0 | |
61 | 63 | # via |
62 | 64 | # pytest |
63 | 65 | # tox |
64 | pre-commit==2.12.1 | |
66 | pre-commit==2.15.0 | |
65 | 67 | # via -r requirements/dev.in |
66 | py==1.10.0 | |
68 | py==1.11.0 | |
67 | 69 | # via |
68 | 70 | # pytest |
69 | 71 | # tox |
70 | pygments==2.9.0 | |
72 | pygments==2.10.0 | |
71 | 73 | # via sphinx |
72 | 74 | pyparsing==2.4.7 |
73 | 75 | # via packaging |
74 | pytest==6.2.4 | |
76 | pytest==6.2.5 | |
75 | 77 | # via -r requirements/tests.in |
76 | pytz==2021.1 | |
78 | pytz==2021.3 | |
77 | 79 | # via babel |
78 | pyyaml==5.4.1 | |
80 | pyyaml==6.0 | |
79 | 81 | # via pre-commit |
80 | requests==2.25.1 | |
82 | requests==2.26.0 | |
81 | 83 | # via sphinx |
82 | 84 | six==1.16.0 |
83 | 85 | # via |
85 | 87 | # virtualenv |
86 | 88 | snowballstemmer==2.1.0 |
87 | 89 | # via sphinx |
88 | sphinx-issues==1.2.0 | |
89 | # via -r requirements/docs.in | |
90 | git+https://github.com/sphinx-doc/sphinx.git@96dbe5e3 | |
90 | sphinx==4.2.0 | |
91 | 91 | # via |
92 | 92 | # -r requirements/docs.in |
93 | 93 | # pallets-sphinx-themes |
94 | 94 | # sphinx-issues |
95 | 95 | # sphinxcontrib-log-cabinet |
96 | sphinx-issues==1.2.0 | |
97 | # via -r requirements/docs.in | |
96 | 98 | sphinxcontrib-applehelp==1.0.2 |
97 | 99 | # via sphinx |
98 | 100 | sphinxcontrib-devhelp==1.0.2 |
99 | 101 | # via sphinx |
100 | sphinxcontrib-htmlhelp==1.0.3 | |
102 | sphinxcontrib-htmlhelp==2.0.0 | |
101 | 103 | # via sphinx |
102 | 104 | sphinxcontrib-jsmath==1.0.1 |
103 | 105 | # via sphinx |
105 | 107 | # via -r requirements/docs.in |
106 | 108 | sphinxcontrib-qthelp==1.0.3 |
107 | 109 | # via sphinx |
108 | sphinxcontrib-serializinghtml==1.1.4 | |
110 | sphinxcontrib-serializinghtml==1.1.5 | |
109 | 111 | # via sphinx |
110 | 112 | toml==0.10.2 |
111 | 113 | # via |
112 | # pep517 | |
114 | # mypy | |
113 | 115 | # pre-commit |
114 | 116 | # pytest |
115 | 117 | # tox |
116 | tox==3.23.1 | |
118 | tomli==1.2.2 | |
119 | # via pep517 | |
120 | tox==3.24.4 | |
117 | 121 | # via -r requirements/dev.in |
118 | typed-ast==1.4.3 | |
122 | typing-extensions==3.10.0.2 | |
119 | 123 | # via mypy |
120 | typing-extensions==3.10.0.0 | |
121 | # via mypy | |
122 | urllib3==1.26.4 | |
124 | urllib3==1.26.7 | |
123 | 125 | # via requests |
124 | virtualenv==20.4.6 | |
126 | virtualenv==20.10.0 | |
125 | 127 | # via |
126 | 128 | # pre-commit |
127 | 129 | # tox |
130 | wheel==0.37.0 | |
131 | # via pip-tools | |
128 | 132 | |
129 | 133 | # The following packages are considered to be unsafe in a requirements file: |
130 | 134 | # pip |
0 | 0 | # |
1 | # This file is autogenerated by pip-compile | |
1 | # This file is autogenerated by pip-compile with python 3.10 | |
2 | 2 | # To update, run: |
3 | 3 | # |
4 | 4 | # pip-compile requirements/docs.in |
7 | 7 | # via sphinx |
8 | 8 | babel==2.9.1 |
9 | 9 | # via sphinx |
10 | certifi==2020.12.5 | |
10 | certifi==2021.10.8 | |
11 | 11 | # via requests |
12 | chardet==4.0.0 | |
12 | charset-normalizer==2.0.7 | |
13 | 13 | # via requests |
14 | 14 | docutils==0.17.1 |
15 | 15 | # via sphinx |
16 | idna==2.10 | |
16 | idna==3.3 | |
17 | 17 | # via requests |
18 | 18 | imagesize==1.2.0 |
19 | 19 | # via sphinx |
20 | jinja2==3.0.0 | |
20 | jinja2==3.0.2 | |
21 | 21 | # via sphinx |
22 | markupsafe==2.0.0 | |
22 | markupsafe==2.0.1 | |
23 | 23 | # via jinja2 |
24 | packaging==20.9 | |
24 | packaging==21.2 | |
25 | 25 | # via |
26 | 26 | # pallets-sphinx-themes |
27 | 27 | # sphinx |
28 | pallets-sphinx-themes==2.0.0 | |
28 | pallets-sphinx-themes==2.0.1 | |
29 | 29 | # via -r requirements/docs.in |
30 | pygments==2.9.0 | |
30 | pygments==2.10.0 | |
31 | 31 | # via sphinx |
32 | 32 | pyparsing==2.4.7 |
33 | 33 | # via packaging |
34 | pytz==2021.1 | |
34 | pytz==2021.3 | |
35 | 35 | # via babel |
36 | requests==2.25.1 | |
36 | requests==2.26.0 | |
37 | 37 | # via sphinx |
38 | 38 | snowballstemmer==2.1.0 |
39 | 39 | # via sphinx |
40 | sphinx-issues==1.2.0 | |
41 | # via -r requirements/docs.in | |
42 | git+https://github.com/sphinx-doc/sphinx.git@96dbe5e3 | |
40 | sphinx==4.2.0 | |
43 | 41 | # via |
44 | 42 | # -r requirements/docs.in |
45 | 43 | # pallets-sphinx-themes |
46 | 44 | # sphinx-issues |
47 | 45 | # sphinxcontrib-log-cabinet |
46 | sphinx-issues==1.2.0 | |
47 | # via -r requirements/docs.in | |
48 | 48 | sphinxcontrib-applehelp==1.0.2 |
49 | 49 | # via sphinx |
50 | 50 | sphinxcontrib-devhelp==1.0.2 |
51 | 51 | # via sphinx |
52 | sphinxcontrib-htmlhelp==1.0.3 | |
52 | sphinxcontrib-htmlhelp==2.0.0 | |
53 | 53 | # via sphinx |
54 | 54 | sphinxcontrib-jsmath==1.0.1 |
55 | 55 | # via sphinx |
57 | 57 | # via -r requirements/docs.in |
58 | 58 | sphinxcontrib-qthelp==1.0.3 |
59 | 59 | # via sphinx |
60 | sphinxcontrib-serializinghtml==1.1.4 | |
60 | sphinxcontrib-serializinghtml==1.1.5 | |
61 | 61 | # via sphinx |
62 | urllib3==1.26.4 | |
62 | urllib3==1.26.7 | |
63 | 63 | # via requests |
64 | 64 | |
65 | 65 | # The following packages are considered to be unsafe in a requirements file: |
0 | 0 | # |
1 | # This file is autogenerated by pip-compile | |
1 | # This file is autogenerated by pip-compile with python 3.10 | |
2 | 2 | # To update, run: |
3 | 3 | # |
4 | 4 | # pip-compile requirements/tests.in |
7 | 7 | # via pytest |
8 | 8 | iniconfig==1.1.1 |
9 | 9 | # via pytest |
10 | packaging==20.9 | |
10 | packaging==21.2 | |
11 | 11 | # via pytest |
12 | pluggy==0.13.1 | |
12 | pluggy==1.0.0 | |
13 | 13 | # via pytest |
14 | py==1.10.0 | |
14 | py==1.11.0 | |
15 | 15 | # via pytest |
16 | 16 | pyparsing==2.4.7 |
17 | 17 | # via packaging |
18 | pytest==6.2.4 | |
18 | pytest==6.2.5 | |
19 | 19 | # via -r requirements/tests.in |
20 | 20 | toml==0.10.2 |
21 | 21 | # via pytest |
0 | 0 | # |
1 | # This file is autogenerated by pip-compile | |
1 | # This file is autogenerated by pip-compile with python 3.10 | |
2 | 2 | # To update, run: |
3 | 3 | # |
4 | 4 | # pip-compile requirements/typing.in |
5 | 5 | # |
6 | mypy==0.910 | |
7 | # via -r requirements/typing.in | |
6 | 8 | mypy-extensions==0.4.3 |
7 | 9 | # via mypy |
8 | mypy==0.812 | |
9 | # via -r requirements/typing.in | |
10 | typed-ast==1.4.3 | |
10 | toml==0.10.2 | |
11 | 11 | # via mypy |
12 | typing-extensions==3.10.0.0 | |
12 | typing-extensions==3.10.0.2 | |
13 | 13 | # via mypy |
45 | 45 | testpaths = tests |
46 | 46 | filterwarnings = |
47 | 47 | error |
48 | ignore:The loop argument:DeprecationWarning:asyncio[.]base_events:542 | |
48 | 49 | |
49 | 50 | [coverage:run] |
50 | 51 | branch = True |
0 | 0 | Metadata-Version: 2.1 |
1 | 1 | Name: Jinja2 |
2 | Version: 3.0.1 | |
2 | Version: 3.0.3 | |
3 | 3 | Summary: A very fast and expressive template engine. |
4 | 4 | Home-page: https://palletsprojects.com/p/jinja/ |
5 | 5 | Author: Armin Ronacher |
14 | 14 | Project-URL: Issue Tracker, https://github.com/pallets/jinja/issues/ |
15 | 15 | Project-URL: Twitter, https://twitter.com/PalletsTeam |
16 | 16 | Project-URL: Chat, https://discord.gg/pallets |
17 | Description: Jinja | |
18 | ===== | |
19 | ||
20 | Jinja is a fast, expressive, extensible templating engine. Special | |
21 | placeholders in the template allow writing code similar to Python | |
22 | syntax. Then the template is passed data to render the final document. | |
23 | ||
24 | It includes: | |
25 | ||
26 | - Template inheritance and inclusion. | |
27 | - Define and import macros within templates. | |
28 | - HTML templates can use autoescaping to prevent XSS from untrusted | |
29 | user input. | |
30 | - A sandboxed environment can safely render untrusted templates. | |
31 | - AsyncIO support for generating templates and calling async | |
32 | functions. | |
33 | - I18N support with Babel. | |
34 | - Templates are compiled to optimized Python code just-in-time and | |
35 | cached, or can be compiled ahead-of-time. | |
36 | - Exceptions point to the correct line in templates to make debugging | |
37 | easier. | |
38 | - Extensible filters, tests, functions, and even syntax. | |
39 | ||
40 | Jinja's philosophy is that while application logic belongs in Python if | |
41 | possible, it shouldn't make the template designer's job difficult by | |
42 | restricting functionality too much. | |
43 | ||
44 | ||
45 | Installing | |
46 | ---------- | |
47 | ||
48 | Install and update using `pip`_: | |
49 | ||
50 | .. code-block:: text | |
51 | ||
52 | $ pip install -U Jinja2 | |
53 | ||
54 | .. _pip: https://pip.pypa.io/en/stable/quickstart/ | |
55 | ||
56 | ||
57 | In A Nutshell | |
58 | ------------- | |
59 | ||
60 | .. code-block:: jinja | |
61 | ||
62 | {% extends "base.html" %} | |
63 | {% block title %}Members{% endblock %} | |
64 | {% block content %} | |
65 | <ul> | |
66 | {% for user in users %} | |
67 | <li><a href="{{ user.url }}">{{ user.username }}</a></li> | |
68 | {% endfor %} | |
69 | </ul> | |
70 | {% endblock %} | |
71 | ||
72 | ||
73 | Donate | |
74 | ------ | |
75 | ||
76 | The Pallets organization develops and supports Jinja and other popular | |
77 | packages. In order to grow the community of contributors and users, and | |
78 | allow the maintainers to devote more time to the projects, `please | |
79 | donate today`_. | |
80 | ||
81 | .. _please donate today: https://palletsprojects.com/donate | |
82 | ||
83 | ||
84 | Links | |
85 | ----- | |
86 | ||
87 | - Documentation: https://jinja.palletsprojects.com/ | |
88 | - Changes: https://jinja.palletsprojects.com/changes/ | |
89 | - PyPI Releases: https://pypi.org/project/Jinja2/ | |
90 | - Source Code: https://github.com/pallets/jinja/ | |
91 | - Issue Tracker: https://github.com/pallets/jinja/issues/ | |
92 | - Website: https://palletsprojects.com/p/jinja/ | |
93 | - Twitter: https://twitter.com/PalletsTeam | |
94 | - Chat: https://discord.gg/pallets | |
95 | ||
96 | 17 | Platform: UNKNOWN |
97 | 18 | Classifier: Development Status :: 5 - Production/Stable |
98 | 19 | Classifier: Environment :: Web Environment |
105 | 26 | Requires-Python: >=3.6 |
106 | 27 | Description-Content-Type: text/x-rst |
107 | 28 | Provides-Extra: i18n |
29 | License-File: LICENSE.rst | |
30 | ||
31 | Jinja | |
32 | ===== | |
33 | ||
34 | Jinja is a fast, expressive, extensible templating engine. Special | |
35 | placeholders in the template allow writing code similar to Python | |
36 | syntax. Then the template is passed data to render the final document. | |
37 | ||
38 | It includes: | |
39 | ||
40 | - Template inheritance and inclusion. | |
41 | - Define and import macros within templates. | |
42 | - HTML templates can use autoescaping to prevent XSS from untrusted | |
43 | user input. | |
44 | - A sandboxed environment can safely render untrusted templates. | |
45 | - AsyncIO support for generating templates and calling async | |
46 | functions. | |
47 | - I18N support with Babel. | |
48 | - Templates are compiled to optimized Python code just-in-time and | |
49 | cached, or can be compiled ahead-of-time. | |
50 | - Exceptions point to the correct line in templates to make debugging | |
51 | easier. | |
52 | - Extensible filters, tests, functions, and even syntax. | |
53 | ||
54 | Jinja's philosophy is that while application logic belongs in Python if | |
55 | possible, it shouldn't make the template designer's job difficult by | |
56 | restricting functionality too much. | |
57 | ||
58 | ||
59 | Installing | |
60 | ---------- | |
61 | ||
62 | Install and update using `pip`_: | |
63 | ||
64 | .. code-block:: text | |
65 | ||
66 | $ pip install -U Jinja2 | |
67 | ||
68 | .. _pip: https://pip.pypa.io/en/stable/getting-started/ | |
69 | ||
70 | ||
71 | In A Nutshell | |
72 | ------------- | |
73 | ||
74 | .. code-block:: jinja | |
75 | ||
76 | {% extends "base.html" %} | |
77 | {% block title %}Members{% endblock %} | |
78 | {% block content %} | |
79 | <ul> | |
80 | {% for user in users %} | |
81 | <li><a href="{{ user.url }}">{{ user.username }}</a></li> | |
82 | {% endfor %} | |
83 | </ul> | |
84 | {% endblock %} | |
85 | ||
86 | ||
87 | Donate | |
88 | ------ | |
89 | ||
90 | The Pallets organization develops and supports Jinja and other popular | |
91 | packages. In order to grow the community of contributors and users, and | |
92 | allow the maintainers to devote more time to the projects, `please | |
93 | donate today`_. | |
94 | ||
95 | .. _please donate today: https://palletsprojects.com/donate | |
96 | ||
97 | ||
98 | Links | |
99 | ----- | |
100 | ||
101 | - Documentation: https://jinja.palletsprojects.com/ | |
102 | - Changes: https://jinja.palletsprojects.com/changes/ | |
103 | - PyPI Releases: https://pypi.org/project/Jinja2/ | |
104 | - Source Code: https://github.com/pallets/jinja/ | |
105 | - Issue Tracker: https://github.com/pallets/jinja/issues/ | |
106 | - Website: https://palletsprojects.com/p/jinja/ | |
107 | - Twitter: https://twitter.com/PalletsTeam | |
108 | - Chat: https://discord.gg/pallets | |
109 | ||
110 |
75 | 75 | tests/test_async.py |
76 | 76 | tests/test_async_filters.py |
77 | 77 | tests/test_bytecode_cache.py |
78 | tests/test_compile.py | |
78 | 79 | tests/test_core_tags.py |
79 | 80 | tests/test_debug.py |
80 | 81 | tests/test_ext.py |
86 | 87 | tests/test_lexnparse.py |
87 | 88 | tests/test_loader.py |
88 | 89 | tests/test_nativetypes.py |
90 | tests/test_nodes.py | |
89 | 91 | tests/test_regression.py |
90 | 92 | tests/test_runtime.py |
91 | 93 | tests/test_security.py |
41 | 41 | from .utils import pass_eval_context as pass_eval_context |
42 | 42 | from .utils import select_autoescape as select_autoescape |
43 | 43 | |
44 | __version__ = "3.0.1" | |
44 | __version__ = "3.0.3" |
43 | 43 | return decorator |
44 | 44 | |
45 | 45 | |
46 | _common_primitives = {int, float, bool, str, list, dict, tuple, type(None)} | |
47 | ||
48 | ||
46 | 49 | async def auto_await(value: t.Union[t.Awaitable["V"], "V"]) -> "V": |
50 | # Avoid a costly call to isawaitable | |
51 | if type(value) in _common_primitives: | |
52 | return t.cast("V", value) | |
53 | ||
47 | 54 | if inspect.isawaitable(value): |
48 | 55 | return await t.cast("t.Awaitable[V]", value) |
49 | 56 |
153 | 153 | hash = sha1(name.encode("utf-8")) |
154 | 154 | |
155 | 155 | if filename is not None: |
156 | hash.update(f"|{filename}".encode("utf-8")) | |
156 | hash.update(f"|{filename}".encode()) | |
157 | 157 | |
158 | 158 | return hash.hexdigest() |
159 | 159 |
555 | 555 | visitor.tests, |
556 | 556 | "tests", |
557 | 557 | ): |
558 | for name in names: | |
558 | for name in sorted(names): | |
559 | 559 | if name not in id_map: |
560 | 560 | id_map[name] = self.temporary_identifier() |
561 | 561 | |
1089 | 1089 | self.write( |
1090 | 1090 | f"{f_name}(context.get_all(), True, {self.dump_local_context(frame)})" |
1091 | 1091 | ) |
1092 | elif self.environment.is_async: | |
1093 | self.write("_get_default_module_async()") | |
1094 | else: | |
1095 | self.write("_get_default_module(context)") | |
1092 | else: | |
1093 | self.write(f"_get_default_module{self.choose_async('_async')}(context)") | |
1096 | 1094 | |
1097 | 1095 | def visit_Import(self, node: nodes.Import, frame: Frame) -> None: |
1098 | 1096 | """Visit regular imports.""" |
1289 | 1287 | self.write(", loop)") |
1290 | 1288 | self.end_write(frame) |
1291 | 1289 | |
1290 | # at the end of the iteration, clear any assignments made in the | |
1291 | # loop from the top level | |
1292 | if self._assign_stack: | |
1293 | self._assign_stack[-1].difference_update(loop_frame.symbols.stores) | |
1294 | ||
1292 | 1295 | def visit_If(self, node: nodes.If, frame: Frame) -> None: |
1293 | 1296 | if_frame = frame.soft() |
1294 | 1297 | self.writeline("if ", node) |
101 | 101 | "__jinja_exception__": exc_value, |
102 | 102 | } |
103 | 103 | # Raise an exception at the correct line number. |
104 | code = compile("\n" * (lineno - 1) + "raise __jinja_exception__", filename, "exec") | |
104 | code: CodeType = compile( | |
105 | "\n" * (lineno - 1) + "raise __jinja_exception__", filename, "exec" | |
106 | ) | |
105 | 107 | |
106 | 108 | # Build a new code object that points to the template file and |
107 | 109 | # replaces the location with a block name. |
108 | try: | |
109 | location = "template" | |
110 | ||
111 | if tb is not None: | |
112 | function = tb.tb_frame.f_code.co_name | |
113 | ||
114 | if function == "root": | |
115 | location = "top-level template code" | |
116 | elif function.startswith("block_"): | |
117 | location = f"block {function[6:]!r}" | |
118 | ||
119 | # Collect arguments for the new code object. CodeType only | |
120 | # accepts positional arguments, and arguments were inserted in | |
121 | # new Python versions. | |
122 | code_args = [] | |
123 | ||
124 | for attr in ( | |
125 | "argcount", | |
126 | "posonlyargcount", # Python 3.8 | |
127 | "kwonlyargcount", | |
128 | "nlocals", | |
129 | "stacksize", | |
130 | "flags", | |
131 | "code", # codestring | |
132 | "consts", # constants | |
133 | "names", | |
134 | "varnames", | |
135 | ("filename", filename), | |
136 | ("name", location), | |
137 | "firstlineno", | |
138 | "lnotab", | |
139 | "freevars", | |
140 | "cellvars", | |
141 | "linetable", # Python 3.10 | |
142 | ): | |
143 | if isinstance(attr, tuple): | |
144 | # Replace with given value. | |
145 | code_args.append(attr[1]) | |
146 | continue | |
147 | ||
148 | try: | |
149 | # Copy original value if it exists. | |
150 | code_args.append(getattr(code, "co_" + t.cast(str, attr))) | |
151 | except AttributeError: | |
152 | # Some arguments were added later. | |
153 | continue | |
154 | ||
155 | code = CodeType(*code_args) | |
156 | except Exception: | |
157 | # Some environments such as Google App Engine don't support | |
158 | # modifying code objects. | |
159 | pass | |
110 | location = "template" | |
111 | ||
112 | if tb is not None: | |
113 | function = tb.tb_frame.f_code.co_name | |
114 | ||
115 | if function == "root": | |
116 | location = "top-level template code" | |
117 | elif function.startswith("block_"): | |
118 | location = f"block {function[6:]!r}" | |
119 | ||
120 | if sys.version_info >= (3, 8): | |
121 | code = code.replace(co_name=location) | |
122 | else: | |
123 | code = CodeType( | |
124 | code.co_argcount, | |
125 | code.co_kwonlyargcount, | |
126 | code.co_nlocals, | |
127 | code.co_stacksize, | |
128 | code.co_flags, | |
129 | code.co_code, | |
130 | code.co_consts, | |
131 | code.co_names, | |
132 | code.co_varnames, | |
133 | code.co_filename, | |
134 | location, | |
135 | code.co_firstlineno, | |
136 | code.co_lnotab, | |
137 | code.co_freevars, | |
138 | code.co_cellvars, | |
139 | ) | |
160 | 140 | |
161 | 141 | # Execute the new code, which is guaranteed to raise, and return |
162 | 142 | # the new traceback without this frame. |
1114 | 1114 | |
1115 | 1115 | |
1116 | 1116 | class Template: |
1117 | """The central template object. This class represents a compiled template | |
1118 | and is used to evaluate it. | |
1119 | ||
1120 | Normally the template object is generated from an :class:`Environment` but | |
1121 | it also has a constructor that makes it possible to create a template | |
1122 | instance directly using the constructor. It takes the same arguments as | |
1123 | the environment constructor but it's not possible to specify a loader. | |
1124 | ||
1125 | Every template object has a few methods and members that are guaranteed | |
1126 | to exist. However it's important that a template object should be | |
1127 | considered immutable. Modifications on the object are not supported. | |
1128 | ||
1129 | Template objects created from the constructor rather than an environment | |
1130 | do have an `environment` attribute that points to a temporary environment | |
1131 | that is probably shared with other templates created with the constructor | |
1132 | and compatible settings. | |
1133 | ||
1134 | >>> template = Template('Hello {{ name }}!') | |
1135 | >>> template.render(name='John Doe') == u'Hello John Doe!' | |
1136 | True | |
1137 | >>> stream = template.stream(name='John Doe') | |
1138 | >>> next(stream) == u'Hello John Doe!' | |
1139 | True | |
1140 | >>> next(stream) | |
1141 | Traceback (most recent call last): | |
1142 | ... | |
1143 | StopIteration | |
1117 | """A compiled template that can be rendered. | |
1118 | ||
1119 | Use the methods on :class:`Environment` to create or load templates. | |
1120 | The environment is used to configure how templates are compiled and | |
1121 | behave. | |
1122 | ||
1123 | It is also possible to create a template object directly. This is | |
1124 | not usually recommended. The constructor takes most of the same | |
1125 | arguments as :class:`Environment`. All templates created with the | |
1126 | same environment arguments share the same ephemeral ``Environment`` | |
1127 | instance behind the scenes. | |
1128 | ||
1129 | A template object should be considered immutable. Modifications on | |
1130 | the object are not supported. | |
1144 | 1131 | """ |
1145 | 1132 | |
1146 | 1133 | #: Type of environment to create when creating a template directly |
1349 | 1349 | rv = list(value) |
1350 | 1350 | rv.reverse() |
1351 | 1351 | return rv |
1352 | except TypeError: | |
1353 | raise FilterArgumentError("argument must be iterable") | |
1352 | except TypeError as e: | |
1353 | raise FilterArgumentError("argument must be iterable") from e | |
1354 | 1354 | |
1355 | 1355 | |
1356 | 1356 | @pass_environment |
1690 | 1690 | name = args[0] |
1691 | 1691 | args = args[1:] |
1692 | 1692 | except LookupError: |
1693 | raise FilterArgumentError("map requires a filter argument") | |
1693 | raise FilterArgumentError("map requires a filter argument") from None | |
1694 | 1694 | |
1695 | 1695 | def func(item: t.Any) -> t.Any: |
1696 | 1696 | return context.environment.call_filter( |
1711 | 1711 | try: |
1712 | 1712 | attr = args[0] |
1713 | 1713 | except LookupError: |
1714 | raise FilterArgumentError("Missing parameter for attribute name") | |
1714 | raise FilterArgumentError("Missing parameter for attribute name") from None | |
1715 | 1715 | |
1716 | 1716 | transfunc = make_attrgetter(context.environment, attr) |
1717 | 1717 | off = 1 |
148 | 148 | node: t.Optional["Symbols"] = self |
149 | 149 | |
150 | 150 | while node is not None: |
151 | for name in node.stores: | |
151 | for name in sorted(node.stores): | |
152 | 152 | if name not in rv: |
153 | 153 | rv[name] = self.find_ref(name) # type: ignore |
154 | 154 |
654 | 654 | ) |
655 | 655 | except Exception as e: |
656 | 656 | msg = str(e).split(":")[-1].strip() |
657 | raise TemplateSyntaxError(msg, lineno, name, filename) | |
657 | raise TemplateSyntaxError(msg, lineno, name, filename) from e | |
658 | 658 | elif token == TOKEN_INTEGER: |
659 | 659 | value = int(value_str.replace("_", ""), 0) |
660 | 660 | elif token == TOKEN_FLOAT: |
269 | 269 | package_path: "str" = "templates", |
270 | 270 | encoding: str = "utf-8", |
271 | 271 | ) -> None: |
272 | package_path = os.path.normpath(package_path).rstrip(os.path.sep) | |
273 | ||
274 | # normpath preserves ".", which isn't valid in zip paths. | |
272 | 275 | if package_path == os.path.curdir: |
273 | 276 | package_path = "" |
274 | 277 | elif package_path[:2] == os.path.curdir + os.path.sep: |
275 | 278 | package_path = package_path[2:] |
276 | 279 | |
277 | package_path = os.path.normpath(package_path).rstrip(os.path.sep) | |
278 | 280 | self.package_path = package_path |
279 | 281 | self.package_name = package_name |
280 | 282 | self.encoding = encoding |
294 | 296 | self._archive = loader.archive |
295 | 297 | pkgdir = next(iter(spec.submodule_search_locations)) # type: ignore |
296 | 298 | template_root = os.path.join(pkgdir, package_path) |
297 | elif spec.submodule_search_locations: | |
298 | # This will be one element for regular packages and multiple | |
299 | # for namespace packages. | |
300 | for root in spec.submodule_search_locations: | |
299 | else: | |
300 | roots: t.List[str] = [] | |
301 | ||
302 | # One element for regular packages, multiple for namespace | |
303 | # packages, or None for single module file. | |
304 | if spec.submodule_search_locations: | |
305 | roots.extend(spec.submodule_search_locations) | |
306 | # A single module file, use the parent directory instead. | |
307 | elif spec.origin is not None: | |
308 | roots.append(os.path.dirname(spec.origin)) | |
309 | ||
310 | for root in roots: | |
301 | 311 | root = os.path.join(root, package_path) |
302 | 312 | |
303 | 313 | if os.path.isdir(root): |
335 | 345 | # Package is a zip file. |
336 | 346 | try: |
337 | 347 | source = self._loader.get_data(p) # type: ignore |
338 | except OSError: | |
339 | raise TemplateNotFound(template) | |
348 | except OSError as e: | |
349 | raise TemplateNotFound(template) from e | |
340 | 350 | |
341 | 351 | # Could use the zip's mtime for all template mtimes, but |
342 | 352 | # would need to safely reload the module if it's out of |
475 | 485 | try: |
476 | 486 | prefix, name = template.split(self.delimiter, 1) |
477 | 487 | loader = self.mapping[prefix] |
478 | except (ValueError, KeyError): | |
479 | raise TemplateNotFound(template) | |
488 | except (ValueError, KeyError) as e: | |
489 | raise TemplateNotFound(template) from e | |
480 | 490 | return loader, name |
481 | 491 | |
482 | 492 | def get_source( |
485 | 495 | loader, name = self.get_loader(template) |
486 | 496 | try: |
487 | 497 | return loader.get_source(environment, name) |
488 | except TemplateNotFound: | |
498 | except TemplateNotFound as e: | |
489 | 499 | # re-raise the exception with the correct filename here. |
490 | 500 | # (the one that includes the prefix) |
491 | raise TemplateNotFound(template) | |
501 | raise TemplateNotFound(template) from e | |
492 | 502 | |
493 | 503 | @internalcode |
494 | 504 | def load( |
500 | 510 | loader, local_name = self.get_loader(name) |
501 | 511 | try: |
502 | 512 | return loader.load(environment, local_name, globals) |
503 | except TemplateNotFound: | |
513 | except TemplateNotFound as e: | |
504 | 514 | # re-raise the exception with the correct filename here. |
505 | 515 | # (the one that includes the prefix) |
506 | raise TemplateNotFound(name) | |
516 | raise TemplateNotFound(name) from e | |
507 | 517 | |
508 | 518 | def list_templates(self) -> t.List[str]: |
509 | 519 | result = [] |
626 | 636 | if mod is None: |
627 | 637 | try: |
628 | 638 | mod = __import__(module, None, None, ["root"]) |
629 | except ImportError: | |
630 | raise TemplateNotFound(name) | |
639 | except ImportError as e: | |
640 | raise TemplateNotFound(name) from e | |
631 | 641 | |
632 | 642 | # remove the entry from sys.modules, we only want the attribute |
633 | 643 | # on the module object we have stored on the loader. |
0 | 0 | import typing as t |
1 | 1 | from ast import literal_eval |
2 | from ast import parse | |
2 | 3 | from itertools import chain |
3 | 4 | from itertools import islice |
4 | 5 | |
32 | 33 | raw = "".join([str(v) for v in chain(head, values)]) |
33 | 34 | |
34 | 35 | try: |
35 | return literal_eval(raw) | |
36 | return literal_eval( | |
37 | # In Python 3.10+ ast.literal_eval removes leading spaces/tabs | |
38 | # from the given string. For backwards compatibility we need to | |
39 | # parse the string ourselves without removing leading spaces/tabs. | |
40 | parse(raw, mode="eval") | |
41 | ) | |
36 | 42 | except (ValueError, SyntaxError, MemoryError): |
37 | 43 | return raw |
38 | 44 |
240 | 240 | |
241 | 241 | return tuple(self.iter_fields()) == tuple(other.iter_fields()) |
242 | 242 | |
243 | def __hash__(self) -> int: | |
244 | return hash(tuple(self.iter_fields())) | |
243 | __hash__ = object.__hash__ | |
245 | 244 | |
246 | 245 | def __repr__(self) -> str: |
247 | 246 | args_str = ", ".join(f"{a}={getattr(self, a, None)!r}" for a in self.fields) |
506 | 505 | f = _binop_to_func[self.operator] |
507 | 506 | try: |
508 | 507 | return f(self.left.as_const(eval_ctx), self.right.as_const(eval_ctx)) |
509 | except Exception: | |
510 | raise Impossible() | |
508 | except Exception as e: | |
509 | raise Impossible() from e | |
511 | 510 | |
512 | 511 | |
513 | 512 | class UnaryExpr(Expr): |
530 | 529 | f = _uaop_to_func[self.operator] |
531 | 530 | try: |
532 | 531 | return f(self.node.as_const(eval_ctx)) |
533 | except Exception: | |
534 | raise Impossible() | |
532 | except Exception as e: | |
533 | raise Impossible() from e | |
535 | 534 | |
536 | 535 | |
537 | 536 | class Name(Expr): |
722 | 721 | if node.dyn_args is not None: |
723 | 722 | try: |
724 | 723 | args.extend(node.dyn_args.as_const(eval_ctx)) |
725 | except Exception: | |
726 | raise Impossible() | |
724 | except Exception as e: | |
725 | raise Impossible() from e | |
727 | 726 | |
728 | 727 | if node.dyn_kwargs is not None: |
729 | 728 | try: |
730 | 729 | kwargs.update(node.dyn_kwargs.as_const(eval_ctx)) |
731 | except Exception: | |
732 | raise Impossible() | |
730 | except Exception as e: | |
731 | raise Impossible() from e | |
733 | 732 | |
734 | 733 | return args, kwargs |
735 | 734 | |
778 | 777 | |
779 | 778 | try: |
780 | 779 | return func(*args, **kwargs) |
781 | except Exception: | |
782 | raise Impossible() | |
780 | except Exception as e: | |
781 | raise Impossible() from e | |
783 | 782 | |
784 | 783 | |
785 | 784 | class Filter(_FilterTestCommon): |
846 | 845 | return eval_ctx.environment.getitem( |
847 | 846 | self.node.as_const(eval_ctx), self.arg.as_const(eval_ctx) |
848 | 847 | ) |
849 | except Exception: | |
850 | raise Impossible() | |
848 | except Exception as e: | |
849 | raise Impossible() from e | |
851 | 850 | |
852 | 851 | |
853 | 852 | class Getattr(Expr): |
868 | 867 | |
869 | 868 | try: |
870 | 869 | return eval_ctx.environment.getattr(self.node.as_const(eval_ctx), self.attr) |
871 | except Exception: | |
872 | raise Impossible() | |
870 | except Exception as e: | |
871 | raise Impossible() from e | |
873 | 872 | |
874 | 873 | |
875 | 874 | class Slice(Expr): |
928 | 927 | return False |
929 | 928 | |
930 | 929 | value = new_value |
931 | except Exception: | |
932 | raise Impossible() | |
930 | except Exception as e: | |
931 | raise Impossible() from e | |
933 | 932 | |
934 | 933 | return result |
935 | 934 | |
955 | 954 | |
956 | 955 | |
957 | 956 | class FloorDiv(BinExpr): |
958 | """Divides the left by the right node and truncates conver the | |
957 | """Divides the left by the right node and converts the | |
959 | 958 | result into an integer by truncating. |
960 | 959 | """ |
961 | 960 |
914 | 914 | __floordiv__ = __rfloordiv__ = _fail_with_undefined_error |
915 | 915 | __mod__ = __rmod__ = _fail_with_undefined_error |
916 | 916 | __pos__ = __neg__ = _fail_with_undefined_error |
917 | __call__ = __getitem__ = __contains__ = _fail_with_undefined_error | |
917 | __call__ = __getitem__ = _fail_with_undefined_error | |
918 | 918 | __lt__ = __le__ = __gt__ = __ge__ = _fail_with_undefined_error |
919 | 919 | __int__ = __float__ = __complex__ = _fail_with_undefined_error |
920 | 920 | __pow__ = __rpow__ = _fail_with_undefined_error |
1090 | 1090 | __slots__ = () |
1091 | 1091 | __iter__ = __str__ = __len__ = Undefined._fail_with_undefined_error |
1092 | 1092 | __eq__ = __ne__ = __bool__ = __hash__ = Undefined._fail_with_undefined_error |
1093 | __contains__ = Undefined._fail_with_undefined_error | |
1093 | 1094 | |
1094 | 1095 | |
1095 | 1096 | # Remove slots attributes, after the metaclass is applied they are |
823 | 823 | try: |
824 | 824 | return self.__attrs[name] |
825 | 825 | except KeyError: |
826 | raise AttributeError(name) | |
826 | raise AttributeError(name) from None | |
827 | 827 | |
828 | 828 | def __setitem__(self, name: str, value: t.Any) -> None: |
829 | 829 | self.__attrs[name] = value |
315 | 315 | assert env.from_string("{{ foo.missing }}").render(foo=42) == "" |
316 | 316 | assert env.from_string("{{ not missing }}").render() == "True" |
317 | 317 | pytest.raises(UndefinedError, env.from_string("{{ missing - 1}}").render) |
318 | pytest.raises(UndefinedError, env.from_string("{{ 'foo' in missing }}").render) | |
318 | assert env.from_string("{{ 'foo' in missing }}").render() == "False" | |
319 | 319 | und1 = Undefined(name="x") |
320 | 320 | und2 = Undefined(name="y") |
321 | 321 | assert und1 == und2 |
374 | 374 | pytest.raises(UndefinedError, env.from_string("{{ missing }}").render) |
375 | 375 | pytest.raises(UndefinedError, env.from_string("{{ missing.attribute }}").render) |
376 | 376 | pytest.raises(UndefinedError, env.from_string("{{ missing|list }}").render) |
377 | pytest.raises(UndefinedError, env.from_string("{{ 'foo' in missing }}").render) | |
377 | 378 | assert env.from_string("{{ missing is not defined }}").render() == "True" |
378 | 379 | pytest.raises( |
379 | 380 | UndefinedError, env.from_string("{{ foo.missing }}").render, foo=42 |
188 | 188 | assert m.variable == 42 |
189 | 189 | assert not hasattr(m, "notthere") |
190 | 190 | |
191 | def test_import_with_globals(self, test_env_async): | |
192 | t = test_env_async.from_string( | |
193 | '{% import "module" as m %}{{ m.test() }}', globals={"foo": 42} | |
194 | ) | |
195 | assert t.render() == "[42|23]" | |
196 | ||
197 | t = test_env_async.from_string('{% import "module" as m %}{{ m.test() }}') | |
198 | assert t.render() == "[|23]" | |
199 | ||
200 | def test_import_with_globals_override(self, test_env_async): | |
201 | t = test_env_async.from_string( | |
202 | '{% set foo = 41 %}{% import "module" as m %}{{ m.test() }}', | |
203 | globals={"foo": 42}, | |
204 | ) | |
205 | assert t.render() == "[42|23]" | |
206 | ||
207 | def test_from_import_with_globals(self, test_env_async): | |
208 | t = test_env_async.from_string( | |
209 | '{% from "module" import test %}{{ test() }}', | |
210 | globals={"foo": 42}, | |
211 | ) | |
212 | assert t.render() == "[42|23]" | |
213 | ||
191 | 214 | |
192 | 215 | class TestAsyncIncludes: |
193 | 216 | def test_context_include(self, test_env_async): |
0 | import os | |
1 | import re | |
2 | ||
3 | from jinja2.environment import Environment | |
4 | from jinja2.loaders import DictLoader | |
5 | ||
6 | ||
7 | def test_filters_deterministic(tmp_path): | |
8 | src = "".join(f"{{{{ {i}|filter{i} }}}}" for i in range(10)) | |
9 | env = Environment(loader=DictLoader({"foo": src})) | |
10 | env.filters.update(dict.fromkeys((f"filter{i}" for i in range(10)), lambda: None)) | |
11 | env.compile_templates(tmp_path, zip=None) | |
12 | name = os.listdir(tmp_path)[0] | |
13 | content = (tmp_path / name).read_text("utf8") | |
14 | expect = [f"filters['filter{i}']" for i in range(10)] | |
15 | found = re.findall(r"filters\['filter\d']", content) | |
16 | assert found == expect | |
17 | ||
18 | ||
19 | def test_import_as_with_context_deterministic(tmp_path): | |
20 | src = "\n".join(f'{{% import "bar" as bar{i} with context %}}' for i in range(10)) | |
21 | env = Environment(loader=DictLoader({"foo": src})) | |
22 | env.compile_templates(tmp_path, zip=None) | |
23 | name = os.listdir(tmp_path)[0] | |
24 | content = (tmp_path / name).read_text("utf8") | |
25 | expect = [f"'bar{i}': " for i in range(10)] | |
26 | found = re.findall(r"'bar\d': ", content)[:10] | |
27 | assert found == expect |
35 | 35 | test, |
36 | 36 | r""" |
37 | 37 | File ".*?broken.html", line 2, in (top-level template code|<module>) |
38 | \{\{ fail\(\) \}\} | |
38 | \{\{ fail\(\) \}\}( | |
39 | \^{12})? | |
39 | 40 | File ".*debug?.pyc?", line \d+, in <lambda> |
40 | tmpl\.render\(fail=lambda: 1 / 0\) | |
41 | tmpl\.render\(fail=lambda: 1 / 0\)( | |
42 | ~~\^~~)? | |
41 | 43 | ZeroDivisionError: (int(eger)? )?division (or modulo )?by zero |
42 | 44 | """, |
43 | 45 | ) |
65 | 67 | test, |
66 | 68 | r""" |
67 | 69 | File ".*debug.pyc?", line \d+, in test |
68 | raise TemplateSyntaxError\("wtf", 42\) | |
70 | raise TemplateSyntaxError\("wtf", 42\)( | |
71 | \^{36})? | |
69 | 72 | (jinja2\.exceptions\.)?TemplateSyntaxError: wtf |
70 | 73 | line 42""", |
71 | 74 | ) |
98 | 98 | t.render() |
99 | 99 | |
100 | 100 | def test_import_with_globals(self, test_env): |
101 | env = Environment( | |
102 | loader=DictLoader( | |
103 | { | |
104 | "macros": "{% macro test() %}foo: {{ foo }}{% endmacro %}", | |
105 | "test": "{% import 'macros' as m %}{{ m.test() }}", | |
106 | "test1": "{% import 'macros' as m %}{{ m.test() }}", | |
107 | } | |
108 | ) | |
109 | ) | |
110 | tmpl = env.get_template("test", globals={"foo": "bar"}) | |
111 | assert tmpl.render() == "foo: bar" | |
112 | ||
113 | tmpl = env.get_template("test1") | |
114 | assert tmpl.render() == "foo: " | |
101 | t = test_env.from_string( | |
102 | '{% import "module" as m %}{{ m.test() }}', globals={"foo": 42} | |
103 | ) | |
104 | assert t.render() == "[42|23]" | |
105 | ||
106 | t = test_env.from_string('{% import "module" as m %}{{ m.test() }}') | |
107 | assert t.render() == "[|23]" | |
115 | 108 | |
116 | 109 | def test_import_with_globals_override(self, test_env): |
117 | env = Environment( | |
118 | loader=DictLoader( | |
119 | { | |
120 | "macros": "{% set foo = '42' %}{% macro test() %}" | |
121 | "foo: {{ foo }}{% endmacro %}", | |
122 | "test": "{% from 'macros' import test %}{{ test() }}", | |
123 | } | |
124 | ) | |
125 | ) | |
126 | tmpl = env.get_template("test", globals={"foo": "bar"}) | |
127 | assert tmpl.render() == "foo: 42" | |
110 | t = test_env.from_string( | |
111 | '{% set foo = 41 %}{% import "module" as m %}{{ m.test() }}', | |
112 | globals={"foo": 42}, | |
113 | ) | |
114 | assert t.render() == "[42|23]" | |
128 | 115 | |
129 | 116 | def test_from_import_with_globals(self, test_env): |
130 | env = Environment( | |
131 | loader=DictLoader( | |
132 | { | |
133 | "macros": "{% macro testing() %}foo: {{ foo }}{% endmacro %}", | |
134 | "test": "{% from 'macros' import testing %}{{ testing() }}", | |
135 | } | |
136 | ) | |
137 | ) | |
138 | tmpl = env.get_template("test", globals={"foo": "bar"}) | |
139 | assert tmpl.render() == "foo: bar" | |
117 | t = test_env.from_string( | |
118 | '{% from "module" import test %}{{ test() }}', | |
119 | globals={"foo": 42}, | |
120 | ) | |
121 | assert t.render() == "[42|23]" | |
140 | 122 | |
141 | 123 | |
142 | 124 | class TestIncludes: |
36 | 36 | {% block block1 %} |
37 | 37 | {% if false %} |
38 | 38 | {% block block2 %} |
39 | this should workd | |
39 | this should work | |
40 | 40 | {% endblock %} |
41 | 41 | {% endif %} |
42 | 42 | {% endblock %} |
48 | 48 | {% block block1 %} |
49 | 49 | {% if false %} |
50 | 50 | {% block block2 %} |
51 | this should workd | |
51 | this should work | |
52 | 52 | {% endblock %} |
53 | 53 | {% endif %} |
54 | 54 | {% endblock %} |
313 | 313 | |
314 | 314 | |
315 | 315 | @pytest.fixture() |
316 | def package_file_loader(monkeypatch): | |
317 | monkeypatch.syspath_prepend(Path(__file__).parent / "res") | |
318 | return PackageLoader("__init__") | |
319 | ||
320 | ||
321 | @pytest.mark.parametrize( | |
322 | ("template", "expect"), [("foo/test.html", "FOO"), ("test.html", "BAR")] | |
323 | ) | |
324 | def test_package_file_source(package_file_loader, template, expect): | |
325 | source, name, up_to_date = package_file_loader.get_source(None, template) | |
326 | assert source.rstrip() == expect | |
327 | assert name.endswith(os.path.join(*split_template_path(template))) | |
328 | assert up_to_date() | |
329 | ||
330 | ||
331 | def test_package_file_list(package_file_loader): | |
332 | templates = package_file_loader.list_templates() | |
333 | assert "foo/test.html" in templates | |
334 | assert "test.html" in templates | |
335 | ||
336 | ||
337 | @pytest.fixture() | |
316 | 338 | def package_zip_loader(monkeypatch): |
317 | 339 | package_zip = (Path(__file__) / ".." / "res" / "package.zip").resolve() |
318 | 340 | monkeypatch.syspath_prepend(package_zip) |
338 | 360 | assert package_zip_loader.list_templates() == ["foo/test.html", "test.html"] |
339 | 361 | |
340 | 362 | |
363 | @pytest.mark.parametrize("package_path", ["", ".", "./"]) | |
364 | def test_package_zip_omit_curdir(package_zip_loader, package_path): | |
365 | """PackageLoader should not add or include "." or "./" in the root | |
366 | path, it is invalid in zip paths. | |
367 | """ | |
368 | loader = PackageLoader("t_pack", package_path) | |
369 | assert loader.package_path == "" | |
370 | source, _, _ = loader.get_source(None, "templates/foo/test.html") | |
371 | assert source.rstrip() == "FOO" | |
372 | ||
373 | ||
341 | 374 | def test_pep_451_import_hook(): |
342 | 375 | class ImportHook(importlib.abc.MetaPathFinder, importlib.abc.Loader): |
343 | 376 | def find_spec(self, name, path=None, target=None): |
146 | 146 | def test_spontaneous_env(): |
147 | 147 | t = NativeTemplate("{{ true }}") |
148 | 148 | assert isinstance(t.environment, NativeEnvironment) |
149 | ||
150 | ||
151 | def test_leading_spaces(env): | |
152 | t = env.from_string(" {{ True }}") | |
153 | result = t.render() | |
154 | assert result == " True" |
745 | 745 | tmpl = env.get_template("base") |
746 | 746 | assert tmpl.render() == "42 y" |
747 | 747 | |
748 | def test_nested_loop_scoping(self, env): | |
749 | tmpl = env.from_string( | |
750 | "{% set output %}{% for x in [1,2,3] %}hello{% endfor %}" | |
751 | "{% endset %}{{ output }}" | |
752 | ) | |
753 | assert tmpl.render() == "hellohellohello" | |
754 | ||
748 | 755 | |
749 | 756 | @pytest.mark.parametrize("unicode_char", ["\N{FORM FEED}", "\x85"]) |
750 | 757 | def test_unicode_whitespace(env, unicode_char): |