Esempio n. 1
0
  def throw(self, error, info=None, output=None):
    """Raises a TemplateException.

    This method may be passed an existing TemplateException object; a
    single value containing an error message which is used to instantiate
    a TemplateException of type 'None'; or a pair of values representing
    the exception type and info from which a TemplateException object is
    instantiated.  e.g.

      context.throw(exception)
      context.throw("I'm sorry Dave, I can't do that")
      context.throw('denied', "I'm sorry Dave, I can't do that")

    An optional third parameter can be supplied in the last case which
    is a reference to the current output buffer containing the results
    of processing the template up to the point at which the exception
    was thrown.  The RETURN and STOP directives, for example, use this
    to propagate output back to the user, but it can safely be ignored
    in most cases.
    """
    error = unscalar(error)
    info = unscalar(info)
    if isinstance(error, TemplateException):
      raise error
    elif info is not None:
      raise TemplateException(error, info, output)
    else:
      raise TemplateException("None", error or "", output)
Esempio n. 2
0
  def insert(self, files):
    """Insert the contents of a file without parsing."""
    # TODO: Clean this up; unify the way "files" is passed to this routine.
    files = unscalar(files)
    if is_seq(files):
      files = unscalar_list(files)
    else:
      files = [unscalar(files)]
    prefix = providers = text = None
    output = cStringIO.StringIO()

    for file in files:
      prefix, name = split_prefix(file)
      if prefix:
        providers = self.__prefix_map.get(prefix)
        if not providers:
          self.throw(ERROR_FILE, "no providers for file prefix '%s'" % prefix)
      else:
        providers = self.__prefix_map.get("default") or self.__load_templates

      for provider in providers:
        try:
          text = provider.load(name, prefix)
        except Exception, e:
          self.throw(ERROR_FILE, str(e))
        if text is not None:
          output.write(text)
          break
      else:
        self.throw(ERROR_FILE, "%s: not found" % file)
 def next(self):
   if not self.ready:
     self.ready = True
     if self.data:
       return unscalar(self.data[0])
   elif self.advance():
     return unscalar(self.data[self.index])
   raise StopIteration
Esempio n. 4
0
 def __next__(self):
   if not self.ready:
     self.ready = True
     if self.data:
       return unscalar(self.data[0])
   elif self.advance():
     return unscalar(self.data[self.index])
   raise StopIteration
Esempio n. 5
0
  def get(self, ident, args=None):
    """Returns the value for an variable stored in the stash.

    The variable may be specified as a simple string, e.g. 'foo', or
    as an array reference representing compound variables.  In the
    latter case, each pair of successive elements in the list
    represent a node in the compound variable.  The first is the
    variable name, the second a list of arguments or 0 if undefined.
    So, the compound variable [% foo.bar('foo').baz %] would be
    represented as the list [ 'foo', 0, 'bar', ['foo'], 'baz', 0 ].
    Returns the value of the identifier or an empty string if
    undefined.
    """
    ident = util.unscalar(ident)
    root = self
    if isinstance(ident, str) and ident.find(".") != -1:
      ident = [y for x in ident.split(".")
                 for y in (re.sub(r"\(.*$", "", x), 0)]
    if isinstance(ident, (list, tuple)):
      for a, b in util.chop(ident, 2):
        result = self.__dotop(root, a, b)
        if result is not None:
          root = result
        else:
          break
    else:
      result = self.__dotop(root, ident, args)

    if result is None:
      result = self.undefined(ident, args)
    return util.PerlScalar(result)
Esempio n. 6
0
  def __assign(self, root, item, args=None, value=None, default=False):
    """Similar to __dotop, but assigns a value to the given variable
    instead of simply returning it.

    The first three parameters are the root item, the item and
    arguments, as per __dotop, followed by the value to which the
    variable should be set and an optional 'default' flag.  If set
    true, the variable will only be set if currently false.
    """
    item = util.unscalar(item)
    args = util.unscalar_list(args)
    atroot = root is self
    if root is None or item is None:
      return None
    elif self.PRIVATE and re.search(self.PRIVATE, item):
      return None
    elif isinstance(root, dict) or atroot:
      if not (default and root.get(item)):
        root[item] = value
        return value
    elif isinstance(root, (list, tuple)) and re.match(r"-?\d+$", str(item)):
      item = int(item)
      if not (default and 0 <= item < len(root) and root[item]):
        root[item] = value
        return value
    elif util.is_object(root):
      if not (default and getattr(root, item)()):
        args.append(value)
        return getattr(root, item)(*args)
    else:
      raise Error("don't know how to assign to %s.%s" % (root, item))

    return None
