jinja

Форк
0
/
test_async.py 
722 строки · 23.3 Кб
1
import pytest
2

3
from jinja2 import ChainableUndefined
4
from jinja2 import DictLoader
5
from jinja2 import Environment
6
from jinja2 import Template
7
from jinja2.async_utils import auto_aiter
8
from jinja2.exceptions import TemplateNotFound
9
from jinja2.exceptions import TemplatesNotFound
10
from jinja2.exceptions import UndefinedError
11
from jinja2.nativetypes import NativeEnvironment
12

13

14
def test_basic_async(run_async_fn):
15
    t = Template(
16
        "{% for item in [1, 2, 3] %}[{{ item }}]{% endfor %}", enable_async=True
17
    )
18

19
    async def func():
20
        return await t.render_async()
21

22
    rv = run_async_fn(func)
23
    assert rv == "[1][2][3]"
24

25

26
def test_await_on_calls(run_async_fn):
27
    t = Template("{{ async_func() + normal_func() }}", enable_async=True)
28

29
    async def async_func():
30
        return 42
31

32
    def normal_func():
33
        return 23
34

35
    async def func():
36
        return await t.render_async(async_func=async_func, normal_func=normal_func)
37

38
    rv = run_async_fn(func)
39
    assert rv == "65"
40

41

42
def test_await_on_calls_normal_render():
43
    t = Template("{{ async_func() + normal_func() }}", enable_async=True)
44

45
    async def async_func():
46
        return 42
47

48
    def normal_func():
49
        return 23
50

51
    rv = t.render(async_func=async_func, normal_func=normal_func)
52
    assert rv == "65"
53

54

55
def test_await_and_macros(run_async_fn):
56
    t = Template(
57
        "{% macro foo(x) %}[{{ x }}][{{ async_func() }}]{% endmacro %}{{ foo(42) }}",
58
        enable_async=True,
59
    )
60

61
    async def async_func():
62
        return 42
63

64
    async def func():
65
        return await t.render_async(async_func=async_func)
66

67
    rv = run_async_fn(func)
68
    assert rv == "[42][42]"
69

70

71
def test_async_blocks(run_async_fn):
72
    t = Template(
73
        "{% block foo %}<Test>{% endblock %}{{ self.foo() }}",
74
        enable_async=True,
75
        autoescape=True,
76
    )
77

78
    async def func():
79
        return await t.render_async()
80

81
    rv = run_async_fn(func)
82
    assert rv == "<Test><Test>"
83

84

85
def test_async_generate():
86
    t = Template("{% for x in [1, 2, 3] %}{{ x }}{% endfor %}", enable_async=True)
87
    rv = list(t.generate())
88
    assert rv == ["1", "2", "3"]
89

90

91
def test_async_iteration_in_templates():
92
    t = Template("{% for x in rng %}{{ x }}{% endfor %}", enable_async=True)
93

94
    async def async_iterator():
95
        for item in [1, 2, 3]:
96
            yield item
97

98
    rv = list(t.generate(rng=async_iterator()))
99
    assert rv == ["1", "2", "3"]
100

101

102
def test_async_iteration_in_templates_extended():
103
    t = Template(
104
        "{% for x in rng %}{{ loop.index0 }}/{{ x }}{% endfor %}", enable_async=True
105
    )
106
    stream = t.generate(rng=auto_aiter(range(1, 4)))
107
    assert next(stream) == "0"
108
    assert "".join(stream) == "/11/22/3"
109

110

111
@pytest.fixture
112
def test_env_async():
113
    env = Environment(
114
        loader=DictLoader(
115
            dict(
116
                module="{% macro test() %}[{{ foo }}|{{ bar }}]{% endmacro %}",
117
                header="[{{ foo }}|{{ 23 }}]",
118
                o_printer="({{ o }})",
119
            )
120
        ),
121
        enable_async=True,
122
    )
123
    env.globals["bar"] = 23
124
    return env
125

126

127
class TestAsyncImports:
128
    def test_context_imports(self, test_env_async):
