Changeset 4524:00f8808b9221 in livinglogic.python.xist

Show
Ignore:
Timestamp:
07/20/11 17:12:04 (8 years ago)
Author:
Walter Doerwald <walter@…>
Branch:
default
Message:

Names for UL4 templates.

Files:
7 modified

Legend:

Unmodified
Added
Removed
  • MIGRATION.rst

    r4500 r4524  
     1Migrating to version 3.23 
     2========================= 
     3 
     4Changes to :mod:`ll.ul4c` 
     5------------------------- 
     6 
     7*   The module global functions :func:`ll.ul4c.compile`, :func:`ll.ul4c.load` and 
     8    :func:`ll.ul4c.loads` have been removed. Instead of them the :class:`Template` 
     9    constructor and the class methods :meth:`load` and :meth:`loads` can be used. 
     10 
     11 
    112Migrating to version 3.20 
    213========================= 
  • NEWS.rst

    r4521 r4524  
    1 Changes in 3.23 (released ??/??/2011) 
     1Changes in 3.23 (released 07/20/2011) 
    22------------------------------------- 
     3 
     4*   UL4 template objects now have a name. This name will be displayed in 
     5    exception messages. Nested templates display their own name in the exception 
     6    message. 
     7 
     8*   The module global functions :func:`ll.ul4c.compile`, :func:`ll.ul4c.load` and 
     9    :func:`ll.ul4c.loads` have been removed. Instead of them the :class:`Template` 
     10    constructor and the class methods :meth:`load` and :meth:`loads` can be used. 
    311 
    412*   The script ``oradelete`` now supports the options :option:`--include`, 
  • setup.py

    r4519 r4524  
    228228args = dict( 
    229229    name="ll-xist", 
    230     version="3.22", 
     230    version="3.23", 
    231231    description="Extensible HTML/XML generator, cross-platform templating language, Oracle utilities and various other tools", 
    232232    long_description=description, 
  • src/ll/misc.py

    r4498 r4524  
    548548        return "com.livinglogic.ul4.Utils.makeMap({})".format(", ".join("{}, {}".format(javaexpr(key), javaexpr(value)) for (key, value) in obj.iteritems())) 
    549549    elif isinstance(obj, ul4c.Template): 
    550         return "new com.livinglogic.ul4.JSPTemplate() {{ public void render(java.io.Writer out, java.util.Map<String, Object> variables) throws java.io.IOException {{ {} }} }}".format(" ".join(line.strip() for line in obj.javasource().splitlines())) 
     550        return 'new com.livinglogic.ul4.JSPTemplate() {{ public String getName() {{ return {}; }} public void render(java.io.Writer out, java.util.Map<String, Object> variables) throws java.io.IOException {{ {} }} }}'.format(javaexpr(obj.name), " ".join(line.strip() for line in obj.javasource().splitlines())) 
    551551    else: 
    552552        raise TypeError("can't handle object of type {}".format(type(obj))) 
  • src/ll/ul4c.py

    r4523 r4524  
    4242    template tag. 
    4343    """ 
    44     __slots__ = ("source", "type", "starttag", "endtag", "startcode", "endcode") 
    45  
    46     def __init__(self, source, type, starttag, endtag, startcode, endcode): 
     44    __slots__ = ("source", "name", "type", "starttag", "endtag", "startcode", "endcode") 
     45 
     46    def __init__(self, source, name, type, starttag, endtag, startcode, endcode): 
    4747        """ 
    4848        Create a new :class:`Location` object. The arguments have the following 
    4949        meaning: 
    5050 
    51         :var:`source` 
    52             The complete source string 
    53  
    54         :var:`type` 
    55             The tag type (i.e. ``"for"``, ``"if"``, etc. or ``None`` for 
    56             literal text) 
    57  
    58         :var:`starttag` 
    59             The start position of the start delimiter. 
    60  
    61         :var:`endtag` 
    62             The end position of the end delimiter. 
    63  
    64         :var:`startcode` 
    65             The start position of the tag code. 
    66  
    67         :var:`endcode` 
    68             The end position of the tag code. 
     51            :var:`source` 
     52                The complete source string 
     53 
     54            :var:`name` 
     55                The name of the template the location belongs to. 
     56 
     57            :var:`type` 
     58                The tag type (i.e. ``"for"``, ``"if"``, etc. or ``None`` for 
     59                literal text) 
     60 
     61            :var:`starttag` 
     62                The start position of the start delimiter. 
     63 
     64            :var:`endtag` 
     65                The end position of the end delimiter. 
     66 
     67            :var:`startcode` 
     68                The start position of the tag code. 
     69 
     70            :var:`endcode` 
     71                The end position of the tag code. 
    6972        """ 
    7073        self.source = source 
     74        self.name = name 
    7175        self.type = type 
    7276        self.starttag = starttag 
     
    7680 
    7781    def __getitem__(self, key): 
    78         if key in {"type", "starttag", "endtag", "startcode", "endcode"}: 
     82        if key in {"name", "type", "starttag", "endtag", "startcode", "endcode"}: 
    7983            return getattr(self, key) 
    8084        raise KeyError(key) 
     
    100104    def __str__(self): 
    101105        (line, col) = self.pos() 
    102         return "{!r} at {} (line {}, col {})".format(self.tag, self.starttag+1, line, col) 
     106        return "{!r} at {} (line {}, col {}, template {})".format(self.tag, self.starttag+1, line, col, self.name) 
    103107 
    104108 
     
    121125        path = [] 
    122126 
     127        # FIXME: Drop ``__cause__`` traversal in Python 3, as this is done by Python itself 
    123128        exc = self 
    124129        while isinstance(exc, Error): 
     
    130135        if module != "exceptions": 
    131136            name = "{}.{}".format(module, name) 
    132         return "{} {} {}".format(name, " ".join("in {}:".format(location) for location in path), exc) 
     137        return "{} {} {}".format(" ".join("in {}:".format(location) for location in path), name, exc) 
    133138 
    134139 
     
    582587    is a generator) or :meth:`renders` (which returns a string). 
    583588    """ 
    584     version = "15" 
    585  
    586     def __init__(self, source=None, startdelim="<?", enddelim="?>"): 
     589    version = "16" 
     590 
     591    def __init__(self, source=None, name="unnamed", startdelim="<?", enddelim="?>"): 
    587592        """ 
    588593        Create a :class:`Template` object. If :var:`source` is ``None``, the 
    589594        :class:`Template` remains uninitialized, otherwise :var:`source` will be 
    590595        compiled (using :var:`startdelim` and :var:`enddelim` as the tag 
    591         delimiters). 
     596        delimiters). :var:`name` is the name of the template. It will be used in 
     597        exception messages and should be a valid Python identifier. 
    592598 
    593599        """ 
    594600        self.startdelim = startdelim 
    595601        self.enddelim = enddelim 
     602        self.name = name 
    596603        self.source = None 
    597604        self.opcodes = None 
     
    599606        self._pythonfunction = None 
    600607        if source is not None: 
    601             self._compile(source, startdelim, enddelim) 
     608            self._compile(source, name, startdelim, enddelim) 
    602609 
    603610    def __getitem__(self, key): 
     
    612619        :var:`data` must contain the template in compiled format. 
    613620        """ 
     621        defnames = [] # Names of nested templates 
     622 
    614623        def _readint(prefix): 
    615624            if prefix is not None: 
     
    670679        if version != self.version: 
    671680            raise ValueError("invalid version, expected {!r}, got {!r}".format(self.version, version)) 
     681        self.name = _readstr(u"N") 
     682        defnames.append(self.name) 
     683        _readcr() 
    672684        self.startdelim = _readstr(u"SD") 
    673685        _readcr() 
     
    689701            arg = _readstr("A") 
    690702            locspec = stream.read(1) 
     703            if code == "enddef": 
     704                defnames.pop() 
    691705            if locspec == u"^": 
    692706                if location is None: 
     
    696710                if locspec2 != "|": 
    697711                    raise ValueError("invalid location spec {!r}".format(locspec + locspec2)) 
    698                 location = Location(self.source, _readstr("T"), _readint("st"), _readint("et"), _readint("sc"), _readint("ec")) 
     712                location = Location(self.source, defnames[-1], _readstr("T"), _readint("st"), _readint("et"), _readint("sc"), _readint("ec")) 
    699713            else: 
    700714                raise ValueError("invalid location spec {!r}".format(locspec)) 
     
    702716            count -= 1 
    703717            self.opcodes.append(Opcode(code, r1, r2, r3, r4, r5, arg, location)) 
     718            if code == "def": 
     719                defnames.append(arg) 
    704720        return self 
    705721 
     
    732748 
    733749        yield "ul4\n{}\n".format(self.version) 
     750        for p in _writestr("N", self.name): yield p 
     751        yield "\n" 
    734752        for p in _writestr("SD", self.startdelim): yield p 
    735753        yield "\n" 
     
    796814        """ 
    797815        if self._pythonfunction is None: 
    798             code = self.pythonsource("render") 
     816            code = self.pythonsource() 
    799817            ns = {} 
    800             exec code.encode("utf-8") in ns # FIXME: no need to encode in Python 3.0 
    801             self._pythonfunction = ns["render"] 
     818            exec code.encode("utf-8") in ns # FIXME: no need to encode in Python 3 
     819            self._pythonfunction = ns[self.name] 
    802820        return self._pythonfunction 
    803821 
     
    834852        to indent blocks (defaulting to ``"\\t"``). 
    835853        """ 
    836         i = 0 
     854        yield "def {} {{".format(self.name) 
     855        i = 1 
    837856        for opcode in self.opcodes: 
    838857            if opcode.code in ("else", "endif", "endfor", "enddef"): 
     
    848867            if opcode.code in ("for", "if", "else", "def"): 
    849868                i += 1 
    850  
    851     def _tokenize(self, source, startdelim, enddelim): 
     869        yield "}" 
     870 
     871    def _tokenize(self, source, name, startdelim, enddelim): 
    852872        """ 
    853873        Tokenize the template source code :var:`source` into tags and non-tag 
     
    861881        for match in re.finditer(pattern, source): 
    862882            if match.start() != pos: 
    863                 yield Location(source, None, pos, match.start(), pos, match.start()) 
     883                yield Location(source, None, None, pos, match.start(), pos, match.start()) 
    864884            type = source[match.start(1):match.end(1)] 
    865885            if type != "note": 
    866                 yield Location(source, type, match.start(), match.end(), match.start(3), match.end(3)) 
     886                yield Location(source, None, type, match.start(), match.end(), match.start(3), match.end(3)) 
    867887            pos = match.end() 
    868888        end = len(source) 
    869889        if pos != end: 
    870             yield Location(source, None, pos, end, pos, end) 
     890            yield Location(source, None, None, pos, end, pos, end) 
    871891 
    872892    def _allocreg(self): 
     
    892912        self.opcodes.append(Opcode(code, r1, r2, r3, r4, r5, arg, self.location)) 
    893913 
    894     def _compile(self, source, startdelim, enddelim): 
     914    def _compile(self, source, name, startdelim, enddelim): 
    895915        """ 
    896916        Compile the template source code :var:`source` into opcodes. 
    897917        :var:`startdelim` and :var:`enddelim` are used as the tag delimiters. 
    898918        """ 
     919        self.name = name 
    899920        self.startdelim = startdelim 
    900921        self.enddelim = enddelim 
     
    905926        parserender = RenderParser(scanner).compile 
    906927 
    907         # This stack stores for each nested for/foritem/if/elif/else the following information: 
     928        # This stack stores for each nested for/if/elif/else/def the following information: 
    908929        # 1) Which construct we're in (i.e. "if" or "for") 
    909930        # 2) The start location of the construct 
     
    916937        self.opcodes = [] 
    917938 
    918         for location in self._tokenize(source, startdelim, enddelim): 
     939        for location in self._tokenize(source, name, startdelim, enddelim): 
    919940            self.location = location 
    920941            try: 
     
    9921013                    raise ValueError("unknown tag {!r}".format(location.type)) 
    9931014            except Exception, exc: 
    994                 newexc = Error(location) # FIXME: use ``raise ... from`` in Python 3.0 
     1015                newexc = Error(location) # FIXME: use ``raise ... from`` in Python 3 
    9951016                newexc.__cause__ = exc 
    9961017                raise newexc 
     
    9981019                del self.location 
    9991020        if stack: 
    1000             newexc = Error(stack[-1][1]) # FIXME: use ``raise ... from`` in Python 3.0 
     1021            newexc = Error(stack[-1][1]) # FIXME: use ``raise ... from`` in Python 3 
    10011022            newexc.__cause__ = BlockError("block unclosed") 
    10021023            raise newexc 
    10031024 
     1025        # Do an extra loop over the opcodes to fix the template names in the location objects 
     1026        defnames = [name] # This stack stores the names of the nested templates. 
     1027        for opcode in self.opcodes: 
     1028            if opcode.code == "enddef": 
     1029                defnames.pop() 
     1030            opcode.location.name = defnames[-1] 
     1031            if opcode.code == "def": 
     1032                defnames.append(opcode.arg) 
     1033 
    10041034    def __str__(self): 
    10051035        return "\n".join(self.format()) 
     
    10101040    def __repr__(self): 
    10111041        return "<{}.{} object with {} opcodes at {:#x}>".format(self.__class__.__module__, self.__class__.__name__, len(self.opcodes), id(self)) 
    1012  
    1013  
    1014 def compile(source, startdelim="<?", enddelim="?>"): 
    1015     return Template(source, startdelim, enddelim) 
    1016  
    1017  
    1018 load = Template.load 
    1019 loads = Template.loads 
    10201042 
    10211043 
     
    10301052    """ 
    10311053 
    1032     def __init__(self, template, function=None): 
     1054    def __init__(self, template): 
    10331055        """ 
    10341056        Create a :class:`PythonSource` object. :var:`template` is the 
    1035         :class:`Template` object. If :var:`function` is specified the code will be 
    1036         wrapped in a function with this name. 
     1057        :class:`Template` object. 
    10371058        """ 
    10381059        self.template = template 
    1039         self.function = function 
    10401060 
    10411061    def __unicode__(self): 
     
    10501070        self.defs = [] # Stack for currently open def opcodes 
    10511071        self.lastopcode = None 
    1052         self.lastlocation = Location(self.template.source, None, 0, 0, 0, 0) 
    1053  
    1054         if self.function is not None: 
    1055             self._line(self.lastlocation, "def {}(**variables):".format(self.function)) 
    1056             self.indent += 1 
    1057             self.lines2locs = [] # We initialize startline one line below, which restarts the counter 
     1072        self.lastlocation = Location(self.template.source, self.template.name, None, 0, 0, 0, 0) 
     1073 
     1074        self._line(self.lastlocation, "def {}(**variables):".format(self.template.name)) 
     1075        self.indent += 1 
     1076        self.lines2locs = [] # We initialize startline one line below, which restarts the counter 
    10581077        self._line(self.lastlocation, "import sys, datetime, itertools, json, random, collections; from ll.misc import xmlescape; from ll import ul4c, color; startline = sys._getframe().f_lineno") # The line number of this line 
    10591078        self._line(self.lastlocation, "__1__") 
    10601079        self._line(self.lastlocation, "__2__") 
    10611080        self._line(self.lastlocation, "source = {!r}".format(self.template.source)) 
    1062         self._line(self.lastlocation, 'variables = {key.decode("utf-8"): value for (key, value) in variables.iteritems()}') # FIXME: This can be dropped in Python 3.0 where strings are unicode 
     1081        self._line(self.lastlocation, "name = {!r}".format(self.template.name)) 
     1082        self._line(self.lastlocation, 'variables = {key.decode("utf-8"): value for (key, value) in variables.iteritems()}') # FIXME: This can be dropped in Python 3 where strings are unicode 
    10631083        self._line(self.lastlocation, "r0 = r1 = r2 = r3 = r4 = r5 = r6 = r7 = r8 = r9 = None") 
    10641084        self._line(self.lastlocation, "try:") 
     
    10741094                self.lastopcode = opcode.code 
    10751095        except Exception, exc: 
    1076             newexc = Error(opcode.location) # FIXME: Use ``raise ... from`` in Python 3.0 
     1096            newexc = Error(opcode.location) # FIXME: Use ``raise ... from`` in Python 3 
    10771097            newexc.__cause__ = exc 
    10781098            raise newexc 
     
    10801100        self._line(self.lastlocation, "except Exception, exc:") 
    10811101        self.indent += 1 
    1082         self._line(self.lastlocation, "newexc = ul4c.Error(ul4c.Location(source, *locations[lines2locs[sys.exc_info()[2].tb_lineno-startline]]))") # FIXME: Use ``raise ... from`` in Python 3.0 
     1102        self._line(self.lastlocation, "newexc = ul4c.Error(ul4c.Location(source, name, *locations[lines2locs[sys.exc_info()[2].tb_lineno-startline]]))") # FIXME: Use ``raise ... from`` in Python 3 
    10831103        self._line(self.lastlocation, "newexc.__cause__ = exc") 
    10841104        self._line(self.lastlocation, "raise newexc") 
     
    12601280    def _dispatch_callmethkw(self, opcode): 
    12611281        if opcode.arg == "render": 
    1262             self._line(opcode.location, 'r{op.r1:d} = "".join(r{op.r2:d}(**{{key.encode("utf-8"): value for (key, value) in r{op.r3:d}.iteritems()}}))'.format(op=opcode)) # FIXME: This can be simplified in Python 3.0 where strings are unicode 
     1282            self._line(opcode.location, 'r{op.r1:d} = "".join(r{op.r2:d}(**{{key.encode("utf-8"): value for (key, value) in r{op.r3:d}.iteritems()}}))'.format(op=opcode)) # FIXME: This can be simplified in Python 3 where strings are unicode 
    12631283        else: 
    12641284            raise UnknownMethodError(opcode.arg) 
     
    12771297        self.indent -= 1 
    12781298    def _dispatch_def(self, opcode): 
    1279         self._line(opcode.location, "def _(**variables):") 
     1299        self._line(opcode.location, "def _template_{}(**variables):".format(opcode.arg)) 
    12801300        self.defs.append(opcode) 
    12811301        self.indent += 1 
    1282         self._line(opcode.location, 'variables = {key.decode("utf-8"): value for (key, value) in variables.iteritems()}') # FIXME: This can be dropped in Python 3.0 where strings are unicode 
     1302        self._line(opcode.location, "name = {!r}".format(opcode.arg)) 
     1303        self._line(opcode.location, 'variables = {key.decode("utf-8"): value for (key, value) in variables.iteritems()}') # FIXME: This can be dropped in Python 3 where strings are unicode 
    12831304        self._line(opcode.location, "r0 = r1 = r2 = r3 = r4 = r5 = r6 = r7 = r8 = r9 = None") 
    12841305        self._line(opcode.location, "try:") 
     
    12911312        self._line(opcode.location, "except Exception, exc:") 
    12921313        self.indent += 1 
    1293         self._line(opcode.location, "newexc = ul4c.Error(ul4c.Location(source, *locations[lines2locs[sys.exc_info()[2].tb_lineno-startline]]))") # FIXME: Use ``raise ... from`` in Python 3.0 
     1314        self._line(opcode.location, "newexc = ul4c.Error(ul4c.Location(source, name, *locations[lines2locs[sys.exc_info()[2].tb_lineno-startline]]))") # FIXME: Use ``raise ... from`` in Python 3 
    12941315        self._line(opcode.location, "newexc.__cause__ = exc") 
    12951316        self._line(opcode.location, "raise newexc") 
    12961317        self.indent -= 2 
    1297         self._line(opcode.location, "variables[{op.arg!r}] = _".format(op=defopcode)) 
     1318        self._line(opcode.location, "variables[{op.arg!r}] = _template_{op.arg}".format(op=defopcode)) 
    12981319    def _dispatch_render(self, opcode): 
    12991320        self._line(opcode.location, 'for chunk in r{op.r1:d}(**{{key.encode("utf-8"): value for (key, value) in r{op.r2:d}.iteritems()}}): yield chunk'.format(op=opcode)) 
     
    14311452        self._varcounter = 0 
    14321453 
    1433         self._line("ul4.Template.create(function(vars){") 
     1454        self._line("ul4.Template.create('{}', function(vars){{".format(self.template.name)) 
    14341455        self._indent += 1 
    14351456 
     
    15481569        self._line(u"}") 
    15491570    def _dispatch_def(self, opcode): 
    1550         self._line(u"vars[{arg}] = ul4.Template.create(function(vars){{".format(arg=json.dumps(opcode.arg))) 
     1571        self._line(u"vars[{arg}] = ul4.Template.create({arg}, function(vars){{".format(arg=json.dumps(opcode.arg))) 
    15511572        self._indent += 1 
    15521573        self._line(u"var out = [], {};".format(", ".join("r{} = null".format(i) for i in xrange(10)))) 
     
    18831904        level = self._stack.pop() 
    18841905        # define new template object 
    1885         self._do(u"{var}.put({arg}, new com.livinglogic.ul4.JSPTemplate()".format(var=self._stack[-1].variables, arg=misc.javaexpr(level.name))) 
     1906        self._do(u'{var}.put({arg}, new com.livinglogic.ul4.JSPTemplate()'.format(var=self._stack[-1].variables, arg=misc.javaexpr(level.name))) 
    18861907        self._do(u"{") 
    18871908        self._do(1) 
     1909        self._do(u"public String getName()") 
     1910        self._do(u"{") 
     1911        self._do(1) 
     1912        self._do(u'return {};'.format(misc.javaexpr(level.name))) 
     1913        self._do(-1) 
     1914        self._do(u"}") 
    18881915        self._do(u"public void render(java.io.Writer out, java.util.Map<String, Object> variables) throws java.io.IOException") 
    18891916        self._do(u"{") 
     
    26162643                raise UnterminatedStringError() 
    26172644        except Exception, exc: 
    2618             newexc = Error(location) # FIXME: use ``raise ... from`` in Python 3.0 
     2645            newexc = Error(location) # FIXME: use ``raise ... from`` in Python 3 
    26192646            newexc.__cause__ = exc 
    26202647            raise newexc 
     
    27872814            return ast.compile(template) 
    27882815        except Exception, exc: 
    2789             newexc = Error(location) # FIXME: Use ``raise ... from`` in Python 3.0 
     2816            newexc = Error(location) # FIXME: Use ``raise ... from`` in Python 3 
    27902817            newexc.__cause__ = exc 
    27912818            raise newexc 
  • src/ll/xist/data/js/ul4.js

    r4352 r4524  
    728728        else if (this.istemplate(obj)) 
    729729        { 
    730             return "ul4.Template.create(" + obj.render.toString() + ")"; 
     730            return "ul4.Template.create('" + obj.name + "', " + obj.render.toString() + ")"; 
    731731        } 
    732732        throw "json() requires a serializable object"; 
     
    14631463        __istemplate__: true, 
    14641464 
    1465         create: function(render) 
     1465        create: function(name, render) 
    14661466        { 
    14671467            var template = ul4._clone(this); 
     1468            template.name = name; 
    14681469            template.render = render; 
    14691470            return template; 
  • test/test_ul4.py

    r4501 r4524  
    5858class RenderPython(Render): 
    5959    def renders(self): 
    60         template = ul4c.compile(self.source) 
     60        template = ul4c.Template(self.source) 
    6161        print "Testing Python template:".format(self.filename, self.lineno) 
    6262        print template.pythonsource() 
     
    6666class RenderPythonDumpS(Render): 
    6767    def renders(self): 
    68         template = ul4c.compile(self.source) 
    69         template = ul4c.loads(template.dumps()) # Recreate the template from the binary dump 
     68        template = ul4c.Template(self.source) 
     69        template = ul4c.Template.loads(template.dumps()) # Recreate the template from the binary dump 
    7070        print "Testing Python template loaded from string ({}, line {}):".format(self.filename, self.lineno) 
    7171        print template.pythonsource() 
     
    7575class RenderPythonDump(Render): 
    7676    def renders(self): 
    77         template = ul4c.compile(self.source) 
     77        template = ul4c.Template(self.source) 
    7878        stream = StringIO.StringIO() 
    7979        template.dump(stream) 
    8080        stream.seek(0) 
    81         template = ul4c.load(stream) # Recreate the template from the stream 
     81        template = ul4c.Template.load(stream) # Recreate the template from the stream 
    8282        print "Testing Python template loaded from stream ({}, line {}):".format(self.filename, self.lineno) 
    8383        print template.pythonsource() 
     
    8888    def renders(self): 
    8989        # Check the Javascript version (this requires an installed ``d8`` shell from V8 (http://code.google.com/p/v8/)) 
    90         template = ul4c.compile(self.source) 
     90        template = ul4c.Template(self.source) 
    9191        js = template.jssource() 
    9292        js = u"template = {};\ndata = {};\nprint(template.renders(data));\n".format(js, ul4c._json(self.variables)) 
     
    118118    def findexception(self, output): 
    119119        lines = output.splitlines() 
     120        msg = None 
    120121        for line in lines: 
    121             prefix = 'Exception in thread "main"' 
    122             if line.startswith(prefix): 
    123                 msg = line[len(prefix):].strip() 
    124                 if msg == "Traceback (most recent call last):": # This is a Jython exception, the message is in the last line 
    125                     msg = lines[-1] 
    126                 print >>sys.stderr, output 
    127                 raise RuntimeError(msg) 
     122            prefix1 = 'Exception in thread "main"' 
     123            prefix2 = "Caused by:" 
     124            if line.startswith(prefix1): 
     125                msg = line[len(prefix1):].strip() 
     126            elif line.startswith(prefix2): 
     127                msg = line[len(prefix2):].strip() 
     128            else: 
     129                continue 
     130            if msg == "Traceback (most recent call last):": # This is a Jython exception, the message is in the last line 
     131                msg = lines[-1] 
     132                break 
     133        if msg is not None: 
     134            print >>sys.stderr, output 
     135            raise RuntimeError(msg) 
    128136 
    129137    def formatsource(self, string): 
     
    171179    com.livinglogic.ul4.Template template = new com.livinglogic.ul4.JSPTemplate() 
    172180    { 
     181        public String getName() 
     182        { 
     183            return "unnamed"; 
     184        } 
    173185        public void render(java.io.Writer out, java.util.Map<String, Object> variables) throws java.io.IOException 
    174186        { 
     
    187199        # Check the Java version 
    188200        print "Testing Java code ({}, line {}):".format(self.filename, self.lineno) 
    189         template = ul4c.compile(self.source) 
     201        template = ul4c.Template(self.source) 
    190202        java = template.javasource(indent=4) 
    191203        java = self.codetemplate % dict(variables=misc.javaexpr(self.variables), template=java) 
     
    207219        # Check the Java version 
    208220        print "Testing Java InterpretedTemplate (interpreted mode, compiled by Python) ({}, line {}):".format(self.filename, self.lineno) 
    209         template = ul4c.compile(self.source) 
     221        template = ul4c.Template(self.source) 
    210222        dump = template.dumps() 
    211223        java = self.codetemplate % dict(variables=misc.javaexpr(self.variables), dump=misc.javaexpr(dump)) 
     
    235247 
    236248all_python_renderers = (RenderPython, RenderPythonDumpS, RenderPythonDump) 
    237 # FIXME: The following really takes a long time to run: all_renderers = (RenderPython, RenderPythonDumpS, RenderPythonDump, RenderJS, RenderJavaSourceCompiledByPython, RenderJavaLoadByJava, RenderJavaSourceCompiledByJava) 
     249# FIXME: The following really takes a long time to run:  
     250#all_renderers = (RenderPython, RenderPythonDumpS, RenderPythonDump, RenderJS, RenderJavaSourceCompiledByPython, RenderJavaLoadByJava, RenderJavaSourceCompiledByJava) 
    238251all_renderers = all_python_renderers 
    239252 
     
    10571070        yield eq, "False", r(code, data=[]) 
    10581071        yield eq, "False", r(code, data={}) 
    1059         yield eq, "False", r(code, data=ul4c.compile(u"")) 
     1072        yield eq, "False", r(code, data=ul4c.Template(u"")) 
    10601073        yield eq, "False", r(code, data=color.red) 
    10611074 
     
    10781091        yield eq, "False", r(code, data=[]) 
    10791092        yield eq, "False", r(code, data={}) 
    1080         yield eq, "False", r(code, data=ul4c.compile(u"")) 
     1093        yield eq, "False", r(code, data=ul4c.Template(u"")) 
    10811094        yield eq, "False", r(code, data=color.red) 
    10821095 
     
    10991112        yield eq, "False", r(code, data=[]) 
    11001113        yield eq, "False", r(code, data={}) 
    1101         yield eq, "False", r(code, data=ul4c.compile(u"")) 
     1114        yield eq, "False", r(code, data=ul4c.Template(u"")) 
    11021115        yield eq, "False", r(code, data=color.red) 
    11031116 
     
    11201133        yield eq, "False", r(code, data=[]) 
    11211134        yield eq, "False", r(code, data={}) 
    1122         yield eq, "False", r(code, data=ul4c.compile(u"")) 
     1135        yield eq, "False", r(code, data=ul4c.Template(u"")) 
    11231136        yield eq, "False", r(code, data=color.red) 
    11241137 
     
    11411154        yield eq, "False", r(code, data=[]) 
    11421155        yield eq, "False", r(code, data={}) 
    1143         yield eq, "False", r(code, data=ul4c.compile(u"")) 
     1156        yield eq, "False", r(code, data=ul4c.Template(u"")) 
    11441157        yield eq, "False", r(code, data=color.red) 
    11451158 
     
    11621175        yield eq, "False", r(code, data=[]) 
    11631176        yield eq, "False", r(code, data={}) 
    1164         yield eq, "False", r(code, data=ul4c.compile(u"")) 
     1177        yield eq, "False", r(code, data=ul4c.Template(u"")) 
    11651178        yield eq, "False", r(code, data=color.red) 
    11661179 
     
    11841197        yield eq, "True", r(code, data=PseudoList([])) 
    11851198        yield eq, "False", r(code, data={}) 
    1186         yield eq, "False", r(code, data=ul4c.compile(u"")) 
     1199        yield eq, "False", r(code, data=ul4c.Template(u"")) 
    11871200        yield eq, "False", r(code, data=color.red) 
    11881201 
     
    12061219        yield eq, "True", r(code, data={}) 
    12071220        yield eq, "True", r(code, data=PseudoDict({})) 
    1208         yield eq, "False", r(code, data=ul4c.compile(u"")) 
     1221        yield eq, "False", r(code, data=ul4c.Template(u"")) 
    12091222        yield eq, "False", r(code, data=color.red) 
    12101223 
     
    12271240        yield eq, "False", r(code, data=[]) 
    12281241        yield eq, "False", r(code, data={}) 
    1229         yield eq, "True", r(code, data=ul4c.compile(u"")) 
     1242        yield eq, "True", r(code, data=ul4c.Template(u"")) 
    12301243        yield eq, "False", r(code, data=color.red) 
    12311244 
     
    12481261        yield eq, "False", r(code, data=[]) 
    12491262        yield eq, "False", r(code, data={}) 
    1250         yield eq, "False", r(code, data=ul4c.compile(u"")) 
     1263        yield eq, "False", r(code, data=ul4c.Template(u"")) 
    12511264        yield eq, "True", r(code, data=color.red) 
    12521265 
     
    14611474        yield eq, "dict", r(code, x={1: 2}) 
    14621475        yield eq, "dict", r(code, x=PseudoDict({1: 2})) 
    1463         yield eq, "template", r(code, x=ul4c.compile("")) 
     1476        yield eq, "template", r(code, x=ul4c.Template("")) 
    14641477        yield eq, "color", r(code, x=color.red) 
    14651478 
     
    15781591def test_method_render(): 
    15791592    for r in all_renderers: 
    1580         t = ul4c.compile(u'(<?print data?>)') 
     1593        t = ul4c.Template(u'(<?print data?>)') 
    15811594        yield eq, '(GURK)', r(u"<?print t.render(data='gurk').upper()?>", t=t) 
    15821595        yield eq, '(GURK)', r(u"<?print t.render(**{'data': 'gurk'}).upper()?>", t=t) 
    15831596 
    1584         t = ul4c.compile(u'(gurk)') 
     1597        t = ul4c.Template(u'(gurk)') 
    15851598        yield eq, '(GURK)', r(u"<?print t.render().upper()?>", t=t) 
    15861599 
     
    17641777@py.test.mark.ul4 
    17651778def test_render(): 
    1766     t = ul4c.compile(u'<?print prefix?><?print data?><?print suffix?>') 
     1779    t = ul4c.Template(u'<?print prefix?><?print data?><?print suffix?>') 
    17671780    for r in all_renderers: 
    17681781        yield eq, '(f)(o)(o)', r(u'<?for c in data?><?render t(data=c, prefix="(", suffix=")")?><?end for?>', t=t, data='foo') 
     
    17721785@py.test.mark.ul4 
    17731786def test_render_var(): 
    1774     t = ul4c.compile(u'<?code x += 1?><?print x?>') 
     1787    t = ul4c.Template(u'<?code x += 1?><?print x?>') 
    17751788    for r in all_renderers: 
    17761789        yield eq, '42,43,42', r(u'<?print x?>,<?render t(x=x)?>,<?print x?>', t=t, x=42) 
     
    17911804@py.test.mark.ul4 
    17921805def test_nested_exceptions(): 
    1793     tmpl1 = ul4c.compile(u"<?print 2*x?>") 
    1794     tmpl2 = ul4c.compile(u"<?render tmpl1(x=x)?>") 
    1795     tmpl3 = ul4c.compile(u"<?render tmpl2(tmpl1=tmpl1, x=x)?>") 
     1806    tmpl1 = ul4c.Template(u"<?print 2*x?>") 
     1807    tmpl2 = ul4c.Template(u"<?render tmpl1(x=x)?>") 
     1808    tmpl3 = ul4c.Template(u"<?render tmpl2(tmpl1=tmpl1, x=x)?>") 
    17961809 
    17971810    for r in all_python_renderers: 
    1798         msg = "TypeError .*render tmpl3.*render tmpl2.*render tmpl1.*print 2.*unsupported operand type|.* \\* .* not supported" 
     1811        msg = "render tmpl3.*render tmpl2.*render tmpl1.*print 2.*TypeError.*unsupported operand type|.* \\* .* not supported" 
    17991812        yield raises, msg, r(u"<?render tmpl3(tmpl1=tmpl1, tmpl2=tmpl2, x=x)?>", tmpl1=tmpl1, tmpl2=tmpl2, tmpl3=tmpl3, x=None) 
    18001813 
     
    18091822def test_templateattributes(): 
    18101823    s = "<?print x?>" 
    1811     t = ul4c.compile(s) 
     1824    t = ul4c.Template(s) 
    18121825 
    18131826    for r in all_python_renderers: 
     
    18251838 
    18261839def universaltemplate(): 
    1827     return ul4c.compile(""" 
     1840    return ul4c.Template(""" 
    18281841        text 
    18291842        <?code x = 'gurk'?> 
     
    18961909    t = universaltemplate() 
    18971910    t.pythonsource() 
    1898     t.pythonsource("template") 
    18991911 
    19001912