Esempio n. 7
0
    def __assign(self, root, item, args=None, value=None, default=False):
        """Similar to __dotop, but assigns a value to the given variable
    instead of simply returning it.

    The first three parameters are the root item, the item and
    arguments, as per __dotop, followed by the value to which the
    variable should be set and an optional 'default' flag.  If set
    true, the variable will only be set if currently false.
    """
        item = util.unscalar(item)
        args = util.unscalar_list(args)
        atroot = root is self
        if root is None or item is None:
            return None
        elif self.PRIVATE and re.search(self.PRIVATE, item):
            return None
        elif isinstance(root, dict) or atroot:
            if not (default and root.get(item)):
                root[item] = value
                return value
        elif isinstance(root,
                        (list, tuple)) and re.match(r"-?\d+$", str(item)):
            item = int(item)
            if not (default and 0 <= item < len(root) and root[item]):
                root[item] = value
                return value
        elif util.is_object(root):
            if not (default and getattr(root, item)()):
                args.append(value)
                return getattr(root, item)(*args)
        else:
            raise Error("don't know how to assign to %s.%s" % (root, item))

        return None
Esempio n. 8
0
    def get(self, ident, args=None):
        """Returns the value for an variable stored in the stash.

    The variable may be specified as a simple string, e.g. 'foo', or
    as an array reference representing compound variables.  In the
    latter case, each pair of successive elements in the list
    represent a node in the compound variable.  The first is the
    variable name, the second a list of arguments or 0 if undefined.
    So, the compound variable [% foo.bar('foo').baz %] would be
    represented as the list [ 'foo', 0, 'bar', ['foo'], 'baz', 0 ].
    Returns the value of the identifier or an empty string if
    undefined.
    """
        ident = util.unscalar(ident)
        root = self
        if isinstance(ident, str) and ident.find(".") != -1:
            ident = [
                y for x in ident.split(".")
                for y in (re.sub(r"\(.*$", "", x), 0)
            ]
        if isinstance(ident, (list, tuple)):
            for a, b in util.chop(ident, 2):
                result = self.__dotop(root, a, b)
                if result is not None:
                    root = result
                else:
                    break
        else:
            result = self.__dotop(root, ident, args)

        if result is None:
            result = self.undefined(ident, args)
        return util.PerlScalar(result)
Esempio n. 9
0
    def set(self, ident, value, default=False):
        """Updates the value for a variable in the stash.

    The first parameter should be the variable name or list, as per
    get().  The second parameter should be the intended value for the
    variable.  The third, optional parameter is a flag which may be
    set to indicate 'default' mode.  When set true, the variable will
    only be updated if it is currently undefined or has a false value.
    The magical 'IMPORT' variable identifier may be used to indicate
    that value is a dictionary whose values should be imported.
    Returns the value set, or an empty string if not set (e.g. default
    mode).  In the case of IMPORT, returns the number of items
    imported from the hash.
    """

        root = self
        ident = util.unscalar(ident)
        value = util.unscalar(value)
        # ELEMENT: {
        if isinstance(ident, str) and ident.find(".") >= 0:
            ident = [
                y for x in ident.split(".")
                for y in (re.sub(r"\(.*$", "", x), 0)
            ]
        if isinstance(ident, (list, tuple)):
            chopped = list(util.chop(ident, 2))
            for i in range(len(chopped) - 1):
                x, y = chopped[i]
                result = self.__dotop(root, x, y, True)
                if result is None:
                    # last ELEMENT
                    return ""
                else:
                    root = result
            result = self.__assign(root, chopped[-1][0], chopped[-1][1], value,
                                   default)
        else:
            result = self.__assign(root, ident, 0, value, default)

        if result is None:
            return ""
        else:
            return result