129
        t = test_env_async.from_string('{% import "module" as m %}{{ m.test() }}')
130
        assert t.render(foo=42) == "[|23]"
131
        t = test_env_async.from_string(
132
            '{% import "module" as m without context %}{{ m.test() }}'
133
        )
134
        assert t.render(foo=42) == "[|23]"
135
        t = test_env_async.from_string(
136
            '{% import "module" as m with context %}{{ m.test() }}'
137
        )
138
        assert t.render(foo=42) == "[42|23]"
139
        t = test_env_async.from_string('{% from "module" import test %}{{ test() }}')
140
        assert t.render(foo=42) == "[|23]"
141
        t = test_env_async.from_string(
142
            '{% from "module" import test without context %}{{ test() }}'
143
        )
144
        assert t.render(foo=42) == "[|23]"
145
        t = test_env_async.from_string(
146
            '{% from "module" import test with context %}{{ test() }}'
147
        )
148
        assert t.render(foo=42) == "[42|23]"
149

150
    def test_trailing_comma(self, test_env_async):
151
        test_env_async.from_string('{% from "foo" import bar, baz with context %}')
152
        test_env_async.from_string('{% from "foo" import bar, baz, with context %}')
153
        test_env_async.from_string('{% from "foo" import bar, with context %}')
154
        test_env_async.from_string('{% from "foo" import bar, with, context %}')
155
        test_env_async.from_string('{% from "foo" import bar, with with context %}')
156

157
    def test_exports(self, test_env_async, run_async_fn):
158
        coro_fn = test_env_async.from_string(
159
            """
160
            {% macro toplevel() %}...{% endmacro %}
161
            {% macro __private() %}...{% endmacro %}
162
            {% set variable = 42 %}
163
            {% for item in [1] %}
164
                {% macro notthere() %}{% endmacro %}
165
            {% endfor %}
166
            """
167
        )._get_default_module_async
168
        m = run_async_fn(coro_fn)
169
        assert run_async_fn(m.toplevel) == "..."
170
        assert not hasattr(m, "__missing")
171
        assert m.variable == 42
172
        assert not hasattr(m, "notthere")
173

174
    def test_import_with_globals(self, test_env_async):
175
        t = test_env_async.from_string(
176
            '{% import "module" as m %}{{ m.test() }}', globals={"foo": 42}
177
        )
178
        assert t.render() == "[42|23]"
179

180
        t = test_env_async.from_string('{% import "module" as m %}{{ m.test() }}')
181
        assert t.render() == "[|23]"
182

183
    def test_import_with_globals_override(self, test_env_async):
184
        t = test_env_async.from_string(
185
            '{% set foo = 41 %}{% import "module" as m %}{{ m.test() }}',
186
            globals={"foo": 42},
187
        )
188
        assert t.render() == "[42|23]"
189

190
    def test_from_import_with_globals(self, test_env_async):
191
        t = test_env_async.from_string(
192
            '{% from "module" import test %}{{ test() }}',
193
            globals={"foo": 42},
194
        )
195
        assert t.render() == "[42|23]"
196

197

198
class TestAsyncIncludes:
199
    def test_context_include(self, test_env_async):
200
        t = test_env_async.from_string('{% include "header" %}')
201
        assert t.render(foo=42) == "[42|23]"
202
        t = test_env_async.from_string('{% include "header" with context %}')
203
        assert t.render(foo=42) == "[42|23]"
204
        t = test_env_async.from_string('{% include "header" without context %}')
205
        assert t.render(foo=42) == "[|23]"
206

207
    def test_choice_includes(self, test_env_async):
208
        t = test_env_async.from_string('{% include ["missing", "header"] %}')
209
        assert t.render(foo=42) == "[42|23]"
210

211
        t = test_env_async.from_string(
212
            '{% include ["missing", "missing2"] ignore missing %}'
213
        )
214
        assert t.render(foo=42) == ""
215

216
        t = test_env_async.from_string('{% include ["missing", "missing2"] %}')
