Source code for horetu.program

import logging
from inspect import getmembers
from copy import copy
from itertools import chain
from triedict import triedict
from collections import Mapping
from .function import Function
from .config import Configuration
logger = logging.getLogger(__name__)

[docs]class Program(Mapping): def __init__(self, function, *configurations, name=None): ''' :param functions: Base function or functions :param Configuration configurations: Configuration files and other configuration sources :param name: Force the program to have a particular name. ''' if name is None and hasattr(function, '__call__'): name = function.__name__ self.name = name self._function = function self._configurations = tuple(map(Configuration, configurations)) self._d = triedict(_sub(tuple(), function)) def subset(self, prefix): for section, function in self.items(): if section[:len(prefix)] == prefix: yield section def __repr__(self): tpl = '%(class)s(%(function)s, %(configuration)s, name=%(name)s)' return tpl % { 'class': self.__class__.__name__, 'function': getattr(self._function, '__name__', repr(self._function)), 'configuration': repr(self.configuration()), 'name': repr(self.name), } def configuration(self): return Configuration.merge(*self._configurations) def __getitem__(self, section): c = self.configuration() defaults = {} for name, value in chain(c[None].items(), c.get(section, {}).items()): defaults[name] = value return Function(self._d[section], defaults) def __copy__(self): return Program(self._function, *self._configurations, name=self.name) def __iter__(self): for section, function in self._d.items(): if callable(function): yield section def __len__(self): return len(self._d)
def _sub(section, fs): ''' :param tuple section: Sections that this sub-program is under ''' if hasattr(fs, 'items'): items = fs.items() elif hasattr(fs, '__iter__'): gs = list(fs) if all(hasattr(g, '__name__') for g in gs): items = ((g.__name__, g) for g in gs) else: raise TypeError('Bad function component: %s' % repr(fs)) elif hasattr(fs, '__call__'): yield section, fs if isinstance(fs, type): items = (item for item in getmembers(fs) \ if not item[0].startswith('_')) else: items = [] else: raise TypeError('Bad function component: %s' % repr(fs)) for name, f in items: _validate_param_name(*name) yield from _sub(section + (name,), f) def _validate_param_name(*xs): msg = 'It is best if you remove "%s" from the argument name "%s".' for x in xs: for c in '/?[]<>():': if x in c: logger.warning(msg % (c, x))