Esempio n. 10
0
  def set(self, ident, value, default=False):
    """Updates the value for a variable in the stash.

    The first parameter should be the variable name or list, as per
    get().  The second parameter should be the intended value for the
    variable.  The third, optional parameter is a flag which may be
    set to indicate 'default' mode.  When set true, the variable will
    only be updated if it is currently undefined or has a false value.
    The magical 'IMPORT' variable identifier may be used to indicate
    that value is a dictionary whose values should be imported.
    Returns the value set, or an empty string if not set (e.g. default
    mode).  In the case of IMPORT, returns the number of items
    imported from the hash.
    """

    root = self
    ident = util.unscalar(ident)
    value = util.unscalar(value)
    # ELEMENT: {
    if isinstance(ident, str) and ident.find(".") >= 0:
      ident = [y for x in ident.split(".")
                 for y in (re.sub(r"\(.*$", "", x), 0)]
    if isinstance(ident, (list, tuple)):
      chopped = list(util.chop(ident, 2))
      for i in range(len(chopped)-1):
        x, y = chopped[i]
        result = self.__dotop(root, x, y, True)
        if result is None:
          # last ELEMENT
          return ""
        else:
          root = result
      result = self.__assign(root, chopped[-1][0], chopped[-1][1],
                            value, default)
    else:
      result = self.__assign(root, ident, 0, value, default)

    if result is None:
      return ""
    else:
      return result
Esempio n. 11
0
  def filter(self, name, args=None, alias=None):
    """Similar to plugin() above, but querying the LOAD_FILTERS providers
    to return filter instances.

    An alias may be provided which is used to save the returned filter
    in a local cache.
    """
    name = unscalar(name)
    args = unscalar_list(args or [])
    filter = None
    if not args and isinstance(name, str):
      filter = self.__filter_cache.get(name)
      if filter:
        return filter
    for provider in self.__load_filters:
      filter = provider.fetch(name, args, self)
      if filter:
        if alias:
          self.__filter_cache[alias] = filter
        return filter
    self.throw("%s: filter not found" % name)
Esempio n. 12
0
  def __dotop(self, root, item, args=None, lvalue=False):
    """This is the core 'dot' operation method which evaluates
    elements of variables against their root.

    All variables have an implicit root which is the stash object
    itself.  Thus, a non-compound variable 'foo' is actually
    '(stash.)foo', the compound 'foo.bar' is '(stash.)foo.bar'.  The
    first parameter is the current root, initially the stash itself.
    The second parameter contains the name of the variable element,
    e.g. 'foo'.  The third optional parameter is a list of any
    parenthesised arguments specified for the variable, which are
    passed to sub-routines, object methods, etc.  The final parameter
    is an optional flag to indicate if this variable is being
    evaluated on the left side of an assignment (e.g. foo.bar.baz =
    10).  When set true, intermediated dictionaries will be created
    (e.g. bar) if necessary.

    Returns the result of evaluating the item against the root, having
    performed any variable "magic".  The value returned can then be used
    as the root of the next __dotop() in a compound sequence.  Returns
    None if the variable is undefined.
    """
    root = util.unscalar(root)
    item = util.unscalar(item)
    args = util.unscalar_list(args)
    atroot = root is self
    result = None

    # return undef without an error if either side of dot is unviable
    if root is None or item is None:
      return None

    # or if an attempt is made to access a private member, starting _ or .
    if (self.PRIVATE
        and isinstance(item, str)
        and re.search(self.PRIVATE, item)):
      return None

    found = True
    isdict = isinstance(root, dict)
    if atroot or isdict:
      # if root is a regular dict or a Template::Stash kinda dict (the
      # *real* root of everything).  We first lookup the named key
      # in the hash, or create an empty hash in its place if undefined
      # and the lvalue flag is set.  Otherwise, we check the HASH_OPS
      # pseudo-methods table, calling the code if found, or return None
      if isdict:
        # We have to try all these variants because Perl hash keys are
        # stringified, but Python's aren't.
        try:
          value = root[item]
        except (KeyError, TypeError):
          try:
            value = root[str(item)]
          except (KeyError, TypeError):
            try:
              value = root[int(item)]
            except (KeyError, TypeError, ValueError):
              value = None
      else:
        value = root[item]
      if value is not None:
        if callable(value):
          result = value(*args)
        else:
          return value
      elif lvalue:
        # we create an intermediate hash if this is an lvalue
        root[item] = {}
        return root[item]
      # ugly hack: only allow import vmeth to be called on root stash
      else:
        try:
          value = self.HASH_OPS.get(item)
        except TypeError:  # Because item is not hashable, presumably.
          value = None
        if (value and not atroot) or item == "import":
          result = value(root, *args)
        else:
          try:
            return _slice(root, item)
          except TypeError:
            found = False
    elif isinstance(root, (list, tuple, util.Sequence)):
      # if root is a list then we check for a LIST_OPS pseudo-method
      # or return the numerical index into the list, or None
      if isinstance(root, util.Sequence):
        root = root.as_list()
      try:
        value = self.LIST_OPS.get(item)
      except TypeError:  # Because item is not hashable, presumably.
        value = None
      if value:
        result = value(root, *args)
      else:
        try:
          value = root[int(item)]
        except TypeError:
          sliced = []
          try:
            return _slice(root, item)
          except TypeError:
            pass
        except IndexError:
          return None
        else:
          if callable(value):
            result = value(*args)
          else:
            return value
    elif util.is_object(root):
      try:
        value = getattr(root, item)
      except (AttributeError, TypeError):
        # Failed to get object method, so try some fallbacks.
        try:
          func = self.HASH_OPS[item]
        except (KeyError, TypeError):
          pass
        else:
          return func(root.__dict__, *args)
      else:
        if callable(value):
          return value(*args)
        else:
          return value
    elif item in self.SCALAR_OPS and not lvalue:
      result = self.SCALAR_OPS[item](root, *args)
    elif item in self.LIST_OPS and not lvalue:
      result = self.LIST_OPS[item]([root], *args)
    elif self.__debug:
      raise Error("don't know how to access [%r].%s" % (root, item))
    else:
      result = []

    if not found and self.__debug:
      raise Error("%s is undefined" % (item,))
    elif result is not None:
      return result
    elif self.__debug:
      raise Error("%s is undefined" % (item,))
    else:
      return None