217
        pytest.raises(TemplateNotFound, t.render)
218
        with pytest.raises(TemplatesNotFound) as e:
219
            t.render()
220

221
        assert e.value.templates == ["missing", "missing2"]
222
        assert e.value.name == "missing2"
223

224
        def test_includes(t, **ctx):
225
            ctx["foo"] = 42
226
            assert t.render(ctx) == "[42|23]"
227

228
        t = test_env_async.from_string('{% include ["missing", "header"] %}')
229
        test_includes(t)
230
        t = test_env_async.from_string("{% include x %}")
231
        test_includes(t, x=["missing", "header"])
232
        t = test_env_async.from_string('{% include [x, "header"] %}')
233
        test_includes(t, x="missing")
234
        t = test_env_async.from_string("{% include x %}")
235
        test_includes(t, x="header")
236
        t = test_env_async.from_string("{% include x %}")
237
        test_includes(t, x="header")
238
        t = test_env_async.from_string("{% include [x] %}")
239
        test_includes(t, x="header")
240

241
    def test_include_ignoring_missing(self, test_env_async):
242
        t = test_env_async.from_string('{% include "missing" %}')
243
        pytest.raises(TemplateNotFound, t.render)
244
        for extra in "", "with context", "without context":
245
            t = test_env_async.from_string(
246
                '{% include "missing" ignore missing ' + extra + " %}"
247
            )
248
            assert t.render() == ""
249

250
    def test_context_include_with_overrides(self, test_env_async):
251
        env = Environment(
252
            loader=DictLoader(
253
                dict(
254
                    main="{% for item in [1, 2, 3] %}{% include 'item' %}{% endfor %}",
255
                    item="{{ item }}",
256
                )
257
            )
258
        )
259
        assert env.get_template("main").render() == "123"
260

261
    def test_unoptimized_scopes(self, test_env_async):
262
        t = test_env_async.from_string(
263
            """
264
            {% macro outer(o) %}
265
            {% macro inner() %}
266
            {% include "o_printer" %}
267
            {% endmacro %}
268
            {{ inner() }}
269
            {% endmacro %}
270
            {{ outer("FOO") }}
271
        """
272
        )
273
        assert t.render().strip() == "(FOO)"
274

275
    def test_unoptimized_scopes_autoescape(self):
276
        env = Environment(
277
            loader=DictLoader({"o_printer": "({{ o }})"}),
278
            autoescape=True,
279
            enable_async=True,
280
        )
281
        t = env.from_string(
282
            """
283
            {% macro outer(o) %}
284
            {% macro inner() %}
285
            {% include "o_printer" %}
286
            {% endmacro %}
287
            {{ inner() }}
288
            {% endmacro %}
289
            {{ outer("FOO") }}
290
        """
291
        )
292
        assert t.render().strip() == "(FOO)"
293

294

295
class TestAsyncForLoop:
296
    def test_simple(self, test_env_async):
297
        tmpl = test_env_async.from_string("{% for item in seq %}{{ item }}{% endfor %}")
298
        assert tmpl.render(seq=list(range(10))) == "0123456789"
299

300
    def test_else(self, test_env_async):
301
        tmpl = test_env_async.from_string(
302
            "{% for item in seq %}XXX{% else %}...{% endfor %}"
303
        )
304
        assert tmpl.render() == "..."
305

306
    def test_empty_blocks(self, test_env_async):
307
        tmpl = test_env_async.from_string(
308
            "<{% for item in seq %}{% else %}{% endfor %}>"
309
        )
310
        assert tmpl.render() == "<>"
311

312
    @pytest.mark.parametrize(
313
        "transform", [lambda x: x, iter, reversed, lambda x: (i for i in x), auto_aiter]
314
    )
315
    def test_context_vars(self, test_env_async, transform):
316
        t = test_env_async.from_string(
317
            "{% for item in seq %}{{ loop.index }}|{{ loop.index0 }}"
318
            "|{{ loop.revindex }}|{{ loop.revindex0 }}|{{ loop.first }}"
319
            "|{{ loop.last }}|{{ loop.length }}\n{% endfor %}"
320
        )
