Example #1
0
class SpoolTag(FilterTag):
    """
    This is a trivial subclass of FilterTag; the only
    difference is that the name parameter is required.
    """
    signature=Signature(('name', ('filter', None)))
    tagName='spool'
Example #2
0
class HaltTag(EmptyTag):
    tagName='halt'
    signature=Signature(())
    _top=True

    def genCode(self, codeStream):
        codeStream.writeln('raise ReturnValue')
Example #3
0
class ImportTag(EmptyTag):
    signature=Signature(('module', ('items', None), ('as', None)))
    tagName='import'
    _top=True
                         
    def genCode(self, codeStream):
        """
        This supports eight kinds of import:
        
        1. import M                     :==   <:import M:>
        2. import M as C                :==   <:import M as=C:> or <:import "M as C":>
        3. from M import X              :==   <:import M X:>
        4. from M import X, Y           :==   <:import M "X, Y":>
        5. from M import X as C         :==   <:import M X as=C:>
        6. from M import *              :==   <:import M *:>
        7. import M1, M2                :==   <:import "M1, M2":>
        8. import M1 as C, M2, M3 as D  :==   <:import "M1 as C, M2, M3 as D":>

        Note that case 6. cannot have an "as" clause.

        """
        module=self._parsed_args['module']
        items=self._parsed_args['items']
        asClause=self._parsed_args['as']

        if items=='*' and asClause is not None:
            raise STMLSyntaxError, "cannot use 'as' clause with from <module> import *"

        if items:
            codeStream.write('from %s import %s ' % (module, items))
        else:
            codeStream.write('import %s' % module)
        if asClause:
            codeStream.write('as %s' % asClause)
        codeStream.write('\n')
Example #4
0
class DelTag(EmptyTag):
    signature=Signature(('name',))
    tagName='del'
    _top=True

    def genCode(self, codeStream):
        codeStream.writeln('del %s' % self._parsed_args['name'])
Example #5
0
class IncludeComponentTag(ComponentTagBase):
    tagName='include'
    signature=Signature(('name',))

    def genCode(self, codeStream):
        handle=self._parsed_args['name']
        s='OUTPUT.write(COMPONENT.callIncludeComponent(%r))' % handle
        codeStream.writeln(s)
Example #6
0
class SetTag(EmptyTag):
    signature=Signature(('name', 'value'))
    tagName='set'
    _top=True

                          
    def genCode(self, codeStream):
        codeStream.writeln("%s=(%r)" % (self._parsed_args['name'],
                                        self._parsed_args['value']))
Example #7
0
class CompargsTag(EmptyTag):
    tagName='compargs'
    signature=Signature((), 'args', 'kwargs')
    _top=True

    def genCode(self, codeStream):
        args=self._parsed_args['args']
        kwargs=self._parsed_args['kwargs']
        s="COMPONENT.check_args(%r, %r)" % (args, kwargs)
        codeStream.writeln(s)
Example #8
0
class ElifTag(EmptyTag):
    tagName='elif'
    signature=Signature(('expr',))
    
    def genCode(self, codeStream):
        codeStream.dedent()
        codeStream.writeln('elif %r:' % self._parsed_args['expr'])
        codeStream.indent()
        # in case no other code is generated for the block
        codeStream.writeln('pass')
Example #9
0
class RaiseTag(EmptyTag):
    signature=Signature((('exc', None),))
    tagName='raise'
    _top=True
    
    def genCode(self, codeStream):
        exc=self._parsed_args['exc']
        if exc is None:
            codeStream.writeln('raise')
        else:
            codeStream.writeln('raise (%r)' % exc)
Example #10
0
class CallTag(EmptyTag):
    signature=Signature(('expr',))
    tagName='call'
    _top=True

    def genCode(self, codeStream):
        tocall=self._parsed_args['expr']
        if not isinstance(tocall, Expr):
            raise STMLSyntaxError, "argument to call must be an expression"
        s=tocall.text
        for l in s.splitlines():
            codeStream.writeln(l)