Esempio n. 13
0
    def __dotop(self, root, item, args=None, lvalue=False):
        """This is the core 'dot' operation method which evaluates
    elements of variables against their root.

    All variables have an implicit root which is the stash object
    itself.  Thus, a non-compound variable 'foo' is actually
    '(stash.)foo', the compound 'foo.bar' is '(stash.)foo.bar'.  The
    first parameter is the current root, initially the stash itself.
    The second parameter contains the name of the variable element,
    e.g. 'foo'.  The third optional parameter is a list of any
    parenthesised arguments specified for the variable, which are
    passed to sub-routines, object methods, etc.  The final parameter
    is an optional flag to indicate if this variable is being
    evaluated on the left side of an assignment (e.g. foo.bar.baz =
    10).  When set true, intermediated dictionaries will be created
    (e.g. bar) if necessary.

    Returns the result of evaluating the item against the root, having
    performed any variable "magic".  The value returned can then be used
    as the root of the next __dotop() in a compound sequence.  Returns
    None if the variable is undefined.
    """
        root = util.unscalar(root)
        item = util.unscalar(item)
        args = util.unscalar_list(args)
        atroot = root is self
        result = None

        # return undef without an error if either side of dot is unviable
        if root is None or item is None:
            return None

        # or if an attempt is made to access a private member, starting _ or .
        if (self.PRIVATE and isinstance(item, str)
                and re.search(self.PRIVATE, item)):
            return None

        found = True
        isdict = isinstance(root, dict)
        if atroot or isdict:
            # if root is a regular dict or a Template::Stash kinda dict (the
            # *real* root of everything).  We first lookup the named key
            # in the hash, or create an empty hash in its place if undefined
            # and the lvalue flag is set.  Otherwise, we check the HASH_OPS
            # pseudo-methods table, calling the code if found, or return None
            if isdict:
                # We have to try all these variants because Perl hash keys are
                # stringified, but Python's aren't.
                try:
                    value = root[item]
                except (KeyError, TypeError):
                    try:
                        value = root[str(item)]
                    except (KeyError, TypeError):
                        try:
                            value = root[int(item)]
                        except (KeyError, TypeError, ValueError):
                            value = None
            else:
                value = root[item]
            if value is not None:
                if callable(value):
                    result = value(*args)
                else:
                    return value
            elif lvalue:
                # we create an intermediate hash if this is an lvalue
                root[item] = {}
                return root[item]
            # ugly hack: only allow import vmeth to be called on root stash
            else:
                try:
                    value = self.HASH_OPS.get(item)
                except TypeError:  # Because item is not hashable, presumably.
                    value = None
                if (value and not atroot) or item == "import":
                    result = value(root, *args)
                else:
                    try:
                        return _slice(root, item)
                    except TypeError:
                        found = False
        elif isinstance(root, (list, tuple, util.Sequence)):
            # if root is a list then we check for a LIST_OPS pseudo-method
            # or return the numerical index into the list, or None
            if isinstance(root, util.Sequence):
                root = root.as_list()
            try:
                value = self.LIST_OPS.get(item)
            except TypeError:  # Because item is not hashable, presumably.
                value = None
            if value:
                result = value(root, *args)
            else:
                try:
                    value = root[int(item)]
                except TypeError:
                    sliced = []
                    try:
                        return _slice(root, item)
                    except TypeError:
                        pass
                except IndexError:
                    return None
                else:
                    if callable(value):
                        result = value(*args)
                    else:
                        return value
        elif util.is_object(root):
            try:
                value = getattr(root, item)
            except (AttributeError, TypeError):
                # Failed to get object method, so try some fallbacks.
                try:
                    func = self.HASH_OPS[item]
                except (KeyError, TypeError):
                    pass
                else:
                    return func(root.__dict__, *args)
            else:
                if callable(value):
                    return value(*args)
                else:
                    return value
        elif item in self.SCALAR_OPS and not lvalue:
            result = self.SCALAR_OPS[item](root, *args)
        elif item in self.LIST_OPS and not lvalue:
            result = self.LIST_OPS[item]([root], *args)
        elif self.__debug:
            raise Error("don't know how to access [%r].%s" % (root, item))
        else:
            result = []

        if not found and self.__debug:
            raise Error("%s is undefined" % (item, ))
        elif result is not None:
            return result
        elif self.__debug:
            raise Error("%s is undefined" % (item, ))
        else:
            return None