321
        out = t.render(seq=transform([42, 24]))
322
        assert out == "1|0|2|1|True|False|2\n2|1|1|0|False|True|2\n"
323

324
    def test_cycling(self, test_env_async):
325
        tmpl = test_env_async.from_string(
326
            """{% for item in seq %}{{
327
            loop.cycle('<1>', '<2>') }}{% endfor %}{%
328
            for item in seq %}{{ loop.cycle(*through) }}{% endfor %}"""
329
        )
330
        output = tmpl.render(seq=list(range(4)), through=("<1>", "<2>"))
331
        assert output == "<1><2>" * 4
332

333
    def test_lookaround(self, test_env_async):
334
        tmpl = test_env_async.from_string(
335
            """{% for item in seq -%}
336
            {{ loop.previtem|default('x') }}-{{ item }}-{{
337
            loop.nextitem|default('x') }}|
338
        {%- endfor %}"""
339
        )
340
        output = tmpl.render(seq=list(range(4)))
341
        assert output == "x-0-1|0-1-2|1-2-3|2-3-x|"
342

343
    def test_changed(self, test_env_async):
344
        tmpl = test_env_async.from_string(
345
            """{% for item in seq -%}
346
            {{ loop.changed(item) }},
347
        {%- endfor %}"""
348
        )
349
        output = tmpl.render(seq=[None, None, 1, 2, 2, 3, 4, 4, 4])
350
        assert output == "True,False,True,True,False,True,True,False,False,"
351

352
    def test_scope(self, test_env_async):
353
        tmpl = test_env_async.from_string("{% for item in seq %}{% endfor %}{{ item }}")
354
        output = tmpl.render(seq=list(range(10)))
355
        assert not output
356

357
    def test_varlen(self, test_env_async):
358
        def inner():
359
            yield from range(5)
360

361
        tmpl = test_env_async.from_string(
362
            "{% for item in iter %}{{ item }}{% endfor %}"
363
        )
364
        output = tmpl.render(iter=inner())
365
        assert output == "01234"
366

367
    def test_noniter(self, test_env_async):
368
        tmpl = test_env_async.from_string("{% for item in none %}...{% endfor %}")
369
        pytest.raises(TypeError, tmpl.render)
370

371
    def test_recursive(self, test_env_async):
372
        tmpl = test_env_async.from_string(
373
            """{% for item in seq recursive -%}
374
            [{{ item.a }}{% if item.b %}<{{ loop(item.b) }}>{% endif %}]
375
        {%- endfor %}"""
376
        )
377
        assert (
378
            tmpl.render(
379
                seq=[
380
                    dict(a=1, b=[dict(a=1), dict(a=2)]),
381
                    dict(a=2, b=[dict(a=1), dict(a=2)]),
382
                    dict(a=3, b=[dict(a="a")]),
383
                ]
384
            )
385
            == "[1<[1][2]>][2<[1][2]>][3<[a]>]"
386
        )
387

388
    def test_recursive_lookaround(self, test_env_async):
389
        tmpl = test_env_async.from_string(
390
            """{% for item in seq recursive -%}
391
            [{{ loop.previtem.a if loop.previtem is defined else 'x' }}.{{
392
            item.a }}.{{ loop.nextitem.a if loop.nextitem is defined else 'x'
393
            }}{% if item.b %}<{{ loop(item.b) }}>{% endif %}]
394
        {%- endfor %}"""
395
        )
396
        assert (
397
            tmpl.render(
398
                seq=[
399
                    dict(a=1, b=[dict(a=1), dict(a=2)]),
400
                    dict(a=2, b=[dict(a=1), dict(a=2)]),
401
                    dict(a=3, b=[dict(a="a")]),
402
                ]
403
            )
404
            == "[x.1.2<[x.1.2][1.2.x]>][1.2.3<[x.1.2][1.2.x]>][2.3.x<[x.a.x]>]"
405
        )
