Mercurial > hg > pyloader
view pyloader/factory.py @ 22:b16d6a204ac1
stub a command line entry point
author | Jeff Hammel <jhammel@mozilla.com> |
---|---|
date | Mon, 06 Jun 2011 07:41:23 -0700 |
parents | 4f7c05630f36 |
children | 9b2ca32e7a36 |
line wrap: on
line source
""" abstract factories """ import cast import loader import os import sys from ConfigParser import InterpolationMissingOptionError from ConfigParser import InterpolationSyntaxError from ConfigParser import SafeConfigParser as ConfigParser __all__ = ['CircularReferenceError', 'PyFactory', 'IniFactory'] class CircularReferenceError(Exception): """factory has detected a circular reference""" class PyFactory(object): delimeters = ('%(', ')s') def __init__(self, config=None, main=''): self.main = main # main section self.configure(config or {}) def configure(self, config): """load a new configuration""" # TODO: this should really be a configuration update. If you keep # track of all "apps" and their parents (i.e. as a ADG) # you should be able to update only relevent apps self.config = config self.seen = set() # already seen apps to note cyclic dependencies self.parsed = {} # instantiated apps def load(self, name=None): """load an object""" name = name or self.main # load main section by default assert name in self.config, "'%s' not found in configuration" if name in self.parsed: return self.parsed[name] if name in self.seen: raise CircularReferenceError('Circular reference! : %s' % name) self.seen.add(name) # get section section = self.config[name] assert 'path' in section # load object obj = loader.load(section['path']) # get the object's arguments (if any) args = section.get('args', None) kwargs = section.get('kwargs', None) # if args and kwargs aren't there, you're done! if args is None and kwargs is None: self.parsed[name] = obj return obj # interpolate arguments if args: args = [self.interpolate(arg) for arg in args] else: args = [] if kwargs: kwargs = dict([(key, self.interpolate(value)) for key, value in kwargs.items()]) else: kwargs = {} # invoke self.parsed[name] = obj(*args, **kwargs) return self.parsed[name] def interpolate(self, value): # only interpolate strings if not isinstance(value, basestring): return value if value.startswith(self.delimeters[0]) and value.endswith(self.delimeters[1]): value = value[len(self.delimeters[0]):-len(self.delimeters[1])] if value in self.config: return self.load(value) return value class IniFactory(PyFactory): def __init__(self, inifile, main=''): assert os.path.exists(inifile), "File not found: %s" % inifile self.inifile = inifile config = self.read(inifile) PyFactory.__init__(self, config, main) @classmethod def read(cls, inifile): """reads configuration from an .ini file""" here = os.path.dirname(os.path.abspath(inifile)) # read configuration defaults={'here': here, 'this': os.path.abspath(inifile)} parser = ConfigParser(defaults=defaults) parser.optionxform = str # use whole case parser.read(inifile) # parse configuration config = {} for section in parser.sections(): # sanity check assert ':' in section, "No : in section: %s" % section # make a dict for the section name, path = section.split(':', 1) sect = config[name] = dict(path=path) # read the options for option in parser.options(section): if option in parser.defaults(): # don't include the defaults continue # try to interpolate the option # otherwise, use the raw value try: value = parser.get(section, option) except (InterpolationMissingOptionError, InterpolationSyntaxError): value = parser.get(section, option, raw=True) if option = '.': # positional arguments sect['args'] = cast.str2list(value) else: sect.setdefault('kwargs', {})[option] = value return config def main(args=sys.argv[1:]): """command line entry point""" if __name__ == '__main__': main()