1# -*- coding: utf-8 -*- 2 3import os 4import unittest 5 6from mako import compat 7from mako import exceptions 8from mako import runtime 9from mako import util 10from mako.compat import u 11from mako.ext.preprocessors import convert_comments 12from mako.lookup import TemplateLookup 13from mako.template import ModuleInfo 14from mako.template import ModuleTemplate 15from mako.template import Template 16from test import assert_raises 17from test import assert_raises_message 18from test import eq_ 19from test import module_base 20from test import requires_python_2 21from test import template_base 22from test import TemplateTest 23from test.util import flatten_result 24from test.util import result_lines 25 26 27class ctx(object): 28 def __init__(self, a, b): 29 pass 30 31 def __enter__(self): 32 return self 33 34 def __exit__(self, *arg): 35 pass 36 37 38class EncodingTest(TemplateTest): 39 def test_escapes_html_tags(self): 40 from mako.exceptions import html_error_template 41 42 x = Template( 43 """ 44 X: 45 <% raise Exception('<span style="color:red">Foobar</span>') %> 46 """ 47 ) 48 49 try: 50 x.render() 51 except: 52 # <h3>Exception: <span style="color:red">Foobar</span></h3> 53 markup = html_error_template().render(full=False, css=False) 54 if compat.py3k: 55 assert ( 56 '<span style="color:red">Foobar</span></h3>'.encode( 57 "ascii" 58 ) 59 not in markup 60 ) 61 assert ( 62 "<span style="color:red"" 63 ">Foobar</span>".encode("ascii") in markup 64 ) 65 else: 66 assert ( 67 '<span style="color:red">Foobar</span></h3>' not in markup 68 ) 69 assert ( 70 "<span style="color:red"" 71 ">Foobar</span>" in markup 72 ) 73 74 def test_unicode(self): 75 self._do_memory_test( 76 u( 77 "Alors vous imaginez ma surprise, au lever du jour, quand " 78 "une drôle de petite voix m’a réveillé. Elle disait: " 79 "« S’il vous plaît… dessine-moi un mouton! »" 80 ), 81 u( 82 "Alors vous imaginez ma surprise, au lever du jour, quand " 83 "une drôle de petite voix m’a réveillé. Elle disait: " 84 "« S’il vous plaît… dessine-moi un mouton! »" 85 ), 86 ) 87 88 def test_encoding_doesnt_conflict(self): 89 self._do_memory_test( 90 u( 91 "Alors vous imaginez ma surprise, au lever du jour, quand " 92 "une drôle de petite voix m’a réveillé. Elle disait: " 93 "« S’il vous plaît… dessine-moi un mouton! »" 94 ), 95 u( 96 "Alors vous imaginez ma surprise, au lever du jour, quand " 97 "une drôle de petite voix m’a réveillé. Elle disait: " 98 "« S’il vous plaît… dessine-moi un mouton! »" 99 ), 100 output_encoding="utf-8", 101 ) 102 103 def test_unicode_arg(self): 104 val = u( 105 "Alors vous imaginez ma surprise, au lever du jour, quand " 106 "une drôle de petite voix m’a réveillé. Elle disait: " 107 "« S’il vous plaît… dessine-moi un mouton! »" 108 ) 109 self._do_memory_test( 110 "${val}", 111 u( 112 "Alors vous imaginez ma surprise, au lever du jour, quand " 113 "une drôle de petite voix m’a réveillé. Elle disait: " 114 "« S’il vous plaît… dessine-moi un mouton! »" 115 ), 116 template_args={"val": val}, 117 ) 118 119 def test_unicode_file(self): 120 self._do_file_test( 121 "unicode.html", 122 u( 123 "Alors vous imaginez ma surprise, au lever du jour, quand " 124 "une drôle de petite voix m’a réveillé. Elle disait: " 125 "« S’il vous plaît… dessine-moi un mouton! »" 126 ), 127 ) 128 129 def test_unicode_file_code(self): 130 self._do_file_test( 131 "unicode_code.html", 132 u("""hi, drôle de petite voix m’a réveillé."""), 133 filters=flatten_result, 134 ) 135 136 def test_unicode_file_lookup(self): 137 lookup = TemplateLookup( 138 directories=[template_base], 139 output_encoding="utf-8", 140 default_filters=["decode.utf8"], 141 ) 142 if compat.py3k: 143 template = lookup.get_template("/chs_unicode_py3k.html") 144 else: 145 template = lookup.get_template("/chs_unicode.html") 146 eq_( 147 flatten_result(template.render_unicode(name="毛泽东")), 148 u("毛泽东 是 新中国的主席<br/> Welcome 你 to 北京."), 149 ) 150 151 def test_unicode_bom(self): 152 self._do_file_test( 153 "bom.html", 154 u( 155 "Alors vous imaginez ma surprise, au lever du jour, quand " 156 "une drôle de petite voix m’a réveillé. Elle disait: " 157 "« S’il vous plaît… dessine-moi un mouton! »" 158 ), 159 ) 160 161 self._do_file_test( 162 "bommagic.html", 163 u( 164 "Alors vous imaginez ma surprise, au lever du jour, quand " 165 "une drôle de petite voix m’a réveillé. Elle disait: " 166 "« S’il vous plaît… dessine-moi un mouton! »" 167 ), 168 ) 169 170 self.assertRaises( 171 exceptions.CompileException, 172 Template, 173 filename=self._file_path("badbom.html"), 174 module_directory=module_base, 175 ) 176 177 def test_unicode_memory(self): 178 val = u( 179 "Alors vous imaginez ma surprise, au lever du jour, quand " 180 "une drôle de petite voix m’a réveillé. Elle disait: " 181 "« S’il vous plaît… dessine-moi un mouton! »" 182 ) 183 self._do_memory_test( 184 ("## -*- coding: utf-8 -*-\n" + val).encode("utf-8"), 185 u( 186 "Alors vous imaginez ma surprise, au lever du jour, quand " 187 "une drôle de petite voix m’a réveillé. Elle disait: " 188 "« S’il vous plaît… dessine-moi un mouton! »" 189 ), 190 ) 191 192 def test_unicode_text(self): 193 val = u( 194 "<%text>Alors vous imaginez ma surprise, au lever du jour, quand " 195 "une drôle de petite voix m’a réveillé. Elle disait: " 196 "« S’il vous plaît… dessine-moi un mouton! »</%text>" 197 ) 198 self._do_memory_test( 199 ("## -*- coding: utf-8 -*-\n" + val).encode("utf-8"), 200 u( 201 "Alors vous imaginez ma surprise, au lever du jour, quand " 202 "une drôle de petite voix m’a réveillé. Elle disait: " 203 "« S’il vous plaît… dessine-moi un mouton! »" 204 ), 205 ) 206 207 def test_unicode_text_ccall(self): 208 val = u( 209 """ 210 <%def name="foo()"> 211 ${capture(caller.body)} 212 </%def> 213 <%call expr="foo()"> 214 <%text>Alors vous imaginez ma surprise, au lever du jour, 215quand une drôle de petite voix m’a réveillé. Elle disait: 216« S’il vous plaît… dessine-moi un mouton! »</%text> 217 </%call>""" 218 ) 219 self._do_memory_test( 220 ("## -*- coding: utf-8 -*-\n" + val).encode("utf-8"), 221 u( 222 "Alors vous imaginez ma surprise, au lever du jour, quand " 223 "une drôle de petite voix m’a réveillé. Elle disait: " 224 "« S’il vous plaît… dessine-moi un mouton! »" 225 ), 226 filters=flatten_result, 227 ) 228 229 def test_unicode_literal_in_expr(self): 230 if compat.py3k: 231 self._do_memory_test( 232 u( 233 "## -*- coding: utf-8 -*-\n" 234 '${"Alors vous imaginez ma surprise, au lever du jour, ' 235 "quand une drôle de petite voix m’a réveillé. " 236 "Elle disait: " 237 '« S’il vous plaît… dessine-moi un mouton! »"}\n' 238 ).encode("utf-8"), 239 u( 240 "Alors vous imaginez ma surprise, au lever du jour, " 241 "quand une drôle de petite voix m’a réveillé. " 242 "Elle disait: « S’il vous plaît… dessine-moi un mouton! »" 243 ), 244 filters=lambda s: s.strip(), 245 ) 246 else: 247 self._do_memory_test( 248 u( 249 "## -*- coding: utf-8 -*-\n" 250 '${u"Alors vous imaginez ma surprise, au lever du jour, ' 251 "quand une drôle de petite voix m’a réveillé. " 252 "Elle disait: « S’il vous plaît… dessine-moi un " 253 'mouton! »"}' 254 ).encode("utf-8"), 255 u( 256 "Alors vous imaginez ma surprise, au lever du jour, " 257 "quand une drôle de petite voix m’a réveillé. " 258 "Elle disait: « S’il vous plaît… dessine-moi un mouton! »" 259 ), 260 filters=lambda s: s.strip(), 261 ) 262 263 def test_unicode_literal_in_expr_file(self): 264 self._do_file_test( 265 "unicode_expr.html", 266 u( 267 "Alors vous imaginez ma surprise, au lever du jour, " 268 "quand une drôle de petite voix m’a réveillé. " 269 "Elle disait: « S’il vous plaît… dessine-moi un mouton! »" 270 ), 271 lambda t: t.strip(), 272 ) 273 274 def test_unicode_literal_in_code(self): 275 if compat.py3k: 276 self._do_memory_test( 277 u( 278 """## -*- coding: utf-8 -*- 279 <% 280 context.write("Alors vous imaginez ma surprise, au """ 281 """lever du jour, quand une drôle de petite voix m’a """ 282 """réveillé. Elle disait: """ 283 """« S’il vous plaît… dessine-moi un mouton! »") 284 %> 285 """ 286 ).encode("utf-8"), 287 u( 288 "Alors vous imaginez ma surprise, au lever du jour, " 289 "quand une drôle de petite voix m’a réveillé. " 290 "Elle disait: « S’il vous plaît… dessine-moi un mouton! »" 291 ), 292 filters=lambda s: s.strip(), 293 ) 294 else: 295 self._do_memory_test( 296 u( 297 """## -*- coding: utf-8 -*- 298 <% 299 context.write(u"Alors vous imaginez ma surprise, """ 300 """au lever du jour, quand une drôle de petite voix """ 301 """m’a réveillé. Elle disait: « S’il vous plaît… """ 302 """dessine-moi un mouton! »") 303 %> 304 """ 305 ).encode("utf-8"), 306 u( 307 "Alors vous imaginez ma surprise, au lever du jour, " 308 "quand une drôle de petite voix m’a réveillé. " 309 "Elle disait: « S’il vous plaît… dessine-moi un mouton! »" 310 ), 311 filters=lambda s: s.strip(), 312 ) 313 314 def test_unicode_literal_in_controlline(self): 315 if compat.py3k: 316 self._do_memory_test( 317 u( 318 """## -*- coding: utf-8 -*- 319 <% 320 x = "drôle de petite voix m’a réveillé." 321 %> 322 % if x=="drôle de petite voix m’a réveillé.": 323 hi, ${x} 324 % endif 325 """ 326 ).encode("utf-8"), 327 u("""hi, drôle de petite voix m’a réveillé."""), 328 filters=lambda s: s.strip(), 329 ) 330 else: 331 self._do_memory_test( 332 u( 333 """## -*- coding: utf-8 -*- 334 <% 335 x = u"drôle de petite voix m’a réveillé." 336 %> 337 % if x==u"drôle de petite voix m’a réveillé.": 338 hi, ${x} 339 % endif 340 """ 341 ).encode("utf-8"), 342 u("""hi, drôle de petite voix m’a réveillé."""), 343 filters=lambda s: s.strip(), 344 ) 345 346 def test_unicode_literal_in_tag(self): 347 self._do_file_test( 348 "unicode_arguments.html", 349 [ 350 u("x is: drôle de petite voix m’a réveillé"), 351 u("x is: drôle de petite voix m’a réveillé"), 352 u("x is: drôle de petite voix m’a réveillé"), 353 u("x is: drôle de petite voix m’a réveillé"), 354 ], 355 filters=result_lines, 356 ) 357 358 self._do_memory_test( 359 util.read_file(self._file_path("unicode_arguments.html")), 360 [ 361 u("x is: drôle de petite voix m’a réveillé"), 362 u("x is: drôle de petite voix m’a réveillé"), 363 u("x is: drôle de petite voix m’a réveillé"), 364 u("x is: drôle de petite voix m’a réveillé"), 365 ], 366 filters=result_lines, 367 ) 368 369 def test_unicode_literal_in_def(self): 370 if compat.py3k: 371 self._do_memory_test( 372 u( 373 """## -*- coding: utf-8 -*- 374 <%def name="bello(foo, bar)"> 375 Foo: ${ foo } 376 Bar: ${ bar } 377 </%def> 378 <%call expr="bello(foo='árvíztűrő tükörfúrógép', """ 379 """bar='ÁRVÍZTŰRŐ TÜKÖRFÚRÓGÉP')"> 380 </%call>""" 381 ).encode("utf-8"), 382 u( 383 """Foo: árvíztűrő tükörfúrógép """ 384 """Bar: ÁRVÍZTŰRŐ TÜKÖRFÚRÓGÉP""" 385 ), 386 filters=flatten_result, 387 ) 388 389 self._do_memory_test( 390 u( 391 "## -*- coding: utf-8 -*-\n" 392 """<%def name="hello(foo='árvíztűrő tükörfúrógép', """ 393 """bar='ÁRVÍZTŰRŐ TÜKÖRFÚRÓGÉP')">\n""" 394 "Foo: ${ foo }\n" 395 "Bar: ${ bar }\n" 396 "</%def>\n" 397 "${ hello() }" 398 ).encode("utf-8"), 399 u( 400 """Foo: árvíztűrő tükörfúrógép Bar: """ 401 """ÁRVÍZTŰRŐ TÜKÖRFÚRÓGÉP""" 402 ), 403 filters=flatten_result, 404 ) 405 else: 406 self._do_memory_test( 407 u( 408 """## -*- coding: utf-8 -*- 409 <%def name="bello(foo, bar)"> 410 Foo: ${ foo } 411 Bar: ${ bar } 412 </%def> 413 <%call expr="bello(foo=u'árvíztűrő tükörfúrógép', """ 414 """bar=u'ÁRVÍZTŰRŐ TÜKÖRFÚRÓGÉP')"> 415 </%call>""" 416 ).encode("utf-8"), 417 u( 418 """Foo: árvíztűrő tükörfúrógép Bar: """ 419 """ÁRVÍZTŰRŐ TÜKÖRFÚRÓGÉP""" 420 ), 421 filters=flatten_result, 422 ) 423 424 self._do_memory_test( 425 u( 426 """## -*- coding: utf-8 -*- 427 <%def name="hello(foo=u'árvíztűrő tükörfúrógép', """ 428 """bar=u'ÁRVÍZTŰRŐ TÜKÖRFÚRÓGÉP')"> 429 Foo: ${ foo } 430 Bar: ${ bar } 431 </%def> 432 ${ hello() }""" 433 ).encode("utf-8"), 434 u( 435 """Foo: árvíztűrő tükörfúrógép Bar: """ 436 """ÁRVÍZTŰRŐ TÜKÖRFÚRÓGÉP""" 437 ), 438 filters=flatten_result, 439 ) 440 441 def test_input_encoding(self): 442 """test the 'input_encoding' flag on Template, and that unicode 443 objects arent double-decoded""" 444 445 if compat.py3k: 446 self._do_memory_test( 447 u("hello ${f('śląsk')}"), 448 u("hello śląsk"), 449 input_encoding="utf-8", 450 template_args={"f": lambda x: x}, 451 ) 452 453 self._do_memory_test( 454 u("## -*- coding: utf-8 -*-\nhello ${f('śląsk')}"), 455 u("hello śląsk"), 456 template_args={"f": lambda x: x}, 457 ) 458 else: 459 self._do_memory_test( 460 u("hello ${f(u'śląsk')}"), 461 u("hello śląsk"), 462 input_encoding="utf-8", 463 template_args={"f": lambda x: x}, 464 ) 465 466 self._do_memory_test( 467 u("## -*- coding: utf-8 -*-\nhello ${f(u'śląsk')}"), 468 u("hello śląsk"), 469 template_args={"f": lambda x: x}, 470 ) 471 472 def test_raw_strings(self): 473 """test that raw strings go straight thru with default_filters 474 turned off, bytestring_passthrough enabled. 475 476 """ 477 478 self._do_memory_test( 479 u("## -*- coding: utf-8 -*-\nhello ${x}"), 480 "hello śląsk", 481 default_filters=[], 482 template_args={"x": "śląsk"}, 483 unicode_=False, 484 bytestring_passthrough=True, 485 output_encoding=None, # 'ascii' 486 ) 487 488 # now, the way you *should* be doing it.... 489 self._do_memory_test( 490 u("## -*- coding: utf-8 -*-\nhello ${x}"), 491 u("hello śląsk"), 492 template_args={"x": u("śląsk")}, 493 ) 494 495 def test_encoding(self): 496 self._do_memory_test( 497 u( 498 "Alors vous imaginez ma surprise, au lever du jour, quand " 499 "une drôle de petite voix m’a réveillé. Elle disait: " 500 "« S’il vous plaît… dessine-moi un mouton! »" 501 ), 502 u( 503 "Alors vous imaginez ma surprise, au lever du jour, quand " 504 "une drôle de petite voix m’a réveillé. Elle disait: " 505 "« S’il vous plaît… dessine-moi un mouton! »" 506 ).encode("utf-8"), 507 output_encoding="utf-8", 508 unicode_=False, 509 ) 510 511 def test_encoding_errors(self): 512 self._do_memory_test( 513 u( 514 """KGB (transliteration of "КГБ") is the Russian-language """ 515 """abbreviation for Committee for State Security, """ 516 """(Russian: Комит́ет Госуд́арственной Безоп́асности """ 517 """(help·info); Komitet Gosudarstvennoy Bezopasnosti)""" 518 ), 519 u( 520 """KGB (transliteration of "КГБ") is the Russian-language """ 521 """abbreviation for Committee for State Security, """ 522 """(Russian: Комит́ет Госуд́арственной Безоп́асности """ 523 """(help·info); Komitet Gosudarstvennoy Bezopasnosti)""" 524 ).encode("iso-8859-1", "replace"), 525 output_encoding="iso-8859-1", 526 encoding_errors="replace", 527 unicode_=False, 528 ) 529 530 def test_read_unicode(self): 531 lookup = TemplateLookup( 532 directories=[template_base], 533 filesystem_checks=True, 534 output_encoding="utf-8", 535 ) 536 if compat.py3k: 537 template = lookup.get_template("/read_unicode_py3k.html") 538 else: 539 template = lookup.get_template("/read_unicode.html") 540 # TODO: I've no idea what encoding this file is, Python 3.1.2 541 # won't read the file even with open(...encoding='utf-8') unless 542 # errors is specified. or if there's some quirk in 3.1.2 543 # since I'm pretty sure this test worked with py3k when I wrote it. 544 template.render( 545 path=self._file_path("internationalization.html") 546 ) 547 548 @requires_python_2 549 def test_bytestring_passthru(self): 550 self._do_file_test( 551 "chs_utf8.html", 552 "毛泽东 是 新中国的主席<br/> Welcome 你 to 北京. Welcome 你 to 北京.", 553 default_filters=[], 554 disable_unicode=True, 555 output_encoding=None, 556 template_args={"name": "毛泽东"}, 557 filters=flatten_result, 558 unicode_=False, 559 ) 560 561 self._do_file_test( 562 "chs_utf8.html", 563 "毛泽东 是 新中国的主席<br/> Welcome 你 to 北京. Welcome 你 to 北京.", 564 disable_unicode=True, 565 output_encoding=None, 566 template_args={"name": "毛泽东"}, 567 filters=flatten_result, 568 unicode_=False, 569 ) 570 571 template = self._file_template( 572 "chs_utf8.html", output_encoding=None, disable_unicode=True 573 ) 574 self.assertRaises( 575 UnicodeDecodeError, template.render_unicode, name="毛泽东" 576 ) 577 578 template = Template( 579 "${'Alors vous imaginez ma surprise, au lever" 580 " du jour, quand une drôle de petite voix m’a " 581 "réveillé. Elle disait: « S’il vous plaît… " 582 "dessine-moi un mouton! »'}", 583 output_encoding=None, 584 disable_unicode=True, 585 input_encoding="utf-8", 586 ) 587 assert ( 588 template.render() == "Alors vous imaginez ma surprise, " 589 "au lever du jour, quand une drôle de petite " 590 "voix m’a réveillé. Elle disait: « S’il vous " 591 "plaît… dessine-moi un mouton! »" 592 ) 593 template = Template( 594 "${'Alors vous imaginez ma surprise, au " 595 "lever du jour, quand une drôle de petite " 596 "voix m’a réveillé. Elle disait: « S’il " 597 "vous plaît… dessine-moi un mouton! »'}", 598 input_encoding="utf8", 599 output_encoding="utf8", 600 disable_unicode=False, 601 default_filters=[], 602 ) 603 # raises because expression contains an encoded bytestring which cannot 604 # be decoded 605 self.assertRaises(UnicodeDecodeError, template.render) 606 607 608class PageArgsTest(TemplateTest): 609 def test_basic(self): 610 template = Template( 611 """ 612 <%page args="x, y, z=7"/> 613 614 this is page, ${x}, ${y}, ${z} 615""" 616 ) 617 618 assert ( 619 flatten_result(template.render(x=5, y=10)) 620 == "this is page, 5, 10, 7" 621 ) 622 assert ( 623 flatten_result(template.render(x=5, y=10, z=32)) 624 == "this is page, 5, 10, 32" 625 ) 626 assert_raises(TypeError, template.render, y=10) 627 628 def test_inherits(self): 629 lookup = TemplateLookup() 630 lookup.put_string( 631 "base.tmpl", 632 """ 633 <%page args="bar" /> 634 ${bar} 635 ${pageargs['foo']} 636 ${self.body(**pageargs)} 637 """, 638 ) 639 lookup.put_string( 640 "index.tmpl", 641 """ 642 <%inherit file="base.tmpl" /> 643 <%page args="variable" /> 644 ${variable} 645 """, 646 ) 647 648 self._do_test( 649 lookup.get_template("index.tmpl"), 650 "bar foo var", 651 filters=flatten_result, 652 template_args={"variable": "var", "bar": "bar", "foo": "foo"}, 653 ) 654 655 def test_includes(self): 656 lookup = TemplateLookup() 657 lookup.put_string( 658 "incl1.tmpl", 659 """ 660 <%page args="bar" /> 661 ${bar} 662 ${pageargs['foo']} 663 """, 664 ) 665 lookup.put_string( 666 "incl2.tmpl", 667 """ 668 ${pageargs} 669 """, 670 ) 671 lookup.put_string( 672 "index.tmpl", 673 """ 674 <%include file="incl1.tmpl" args="**pageargs"/> 675 <%page args="variable" /> 676 ${variable} 677 <%include file="incl2.tmpl" /> 678 """, 679 ) 680 681 self._do_test( 682 lookup.get_template("index.tmpl"), 683 "bar foo var {}", 684 filters=flatten_result, 685 template_args={"variable": "var", "bar": "bar", "foo": "foo"}, 686 ) 687 688 def test_context_small(self): 689 ctx = runtime.Context([].append, x=5, y=4) 690 eq_(sorted(ctx.keys()), ["caller", "capture", "x", "y"]) 691 692 def test_with_context(self): 693 template = Template( 694 """ 695 <%page args="x, y, z=7"/> 696 697 this is page, ${x}, ${y}, ${z}, ${w} 698""" 699 ) 700 # print template.code 701 assert ( 702 flatten_result(template.render(x=5, y=10, w=17)) 703 == "this is page, 5, 10, 7, 17" 704 ) 705 706 def test_overrides_builtins(self): 707 template = Template( 708 """ 709 <%page args="id"/> 710 711 this is page, id is ${id} 712 """ 713 ) 714 715 assert ( 716 flatten_result(template.render(id="im the id")) 717 == "this is page, id is im the id" 718 ) 719 720 def test_canuse_builtin_names(self): 721 template = Template( 722 """ 723 exception: ${Exception} 724 id: ${id} 725 """ 726 ) 727 assert ( 728 flatten_result( 729 template.render(id="some id", Exception="some exception") 730 ) 731 == "exception: some exception id: some id" 732 ) 733 734 def test_builtin_names_dont_clobber_defaults_in_includes(self): 735 lookup = TemplateLookup() 736 lookup.put_string( 737 "test.mako", 738 """ 739 <%include file="test1.mako"/> 740 741 """, 742 ) 743 744 lookup.put_string( 745 "test1.mako", 746 """ 747 <%page args="id='foo'"/> 748 749 ${id} 750 """, 751 ) 752 753 for template in ("test.mako", "test1.mako"): 754 assert ( 755 flatten_result(lookup.get_template(template).render()) == "foo" 756 ) 757 assert ( 758 flatten_result(lookup.get_template(template).render(id=5)) 759 == "5" 760 ) 761 assert ( 762 flatten_result(lookup.get_template(template).render(id=id)) 763 == "<built-in function id>" 764 ) 765 766 def test_dict_locals(self): 767 template = Template( 768 """ 769 <% 770 dict = "this is dict" 771 locals = "this is locals" 772 %> 773 dict: ${dict} 774 locals: ${locals} 775 """ 776 ) 777 assert ( 778 flatten_result(template.render()) 779 == "dict: this is dict locals: this is locals" 780 ) 781 782 783class IncludeTest(TemplateTest): 784 def test_basic(self): 785 lookup = TemplateLookup() 786 lookup.put_string( 787 "a", 788 """ 789 this is a 790 <%include file="b" args="a=3,b=4,c=5"/> 791 """, 792 ) 793 lookup.put_string( 794 "b", 795 """ 796 <%page args="a,b,c"/> 797 this is b. ${a}, ${b}, ${c} 798 """, 799 ) 800 assert ( 801 flatten_result(lookup.get_template("a").render()) 802 == "this is a this is b. 3, 4, 5" 803 ) 804 805 def test_localargs(self): 806 lookup = TemplateLookup() 807 lookup.put_string( 808 "a", 809 """ 810 this is a 811 <%include file="b" args="a=a,b=b,c=5"/> 812 """, 813 ) 814 lookup.put_string( 815 "b", 816 """ 817 <%page args="a,b,c"/> 818 this is b. ${a}, ${b}, ${c} 819 """, 820 ) 821 assert ( 822 flatten_result(lookup.get_template("a").render(a=7, b=8)) 823 == "this is a this is b. 7, 8, 5" 824 ) 825 826 def test_viakwargs(self): 827 lookup = TemplateLookup() 828 lookup.put_string( 829 "a", 830 """ 831 this is a 832 <%include file="b" args="c=5, **context.kwargs"/> 833 """, 834 ) 835 lookup.put_string( 836 "b", 837 """ 838 <%page args="a,b,c"/> 839 this is b. ${a}, ${b}, ${c} 840 """, 841 ) 842 # print lookup.get_template("a").code 843 assert ( 844 flatten_result(lookup.get_template("a").render(a=7, b=8)) 845 == "this is a this is b. 7, 8, 5" 846 ) 847 848 def test_include_withargs(self): 849 lookup = TemplateLookup() 850 lookup.put_string( 851 "a", 852 """ 853 this is a 854 <%include file="${i}" args="c=5, **context.kwargs"/> 855 """, 856 ) 857 lookup.put_string( 858 "b", 859 """ 860 <%page args="a,b,c"/> 861 this is b. ${a}, ${b}, ${c} 862 """, 863 ) 864 assert ( 865 flatten_result(lookup.get_template("a").render(a=7, b=8, i="b")) 866 == "this is a this is b. 7, 8, 5" 867 ) 868 869 def test_within_ccall(self): 870 lookup = TemplateLookup() 871 lookup.put_string("a", """this is a""") 872 lookup.put_string( 873 "b", 874 """ 875 <%def name="bar()"> 876 bar: ${caller.body()} 877 <%include file="a"/> 878 </%def> 879 """, 880 ) 881 lookup.put_string( 882 "c", 883 """ 884 <%namespace name="b" file="b"/> 885 <%b:bar> 886 calling bar 887 </%b:bar> 888 """, 889 ) 890 assert ( 891 flatten_result(lookup.get_template("c").render()) 892 == "bar: calling bar this is a" 893 ) 894 895 def test_include_error_handler(self): 896 def handle(context, error): 897 context.write("include error") 898 return True 899 900 lookup = TemplateLookup(include_error_handler=handle) 901 lookup.put_string( 902 "a", 903 """ 904 this is a. 905 <%include file="b"/> 906 """, 907 ) 908 lookup.put_string( 909 "b", 910 """ 911 this is b ${1/0} end. 912 """, 913 ) 914 assert ( 915 flatten_result(lookup.get_template("a").render()) 916 == "this is a. this is b include error" 917 ) 918 919 920class UndefinedVarsTest(TemplateTest): 921 def test_undefined(self): 922 t = Template( 923 """ 924 % if x is UNDEFINED: 925 undefined 926 % else: 927 x: ${x} 928 % endif 929 """ 930 ) 931 932 assert result_lines(t.render(x=12)) == ["x: 12"] 933 assert result_lines(t.render(y=12)) == ["undefined"] 934 935 def test_strict(self): 936 t = Template( 937 """ 938 % if x is UNDEFINED: 939 undefined 940 % else: 941 x: ${x} 942 % endif 943 """, 944 strict_undefined=True, 945 ) 946 947 assert result_lines(t.render(x=12)) == ["x: 12"] 948 949 assert_raises(NameError, t.render, y=12) 950 951 l = TemplateLookup(strict_undefined=True) 952 l.put_string("a", "some template") 953 l.put_string( 954 "b", 955 """ 956 <%namespace name='a' file='a' import='*'/> 957 % if x is UNDEFINED: 958 undefined 959 % else: 960 x: ${x} 961 % endif 962 """, 963 ) 964 965 assert result_lines(t.render(x=12)) == ["x: 12"] 966 967 assert_raises(NameError, t.render, y=12) 968 969 def test_expression_declared(self): 970 t = Template( 971 """ 972 ${",".join([t for t in ("a", "b", "c")])} 973 """, 974 strict_undefined=True, 975 ) 976 977 eq_(result_lines(t.render()), ["a,b,c"]) 978 979 t = Template( 980 """ 981 <%self:foo value="${[(val, n) for val, n in [(1, 2)]]}"/> 982 983 <%def name="foo(value)"> 984 ${value} 985 </%def> 986 987 """, 988 strict_undefined=True, 989 ) 990 991 eq_(result_lines(t.render()), ["[(1, 2)]"]) 992 993 t = Template( 994 """ 995 <%call expr="foo(value=[(val, n) for val, n in [(1, 2)]])" /> 996 997 <%def name="foo(value)"> 998 ${value} 999 </%def> 1000 1001 """, 1002 strict_undefined=True, 1003 ) 1004 1005 eq_(result_lines(t.render()), ["[(1, 2)]"]) 1006 1007 l = TemplateLookup(strict_undefined=True) 1008 l.put_string("i", "hi, ${pageargs['y']}") 1009 l.put_string( 1010 "t", 1011 """ 1012 <%include file="i" args="y=[x for x in range(3)]" /> 1013 """, 1014 ) 1015 eq_(result_lines(l.get_template("t").render()), ["hi, [0, 1, 2]"]) 1016 1017 l.put_string( 1018 "q", 1019 """ 1020 <%namespace name="i" file="${(str([x for x in range(3)][2]) + """ 1021 """'i')[-1]}" /> 1022 ${i.body(y='x')} 1023 """, 1024 ) 1025 eq_(result_lines(l.get_template("q").render()), ["hi, x"]) 1026 1027 t = Template( 1028 """ 1029 <% 1030 y = lambda q: str(q) 1031 %> 1032 ${y('hi')} 1033 """, 1034 strict_undefined=True, 1035 ) 1036 eq_(result_lines(t.render()), ["hi"]) 1037 1038 def test_list_comprehensions_plus_undeclared_nonstrict(self): 1039 # traditional behavior. variable inside a list comprehension 1040 # is treated as an "undefined", so is pulled from the context. 1041 t = Template( 1042 """ 1043 t is: ${t} 1044 1045 ${",".join([t for t in ("a", "b", "c")])} 1046 """ 1047 ) 1048 1049 eq_(result_lines(t.render(t="T")), ["t is: T", "a,b,c"]) 1050 1051 def test_traditional_assignment_plus_undeclared(self): 1052 t = Template( 1053 """ 1054 t is: ${t} 1055 1056 <% 1057 t = 12 1058 %> 1059 """ 1060 ) 1061 assert_raises(UnboundLocalError, t.render, t="T") 1062 1063 def test_list_comprehensions_plus_undeclared_strict(self): 1064 # with strict, a list comprehension now behaves 1065 # like the undeclared case above. 1066 t = Template( 1067 """ 1068 t is: ${t} 1069 1070 ${",".join([t for t in ("a", "b", "c")])} 1071 """, 1072 strict_undefined=True, 1073 ) 1074 1075 eq_(result_lines(t.render(t="T")), ["t is: T", "a,b,c"]) 1076 1077 1078class StopRenderingTest(TemplateTest): 1079 def test_return_in_template(self): 1080 t = Template( 1081 """ 1082 Line one 1083 <% return STOP_RENDERING %> 1084 Line Three 1085 """, 1086 strict_undefined=True, 1087 ) 1088 1089 eq_(result_lines(t.render()), ["Line one"]) 1090 1091 1092class ReservedNameTest(TemplateTest): 1093 def test_names_on_context(self): 1094 for name in ("context", "loop", "UNDEFINED", "STOP_RENDERING"): 1095 assert_raises_message( 1096 exceptions.NameConflictError, 1097 r"Reserved words passed to render\(\): %s" % name, 1098 Template("x").render, 1099 **{name: "foo"} 1100 ) 1101 1102 def test_names_in_template(self): 1103 for name in ("context", "loop", "UNDEFINED", "STOP_RENDERING"): 1104 assert_raises_message( 1105 exceptions.NameConflictError, 1106 r"Reserved words declared in template: %s" % name, 1107 Template, 1108 "<%% %s = 5 %%>" % name, 1109 ) 1110 1111 def test_exclude_loop_context(self): 1112 self._do_memory_test( 1113 "loop is ${loop}", 1114 "loop is 5", 1115 template_args=dict(loop=5), 1116 enable_loop=False, 1117 ) 1118 1119 def test_exclude_loop_template(self): 1120 self._do_memory_test( 1121 "<% loop = 12 %>loop is ${loop}", "loop is 12", enable_loop=False 1122 ) 1123 1124 1125class ControlTest(TemplateTest): 1126 def test_control(self): 1127 t = Template( 1128 """ 1129 ## this is a template. 1130 % for x in y: 1131 % if 'test' in x: 1132 yes x has test 1133 % else: 1134 no x does not have test 1135 %endif 1136 %endfor 1137""" 1138 ) 1139 assert result_lines( 1140 t.render( 1141 y=[ 1142 {"test": "one"}, 1143 {"foo": "bar"}, 1144 {"foo": "bar", "test": "two"}, 1145 ] 1146 ) 1147 ) == ["yes x has test", "no x does not have test", "yes x has test"] 1148 1149 def test_blank_control_1(self): 1150 self._do_memory_test( 1151 """ 1152 % if True: 1153 % endif 1154 """, 1155 "", 1156 filters=lambda s: s.strip(), 1157 ) 1158 1159 def test_blank_control_2(self): 1160 self._do_memory_test( 1161 """ 1162 % if True: 1163 % elif True: 1164 % endif 1165 """, 1166 "", 1167 filters=lambda s: s.strip(), 1168 ) 1169 1170 def test_blank_control_3(self): 1171 self._do_memory_test( 1172 """ 1173 % if True: 1174 % else: 1175 % endif 1176 """, 1177 "", 1178 filters=lambda s: s.strip(), 1179 ) 1180 1181 def test_blank_control_4(self): 1182 self._do_memory_test( 1183 """ 1184 % if True: 1185 % elif True: 1186 % else: 1187 % endif 1188 """, 1189 "", 1190 filters=lambda s: s.strip(), 1191 ) 1192 1193 def test_blank_control_5(self): 1194 self._do_memory_test( 1195 """ 1196 % for x in range(10): 1197 % endfor 1198 """, 1199 "", 1200 filters=lambda s: s.strip(), 1201 ) 1202 1203 def test_blank_control_6(self): 1204 self._do_memory_test( 1205 """ 1206 % while False: 1207 % endwhile 1208 """, 1209 "", 1210 filters=lambda s: s.strip(), 1211 ) 1212 1213 def test_blank_control_7(self): 1214 self._do_memory_test( 1215 """ 1216 % try: 1217 % except: 1218 % endtry 1219 """, 1220 "", 1221 filters=lambda s: s.strip(), 1222 ) 1223 1224 def test_blank_control_8(self): 1225 self._do_memory_test( 1226 """ 1227 % with ctx('x', 'w') as fp: 1228 % endwith 1229 """, 1230 "", 1231 filters=lambda s: s.strip(), 1232 template_args={"ctx": ctx}, 1233 ) 1234 1235 def test_commented_blank_control_1(self): 1236 self._do_memory_test( 1237 """ 1238 % if True: 1239 ## comment 1240 % endif 1241 """, 1242 "", 1243 filters=lambda s: s.strip(), 1244 ) 1245 1246 def test_commented_blank_control_2(self): 1247 self._do_memory_test( 1248 """ 1249 % if True: 1250 ## comment 1251 % elif True: 1252 ## comment 1253 % endif 1254 """, 1255 "", 1256 filters=lambda s: s.strip(), 1257 ) 1258 1259 def test_commented_blank_control_3(self): 1260 self._do_memory_test( 1261 """ 1262 % if True: 1263 ## comment 1264 % else: 1265 ## comment 1266 % endif 1267 """, 1268 "", 1269 filters=lambda s: s.strip(), 1270 ) 1271 1272 def test_commented_blank_control_4(self): 1273 self._do_memory_test( 1274 """ 1275 % if True: 1276 ## comment 1277 % elif True: 1278 ## comment 1279 % else: 1280 ## comment 1281 % endif 1282 """, 1283 "", 1284 filters=lambda s: s.strip(), 1285 ) 1286 1287 def test_commented_blank_control_5(self): 1288 self._do_memory_test( 1289 """ 1290 % for x in range(10): 1291 ## comment 1292 % endfor 1293 """, 1294 "", 1295 filters=lambda s: s.strip(), 1296 ) 1297 1298 def test_commented_blank_control_6(self): 1299 self._do_memory_test( 1300 """ 1301 % while False: 1302 ## comment 1303 % endwhile 1304 """, 1305 "", 1306 filters=lambda s: s.strip(), 1307 ) 1308 1309 def test_commented_blank_control_7(self): 1310 self._do_memory_test( 1311 """ 1312 % try: 1313 ## comment 1314 % except: 1315 ## comment 1316 % endtry 1317 """, 1318 "", 1319 filters=lambda s: s.strip(), 1320 ) 1321 1322 def test_commented_blank_control_8(self): 1323 self._do_memory_test( 1324 """ 1325 % with ctx('x', 'w') as fp: 1326 ## comment 1327 % endwith 1328 """, 1329 "", 1330 filters=lambda s: s.strip(), 1331 template_args={"ctx": ctx}, 1332 ) 1333 1334 def test_multiline_control(self): 1335 t = Template( 1336 """ 1337 % for x in \\ 1338 [y for y in [1,2,3]]: 1339 ${x} 1340 % endfor 1341""" 1342 ) 1343 # print t.code 1344 assert flatten_result(t.render()) == "1 2 3" 1345 1346 1347class GlobalsTest(TemplateTest): 1348 def test_globals(self): 1349 self._do_memory_test( 1350 """ 1351 <%! 1352 y = "hi" 1353 %> 1354 y is ${y} 1355 """, 1356 "y is hi", 1357 filters=lambda t: t.strip(), 1358 ) 1359 1360 1361class RichTracebackTest(TemplateTest): 1362 def _do_test_traceback(self, utf8, memory, syntax): 1363 if memory: 1364 if syntax: 1365 source = u( 1366 '## coding: utf-8\n<% print "m’a réveillé. ' 1367 "Elle disait: « S’il vous plaît… dessine-moi " 1368 "un mouton! » %>" 1369 ) 1370 else: 1371 source = u( 1372 '## coding: utf-8\n<% print u"m’a réveillé. ' 1373 "Elle disait: « S’il vous plaît… dessine-moi un " 1374 'mouton! »" + str(5/0) %>' 1375 ) 1376 if utf8: 1377 source = source.encode("utf-8") 1378 else: 1379 source = source 1380 templateargs = {"text": source} 1381 else: 1382 if syntax: 1383 filename = "unicode_syntax_error.html" 1384 else: 1385 filename = "unicode_runtime_error.html" 1386 source = util.read_file(self._file_path(filename), "rb") 1387 if not utf8: 1388 source = source.decode("utf-8") 1389 templateargs = {"filename": self._file_path(filename)} 1390 try: 1391 template = Template(**templateargs) 1392 if not syntax: 1393 template.render_unicode() 1394 assert False 1395 except Exception: 1396 tback = exceptions.RichTraceback() 1397 if utf8: 1398 assert tback.source == source.decode("utf-8") 1399 else: 1400 assert tback.source == source 1401 1402 1403for utf8 in (True, False): 1404 for memory in (True, False): 1405 for syntax in (True, False): 1406 1407 def _do_test(self): 1408 self._do_test_traceback(utf8, memory, syntax) 1409 1410 name = "test_%s_%s_%s" % ( 1411 utf8 and "utf8" or "unicode", 1412 memory and "memory" or "file", 1413 syntax and "syntax" or "runtime", 1414 ) 1415 _do_test.__name__ = name 1416 setattr(RichTracebackTest, name, _do_test) 1417 del _do_test 1418 1419 1420class ModuleDirTest(TemplateTest): 1421 def tearDown(self): 1422 import shutil 1423 1424 shutil.rmtree(module_base, True) 1425 1426 def test_basic(self): 1427 t = self._file_template("modtest.html") 1428 t2 = self._file_template("subdir/modtest.html") 1429 1430 eq_(t.module.__file__, os.path.join(module_base, "modtest.html.py")) 1431 eq_( 1432 t2.module.__file__, 1433 os.path.join(module_base, "subdir", "modtest.html.py"), 1434 ) 1435 1436 def test_callable(self): 1437 def get_modname(filename, uri): 1438 return os.path.join( 1439 module_base, 1440 os.path.dirname(uri)[1:], 1441 "foo", 1442 os.path.basename(filename) + ".py", 1443 ) 1444 1445 lookup = TemplateLookup(template_base, modulename_callable=get_modname) 1446 t = lookup.get_template("/modtest.html") 1447 t2 = lookup.get_template("/subdir/modtest.html") 1448 eq_( 1449 t.module.__file__, 1450 os.path.join(module_base, "foo", "modtest.html.py"), 1451 ) 1452 eq_( 1453 t2.module.__file__, 1454 os.path.join(module_base, "subdir", "foo", "modtest.html.py"), 1455 ) 1456 1457 def test_custom_writer(self): 1458 canary = [] 1459 1460 def write_module(source, outputpath): 1461 f = open(outputpath, "wb") 1462 canary.append(outputpath) 1463 f.write(source) 1464 f.close() 1465 1466 lookup = TemplateLookup( 1467 template_base, 1468 module_writer=write_module, 1469 module_directory=module_base, 1470 ) 1471 lookup.get_template("/modtest.html") 1472 lookup.get_template("/subdir/modtest.html") 1473 eq_( 1474 canary, 1475 [ 1476 os.path.join(module_base, "modtest.html.py"), 1477 os.path.join(module_base, "subdir", "modtest.html.py"), 1478 ], 1479 ) 1480 1481 1482class FilenameToURITest(TemplateTest): 1483 def test_windows_paths(self): 1484 """test that windows filenames are handled appropriately by 1485 Template.""" 1486 1487 current_path = os.path 1488 import ntpath 1489 1490 os.path = ntpath 1491 try: 1492 1493 class NoCompileTemplate(Template): 1494 def _compile_from_file(self, path, filename): 1495 self.path = path 1496 return Template("foo bar").module 1497 1498 t1 = NoCompileTemplate( 1499 filename="c:\\foo\\template.html", 1500 module_directory="c:\\modules\\", 1501 ) 1502 1503 eq_(t1.uri, "/foo/template.html") 1504 eq_(t1.path, "c:\\modules\\foo\\template.html.py") 1505 1506 t1 = NoCompileTemplate( 1507 filename="c:\\path\\to\\templates\\template.html", 1508 uri="/bar/template.html", 1509 module_directory="c:\\modules\\", 1510 ) 1511 1512 eq_(t1.uri, "/bar/template.html") 1513 eq_(t1.path, "c:\\modules\\bar\\template.html.py") 1514 1515 finally: 1516 os.path = current_path 1517 1518 def test_posix_paths(self): 1519 """test that posixs filenames are handled appropriately by Template.""" 1520 1521 current_path = os.path 1522 import posixpath 1523 1524 os.path = posixpath 1525 try: 1526 1527 class NoCompileTemplate(Template): 1528 def _compile_from_file(self, path, filename): 1529 self.path = path 1530 return Template("foo bar").module 1531 1532 t1 = NoCompileTemplate( 1533 filename="/var/www/htdocs/includes/template.html", 1534 module_directory="/var/lib/modules", 1535 ) 1536 1537 eq_(t1.uri, "/var/www/htdocs/includes/template.html") 1538 eq_( 1539 t1.path, 1540 "/var/lib/modules/var/www/htdocs/includes/template.html.py", 1541 ) 1542 1543 t1 = NoCompileTemplate( 1544 filename="/var/www/htdocs/includes/template.html", 1545 uri="/bar/template.html", 1546 module_directory="/var/lib/modules", 1547 ) 1548 1549 eq_(t1.uri, "/bar/template.html") 1550 eq_(t1.path, "/var/lib/modules/bar/template.html.py") 1551 1552 finally: 1553 os.path = current_path 1554 1555 def test_dont_accept_relative_outside_of_root(self): 1556 assert_raises_message( 1557 exceptions.TemplateLookupException, 1558 'Template uri "../../foo.html" is invalid - it ' 1559 "cannot be relative outside of the root path", 1560 Template, 1561 "test", 1562 uri="../../foo.html", 1563 ) 1564 1565 assert_raises_message( 1566 exceptions.TemplateLookupException, 1567 'Template uri "/../../foo.html" is invalid - it ' 1568 "cannot be relative outside of the root path", 1569 Template, 1570 "test", 1571 uri="/../../foo.html", 1572 ) 1573 1574 # normalizes in the root is OK 1575 t = Template("test", uri="foo/bar/../../foo.html") 1576 eq_(t.uri, "foo/bar/../../foo.html") 1577 1578 1579class ModuleTemplateTest(TemplateTest): 1580 def test_module_roundtrip(self): 1581 lookup = TemplateLookup() 1582 1583 template = Template( 1584 """ 1585 <%inherit file="base.html"/> 1586 1587 % for x in range(5): 1588 ${x} 1589 % endfor 1590""", 1591 lookup=lookup, 1592 ) 1593 1594 base = Template( 1595 """ 1596 This is base. 1597 ${self.body()} 1598""", 1599 lookup=lookup, 1600 ) 1601 1602 lookup.put_template("base.html", base) 1603 lookup.put_template("template.html", template) 1604 1605 assert result_lines(template.render()) == [ 1606 "This is base.", 1607 "0", 1608 "1", 1609 "2", 1610 "3", 1611 "4", 1612 ] 1613 1614 lookup = TemplateLookup() 1615 template = ModuleTemplate(template.module, lookup=lookup) 1616 base = ModuleTemplate(base.module, lookup=lookup) 1617 1618 lookup.put_template("base.html", base) 1619 lookup.put_template("template.html", template) 1620 1621 assert result_lines(template.render()) == [ 1622 "This is base.", 1623 "0", 1624 "1", 1625 "2", 1626 "3", 1627 "4", 1628 ] 1629 1630 1631class TestTemplateAPI(unittest.TestCase): 1632 def test_metadata(self): 1633 t = Template( 1634 """ 1635Text 1636Text 1637% if bar: 1638 ${expression} 1639% endif 1640 1641<%include file='bar'/> 1642 1643""", 1644 uri="/some/template", 1645 ) 1646 eq_( 1647 ModuleInfo.get_module_source_metadata(t.code, full_line_map=True), 1648 { 1649 "full_line_map": [ 1650 1, 1651 1, 1652 1, 1653 1, 1654 1, 1655 1, 1656 1, 1657 1, 1658 1, 1659 1, 1660 1, 1661 1, 1662 1, 1663 1, 1664 0, 1665 0, 1666 0, 1667 0, 1668 0, 1669 0, 1670 0, 1671 1, 1672 4, 1673 5, 1674 5, 1675 5, 1676 7, 1677 8, 1678 8, 1679 8, 1680 8, 1681 8, 1682 8, 1683 8, 1684 ], 1685 "source_encoding": "ascii", 1686 "filename": None, 1687 "line_map": { 1688 35: 29, 1689 15: 0, 1690 22: 1, 1691 23: 4, 1692 24: 5, 1693 25: 5, 1694 26: 5, 1695 27: 7, 1696 28: 8, 1697 29: 8, 1698 }, 1699 "uri": "/some/template", 1700 }, 1701 ) 1702 1703 def test_metadata_two(self): 1704 t = Template( 1705 """ 1706Text 1707Text 1708% if bar: 1709 ${expression} 1710% endif 1711 1712 <%block name="foo"> 1713 hi block 1714 </%block> 1715 1716 1717""", 1718 uri="/some/template", 1719 ) 1720 eq_( 1721 ModuleInfo.get_module_source_metadata(t.code, full_line_map=True), 1722 { 1723 "full_line_map": [ 1724 1, 1725 1, 1726 1, 1727 1, 1728 1, 1729 1, 1730 1, 1731 1, 1732 1, 1733 1, 1734 1, 1735 1, 1736 1, 1737 1, 1738 0, 1739 0, 1740 0, 1741 0, 1742 0, 1743 0, 1744 0, 1745 0, 1746 0, 1747 1, 1748 4, 1749 5, 1750 5, 1751 5, 1752 7, 1753 7, 1754 7, 1755 7, 1756 7, 1757 10, 1758 10, 1759 10, 1760 10, 1761 10, 1762 10, 1763 8, 1764 8, 1765 8, 1766 8, 1767 8, 1768 8, 1769 8, 1770 8, 1771 8, 1772 8, 1773 8, 1774 8, 1775 ], 1776 "source_encoding": "ascii", 1777 "filename": None, 1778 "line_map": { 1779 34: 10, 1780 40: 8, 1781 46: 8, 1782 15: 0, 1783 52: 46, 1784 24: 1, 1785 25: 4, 1786 26: 5, 1787 27: 5, 1788 28: 5, 1789 29: 7, 1790 }, 1791 "uri": "/some/template", 1792 }, 1793 ) 1794 1795 1796class PreprocessTest(TemplateTest): 1797 def test_old_comments(self): 1798 t = Template( 1799 """ 1800 im a template 1801# old style comment 1802 # more old style comment 1803 1804 ## new style comment 1805 - # not a comment 1806 - ## not a comment 1807""", 1808 preprocessor=convert_comments, 1809 ) 1810 1811 assert ( 1812 flatten_result(t.render()) 1813 == "im a template - # not a comment - ## not a comment" 1814 ) 1815 1816 1817class LexerTest(TemplateTest): 1818 def _fixture(self): 1819 from mako.parsetree import TemplateNode, Text 1820 1821 class MyLexer(object): 1822 encoding = "ascii" 1823 1824 def __init__(self, *arg, **kw): 1825 pass 1826 1827 def parse(self): 1828 t = TemplateNode("foo") 1829 t.nodes.append( 1830 Text( 1831 "hello world", 1832 source="foo", 1833 lineno=0, 1834 pos=0, 1835 filename=None, 1836 ) 1837 ) 1838 return t 1839 1840 return MyLexer 1841 1842 def _test_custom_lexer(self, template): 1843 eq_(result_lines(template.render()), ["hello world"]) 1844 1845 def test_via_template(self): 1846 t = Template("foo", lexer_cls=self._fixture()) 1847 self._test_custom_lexer(t) 1848 1849 def test_via_lookup(self): 1850 tl = TemplateLookup(lexer_cls=self._fixture()) 1851 tl.put_string("foo", "foo") 1852 t = tl.get_template("foo") 1853 self._test_custom_lexer(t) 1854 1855 1856class FuturesTest(TemplateTest): 1857 def test_future_import(self): 1858 t = Template("${ x / y }", future_imports=["division"]) 1859 assert result_lines(t.render(x=12, y=5)) == ["2.4"] 1860