406

407
    def test_recursive_depth0(self, test_env_async):
408
        tmpl = test_env_async.from_string(
409
            "{% for item in seq recursive %}[{{ loop.depth0 }}:{{ item.a }}"
410
            "{% if item.b %}<{{ loop(item.b) }}>{% endif %}]{% endfor %}"
411
        )
412
        assert (
413
            tmpl.render(
414
                seq=[
415
                    dict(a=1, b=[dict(a=1), dict(a=2)]),
416
                    dict(a=2, b=[dict(a=1), dict(a=2)]),
417
                    dict(a=3, b=[dict(a="a")]),
418
                ]
419
            )
420
            == "[0:1<[1:1][1:2]>][0:2<[1:1][1:2]>][0:3<[1:a]>]"
421
        )
422

423
    def test_recursive_depth(self, test_env_async):
424
        tmpl = test_env_async.from_string(
425
            "{% for item in seq recursive %}[{{ loop.depth }}:{{ item.a }}"
426
            "{% if item.b %}<{{ loop(item.b) }}>{% endif %}]{% endfor %}"
427
        )
428
        assert (
429
            tmpl.render(
430
                seq=[
431
                    dict(a=1, b=[dict(a=1), dict(a=2)]),
432
                    dict(a=2, b=[dict(a=1), dict(a=2)]),
433
                    dict(a=3, b=[dict(a="a")]),
434
                ]
435
            )
436
            == "[1:1<[2:1][2:2]>][1:2<[2:1][2:2]>][1:3<[2:a]>]"
437
        )
438

439
    def test_looploop(self, test_env_async):
440
        tmpl = test_env_async.from_string(
441
            """{% for row in table %}
442
            {%- set rowloop = loop -%}
443
            {% for cell in row -%}
444
                [{{ rowloop.index }}|{{ loop.index }}]
445
            {%- endfor %}
446
        {%- endfor %}"""
447
        )
448
        assert tmpl.render(table=["ab", "cd"]) == "[1|1][1|2][2|1][2|2]"
449

450
    def test_reversed_bug(self, test_env_async):
451
        tmpl = test_env_async.from_string(
452
            "{% for i in items %}{{ i }}"
453
            "{% if not loop.last %}"
454
            ",{% endif %}{% endfor %}"
455
        )
456
        assert tmpl.render(items=reversed([3, 2, 1])) == "1,2,3"
457

458
    def test_loop_errors(self, test_env_async, run_async_fn):
459
        tmpl = test_env_async.from_string(
460
            """{% for item in [1] if loop.index
461
                                      == 0 %}...{% endfor %}"""
462
        )
463
        with pytest.raises(UndefinedError):
464
            run_async_fn(tmpl.render_async)
465

466
        tmpl = test_env_async.from_string(
467
            """{% for item in [] %}...{% else
468
            %}{{ loop }}{% endfor %}"""
469
        )
470
        assert run_async_fn(tmpl.render_async) == ""
471

472
    def test_loop_filter(self, test_env_async):
473
        tmpl = test_env_async.from_string(
474
            "{% for item in range(10) if item is even %}[{{ item }}]{% endfor %}"
475
        )
476
        assert tmpl.render() == "[0][2][4][6][8]"
477
        tmpl = test_env_async.from_string(
478
            """
479
            {%- for item in range(10) if item is even %}[{{
480
                loop.index }}:{{ item }}]{% endfor %}"""
481
        )
482
        assert tmpl.render() == "[1:0][2:2][3:4][4:6][5:8]"
483

484
    def test_scoped_special_var(self, test_env_async):
485
        t = test_env_async.from_string(
486
            "{% for s in seq %}[{{ loop.first }}{% for c in s %}"
487
            "|{{ loop.first }}{% endfor %}]{% endfor %}"
488
        )
489
        assert t.render(seq=("ab", "cd")) == "[True|True|False][False|True|False]"
490

491
    def test_scoped_loop_var(self, test_env_async):
