예제 #1
0
def bindToEntities(*classes, binders=None, module=None):
    '''
    Creates entity implementation proxies for the provided entities classes found in the provided module. The binding is
    done at the moment of the entity creation so the binding is not dependent of the declared entity return type.
    
    @param classes: arguments(string|class|AOPClasses)
        The classes to be proxied.
    @param binders: None|Callable|list[Callable]|tuple(Callable)
        The binders to be invoked when a proxy is created. The binders Callable's will take one argument that is the newly
        created proxy instance.
    @param module: module|None
        If the setup module is not provided than the calling module will be considered.
    '''
    if not binders: binders = []
    elif not isinstance(binders, (list, tuple)): binders = [binders]
    assert isinstance(binders, (list, tuple)), 'Invalid binders %s' % binders
    if module:
        assert ismodule(module), 'Invalid setup module %s' % module
        registry = module.__dict__
        group = module.__name__
    else:
        registry = callerLocals()
        if '__name__' not in registry:
            raise SetupError('The create proxy call needs to be made directly from the module')
        group = registry['__name__']
    register(SetupEntityProxy(group, _classes(classes), binders), registry)
예제 #2
0
def loadAllEntities(*classes, module=None):
    '''
    Loads all entities that have the type in the provided classes.
    
    @param classes: arguments(string|class|AOPClasses)
        The classes to have the entities loaded for.
    @param module: module|None
        If the setup module is not provided than the calling module will be considered.
    @return: Setup
        The setup start that loads all the entities, the return value can be used for after and before events.
    '''
    def loadAll(prefix, classes):
        for clazz in classes:
            for name, call in Assembly.current().calls.items():
                if name.startswith(prefix) and isinstance(call, CallEntity) and call.type and \
                (call.type == clazz or issubclass(call.type, clazz)): Assembly.process(name)

    if module:
        assert ismodule(module), 'Invalid setup module %s' % module
        registry = module.__dict__
        group = module.__name__
    else:
        registry = callerLocals()
        if '__name__' not in registry:
            raise SetupError('The create proxy call needs to be made directly from the module')
        group = registry['__name__']

    loader = partial(loadAll, group + '.', _classes(classes))
    return register(SetupStart(loader, name='loader_%s' % id(loader)), registry)
예제 #3
0
def listenToEntities(*classes, listeners=None, beforeBinding=True, module=None, all=False):
    '''
    Listens for entities defined in the provided module that are of the provided classes. The listening is done at the 
    moment of the entity creation so the listen is not dependent of the declared entity return type.
    
    @param classes: arguments(string|class|AOPClasses)
        The classes to listen to, this classes can be either the same class or a super class of the instances generated
        by the entity setup functions.
    @param listeners: None|Callable|list[Callable]|tuple(Callable)
        The listeners to be invoked. The listeners Callable's will take one argument that is the instance.
    @param module: module|dictionary{string:object}|None
        If the setup module is not provided than the calling module will be considered as the registry for the setup.
    @param all: boolean
        Flag indicating that the listening should be performed on all assembly.
    @param beforeBinding: boolean
        Flag indicating that the listening should be performed before any binding occurs (True) or after the
        bindings (False).
    '''
    if not listeners: listeners = []
    elif not isinstance(listeners, (list, tuple)): listeners = [listeners]
    assert isinstance(listeners, (list, tuple)), 'Invalid listeners %s' % listeners
    assert isinstance(beforeBinding, bool), 'Invalid before binding flag %s' % beforeBinding
    assert isinstance(all, bool), 'Invalid all flag %s' % all
    if not module:
        registry = callerLocals()
        if '__name__' not in registry:
            raise SetupError('The create proxy call needs to be made directly from the module')
        if all: group = None
        else: group = registry['__name__']
    elif ismodule(module):
        registry = module.__dict__
        if all: group = None
        else: group = module.__name__
    else:
        assert isinstance(module, dict), 'Invalid setup module %s' % module
        if '__name__' not in module:
            raise SetupError('The provided registry dictionary has no __name__')
        registry = module
        if all: group = None
        else: group = module['__name__']

    if beforeBinding: setup = SetupEntityListen(group, _classes(classes), listeners)
    else: setup = SetupEntityListenAfterBinding(group, _classes(classes), listeners)
    register(setup, registry)
