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 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 remaining(self): if self.index >= self.max: return None else: start = self.index + 1 self.index = self.max self.count = self.max + 1 self.first = False self.last = True return unscalar_list(self.dataset[start:])
def plugin(self, name, args=None): """Calls on each of the LOAD_PLUGINS providers in turn to fetch() (i.e. load and instantiate) a plugin of the specified name. Additional parameters passed are propagated to the plugin's constructor. Returns a reference to a new plugin object or other object. On error, a TemplateException is raiased. """ args = unscalar_list(args) for provider in self.__load_plugins: plugin = provider.fetch(name, args, self) if plugin: return plugin self.throw(ERROR_PLUGIN, "%s: plugin not found" % name)
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)
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
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