492
        t = test_env_async.from_string(
493
            "{% for x in seq %}{{ loop.first }}"
494
            "{% for y in seq %}{% endfor %}{% endfor %}"
495
        )
496
        assert t.render(seq="ab") == "TrueFalse"
497
        t = test_env_async.from_string(
498
            "{% for x in seq %}{% for y in seq %}"
499
            "{{ loop.first }}{% endfor %}{% endfor %}"
500
        )
501
        assert t.render(seq="ab") == "TrueFalseTrueFalse"
502

503
    def test_recursive_empty_loop_iter(self, test_env_async):
504
        t = test_env_async.from_string(
505
            """
506
        {%- for item in foo recursive -%}{%- endfor -%}
507
        """
508
        )
509
        assert t.render(dict(foo=[])) == ""
510

511
    def test_call_in_loop(self, test_env_async):
512
        t = test_env_async.from_string(
513
            """
514
        {%- macro do_something() -%}
515
            [{{ caller() }}]
516
        {%- endmacro %}
517

518
        {%- for i in [1, 2, 3] %}
519
            {%- call do_something() -%}
520
                {{ i }}
521
            {%- endcall %}
522
        {%- endfor -%}
523
        """
524
        )
525
        assert t.render() == "[1][2][3]"
526

527
    def test_scoping_bug(self, test_env_async):
528
        t = test_env_async.from_string(
529
            """
530
        {%- for item in foo %}...{{ item }}...{% endfor %}
531
        {%- macro item(a) %}...{{ a }}...{% endmacro %}
532
        {{- item(2) -}}
533
        """
534
        )
535
        assert t.render(foo=(1,)) == "...1......2..."
536

537
    def test_unpacking(self, test_env_async):
538
        tmpl = test_env_async.from_string(
539
            "{% for a, b, c in [[1, 2, 3]] %}{{ a }}|{{ b }}|{{ c }}{% endfor %}"
540
        )
541
        assert tmpl.render() == "1|2|3"
542

543
    def test_recursive_loop_filter(self, test_env_async):
544
        t = test_env_async.from_string(
545
            """
546
        <?xml version="1.0" encoding="UTF-8"?>
547
        <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
548
          {%- for page in [site.root] if page.url != this recursive %}
549
          <url><loc>{{ page.url }}</loc></url>
550
          {{- loop(page.children) }}
551
          {%- endfor %}
552
        </urlset>
553
        """
554
        )
555
        sm = t.render(
556
            this="/foo",
557
            site={"root": {"url": "/", "children": [{"url": "/foo"}, {"url": "/bar"}]}},
558
        )
559
        lines = [x.strip() for x in sm.splitlines() if x.strip()]
560
        assert lines == [
561
            '<?xml version="1.0" encoding="UTF-8"?>',
562
            '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">',
563
            "<url><loc>/</loc></url>",
564
            "<url><loc>/bar</loc></url>",
565
            "</urlset>",
566
        ]
567

568
    def test_nonrecursive_loop_filter(self, test_env_async):
569
        t = test_env_async.from_string(
570
            """
571
        <?xml version="1.0" encoding="UTF-8"?>
572
        <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
573
          {%- for page in items if page.url != this %}
574
          <url><loc>{{ page.url }}</loc></url>
575
          {%- endfor %}
576
        </urlset>
577
        """
578
        )
579
        sm = t.render(
580
            this="/foo", items=[{"url": "/"}, {"url": "/foo"}, {"url": "/bar"}]
581
        )
582
        lines = [x.strip() for x in sm.splitlines() if x.strip()]
583
        assert lines == [
584
            '<?xml version="1.0" encoding="UTF-8"?>',
585
            '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">',
586
            "<url><loc>/</loc></url>",
587
            "<url><loc>/bar</loc></url>",
588
            "</urlset>",
589
        ]
590

591
    def test_bare_async(self, test_env_async):
592
        t = test_env_async.from_string('{% extends "header" %}')
593
        assert t.render(foo=42) == "[42|23]"
594