Example #11
0
class ExceptTag(EmptyTag):
    signature=Signature((('exc', None),))
    tagName='except'

    def genCode(self, codeStream):
        exc=self._parsed_args['exc']
        codeStream.dedent()
        if exc is not None:
            codeStream.writeln('except %s:' % exc)
        else:
            codeStream.writeln('except:')
        codeStream.indent()
        codeStream.writeln('pass')
Example #12
0
class ValTag(EmptyTag):
    """
    Implementation of the <:val `expr` fmt=`None`:> tag, which
    outputs a stringified value of its expr argument, formatted
    by the formatter fmt, if not None.
    """
    signature=Signature(('expr', ('fmt', None)))
    modules=[('skunk.templating.stml', 'stml')]
    tagName='val'
    _top=True

    def genCode(self, codeStream):
        expr=self._parsed_args['expr']
        fmt=self._parsed_args['fmt']
        codeStream.writeln('__h.stml.write_val(%r, OUTPUT, %r)' % (expr, fmt))
Example #13
0
class DefaultTag(EmptyTag):
    signature=Signature(('name', ('value', '')))
    tagName='default'
    _top=True
                          
    def genCode(self, codeStream):
        name=self._parsed_args['name']
        value=self._parsed_args['value']
        codeStream.writeln('try:')
        codeStream.indent()
        codeStream.writeln(name)
        codeStream.dedent()
        codeStream.writeln('except (NameError, AttributeError):')
        codeStream.indent()
        codeStream.writeln('%s=%r' % (name, value))
        codeStream.dedent()
Example #14
0
class IfTag(BlockTag):
    localTagDict={'else' : ElseTag,
                  'elif' : ElifTag}
    signature=Signature(('expr',))
    tagName='if'
    _top=True
    
    def genCode(self, codeStream):
        codeStream.writeln('if %r:' % self._parsed_args['expr'])
        codeStream.indent()
        codeStream.writeln('pass')
        for k in self.children:
            if isinstance(k, basestring):
                codeStream.writeln('OUTPUT.write(%r)' % k)
            else:
                k.genCode(codeStream)
        codeStream.dedent()
Example #15
0
class CacheTag(EmptyTag):
    tagName="cache"
    signature=Signature((('until', None), ('duration', None)))
    modules=[('skunk.date.timeutil', '_timeutil')]
    _top=True

    def genCode(self, codeStream):
        args=[self._parsed_args[x] for x in ('until', 'duration')]
        if args.count(None)!=1:
            raise ValueError, \
                  ("exactly one of 'until' and 'duration' arguments"
                   "may be specified")
        u, d=args
        if u:
            s="__expiration=__h._timeutil.convertUntil(%r)" % u
        else:
            s="__expiration=__h._timeutil.convertDuration(%r)" % d
        codeStream.writeln(s)
Example #16
0
class ForTag(BlockTag):
    localTagDict={'else' : ElseTag,
                  'break' : BreakTag,
                  'continue' : ContinueTag}
    signature=Signature(('expr', ('name', 'sequence_item')))
    tagName='for'
    _top=True
    
    def genCode(self, codeStream):
        codeStream.writeln('for %s in %s:'% \
                           (self._parsed_args['name'],
                            self._parsed_args['expr']))
        codeStream.indent()
        codeStream.writeln('pass')
        for k in self.children:
            if isinstance(k, basestring):
                codeStream.writeln('OUTPUT.write(%r)' % k)
            else:
                k.genCode(codeStream)
        codeStream.dedent()