Esempio n. 14
0
 def view(self, params=None):
   """Create a new View object bound to this context."""
   from template.view import View
   return View(self, unscalar(params))
Esempio n. 15
0
  def process(self, template, params=None, localize=False):
    """Processes the template named or referenced by the first parameter.

    The optional second parameter may reference a dictionary of variable
    definitions.  These are set before the template is processed by
    calling update() on the stash.  Note that, unless the third parameter
    is true, the context is not localised and these, and any other
    variables set in the template will retain their new values after this
    method returns.  The third parameter is in place so that this method
    can handle INCLUDE calls: the stash will be localized.  # Returns the
    output of processing the template.  Errors are raised as
    TemplateException objects.
    """
    template = util.listify(unscalar(template))
    params = unscalar(params)
    compileds = []
    for name in template:
      compileds.append(self.template(name))
    if localize:
      self.__stash = self.__stash.clone(params)
    else:
      self.__stash.update(params)

    output = cStringIO.StringIO()

    try:
      # save current component
      try:
        component = self.__stash.get("component")
      except:
        component = None
      for name, compiled in zip(template, compileds):
        if not callable(compiled):
          element = compiled
        else:
          element = { "name": isinstance(name, str) and name or "",
                      "modtime": time.time() }
        if isinstance(component, Document):
          # FIXME: This block is not exercised by any test.
          elt = Accessor(element)
          elt["caller"] = component.name
          elt["callers"] = getattr(component, "callers", [])
          elt["callers"].append(component.name)
        self.__stash.set("component", element)
        if not localize:
          # merge any local blocks defined in the Template::Document
          # info our local BLOCKS cache
          if isinstance(compiled, Document):
            tblocks = compiled.blocks()
            if tblocks:
              self.__blocks.update(tblocks)
        if callable(compiled):
          tmpout = compiled(self)
        elif util.can(compiled, "process"):
          tmpout = compiled.process(self)
        else:
          self.throw("file", "invalid template reference: %s" % compiled)
        if self.__trim:
          tmpout = tmpout.strip()
        output.write(tmpout)
        # pop last item from callers
        if isinstance(component, Document):
          elt["callers"].pop()
      self.__stash.set("component", component)
    finally:
      if localize:
        # ensure stash is delocalised before dying
        self.__stash = self.__stash.declone()

    return output.getvalue()
Esempio n. 16
0
 def Create(expr):
   expr = unscalar(expr)
   if isinstance(expr, Iterator):
     return expr
   else:
     return Config.iterator(expr)
 def Create(expr):
   expr = unscalar(expr)
   if isinstance(expr, Iterator):
     return expr
   else:
     return Config.iterator(expr)