595
    def test_awaitable_property_slicing(self, test_env_async):
596
        t = test_env_async.from_string("{% for x in a.b[:1] %}{{ x }}{% endfor %}")
597
        assert t.render(a=dict(b=[1, 2, 3])) == "1"
598

599

600
def test_namespace_awaitable(test_env_async, run_async_fn):
601
    async def _test():
602
        t = test_env_async.from_string(
603
            '{% set ns = namespace(foo="Bar") %}{{ ns.foo }}'
604
        )
605
        actual = await t.render_async()
606
        assert actual == "Bar"
607

608
    run_async_fn(_test)
609

610

611
def test_chainable_undefined_aiter(run_async_fn):
612
    async def _test():
613
        t = Template(
614
            "{% for x in a['b']['c'] %}{{ x }}{% endfor %}",
615
            enable_async=True,
616
            undefined=ChainableUndefined,
617
        )
618
        rv = await t.render_async(a={})
619
        assert rv == ""
620

621
    run_async_fn(_test)
622

623

624
@pytest.fixture
625
def async_native_env():
626
    return NativeEnvironment(enable_async=True)
627

628

629
def test_native_async(async_native_env, run_async_fn):
630
    async def _test():
631
        t = async_native_env.from_string("{{ x }}")
632
        rv = await t.render_async(x=23)
633
        assert rv == 23
634

635
    run_async_fn(_test)
636

637

638
def test_native_list_async(async_native_env, run_async_fn):
639
    async def _test():
640
        t = async_native_env.from_string("{{ x }}")
641
        rv = await t.render_async(x=list(range(3)))
642
        assert rv == [0, 1, 2]
643

644
    run_async_fn(_test)
645

646

647
def test_getitem_after_filter():
648
    env = Environment(enable_async=True)
649
    env.filters["add_each"] = lambda v, x: [i + x for i in v]
650
    t = env.from_string("{{ (a|add_each(2))[1:] }}")
651
    out = t.render(a=range(3))
652
    assert out == "[3, 4]"
653

654

655
def test_getitem_after_call():
656
    env = Environment(enable_async=True)
657
    env.globals["add_each"] = lambda v, x: [i + x for i in v]
658
    t = env.from_string("{{ add_each(a, 2)[1:] }}")
659
    out = t.render(a=range(3))
660
    assert out == "[3, 4]"
661

662

663
def test_basic_generate_async(run_async_fn):
664
    t = Template(
665
        "{% for item in [1, 2, 3] %}[{{ item }}]{% endfor %}", enable_async=True
666
    )
667

668
    async def func():
669
        agen = t.generate_async()
670
        try:
671
            return await agen.__anext__()
672
        finally:
673
            await agen.aclose()
674

675
    rv = run_async_fn(func)
676
    assert rv == "["
677

678

679
def test_include_generate_async(run_async_fn, test_env_async):
680
    t = test_env_async.from_string('{% include "header" %}')
681

682
    async def func():
683
        agen = t.generate_async()
684
        try:
685
            return await agen.__anext__()
686
        finally:
687
            await agen.aclose()
688

689
    rv = run_async_fn(func)
690
    assert rv == "["
691

692

693
def test_blocks_generate_async(run_async_fn):
694
    t = Template(
695
        "{% block foo %}<Test>{% endblock %}{{ self.foo() }}",
696
        enable_async=True,
697
        autoescape=True,
698
    )
699

700
    async def func():
701
        agen = t.generate_async()
702
        try:
703
            return await agen.__anext__()
704
        finally:
705
            await agen.aclose()
706

707
    rv = run_async_fn(func)
708
    assert rv == "<Test>"
709

710

711
def test_async_extend(run_async_fn, test_env_async):
712
    t = test_env_async.from_string('{% extends "header" %}')
713

714
    async def func():
715
        agen = t.generate_async()
716
        try:
717
            return await agen.__anext__()
718
        finally:
719
            await agen.aclose()
720

721
    rv = run_async_fn(func)
722
    assert rv == "["
723

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.