Example #17
0
class UseTag(EmptyTag):
    """
    A tag which imports a tag vocabulary into a single STML component,
    optionally with a tag prefix.

    This tag does not generate code, but affects the effective tag
    vocabulary.  The tagdict therefore cannot be a Python expression,
    but a string indicating the complete __name__ of the tag
    dictionary, which must be defined in a Python module.
    """
    tagName='use'
    signature=Signature(('tagdict', ('prefix', None)))
    _top=True

    def parse(self, lexer):
        EmptyTag.parse(self, lexer)
        tagdict=self._parsed_args['tagdict']
        if not isinstance(tagdict, basestring):
            raise STMLSyntaxError, \
                  ("tagdict must be a string")
        prefix=self._parsed_args['prefix']
        i=tagdict.rfind('.')
        if i == -1:
            raise ValueError, \
                  "not an importable name"
        
        modname=tagdict[:i]
        objname=tagdict[i+1:]
        # let ImportError propagate
        mod=__import__(modname)
        moremods=modname.split('.')[1:]
        for m in moremods:
            mod=getattr(mod, m)
        # let AttributeError propagate
        obj=getattr(mod, objname)
        self.root.useTagLibrary(obj, prefix)

    def genCode(self, codeStream):
        pass
Example #18
0
class StringComponentTag(ComponentTagBase):
    tagName='component'
    signature=Signature(('name',
                         ('cache', 'no'),
                         ('namespace', None),
                         ('expiration', None),
                         ('__args__', None)),
                        None,
                        'compArgs')

    def genCode(self, codeStream):
        handle=self._parsed_args['name']
        cachePolicy=self._parsed_args['cache']
        compArgs=self._marshal_args()
        namespace=self._parsed_args['namespace']
        expiration=self._parsed_args['expiration']
        s=('OUTPUT.write(COMPONENT.callStringComponent('
           'componentHandle=%r, compArgs=%r, '
           'cachePolicy=__h.cache.decode(%r), '
           'expiration=%r, namespace=%r))') % \
           (handle, compArgs, cachePolicy, expiration, namespace)
        codeStream.writeln(s)
Example #19
0
class DataComponentTag(ComponentTagBase):
    tagName='datacomp'
    signature=Signature(('var',
                         'name',
                         ('cache', 'no'),
                         ('namespace', None),
                         ('expiration', None),
                         ('__args__', None)),
                        None,
                        'compArgs')    

    def genCode(self, codeStream):
        varname=self._parsed_args['var']
        handle=self._parsed_args['name']
        cachePolicy=self._parsed_args['cache']
        compArgs=self._marshal_args()
        namespace=self._parsed_args['namespace']
        expiration=self._parsed_args['expiration']
        s=('%s=COMPONENT.callDataComponent('
           'componentHandle=%r, compArgs=%r, cachePolicy=__h.cache.decode(%r), '
           'expiration=%r, namespace=%r)') % \
           (varname, handle, compArgs, cachePolicy, expiration, namespace)
        codeStream.writeln(s)
