IRIS YANG | 3121357 | 2020-08-18 13:17:02 +0000 | [diff] [blame] | 1 | import pytest |
| 2 | |
| 3 | from jinja2 import DictLoader |
| 4 | from jinja2 import Environment |
| 5 | from jinja2 import TemplateRuntimeError |
| 6 | from jinja2 import TemplateSyntaxError |
| 7 | from jinja2 import UndefinedError |
| 8 | |
| 9 | |
| 10 | @pytest.fixture |
| 11 | def env_trim(): |
| 12 | return Environment(trim_blocks=True) |
| 13 | |
| 14 | |
| 15 | class TestForLoop: |
| 16 | def test_simple(self, env): |
| 17 | tmpl = env.from_string("{% for item in seq %}{{ item }}{% endfor %}") |
| 18 | assert tmpl.render(seq=list(range(10))) == "0123456789" |
| 19 | |
| 20 | def test_else(self, env): |
| 21 | tmpl = env.from_string("{% for item in seq %}XXX{% else %}...{% endfor %}") |
| 22 | assert tmpl.render() == "..." |
| 23 | |
| 24 | def test_else_scoping_item(self, env): |
| 25 | tmpl = env.from_string("{% for item in [] %}{% else %}{{ item }}{% endfor %}") |
| 26 | assert tmpl.render(item=42) == "42" |
| 27 | |
| 28 | def test_empty_blocks(self, env): |
| 29 | tmpl = env.from_string("<{% for item in seq %}{% else %}{% endfor %}>") |
| 30 | assert tmpl.render() == "<>" |
| 31 | |
| 32 | def test_context_vars(self, env): |
| 33 | slist = [42, 24] |
| 34 | for seq in [slist, iter(slist), reversed(slist), (_ for _ in slist)]: |
| 35 | tmpl = env.from_string( |
| 36 | """{% for item in seq -%} |
| 37 | {{ loop.index }}|{{ loop.index0 }}|{{ loop.revindex }}|{{ |
| 38 | loop.revindex0 }}|{{ loop.first }}|{{ loop.last }}|{{ |
| 39 | loop.length }}###{% endfor %}""" |
| 40 | ) |
| 41 | one, two, _ = tmpl.render(seq=seq).split("###") |
| 42 | ( |
| 43 | one_index, |
| 44 | one_index0, |
| 45 | one_revindex, |
| 46 | one_revindex0, |
| 47 | one_first, |
| 48 | one_last, |
| 49 | one_length, |
| 50 | ) = one.split("|") |
| 51 | ( |
| 52 | two_index, |
| 53 | two_index0, |
| 54 | two_revindex, |
| 55 | two_revindex0, |
| 56 | two_first, |
| 57 | two_last, |
| 58 | two_length, |
| 59 | ) = two.split("|") |
| 60 | |
| 61 | assert int(one_index) == 1 and int(two_index) == 2 |
| 62 | assert int(one_index0) == 0 and int(two_index0) == 1 |
| 63 | assert int(one_revindex) == 2 and int(two_revindex) == 1 |
| 64 | assert int(one_revindex0) == 1 and int(two_revindex0) == 0 |
| 65 | assert one_first == "True" and two_first == "False" |
| 66 | assert one_last == "False" and two_last == "True" |
| 67 | assert one_length == two_length == "2" |
| 68 | |
| 69 | def test_cycling(self, env): |
| 70 | tmpl = env.from_string( |
| 71 | """{% for item in seq %}{{ |
| 72 | loop.cycle('<1>', '<2>') }}{% endfor %}{% |
| 73 | for item in seq %}{{ loop.cycle(*through) }}{% endfor %}""" |
| 74 | ) |
| 75 | output = tmpl.render(seq=list(range(4)), through=("<1>", "<2>")) |
| 76 | assert output == "<1><2>" * 4 |
| 77 | |
| 78 | def test_lookaround(self, env): |
| 79 | tmpl = env.from_string( |
| 80 | """{% for item in seq -%} |
| 81 | {{ loop.previtem|default('x') }}-{{ item }}-{{ |
| 82 | loop.nextitem|default('x') }}| |
| 83 | {%- endfor %}""" |
| 84 | ) |
| 85 | output = tmpl.render(seq=list(range(4))) |
| 86 | assert output == "x-0-1|0-1-2|1-2-3|2-3-x|" |
| 87 | |
| 88 | def test_changed(self, env): |
| 89 | tmpl = env.from_string( |
| 90 | """{% for item in seq -%} |
| 91 | {{ loop.changed(item) }}, |
| 92 | {%- endfor %}""" |
| 93 | ) |
| 94 | output = tmpl.render(seq=[None, None, 1, 2, 2, 3, 4, 4, 4]) |
| 95 | assert output == "True,False,True,True,False,True,True,False,False," |
| 96 | |
| 97 | def test_scope(self, env): |
| 98 | tmpl = env.from_string("{% for item in seq %}{% endfor %}{{ item }}") |
| 99 | output = tmpl.render(seq=list(range(10))) |
| 100 | assert not output |
| 101 | |
| 102 | def test_varlen(self, env): |
| 103 | tmpl = env.from_string("{% for item in iter %}{{ item }}{% endfor %}") |
| 104 | output = tmpl.render(iter=range(5)) |
| 105 | assert output == "01234" |
| 106 | |
| 107 | def test_noniter(self, env): |
| 108 | tmpl = env.from_string("{% for item in none %}...{% endfor %}") |
| 109 | pytest.raises(TypeError, tmpl.render) |
| 110 | |
| 111 | def test_recursive(self, env): |
| 112 | tmpl = env.from_string( |
| 113 | """{% for item in seq recursive -%} |
| 114 | [{{ item.a }}{% if item.b %}<{{ loop(item.b) }}>{% endif %}] |
| 115 | {%- endfor %}""" |
| 116 | ) |
| 117 | assert ( |
| 118 | tmpl.render( |
| 119 | seq=[ |
| 120 | dict(a=1, b=[dict(a=1), dict(a=2)]), |
| 121 | dict(a=2, b=[dict(a=1), dict(a=2)]), |
| 122 | dict(a=3, b=[dict(a="a")]), |
| 123 | ] |
| 124 | ) |
| 125 | == "[1<[1][2]>][2<[1][2]>][3<[a]>]" |
| 126 | ) |
| 127 | |
| 128 | def test_recursive_lookaround(self, env): |
| 129 | tmpl = env.from_string( |
| 130 | """{% for item in seq recursive -%} |
| 131 | [{{ loop.previtem.a if loop.previtem is defined else 'x' }}.{{ |
| 132 | item.a }}.{{ loop.nextitem.a if loop.nextitem is defined else 'x' |
| 133 | }}{% if item.b %}<{{ loop(item.b) }}>{% endif %}] |
| 134 | {%- endfor %}""" |
| 135 | ) |
| 136 | assert ( |
| 137 | tmpl.render( |
| 138 | seq=[ |
| 139 | dict(a=1, b=[dict(a=1), dict(a=2)]), |
| 140 | dict(a=2, b=[dict(a=1), dict(a=2)]), |
| 141 | dict(a=3, b=[dict(a="a")]), |
| 142 | ] |
| 143 | ) |
| 144 | == "[x.1.2<[x.1.2][1.2.x]>][1.2.3<[x.1.2][1.2.x]>][2.3.x<[x.a.x]>]" |
| 145 | ) |
| 146 | |
| 147 | def test_recursive_depth0(self, env): |
| 148 | tmpl = env.from_string( |
| 149 | """{% for item in seq recursive -%} |
| 150 | [{{ loop.depth0 }}:{{ item.a }}{% if item.b %}<{{ loop(item.b) }}>{% endif %}] |
| 151 | {%- endfor %}""" |
| 152 | ) |
| 153 | assert ( |
| 154 | tmpl.render( |
| 155 | seq=[ |
| 156 | dict(a=1, b=[dict(a=1), dict(a=2)]), |
| 157 | dict(a=2, b=[dict(a=1), dict(a=2)]), |
| 158 | dict(a=3, b=[dict(a="a")]), |
| 159 | ] |
| 160 | ) |
| 161 | == "[0:1<[1:1][1:2]>][0:2<[1:1][1:2]>][0:3<[1:a]>]" |
| 162 | ) |
| 163 | |
| 164 | def test_recursive_depth(self, env): |
| 165 | tmpl = env.from_string( |
| 166 | """{% for item in seq recursive -%} |
| 167 | [{{ loop.depth }}:{{ item.a }}{% if item.b %}<{{ loop(item.b) }}>{% endif %}] |
| 168 | {%- endfor %}""" |
| 169 | ) |
| 170 | assert ( |
| 171 | tmpl.render( |
| 172 | seq=[ |
| 173 | dict(a=1, b=[dict(a=1), dict(a=2)]), |
| 174 | dict(a=2, b=[dict(a=1), dict(a=2)]), |
| 175 | dict(a=3, b=[dict(a="a")]), |
| 176 | ] |
| 177 | ) |
| 178 | == "[1:1<[2:1][2:2]>][1:2<[2:1][2:2]>][1:3<[2:a]>]" |
| 179 | ) |
| 180 | |
| 181 | def test_looploop(self, env): |
| 182 | tmpl = env.from_string( |
| 183 | """{% for row in table %} |
| 184 | {%- set rowloop = loop -%} |
| 185 | {% for cell in row -%} |
| 186 | [{{ rowloop.index }}|{{ loop.index }}] |
| 187 | {%- endfor %} |
| 188 | {%- endfor %}""" |
| 189 | ) |
| 190 | assert tmpl.render(table=["ab", "cd"]) == "[1|1][1|2][2|1][2|2]" |
| 191 | |
| 192 | def test_reversed_bug(self, env): |
| 193 | tmpl = env.from_string( |
| 194 | "{% for i in items %}{{ i }}" |
| 195 | "{% if not loop.last %}" |
| 196 | ",{% endif %}{% endfor %}" |
| 197 | ) |
| 198 | assert tmpl.render(items=reversed([3, 2, 1])) == "1,2,3" |
| 199 | |
| 200 | def test_loop_errors(self, env): |
| 201 | tmpl = env.from_string( |
| 202 | """{% for item in [1] if loop.index |
| 203 | == 0 %}...{% endfor %}""" |
| 204 | ) |
| 205 | pytest.raises(UndefinedError, tmpl.render) |
| 206 | tmpl = env.from_string( |
| 207 | """{% for item in [] %}...{% else |
| 208 | %}{{ loop }}{% endfor %}""" |
| 209 | ) |
| 210 | assert tmpl.render() == "" |
| 211 | |
| 212 | def test_loop_filter(self, env): |
| 213 | tmpl = env.from_string( |
| 214 | "{% for item in range(10) if item is even %}[{{ item }}]{% endfor %}" |
| 215 | ) |
| 216 | assert tmpl.render() == "[0][2][4][6][8]" |
| 217 | tmpl = env.from_string( |
| 218 | """ |
| 219 | {%- for item in range(10) if item is even %}[{{ |
| 220 | loop.index }}:{{ item }}]{% endfor %}""" |
| 221 | ) |
| 222 | assert tmpl.render() == "[1:0][2:2][3:4][4:6][5:8]" |
| 223 | |
| 224 | def test_loop_unassignable(self, env): |
| 225 | pytest.raises( |
| 226 | TemplateSyntaxError, env.from_string, "{% for loop in seq %}...{% endfor %}" |
| 227 | ) |
| 228 | |
| 229 | def test_scoped_special_var(self, env): |
| 230 | t = env.from_string( |
| 231 | "{% for s in seq %}[{{ loop.first }}{% for c in s %}" |
| 232 | "|{{ loop.first }}{% endfor %}]{% endfor %}" |
| 233 | ) |
| 234 | assert t.render(seq=("ab", "cd")) == "[True|True|False][False|True|False]" |
| 235 | |
| 236 | def test_scoped_loop_var(self, env): |
| 237 | t = env.from_string( |
| 238 | "{% for x in seq %}{{ loop.first }}" |
| 239 | "{% for y in seq %}{% endfor %}{% endfor %}" |
| 240 | ) |
| 241 | assert t.render(seq="ab") == "TrueFalse" |
| 242 | t = env.from_string( |
| 243 | "{% for x in seq %}{% for y in seq %}" |
| 244 | "{{ loop.first }}{% endfor %}{% endfor %}" |
| 245 | ) |
| 246 | assert t.render(seq="ab") == "TrueFalseTrueFalse" |
| 247 | |
| 248 | def test_recursive_empty_loop_iter(self, env): |
| 249 | t = env.from_string( |
| 250 | """ |
| 251 | {%- for item in foo recursive -%}{%- endfor -%} |
| 252 | """ |
| 253 | ) |
| 254 | assert t.render(dict(foo=[])) == "" |
| 255 | |
| 256 | def test_call_in_loop(self, env): |
| 257 | t = env.from_string( |
| 258 | """ |
| 259 | {%- macro do_something() -%} |
| 260 | [{{ caller() }}] |
| 261 | {%- endmacro %} |
| 262 | |
| 263 | {%- for i in [1, 2, 3] %} |
| 264 | {%- call do_something() -%} |
| 265 | {{ i }} |
| 266 | {%- endcall %} |
| 267 | {%- endfor -%} |
| 268 | """ |
| 269 | ) |
| 270 | assert t.render() == "[1][2][3]" |
| 271 | |
| 272 | def test_scoping_bug(self, env): |
| 273 | t = env.from_string( |
| 274 | """ |
| 275 | {%- for item in foo %}...{{ item }}...{% endfor %} |
| 276 | {%- macro item(a) %}...{{ a }}...{% endmacro %} |
| 277 | {{- item(2) -}} |
| 278 | """ |
| 279 | ) |
| 280 | assert t.render(foo=(1,)) == "...1......2..." |
| 281 | |
| 282 | def test_unpacking(self, env): |
| 283 | tmpl = env.from_string( |
| 284 | "{% for a, b, c in [[1, 2, 3]] %}{{ a }}|{{ b }}|{{ c }}{% endfor %}" |
| 285 | ) |
| 286 | assert tmpl.render() == "1|2|3" |
| 287 | |
| 288 | def test_intended_scoping_with_set(self, env): |
| 289 | tmpl = env.from_string( |
| 290 | "{% for item in seq %}{{ x }}{% set x = item %}{{ x }}{% endfor %}" |
| 291 | ) |
| 292 | assert tmpl.render(x=0, seq=[1, 2, 3]) == "010203" |
| 293 | |
| 294 | tmpl = env.from_string( |
| 295 | "{% set x = 9 %}{% for item in seq %}{{ x }}" |
| 296 | "{% set x = item %}{{ x }}{% endfor %}" |
| 297 | ) |
| 298 | assert tmpl.render(x=0, seq=[1, 2, 3]) == "919293" |
| 299 | |
| 300 | |
| 301 | class TestIfCondition: |
| 302 | def test_simple(self, env): |
| 303 | tmpl = env.from_string("""{% if true %}...{% endif %}""") |
| 304 | assert tmpl.render() == "..." |
| 305 | |
| 306 | def test_elif(self, env): |
| 307 | tmpl = env.from_string( |
| 308 | """{% if false %}XXX{% elif true |
| 309 | %}...{% else %}XXX{% endif %}""" |
| 310 | ) |
| 311 | assert tmpl.render() == "..." |
| 312 | |
| 313 | def test_elif_deep(self, env): |
| 314 | elifs = "\n".join(f"{{% elif a == {i} %}}{i}" for i in range(1, 1000)) |
| 315 | tmpl = env.from_string(f"{{% if a == 0 %}}0{elifs}{{% else %}}x{{% endif %}}") |
| 316 | for x in (0, 10, 999): |
| 317 | assert tmpl.render(a=x).strip() == str(x) |
| 318 | assert tmpl.render(a=1000).strip() == "x" |
| 319 | |
| 320 | def test_else(self, env): |
| 321 | tmpl = env.from_string("{% if false %}XXX{% else %}...{% endif %}") |
| 322 | assert tmpl.render() == "..." |
| 323 | |
| 324 | def test_empty(self, env): |
| 325 | tmpl = env.from_string("[{% if true %}{% else %}{% endif %}]") |
| 326 | assert tmpl.render() == "[]" |
| 327 | |
| 328 | def test_complete(self, env): |
| 329 | tmpl = env.from_string( |
| 330 | "{% if a %}A{% elif b %}B{% elif c == d %}C{% else %}D{% endif %}" |
| 331 | ) |
| 332 | assert tmpl.render(a=0, b=False, c=42, d=42.0) == "C" |
| 333 | |
| 334 | def test_no_scope(self, env): |
| 335 | tmpl = env.from_string("{% if a %}{% set foo = 1 %}{% endif %}{{ foo }}") |
| 336 | assert tmpl.render(a=True) == "1" |
| 337 | tmpl = env.from_string("{% if true %}{% set foo = 1 %}{% endif %}{{ foo }}") |
| 338 | assert tmpl.render() == "1" |
| 339 | |
| 340 | |
| 341 | class TestMacros: |
| 342 | def test_simple(self, env_trim): |
| 343 | tmpl = env_trim.from_string( |
| 344 | """\ |
| 345 | {% macro say_hello(name) %}Hello {{ name }}!{% endmacro %} |
| 346 | {{ say_hello('Peter') }}""" |
| 347 | ) |
| 348 | assert tmpl.render() == "Hello Peter!" |
| 349 | |
| 350 | def test_scoping(self, env_trim): |
| 351 | tmpl = env_trim.from_string( |
| 352 | """\ |
| 353 | {% macro level1(data1) %} |
| 354 | {% macro level2(data2) %}{{ data1 }}|{{ data2 }}{% endmacro %} |
| 355 | {{ level2('bar') }}{% endmacro %} |
| 356 | {{ level1('foo') }}""" |
| 357 | ) |
| 358 | assert tmpl.render() == "foo|bar" |
| 359 | |
| 360 | def test_arguments(self, env_trim): |
| 361 | tmpl = env_trim.from_string( |
| 362 | """\ |
| 363 | {% macro m(a, b, c='c', d='d') %}{{ a }}|{{ b }}|{{ c }}|{{ d }}{% endmacro %} |
| 364 | {{ m() }}|{{ m('a') }}|{{ m('a', 'b') }}|{{ m(1, 2, 3) }}""" |
| 365 | ) |
| 366 | assert tmpl.render() == "||c|d|a||c|d|a|b|c|d|1|2|3|d" |
| 367 | |
| 368 | def test_arguments_defaults_nonsense(self, env_trim): |
| 369 | pytest.raises( |
| 370 | TemplateSyntaxError, |
| 371 | env_trim.from_string, |
| 372 | """\ |
| 373 | {% macro m(a, b=1, c) %}a={{ a }}, b={{ b }}, c={{ c }}{% endmacro %}""", |
| 374 | ) |
| 375 | |
| 376 | def test_caller_defaults_nonsense(self, env_trim): |
| 377 | pytest.raises( |
| 378 | TemplateSyntaxError, |
| 379 | env_trim.from_string, |
| 380 | """\ |
| 381 | {% macro a() %}{{ caller() }}{% endmacro %} |
| 382 | {% call(x, y=1, z) a() %}{% endcall %}""", |
| 383 | ) |
| 384 | |
| 385 | def test_varargs(self, env_trim): |
| 386 | tmpl = env_trim.from_string( |
| 387 | """\ |
| 388 | {% macro test() %}{{ varargs|join('|') }}{% endmacro %}\ |
| 389 | {{ test(1, 2, 3) }}""" |
| 390 | ) |
| 391 | assert tmpl.render() == "1|2|3" |
| 392 | |
| 393 | def test_simple_call(self, env_trim): |
| 394 | tmpl = env_trim.from_string( |
| 395 | """\ |
| 396 | {% macro test() %}[[{{ caller() }}]]{% endmacro %}\ |
| 397 | {% call test() %}data{% endcall %}""" |
| 398 | ) |
| 399 | assert tmpl.render() == "[[data]]" |
| 400 | |
| 401 | def test_complex_call(self, env_trim): |
| 402 | tmpl = env_trim.from_string( |
| 403 | """\ |
| 404 | {% macro test() %}[[{{ caller('data') }}]]{% endmacro %}\ |
| 405 | {% call(data) test() %}{{ data }}{% endcall %}""" |
| 406 | ) |
| 407 | assert tmpl.render() == "[[data]]" |
| 408 | |
| 409 | def test_caller_undefined(self, env_trim): |
| 410 | tmpl = env_trim.from_string( |
| 411 | """\ |
| 412 | {% set caller = 42 %}\ |
| 413 | {% macro test() %}{{ caller is not defined }}{% endmacro %}\ |
| 414 | {{ test() }}""" |
| 415 | ) |
| 416 | assert tmpl.render() == "True" |
| 417 | |
| 418 | def test_include(self, env_trim): |
| 419 | env_trim = Environment( |
| 420 | loader=DictLoader( |
| 421 | {"include": "{% macro test(foo) %}[{{ foo }}]{% endmacro %}"} |
| 422 | ) |
| 423 | ) |
| 424 | tmpl = env_trim.from_string('{% from "include" import test %}{{ test("foo") }}') |
| 425 | assert tmpl.render() == "[foo]" |
| 426 | |
| 427 | def test_macro_api(self, env_trim): |
| 428 | tmpl = env_trim.from_string( |
| 429 | "{% macro foo(a, b) %}{% endmacro %}" |
| 430 | "{% macro bar() %}{{ varargs }}{{ kwargs }}{% endmacro %}" |
| 431 | "{% macro baz() %}{{ caller() }}{% endmacro %}" |
| 432 | ) |
| 433 | assert tmpl.module.foo.arguments == ("a", "b") |
| 434 | assert tmpl.module.foo.name == "foo" |
| 435 | assert not tmpl.module.foo.caller |
| 436 | assert not tmpl.module.foo.catch_kwargs |
| 437 | assert not tmpl.module.foo.catch_varargs |
| 438 | assert tmpl.module.bar.arguments == () |
| 439 | assert not tmpl.module.bar.caller |
| 440 | assert tmpl.module.bar.catch_kwargs |
| 441 | assert tmpl.module.bar.catch_varargs |
| 442 | assert tmpl.module.baz.caller |
| 443 | |
| 444 | def test_callself(self, env_trim): |
| 445 | tmpl = env_trim.from_string( |
| 446 | "{% macro foo(x) %}{{ x }}{% if x > 1 %}|" |
| 447 | "{{ foo(x - 1) }}{% endif %}{% endmacro %}" |
| 448 | "{{ foo(5) }}" |
| 449 | ) |
| 450 | assert tmpl.render() == "5|4|3|2|1" |
| 451 | |
| 452 | def test_macro_defaults_self_ref(self, env): |
| 453 | tmpl = env.from_string( |
| 454 | """ |
| 455 | {%- set x = 42 %} |
| 456 | {%- macro m(a, b=x, x=23) %}{{ a }}|{{ b }}|{{ x }}{% endmacro -%} |
| 457 | """ |
| 458 | ) |
| 459 | assert tmpl.module.m(1) == "1||23" |
| 460 | assert tmpl.module.m(1, 2) == "1|2|23" |
| 461 | assert tmpl.module.m(1, 2, 3) == "1|2|3" |
| 462 | assert tmpl.module.m(1, x=7) == "1|7|7" |
| 463 | |
| 464 | |
| 465 | class TestSet: |
| 466 | def test_normal(self, env_trim): |
| 467 | tmpl = env_trim.from_string("{% set foo = 1 %}{{ foo }}") |
| 468 | assert tmpl.render() == "1" |
| 469 | assert tmpl.module.foo == 1 |
| 470 | |
| 471 | def test_block(self, env_trim): |
| 472 | tmpl = env_trim.from_string("{% set foo %}42{% endset %}{{ foo }}") |
| 473 | assert tmpl.render() == "42" |
| 474 | assert tmpl.module.foo == "42" |
| 475 | |
| 476 | def test_block_escaping(self): |
| 477 | env = Environment(autoescape=True) |
| 478 | tmpl = env.from_string( |
| 479 | "{% set foo %}<em>{{ test }}</em>{% endset %}foo: {{ foo }}" |
| 480 | ) |
| 481 | assert tmpl.render(test="<unsafe>") == "foo: <em><unsafe></em>" |
| 482 | |
| 483 | def test_set_invalid(self, env_trim): |
| 484 | pytest.raises( |
| 485 | TemplateSyntaxError, env_trim.from_string, "{% set foo['bar'] = 1 %}" |
| 486 | ) |
| 487 | tmpl = env_trim.from_string("{% set foo.bar = 1 %}") |
| 488 | exc_info = pytest.raises(TemplateRuntimeError, tmpl.render, foo={}) |
| 489 | assert "non-namespace object" in exc_info.value.message |
| 490 | |
| 491 | def test_namespace_redefined(self, env_trim): |
| 492 | tmpl = env_trim.from_string("{% set ns = namespace() %}{% set ns.bar = 'hi' %}") |
| 493 | exc_info = pytest.raises(TemplateRuntimeError, tmpl.render, namespace=dict) |
| 494 | assert "non-namespace object" in exc_info.value.message |
| 495 | |
| 496 | def test_namespace(self, env_trim): |
| 497 | tmpl = env_trim.from_string( |
| 498 | "{% set ns = namespace() %}{% set ns.bar = '42' %}{{ ns.bar }}" |
| 499 | ) |
| 500 | assert tmpl.render() == "42" |
| 501 | |
| 502 | def test_namespace_block(self, env_trim): |
| 503 | tmpl = env_trim.from_string( |
| 504 | "{% set ns = namespace() %}{% set ns.bar %}42{% endset %}{{ ns.bar }}" |
| 505 | ) |
| 506 | assert tmpl.render() == "42" |
| 507 | |
| 508 | def test_init_namespace(self, env_trim): |
| 509 | tmpl = env_trim.from_string( |
| 510 | "{% set ns = namespace(d, self=37) %}" |
| 511 | "{% set ns.b = 42 %}" |
| 512 | "{{ ns.a }}|{{ ns.self }}|{{ ns.b }}" |
| 513 | ) |
| 514 | assert tmpl.render(d={"a": 13}) == "13|37|42" |
| 515 | |
| 516 | def test_namespace_loop(self, env_trim): |
| 517 | tmpl = env_trim.from_string( |
| 518 | "{% set ns = namespace(found=false) %}" |
| 519 | "{% for x in range(4) %}" |
| 520 | "{% if x == v %}" |
| 521 | "{% set ns.found = true %}" |
| 522 | "{% endif %}" |
| 523 | "{% endfor %}" |
| 524 | "{{ ns.found }}" |
| 525 | ) |
| 526 | assert tmpl.render(v=3) == "True" |
| 527 | assert tmpl.render(v=4) == "False" |
| 528 | |
| 529 | def test_namespace_macro(self, env_trim): |
| 530 | tmpl = env_trim.from_string( |
| 531 | "{% set ns = namespace() %}" |
| 532 | "{% set ns.a = 13 %}" |
| 533 | "{% macro magic(x) %}" |
| 534 | "{% set x.b = 37 %}" |
| 535 | "{% endmacro %}" |
| 536 | "{{ magic(ns) }}" |
| 537 | "{{ ns.a }}|{{ ns.b }}" |
| 538 | ) |
| 539 | assert tmpl.render() == "13|37" |
| 540 | |
| 541 | def test_block_escaping_filtered(self): |
| 542 | env = Environment(autoescape=True) |
| 543 | tmpl = env.from_string( |
| 544 | "{% set foo | trim %}<em>{{ test }}</em> {% endset %}foo: {{ foo }}" |
| 545 | ) |
| 546 | assert tmpl.render(test="<unsafe>") == "foo: <em><unsafe></em>" |
| 547 | |
| 548 | def test_block_filtered(self, env_trim): |
| 549 | tmpl = env_trim.from_string( |
| 550 | "{% set foo | trim | length | string %} 42 {% endset %}{{ foo }}" |
| 551 | ) |
| 552 | assert tmpl.render() == "2" |
| 553 | assert tmpl.module.foo == "2" |
| 554 | |
| 555 | def test_block_filtered_set(self, env_trim): |
| 556 | def _myfilter(val, arg): |
| 557 | assert arg == " xxx " |
| 558 | return val |
| 559 | |
| 560 | env_trim.filters["myfilter"] = _myfilter |
| 561 | tmpl = env_trim.from_string( |
| 562 | '{% set a = " xxx " %}' |
| 563 | "{% set foo | myfilter(a) | trim | length | string %}" |
| 564 | ' {% set b = " yy " %} 42 {{ a }}{{ b }} ' |
| 565 | "{% endset %}" |
| 566 | "{{ foo }}" |
| 567 | ) |
| 568 | assert tmpl.render() == "11" |
| 569 | assert tmpl.module.foo == "11" |
| 570 | |
| 571 | |
| 572 | class TestWith: |
| 573 | def test_with(self, env): |
| 574 | tmpl = env.from_string( |
| 575 | """\ |
| 576 | {% with a=42, b=23 -%} |
| 577 | {{ a }} = {{ b }} |
| 578 | {% endwith -%} |
| 579 | {{ a }} = {{ b }}\ |
| 580 | """ |
| 581 | ) |
| 582 | assert [x.strip() for x in tmpl.render(a=1, b=2).splitlines()] == [ |
| 583 | "42 = 23", |
| 584 | "1 = 2", |
| 585 | ] |
| 586 | |
| 587 | def test_with_argument_scoping(self, env): |
| 588 | tmpl = env.from_string( |
| 589 | """\ |
| 590 | {%- with a=1, b=2, c=b, d=e, e=5 -%} |
| 591 | {{ a }}|{{ b }}|{{ c }}|{{ d }}|{{ e }} |
| 592 | {%- endwith -%} |
| 593 | """ |
| 594 | ) |
| 595 | assert tmpl.render(b=3, e=4) == "1|2|3|4|5" |