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
Exemple #2
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
  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
Exemple #4
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