Example #20
0
class Node(object):
    """
    
    base class for STML tag nodes; also for RootNode, even though it
    has no tag.

    Class attributes, which should be shadowed by sub-classes:
    
    signature
       the tag signature.
       
    isBlock
       whether the tag is a block tag or not.
       
    localTagDict
       if this is a block tag, a dictionary of tags that can occur
       within the block in addition to whatever is globally available

    modules
       modules that code generated by this tag may need; they will be
       imported into the hidden namespace (__h).  Either an actual
       module, a module name, or a tuple (module_or_module_name,
       module_alias) can appear in this list.

    tagName
       the name of the tag.
       
    """

    signature = Signature(())
    isBlock = False
    localTagDict = {}
    modules = []
    tagName = None

    __slots__ = [
        'globalTagDict', 'children', 'args', 'kwargs', '_parsed_args',
        '_token', 'prefix', 'root', 'parent'
    ]

    def __init__(self,
                 globalTagDict=None,
                 parent=None,
                 root=None,
                 prefix=None):
        self.globalTagDict = globalTagDict or {}
        self.children = []
        self.args = []
        self.kwargs = {}
        self._token = None
        self.prefix = prefix
        self.root = root
        self.parent = parent

    def _init_temporary_namespace(cls, nsObj):
        """
        class method usable by subclasses if they need to initialize
        the temporary namespace
        """
        pass

    _init_temporary_namespace = classmethod(_init_temporary_namespace)

    def parse(self, lexer):
        """
        builds the node tree from the lexer.
        """
        self._parse_tag(lexer)
        self._parsed_args = self.signature.resolve_arguments(
            self.args, self.kwargs)
        if self.isBlock:
            self._parse_block(lexer)

    def _parse_tag(self, lexer):
        # you enter this when the tagname has already been identified
        curarg = None
        state = None
        while 1:
            try:
                self._token = token = lexer.next()
            except StopIteration:
                if state is None:
                    break
                else:
                    # the lexer must be broken, it should have
                    # raise a LexicalError earlier
                    raise ParseError("incomplete input, hit EOF in tag")
            else:
                if state is None:
                    state = "intag"

            tokenType = token.tokenType
            if tokenType == t_TAGNAME:
                self.handle_tagname(token.text)
                # this doesn't happen here
                assert False
                continue
            elif tokenType == t_EQUALS:

                if curarg is None:
                    self.handle_error("unexpected equals sign")
                state = "expectval"
                continue
            elif tokenType == t_EXPR:
                if state == 'expectval':
                    if curarg in self.kwargs:
                        self.handle_error("duplicate keyword argument")
                    self.kwargs[curarg] = Expr(token.text)
                    curarg = None
                    state = 'intag'
                else:
                    if curarg is not None:
                        self.args.append(curarg)
                    curarg = Expr(token.text)

            elif tokenType == t_TAGWORD or tokenType == t_QUOTED_STRING:
                if state == 'expectval':
                    if curarg in self.kwargs:
                        self.handle_error("duplicate keyword argument")
                    self.kwargs[curarg] = Expr(repr(token.text))
                    curarg = None
                    state = 'intag'
                else:
                    if curarg is not None:
                        self.args.append(curarg)
                    curarg = token.text

            elif tokenType == t_END_TAG:
                if curarg is not None:
                    self.args.append(curarg)
                break
            else:
                self.handle_error("unexpected token", token)

    def handle_eof_in_block(self):
        """
        if an EOF occurs inside a block, this handles
        it, by default, raising an error.
        """
        self.handle_error("hit EOF, expected close tag")

    def _parse_block(self, lexer):
        while 1:
            try:
                self._token = token = lexer.next()
            except StopIteration:
                if self.isBlock:
                    return self.handle_eof_in_block()
                else:
                    break
            tokenType = token.tokenType
            if tokenType == t_TEXT:
                self.handle_text(token)
            elif tokenType == t_START_TAG:
                # ignore, we'll handle this
                # for t_TAGNAME
                continue
            elif tokenType == t_TAGNAME:
                closed = self.handle_tag(token, lexer)
                if closed:
                    break
            else:
                self.handle_error("unexpected token", token)

    def _find_tag(self, token, tagName, prefix):
        """
        look up the tag in the global, local, and component tag
        dictionaries, then in the inherited local tag dictionaries.
        """
        fulltag = token.text
        try:
            return self.globalTagDict[fulltag]
        except KeyError:
            pass
        if prefix == self.prefix:
            try:
                return self.localTagDict[tagName]
            except KeyError:
                pass

        try:
            return self.root._extraTagDict[fulltag]
        except KeyError:
            pass

        p = self.parent
        while p:
            if p.prefix == prefix:
                try:
                    return p.localTagDict[tagName]
                except KeyError:
                    pass
            p = p.parent

        self.handle_error("tag not found: %s" % fulltag, token)

    def handle_text(self, token):
        self.children.append(token.text)

    def _split_tagname(self, tagname):
        if ':' in tagname:
            return tagname.split(':', 1)
        else:
            return None, tagname

    def handle_tag(self, token, lexer):
        """
        parses any tag in the block, creating child nodes as necessary
        """
        if token.text.startswith('/'):
            return self.handle_close_tag(token, lexer)
        else:
            prefix, tagname = self._split_tagname(token.text)
            tagNodeClass = self._find_tag(token, tagname, prefix)
            if tagNodeClass.isBlock:
                node = tagNodeClass(self.globalTagDict,
                                    prefix=prefix,
                                    parent=self,
                                    root=self.root)
            else:
                node = tagNodeClass(parent=self, prefix=prefix, root=self.root)
            self.children.append(node)
            node.parse(lexer)
            return False

    def handle_close_tag(self, token, lexer):
        """
        handler for a close tag
        """
        prefix, tag = self._split_tagname(token.text[1:])
        if self.tagName == tag and self.prefix == prefix:
            self._token = t = lexer.next()
            if t.tokenType == t_END_TAG:
                return True
            else:
                self.handle_error("malformed tag")
        # if we get here
        self.handle_error('close tag not expected in this context')

    def handle_error(self, msg, token=None):
        """
        raises a ParseError
        """
        if token is None:
            token = self._token
            if token is None:
                raise ParseError(msg, 0, 0)
        raise ParseError("%s: %s (%s)" % (msg, token.text, token.tokenType),
                         token.offset, token.lineno)
