Mercurial > hg > pyloader
view pyloader/factory.py @ 11:ff272dcd5cd8
we have a passing test
author | Jeff Hammel <jhammel@mozilla.com> |
---|---|
date | Fri, 27 May 2011 07:02:27 -0700 |
parents | ba2355d57998 |
children | 30979d82c95d |
line wrap: on
line source
""" abstract factories """ import loader 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) elif value == 'self': # reference this factory # tricky and dangerous return self return value