예제 #4
0
def wireEntities(*classes, module=None):
    '''
    Creates entity wiring setups for the provided classes. The wiring setups consists of configurations found in the
    provided classes that will be published in the setup module.
    
    @param classes: arguments(string|class|AOPClasses)
        The classes to be wired.
    @param module: module|None
        If the setup module is not provided than the calling module will be considered.
    '''
    def processConfig(clazz, wconfig):
        assert isclass(clazz), 'Invalid class %s' % clazz
        assert isinstance(wconfig, WireConfig), 'Invalid wire configuration %s' % wconfig
        value = clazz.__dict__.get(wconfig.name, None)
        if value and not isclass(value): return deepcopy(value)
        if wconfig.hasValue: return deepcopy(wconfig.value)
        raise ConfigError('A configuration value is required for %r in class %r' % (wconfig.name, clazz.__name__))

    if module:
        assert ismodule(module), 'Invalid setup module %s' % module
        registry = module.__dict__
        group = module.__name__
    else:
        registry = callerLocals()
        if '__name__' not in registry:
            raise SetupError('The create wiring call needs to be made directly from the module')
        group = registry['__name__']
    wirings = {}
    for clazz in _classes(classes):
        wiring = Wiring.wiringOf(clazz)
        if wiring:
            wirings[clazz] = wiring
            assert isinstance(wiring, Wiring)
            for wconfig in wiring.configurations:
                assert isinstance(wconfig, WireConfig)
                name = SetupEntityWire.nameFor(group, clazz, wconfig)
                for setup in setupsOf(registry, SetupConfig):
                    assert isinstance(setup, SetupConfig)
                    if setup.name == name: break
                else:
                    configCall = partial(processConfig, clazz, wconfig)
                    configCall.__doc__ = wconfig.description
                    register(SetupConfig(configCall, type=wconfig.type, name=name, group=group), registry)
    if wirings:
        wire = setupFirstOf(registry, SetupEntityWire)
        if wire:
            assert isinstance(wire, SetupEntityWire)
            wire.update(wirings)
        else: register(SetupEntityWire(group, wirings), registry)
예제 #5
0
def createEntitySetup(*classes, formatter=lambda group, clazz, name: group + '.' + name if name else group + '.' + clazz.__name__,
                      module=None):
    '''
    For impl classes create the setup functions for the associated API classes. The name of the setup functions that will be generated
    are formed based on the provided formatter. To create a setup function a class from the impl classes has to inherit the api class.
    
    @param classes: arguments(string|class|AOPClasses)
        The classes to be considered the implementations for the APIs.
    @param formatter: Callable
        The formatter to use in creating the entity setup function name, the Callable will take three arguments, first is
        the group where the setup function is defined, the second is the class for wich the setup is created and the third 
        is optional and is the name of the created instance. 
    @param module: module|None
        If the setup module is not provided than the calling module will be considered.
    '''
    assert callable(formatter), 'Invalid formatter %s' % formatter
    if module:
        assert ismodule(module), 'Invalid setup module %s' % module
        registry = module.__dict__
        group = module.__name__
    else:
        registry = callerLocals()
        if '__name__' not in registry:
            raise SetupError('The create entity call needs to be made directly from the module')
        group = registry['__name__']

    wireClasses = []
    for clazz in _classes(classes):
        if not hasattr(clazz, '__ally_setup__'): continue
        setupTuple = clazz.__ally_setup__
        if not setupTuple: continue
        apiClass, name = setupTuple
        assert issubclass(clazz, apiClass), 'The impl class % do not extend the declared API class %s' % (clazz, apiClass)
        wireClasses.append(clazz)
        register(SetupEntityCreate(clazz, apiClass, name=formatter(group, apiClass, name), group=group), registry)

    wireEntities(*wireClasses, module=module)