Example #21
0
class FilterTag(BlockTag):
    """
    A block tag that gathers the output inside the block
    and can:
       1. store it in a variable rather than output it directly;
       2. apply a filter to it;
       3. both;
       4. neither.
    """
    signature=Signature((('name', None),
                         ('filter', None)))
    tagName='filter'
    modules=['cStringIO',
             ('skunk.templating.stml', 'stml')]
    _top=True

    def _init_temporary_namespace(cls, nsObj):
        # add the filter stack
        nsObj._filter_stack=[]
    _init_temporary_namespace=classmethod(_init_temporary_namespace)

    def genCode(self, codeStream):
        name=self._parsed_args.get('name')
        filter=self._parsed_args.get('filter')
        if not (name or filter):
            # just process the intervening tags
            codeStream.writeln('pass')
            for k in self.children:
                if isinstance(k, basestring):
                    codeStream.writeln('OUTPUT.write(%r)' % k)
                else:
                    k.genCode(codeStream)
        else:
            # replace the output stream with a temporary one,
            # putting the existing stream on a stack
            codeStream.writeln('__t._filter_stack.append(OUTPUT)')
            codeStream.writeln('OUTPUT=__h.cStringIO.StringIO()')
            # process the intervening tags in a try/finally block
            codeStream.writeln('try:')
            codeStream.indent()
            codeStream.writeln('pass')
            for k in self.children:
                if isinstance(k, basestring):
                    codeStream.writeln('OUTPUT.write(%r)' % k)
                else:
                    k.genCode(codeStream)
            codeStream.dedent()
            codeStream.writeln('finally:')
            codeStream.indent()
            if name is not None:
                # we have a name, so store the string in a variable
                # and replace the output stream.
                codeStream.writeln('%s=OUTPUT.getvalue()' % name)
                codeStream.writeln('OUTPUT=__t._filter_stack.pop()')
                codeStream.dedent()
                # apply filter, if any
                if filter:
                    codeStream.writeln('%s=__h.stml.get_formatter(%s)(%s)' % \
                                       (name, filter, name))
            else:
                assert filter
                # fancy switching with the stack to replace the original output stream
                # and write the formatted value of the temporary output stream to it
                codeStream.writeln('__t._filter_stack.append(OUTPUT.getvalue())')
                codeStream.writeln('OUTPUT=__t._filter_stack.pop(-2)')
                s='OUTPUT.write(__h.stml.get_formatter(%s)(__t._filter_stack.pop()))'
                codeStream.writeln(s % filter)
                 
            codeStream.dedent()