1from mako.template import Template 2from mako.testing.assertions import eq_ 3from mako.testing.fixtures import TemplateTest 4from mako.testing.helpers import flatten_result 5from mako.testing.helpers import result_lines 6 7 8class CallTest(TemplateTest): 9 def test_call(self): 10 t = Template( 11 """ 12 <%def name="foo()"> 13 hi im foo ${caller.body(y=5)} 14 </%def> 15 16 <%call expr="foo()" args="y, **kwargs"> 17 this is the body, y is ${y} 18 </%call> 19""" 20 ) 21 assert result_lines(t.render()) == [ 22 "hi im foo", 23 "this is the body, y is 5", 24 ] 25 26 def test_compound_call(self): 27 t = Template( 28 """ 29 30 <%def name="bar()"> 31 this is bar 32 </%def> 33 34 <%def name="comp1()"> 35 this comp1 should not be called 36 </%def> 37 38 <%def name="foo()"> 39 foo calling comp1: ${caller.comp1(x=5)} 40 foo calling body: ${caller.body()} 41 </%def> 42 43 <%call expr="foo()"> 44 <%def name="comp1(x)"> 45 this is comp1, ${x} 46 </%def> 47 this is the body, ${comp1(6)} 48 </%call> 49 ${bar()} 50 51""" 52 ) 53 assert result_lines(t.render()) == [ 54 "foo calling comp1:", 55 "this is comp1, 5", 56 "foo calling body:", 57 "this is the body,", 58 "this is comp1, 6", 59 "this is bar", 60 ] 61 62 def test_new_syntax(self): 63 """test foo:bar syntax, including multiline args and expression 64 eval.""" 65 66 # note the trailing whitespace in the bottom ${} expr, need to strip 67 # that off < python 2.7 68 69 t = Template( 70 """ 71 <%def name="foo(x, y, q, z)"> 72 ${x} 73 ${y} 74 ${q} 75 ${",".join("%s->%s" % (a, b) for a, b in z)} 76 </%def> 77 78 <%self:foo x="this is x" y="${'some ' + 'y'}" q=" 79 this 80 is 81 q" 82 83 z="${[ 84 (1, 2), 85 (3, 4), 86 (5, 6) 87 ] 88 89 }"/> 90 """ 91 ) 92 93 eq_( 94 result_lines(t.render()), 95 ["this is x", "some y", "this", "is", "q", "1->2,3->4,5->6"], 96 ) 97 98 def test_ccall_caller(self): 99 t = Template( 100 """ 101 <%def name="outer_func()"> 102 OUTER BEGIN 103 <%call expr="caller.inner_func()"> 104 INNER CALL 105 </%call> 106 OUTER END 107 </%def> 108 109 <%call expr="outer_func()"> 110 <%def name="inner_func()"> 111 INNER BEGIN 112 ${caller.body()} 113 INNER END 114 </%def> 115 </%call> 116 117 """ 118 ) 119 # print t.code 120 assert result_lines(t.render()) == [ 121 "OUTER BEGIN", 122 "INNER BEGIN", 123 "INNER CALL", 124 "INNER END", 125 "OUTER END", 126 ] 127 128 def test_stack_pop(self): 129 t = Template( 130 """ 131 <%def name="links()" buffered="True"> 132 Some links 133 </%def> 134 135 <%def name="wrapper(links)"> 136 <h1>${caller.body()}</h1> 137 ${links} 138 </%def> 139 140 ## links() pushes a stack frame on. when complete, 141 ## 'nextcaller' must be restored 142 <%call expr="wrapper(links())"> 143 Some title 144 </%call> 145 146 """ 147 ) 148 149 assert result_lines(t.render()) == [ 150 "<h1>", 151 "Some title", 152 "</h1>", 153 "Some links", 154 ] 155 156 def test_conditional_call(self): 157 """test that 'caller' is non-None only if the immediate <%def> was 158 called via <%call>""" 159 160 t = Template( 161 """ 162 <%def name="a()"> 163 % if caller: 164 ${ caller.body() } \\ 165 % endif 166 AAA 167 ${ b() } 168 </%def> 169 170 <%def name="b()"> 171 % if caller: 172 ${ caller.body() } \\ 173 % endif 174 BBB 175 ${ c() } 176 </%def> 177 178 <%def name="c()"> 179 % if caller: 180 ${ caller.body() } \\ 181 % endif 182 CCC 183 </%def> 184 185 <%call expr="a()"> 186 CALL 187 </%call> 188 189 """ 190 ) 191 assert result_lines(t.render()) == ["CALL", "AAA", "BBB", "CCC"] 192 193 def test_chained_call(self): 194 """test %calls that are chained through their targets""" 195 t = Template( 196 """ 197 <%def name="a()"> 198 this is a. 199 <%call expr="b()"> 200 this is a's ccall. heres my body: ${caller.body()} 201 </%call> 202 </%def> 203 <%def name="b()"> 204 this is b. heres my body: ${caller.body()} 205 whats in the body's caller's body ? 206 ${context.caller_stack[-2].body()} 207 </%def> 208 209 <%call expr="a()"> 210 heres the main templ call 211 </%call> 212 213""" 214 ) 215 assert result_lines(t.render()) == [ 216 "this is a.", 217 "this is b. heres my body:", 218 "this is a's ccall. heres my body:", 219 "heres the main templ call", 220 "whats in the body's caller's body ?", 221 "heres the main templ call", 222 ] 223 224 def test_nested_call(self): 225 """test %calls that are nested inside each other""" 226 t = Template( 227 """ 228 <%def name="foo()"> 229 ${caller.body(x=10)} 230 </%def> 231 232 x is ${x} 233 <%def name="bar()"> 234 bar: ${caller.body()} 235 </%def> 236 237 <%call expr="foo()" args="x"> 238 this is foo body: ${x} 239 240 <%call expr="bar()"> 241 this is bar body: ${x} 242 </%call> 243 </%call> 244""" 245 ) 246 assert result_lines(t.render(x=5)) == [ 247 "x is 5", 248 "this is foo body: 10", 249 "bar:", 250 "this is bar body: 10", 251 ] 252 253 def test_nested_call_2(self): 254 t = Template( 255 """ 256 x is ${x} 257 <%def name="foo()"> 258 ${caller.foosub(x=10)} 259 </%def> 260 261 <%def name="bar()"> 262 bar: ${caller.barsub()} 263 </%def> 264 265 <%call expr="foo()"> 266 <%def name="foosub(x)"> 267 this is foo body: ${x} 268 269 <%call expr="bar()"> 270 <%def name="barsub()"> 271 this is bar body: ${x} 272 </%def> 273 </%call> 274 275 </%def> 276 277 </%call> 278""" 279 ) 280 assert result_lines(t.render(x=5)) == [ 281 "x is 5", 282 "this is foo body: 10", 283 "bar:", 284 "this is bar body: 10", 285 ] 286 287 def test_nested_call_3(self): 288 template = Template( 289 """\ 290 <%def name="A()"> 291 ${caller.body()} 292 </%def> 293 294 <%def name="B()"> 295 ${caller.foo()} 296 </%def> 297 298 <%call expr="A()"> 299 <%call expr="B()"> 300 <%def name="foo()"> 301 foo 302 </%def> 303 </%call> 304 </%call> 305 306 """ 307 ) 308 assert flatten_result(template.render()) == "foo" 309 310 def test_nested_call_4(self): 311 base = """ 312 <%def name="A()"> 313 A_def 314 ${caller.body()} 315 </%def> 316 317 <%def name="B()"> 318 B_def 319 ${caller.body()} 320 </%def> 321 """ 322 323 template = Template( 324 base 325 + """ 326 <%def name="C()"> 327 C_def 328 <%self:B> 329 <%self:A> 330 A_body 331 </%self:A> 332 B_body 333 ${caller.body()} 334 </%self:B> 335 </%def> 336 337 <%self:C> 338 C_body 339 </%self:C> 340 """ 341 ) 342 343 eq_( 344 flatten_result(template.render()), 345 "C_def B_def A_def A_body B_body C_body", 346 ) 347 348 template = Template( 349 base 350 + """ 351 <%def name="C()"> 352 C_def 353 <%self:B> 354 B_body 355 ${caller.body()} 356 <%self:A> 357 A_body 358 </%self:A> 359 </%self:B> 360 </%def> 361 362 <%self:C> 363 C_body 364 </%self:C> 365 """ 366 ) 367 368 eq_( 369 flatten_result(template.render()), 370 "C_def B_def B_body C_body A_def A_body", 371 ) 372 373 def test_chained_call_in_nested(self): 374 t = Template( 375 """ 376 <%def name="embedded()"> 377 <%def name="a()"> 378 this is a. 379 <%call expr="b()"> 380 this is a's ccall. heres my body: ${caller.body()} 381 </%call> 382 </%def> 383 <%def name="b()"> 384 this is b. heres my body: ${caller.body()} 385 whats in the body's caller's body ? """ 386 """${context.caller_stack[-2].body()} 387 </%def> 388 389 <%call expr="a()"> 390 heres the main templ call 391 </%call> 392 </%def> 393 ${embedded()} 394""" 395 ) 396 # print t.code 397 # print result_lines(t.render()) 398 assert result_lines(t.render()) == [ 399 "this is a.", 400 "this is b. heres my body:", 401 "this is a's ccall. heres my body:", 402 "heres the main templ call", 403 "whats in the body's caller's body ?", 404 "heres the main templ call", 405 ] 406 407 def test_call_in_nested(self): 408 t = Template( 409 """ 410 <%def name="a()"> 411 this is a ${b()} 412 <%def name="b()"> 413 this is b 414 <%call expr="c()"> 415 this is the body in b's call 416 </%call> 417 </%def> 418 <%def name="c()"> 419 this is c: ${caller.body()} 420 </%def> 421 </%def> 422 ${a()} 423""" 424 ) 425 assert result_lines(t.render()) == [ 426 "this is a", 427 "this is b", 428 "this is c:", 429 "this is the body in b's call", 430 ] 431 432 def test_composed_def(self): 433 t = Template( 434 """ 435 <%def name="f()"><f>${caller.body()}</f></%def> 436 <%def name="g()"><g>${caller.body()}</g></%def> 437 <%def name="fg()"> 438 <%self:f><%self:g>${caller.body()}</%self:g></%self:f> 439 </%def> 440 <%self:fg>fgbody</%self:fg> 441 """ 442 ) 443 assert result_lines(t.render()) == ["<f><g>fgbody</g></f>"] 444 445 def test_regular_defs(self): 446 t = Template( 447 """ 448 <%! 449 @runtime.supports_caller 450 def a(context): 451 context.write("this is a") 452 if context['caller']: 453 context['caller'].body() 454 context.write("a is done") 455 return '' 456 %> 457 458 <%def name="b()"> 459 this is b 460 our body: ${caller.body()} 461 ${a(context)} 462 </%def> 463 test 1 464 <%call expr="a(context)"> 465 this is the body 466 </%call> 467 test 2 468 <%call expr="b()"> 469 this is the body 470 </%call> 471 test 3 472 <%call expr="b()"> 473 this is the body 474 <%call expr="b()"> 475 this is the nested body 476 </%call> 477 </%call> 478 479 480 """ 481 ) 482 assert result_lines(t.render()) == [ 483 "test 1", 484 "this is a", 485 "this is the body", 486 "a is done", 487 "test 2", 488 "this is b", 489 "our body:", 490 "this is the body", 491 "this is aa is done", 492 "test 3", 493 "this is b", 494 "our body:", 495 "this is the body", 496 "this is b", 497 "our body:", 498 "this is the nested body", 499 "this is aa is done", 500 "this is aa is done", 501 ] 502 503 def test_call_in_nested_2(self): 504 t = Template( 505 """ 506 <%def name="a()"> 507 <%def name="d()"> 508 not this d 509 </%def> 510 this is a ${b()} 511 <%def name="b()"> 512 <%def name="d()"> 513 not this d either 514 </%def> 515 this is b 516 <%call expr="c()"> 517 <%def name="d()"> 518 this is d 519 </%def> 520 this is the body in b's call 521 </%call> 522 </%def> 523 <%def name="c()"> 524 this is c: ${caller.body()} 525 the embedded "d" is: ${caller.d()} 526 </%def> 527 </%def> 528 ${a()} 529""" 530 ) 531 assert result_lines(t.render()) == [ 532 "this is a", 533 "this is b", 534 "this is c:", 535 "this is the body in b's call", 536 'the embedded "d" is:', 537 "this is d", 538 ] 539 540 541class SelfCacheTest(TemplateTest): 542 """this test uses a now non-public API.""" 543 544 def test_basic(self): 545 t = Template( 546 """ 547 <%! 548 cached = None 549 %> 550 <%def name="foo()"> 551 <% 552 global cached 553 if cached: 554 return "cached: " + cached 555 __M_writer = context._push_writer() 556 %> 557 this is foo 558 <% 559 buf, __M_writer = context._pop_buffer_and_writer() 560 cached = buf.getvalue() 561 return cached 562 %> 563 </%def> 564 565 ${foo()} 566 ${foo()} 567""" 568 ) 569 assert result_lines(t.render()) == [ 570 "this is foo", 571 "cached:", 572 "this is foo", 573 ] 574