def test_raw_nested(self): if not xml: return td = Domain(DEFAULT_DIR, restricted=RESTRICTED, errors=ERRORS) t = td.get_template('raw_nested.html') self.assertEqual(t.evoque()[:87], """ $begin{table_row} $for{ col in row } <td>${col}</td> $else""") self.failUnless(isinstance(t.evoque(), xml)) # template #snapshot is already loaded with raw=True, quoting=str snap = td.get_template('raw_nested.html#snapshot') self.failUnless(snap.raw) self.failUnless(snap.qsclass is unistr) self.failUnless(isinstance(snap.evoque(), unistr)) # template #snapshot is still already loaded... snapx = td.get_template('raw_nested.html#snapshot_xml') self.failUnless(isinstance(snapx.evoque(), xml)) self.failUnless(snap.qsclass is unistr) self.failUnless(isinstance(snap.evoque(), unistr)) snap.unload() self.failUnless(isinstance(snapx.evoque(), xml)) # reloads #snapshot snap = td.get_template('raw_nested.html#snapshot') self.failUnless(snap.qsclass is xml) self.failUnless(isinstance(snap.evoque(raw=True), xml))
def test_overlay(self): td = Domain(DEFAULT_DIR) t = td.get_template('overlay.html') self.assertEqual(eval("dict(%s)" % (t.eval_overlay)), dict(name="base.html")) space, overlay = t.get_space_overlay() self.assertTrue(space is True) self.assertTrue(t.labels == ["content"]) # t.evoque(title="positive overlay test", parametrized="and happy") chain_pos = td.get_template('overlay_chain_pos.html') self.assertEqual(eval("dict(%s)" % (chain_pos.eval_overlay)), dict(name="overlay_mid.html")) space, overlay = chain_pos.get_space_overlay() self.assertTrue(space is True) self.assertTrue(chain_pos.labels == ["content"]) # chain_pos.evoque(title="positive overlay test", parametrized="and happy") chain_neg = td.get_template('overlay_chain_neg.html') self.assertEqual(eval("dict(%s)" % (chain_neg.eval_overlay)), dict(name="overlay_mid.html", space="negative")) space, overlay = chain_neg.get_space_overlay() self.assertTrue(space is False) self.assertTrue(chain_neg.labels == ["content", "footer"]) # chain_neg.evoque(title="negative overlay test", parametrized="and happy") b = td.get_template('base.html') self.assertTrue(b.labels == ["header", "content", "footer"]) self.assertFalse(b.eval_overlay is not None) self.assertRaises((TypeError, ), b.get_space_overlay)
def test_evoque_local_nested_from_string(self): td = Domain(DEFAULT_DIR, restricted=RESTRICTED, errors=ERRORS) src = open(join(DEFAULT_DIR, "evoque_local_nested.html")).read() name = "fromstr" nested_name = name + "#label" data = dict(title="A Title", param="A Param") r = "<h1>A Title</h1><p>some A Param text</p>" # Load a from_string template that locally-nests another template td.set_template(name, src=src, from_string=True) t1 = td.get_template(name) # Verify nested template is not yet loaded self.assertEqual(False, t1.collection.has_template(nested_name)) # Evoque, and verify response (multiple times, ensure data stays ok) self.assertEqual(r, t1.evoque(data)) # data as locals self.assertEqual(r, t1.evoque(**data)) # data as kw self.assertEqual(r, t1.evoque(data)) # data as locals self.assertEqual(r, t1.evoque(**data)) # data as kw # Verify nested template is now loaded self.assertEqual(True, t1.collection.has_template(nested_name)) # Verify that tring to set nested template will fail self.assertRaises((ValueError,), td.set_template, nested_name, src=src, from_string=True) t2 = td.get_template(nested_name) self.assertEqual(t2.ts, "<h1>%(title)s</h1><p>some %(param)s text</p>") self.assertEqual(r, t2.evoque(**data))
def test_get_mixed_name_src(self): td = Domain(DEFAULT_DIR, restricted=RESTRICTED, errors=ERRORS) name = '#label' src = 'evoque_local_nested.html' # Load a nested template and evoque it t = td.get_template(name, src) self.assertEqual(t.ts, "<h1>%(title)s</h1><p>some %(param)s text</p>")
def test_literals(self): td = Domain(DEFAULT_DIR, restricted=RESTRICTED, errors=ERRORS) name = "template.html" t = td.get_template(name + "#literals") r = "<p>a $ dollar, a literal ${expr}, a % percent... { } ! \ etc.</p>" self.assertEqual(r, t.evoque()) self.assertRaises((SyntaxError,), td.get_template, name+"#unescaped")
def test_from_string_td(self): td = Domain(DEFAULT_DIR, restricted=RESTRICTED, errors=ERRORS) src = "<h1>${title}</h1><p>some ${param} text</p>" data = dict(title="A Title", param="A Param") r = "<h1>A Title</h1><p>some A Param text</p>" td.set_template("fromstr", src=src, from_string=True) t = td.get_template("fromstr") self.assertEqual(r, t.evoque(**data))
def test_overlay_kwargs(self): td = Domain(DEFAULT_DIR) r = "<base>base content!</base>" r_neg = "" responses = [r, r, r, r, r_neg] t = td.get_template('overlay_kwargs.html') for i, s in enumerate(t.test()): self.assertEqual(responses[i], s)
def test_manual_quoting(self): td = Domain(DEFAULT_DIR, restricted=RESTRICTED, errors=ERRORS, quoting="str") name = "template.html#label" t = td.get_template(name) self.failUnless(unistr is t.qsclass) self.failUnless(unistr is t.evoque(title="str", param="<str/>").__class__) from cgi import escape self.assertEqual(self.r_xml_escaped, t.evoque(title="q-xml", param=escape("<in>rm *</in>")))
def test_evoque_raw(self): td = Domain(DEFAULT_DIR, restricted=RESTRICTED, errors=ERRORS) name = 'evoque_local_nested.html#label' r = "<h1>${title}</h1><p>some ${param} text</p>" t = td.get_template(name, raw=True) self.assertEqual([], list(t.test())) self.assertEqual(None, t.ts) self.assertEqual(r, t.evoque(raw=True)) self.assertEqual(r, t.evoque())
def test_expr_formatting(self): td = Domain(DEFAULT_DIR, restricted=RESTRICTED, errors=ERRORS) data = dict(amount=1.0/3) src = "${amount!.4f}" td.set_template("t1", src=src, from_string=True) self.assertEqual("0.3333", td.get_template("t1").evoque(**data)) src = "${ amount ! .3f }" td.set_template("t2", src=src, from_string=True) self.assertEqual("0.333", td.get_template("t2").evoque(**data))
def test_evoque_kwargs(self): td = Domain(DEFAULT_DIR, restricted=RESTRICTED, errors=4) r = "<h1>TITLE</h1><p>some PARAM text</p>" r_raw = "<h1>${title}</h1><p>some ${param} text</p>" r_q_str = "<h1>TITLE</h1><p>some PARAM text</p>" responses = [ r, r, r, r, r, r_raw, r, r_q_str, r ] t = td.get_template('evoque_kwargs.html') for i, s in enumerate(t.test()): self.assertEqual(responses[i], s)
def test_typical_usage_via_domain_implied_collection(self): td = Domain(DEFAULT_DIR, restricted=RESTRICTED, errors=ERRORS) name = 'template.html' t = td.get_template(name) self.failUnless(t.collection is td.get_collection()) self.failUnless(t.collection is td.collections[""]) self.failUnless(t is t.collection.get_template(name)) self.failUnless(t is t.collection.domain.get_template(name, collection=t.collection))
def test_prefer(self): td = Domain(DEFAULT_DIR, restricted=RESTRICTED, errors=ERRORS) t = td.get_template('raw_nested.html') self.assertEqual(t.prefer, dict(raw=False, quoting="xml")) def upper(s): return s.upper() td.set_on_globals("upper", upper) p = td.get_template('raw_nested.html#preferences') self.assertEqual(p.raw, True) self.assertEqual(p.qsclass, unistr)
def test_parse_locator(self): td = Domain(DEFAULT_DIR, restricted=RESTRICTED, errors=ERRORS) name = "template.html" name_label = "template.html#label" label = "#label" t = td.get_template(name) self.assertEqual(["template.html", None], parse_locator(name)) self.assertEqual(["template.html", "label"], parse_locator(name_label)) self.assertEqual(["", "label"], parse_locator(label)) self.assertRaises((ValueError,), parse_locator, "template.html#label#label")
def test_file_addressing_collection_root_relative(self): td = Domain(DEFAULT_DIR, restricted=RESTRICTED, errors=ERRORS) name = '/template.html' src = '/template.html' self.assertRaises((LookupError,), td.get_template, name) self.assertRaises((LookupError,), td.get_template, name, src) # can have names start with "/" as long as the c-rel locator does not src = 'template.html' t = td.get_template(name, src=src) self.assertEqual(t.name, name)
def evoque(dirname, verbose=False, quoting="xml", restricted=False): DEFAULT_DIR = os.path.join(BASEPATH, 'evoque') name = 'subs.html' from evoque.domain import Domain td = Domain(DEFAULT_DIR, restricted=restricted, errors=4, quoting=quoting) t = td.get_template(name) def render(): return t.evoque(DATA.copy()) if verbose: pr(t.ts, render()) return render
def test_inline_nested_if(self): td = Domain(DEFAULT_DIR, restricted=RESTRICTED, errors=ERRORS) t = td.get_template('for_seq_items.html') #print t.ts_raw #print t.ts result = """<ul> <li>7:Apples</li> <li>9:789</li> <li class="last">17:Blue</li> </ul> """ self.assertEqual(result, t.evoque())
def test_evoque_local_nested(self): td = Domain(DEFAULT_DIR, restricted=RESTRICTED, errors=ERRORS) name = 'evoque_local_nested.html' data = dict(title="A Title", param="A Param") r = "<h1>A Title</h1><p>some A Param text</p>" # Load a nested template and evoque it t1 = td.get_template(name + "#label") self.assertEqual(t1.ts, "<h1>%(title)s</h1><p>some %(param)s text</p>") self.assertEqual(r, t1.evoque(**data)) # Load a template that evoques a locally-nested template t2 = td.get_template(name) self.assertEqual(r, t2.evoque(**data))
def test_xml_automatic_quoting(self): if not xml: return td = Domain(DEFAULT_DIR, restricted=RESTRICTED, errors=ERRORS, quoting="xml") name = "template.html#label" t = td.get_template(name) self.failUnless(xml is t.qsclass) self.failUnless(xml is t.evoque(title="xml", param="<xml/>").__class__) self.assertEqual(self.r_xml_escaped, t.evoque(title="q-xml", param="<in>rm *</in>")) r = "<h1>q-xml</h1><p>some <in>rm *</in> text</p>" self.assertEqual(r, t.evoque(title="q-xml", param=xml("<in>rm *</in>")))
def test_extract_test_data(self): td = Domain(DEFAULT_DIR, restricted=RESTRICTED, errors=ERRORS) name = "template.html" t = td.get_template(name) self.assertEqual(t.test_data, [ dict(title="A Title", param="a <param/> for quoting", things=["Apples", 789, "Blue"], something=False, other=False, someexpr='abc', likes_blue=False, flag="Banana", yo="Johnny"), dict(things=[]), dict(something=True), dict(something=False, other=True), dict(other=False, likes_blue=True) ])
def test_overlay_naming_schemes_separate_files(self): domain = Domain(DEFAULT_DIR) t0 = domain.get_template("overlay_naming_base.html") self.assertEqual(t0.evoque(), "<base>base content!</base>") t1 = domain.get_template("overlay_naming_1.html") self.assertEqual(t1.evoque(), "<base><m1>literal unquoted</m1></base>") t2 = domain.get_template("overlay_naming_2.html") self.assertEqual(t2.evoque(), "<base><m2>literal quoted</m2></base>") t3 = domain.get_template("overlay_naming_3.html") self.assertEqual(t3.evoque(site_template="overlay_naming_base.html"), "<base><m3>kw unquoted</m3></base>") t4 = domain.get_template("overlay_naming_4.html") self.assertEqual(t4.evoque(), "<base><m4>kw quoted</m4></base>")
def evoque_mq(dirname, verbose=False): DEFAULT_DIR = os.path.join(BASEPATH, 'evoque') name = 'subs_mq.html' from evoque.domain import Domain td = Domain(DEFAULT_DIR, restricted=False, quoting="str") import cgi td.set_on_globals("quote", cgi.escape) t = td.get_template(name) def render(): return t.evoque(DATA.copy()) if verbose: pr(t.ts, render()) return render
def test_dynamic_site_template(self): domain = Domain(DEFAULT_DIR) # # by reset s = domain.get_template("SITE-TEMPLATE", src="site_template_table.html") t = domain.get_template("site_dyn_page.html") r_table = t.evoque(title="hey tabby!", message="you're kinda square!", footer="you reckon?") self.assertTrue(r_table == """<html> <head><title>site-table: hey tabby!</title></head> <body> <table class="layout"> <tr><th>site-table: <h1>hey tabby!</h1></th></tr> <tr><td>page: you're kinda square!</td></tr> <tr><td>site-table: you reckon?</td></tr> </table> </body> </html> """) s.unload() s = domain.get_template("SITE-TEMPLATE", src="site_template_divs.html") r_divs = t.evoque(title="howdie!", message="ya bin free floatin' good?", footer="sure thang!") self.assertTrue(r_divs == """<html> <head><title>site-div: howdie!</title></head> <body> <div class="layout"> <div class="header">site-div: <h1>howdie!</h1></div> <div class="content">page: ya bin free floatin' good?</div> <div class="footer">site-div: sure thang!</div> </div> </body> </html> """) # by parameter t = domain.get_template("site_dyn_page_var.html") self.assertEqual( r_table, t.evoque(my_site_theme="site_template_table.html", title="hey tabby!", message="you're kinda square!", footer="you reckon?")) self.assertEqual( r_divs, t.evoque(my_site_theme="site_template_divs.html", title="howdie!", message="ya bin free floatin' good?", footer="sure thang!"))
def test_unsafe_file_expressions(self): # Create a new domain for this, to be able to run with a different # errors setting td = Domain(DEFAULT_DIR, restricted=True, errors=2, quoting="str") name = 'restricted_exprs.txt' t = td.get_template(name) result = """ [EvalError(().__class__.mro()[1].__subclasses__())] ().__class__.mro()[1].__subclasses__() ().__class__.mro()[1].__subclasses__() [EvalError(eval(expr))] [EvalError(evoque("test", src="${"+expr+"}", from_string=True))] """ self.assertEqual(result, t.evoque())
def test_prefer_with_overrides(self): td = Domain(DEFAULT_DIR, restricted=RESTRICTED, errors=ERRORS) def upper(s): return s.upper() def trim(s): return s.strip() td.set_on_globals("upper", upper) td.set_on_globals("trim", upper) p = td.get_template('raw_nested.html#preferences', raw=False, filters=[trim, upper]) self.assertEqual(p.raw, False) self.assertEqual(p.qsclass, unistr) r = 'SHOULD REFRESH [QUOTING: NONE OR !="STR"] WHEN TEMPLATE IS LOADED' self.assertEqual(r, p.evoque()) r = 'SHOULD REFRESH [QUOTING: NONE OR !="STR"] WHEN CHANGED TEMPLATE IS LOADED' self.assertEqual(r, p.evoque(what="changed template"))
def set_domain(self): default_dir = abspath(join(dirname(__file__), 'evoque')) # create template domain instance # here restating all defaults, for doc convenience self.domain = Domain(default_dir, restricted=False, errors=3, log=logging.getLogger("evoque"), cache_size=0, auto_reload=60, slurpy_directives=True, quoting="xml", input_encoding="utf-8", filters=[]) # extensions to global namespace self.domain.set_on_globals("pformat", pformat) # preload a default template, e.g. for error pages self.domain.get_collection().get_template("", "base.html")
def setup_domain(): import logging domain = Domain( # root folder for the default template collection, must be abspath "/tmp", # whether evaluation namespace is restricted or not restricted=True, # how should any evaluation errors be rendered # int 0 to 4, for: [silent, zero, name, render, raise] errors=3, # domain logger; additional settings should be specified via the # app's config ini file, just as for any other logger. E.g: # [logger_notifications] # level = DEBUG # handlers = # qualname = notifications log=logging.getLogger("notifications"), # [collections] int, max loaded templates in a collection cache_size=0, # [collections] int, min seconds to wait between checks for # whether a template needs reloading auto_reload=0, # [collections] bool, consume all whitespace trailing a directive slurpy_directives=True, # [collections/templates] str or class, to specify the *escaped* # string class that should be used i.e. if any str input is not of # this type, then cast it to this type). # Builtin str key values are: "xml" -> qpy.xml, "str" -> unicode quoting="str", # [collections/templates] str, preferred encoding to be tried # first when decoding template source. Evoque decodes template # strings heuristically, i.e. guesses the input encoding. input_encoding="utf-8", # [collections/templates] list of filter functions, each having # the following signature: filter_func(s:basestring) -> basestring # The functions will be called, in a left-to-right order, after # template is rendered. NOTE: not settable from the conf ini. filters=[] ) # add "site" settings on globals domain.set_on_globals("site", TemplateNamespaceSite()) return domain
def __init__( self, domain, name, path, # defaults from Domain cache_size=None, auto_reload=None, slurpy_directives=None, # defaults (from Domain) for Templates quoting=None, input_encoding=None, filters=None): """ domain: either(None, Domain) name: str, name by which to retrieve the collection path: str, abs path for root folder for the collection For more on defaults from Domain init parameters, see the docstring in domain.Domain.__init__(). Preferred way to create a new collection: domain.set_collection() """ # $end{init} check_dir(path) self.dir = normpath(path) if name is None: raise ValueError("A Collection cannot have a None name") self.name = name domain_kw = specified_kwargs(self.from_domain, vars()) if domain is None: # in this case self is the default_collection from evoque.domain import Domain domain = Domain(self, **domain_kw) self.domain = domain # defaults -- cascaded down from domain for attr in self.from_domain: setattr(self, attr, domain_kw.get(attr, getattr(domain, attr))) # self.cache = Cache(maxsize=self.cache_size) self.translator = Translator(self)
def test_filter_markdown(self): try: from markdown import markdown except ImportError: pr("Can't import markdown, skipping test [filter_markdown]") return td = Domain(DEFAULT_DIR, restricted=RESTRICTED, errors=ERRORS) td.set_on_globals("markdown", markdown) import logging logging.getLogger("MARKDOWN").setLevel(logging.INFO) # hide markdown DEBUG logging t = td.get_template('markdown.html') sub_out = "item two <xml/>" self.failIf(t.evoque().find(sub_out) == -1) # Test direct evoque'ation of inner my-markdown-template -- that should # now be already loaded with quoting="xml" --- with different quoting. # We retrieve it, and evoque it overriding the quoting (as well as # supplying the needed param="<xml/>") m = td.get_template('markdown.html#my-markdown-template') self.failUnless(m.evoque(quoting="str", param="<xml/>" ).find(sub_out) == -1)
def evoque_mq(verbose=False): from evoque.domain import Domain DEFAULT_DIR = os.path.join(BASEDIR, 'evoque') td = Domain(DEFAULT_DIR) import cgi td.set_on_globals("quote", cgi.escape) template_string = """<table> $for{ row in table } <tr>$for{ col in row }<td>${quote(col)}</td>$rof</tr> $rof </table> $test{ table=[("a","b","c","d","<escape-me/>","f","g","h","i","j")] } """ td.set_template("bigtable", src=template_string, quoting="str", from_string=True) t = td.get_template("bigtable") def render(): return t.evoque({'table':TABLE_DATA}) if verbose: pr(t.ts) pr('--------------------------------------------------------') pr(render()[:300] + "...") return render