Source

callchain / callchain / route.py

# -*- coding: utf-8 -*-
'''callchain routes'''

from collections import defaultdict, deque

from stuf.utils import selfname
from appspace.managers import keyed
from appspace.keys import ConfigurationError

from callchain.registry import Manager
from callchain.base import ResetLocalMixin
from callchain.keys.base import KInternalRoutes, KExternalRoutes
from callchain.keys.settings import (KInternalDefaults, KExternalDefaults,
    KExternalRequired, KInternalRequired)


class ChainManager(ResetLocalMixin):

    '''internal chain configuration'''

    __slots__ = ('pattern', 'required', 'defaults')

    def __init__(self, manager):
        '''
        init

        @param pattern: pattern configuration class or appspace label
        @param required: required global settings (default: None)
        @param defaults: default global settings (default: None)
        '''
#        self.pattern = pattern
#        self.required = required
#        self.defaults = defaults

    def __call__(self, that):
        # internal appspace manager
        that._M = Chains.appspace(
            self.pattern,
            self.required,
            self.defaults,
        )
        # lock internal appspace global settings
        that._M.settings.lock()
        # set internal appspace global settings
        that._G = that._M.settings.final
        return that

    def register(self, thing):
        '''
        register some thing in userspace

        @param thing: some thing
        '''
        self.M.set(thing, selfname(thing), self.G.userspace)


class EventManager(Manager):

    __slots__ = ('pattern', 'required', 'defaults', 'events')

    def __init__(self, patterns, events=None, required=None, defaults=None):
        '''
        init

        @param patterns: pattern config or eventspace label (default: None)
        @param events: events configuration (default: None)
        @param required: required settings (default: None)
        @param defaults: default settings (default: None)
        '''
        super(EventManager, self).__init__(patterns, required, defaults)
        # update event registry with any other events
        if events is not None:
            self.E.update(events)

    def __call__(self, that):
        that = super(EventManager, self).__call__(that)
#        that.E = EventRegistry('events')
#        that.E.update(self.events)
        return that

    def event(self, event):
        '''
        create or fetch `event`

        @param event: event label
        '''
        self.E.event(event)
        return self

    def unevent(self, event):
        '''
        drop `event`

        @param event: event label
        '''
        self.E.unevent(event)
        return self


class Chains(type):

    _manager = Manager

    def __init__(self, *patterns):
        pass

    def defaults(self, *defaults):
        return self

    def required(self, *required):
        return self

    def __new__(cls, name, bases, classdict):
        cfg = defaultdict(deque)
        manager = None
        for base in bases:
            if keyed(KInternalRoutes, base):
                cfg['internal routes'].append(base)
            elif keyed(KExternalRoutes, base):
                cfg['external routes'].append(base)
            elif keyed(KInternalDefaults, base):
                cfg['internal defaults'].append(base)
            elif keyed(KExternalDefaults, base):
                cfg['external defaults'].append(base)
            elif keyed(KExternalRequired, base):
                cfg['external required'].append(base)
            elif keyed(KInternalRequired, base):
                cfg['internal required'].append(base)
        internal_routes = cfg.get('internal routes')
        if internal_routes:
            manager = internal_routes.popleft().build()
            for internal_route in internal_routes:
                manager.update(internal_route)
            settings = manager.internal_settings
            for internal_default in cfg.get('internal defaults'):
                settings.defaults = internal_default
            for internal_required in cfg.get('internal required'):
                settings.required = internal_required
        external_routes = cfg.get('external routes')
        if external_routes:
            manager = (
                manager if manager is not None
                else external_routes.popleft().build()
            )
            for external_route in external_routes:
                manager.update(external_route)
            settings = manager.external_settings
            for external_default in cfg.get('external defaults'):
                settings.defaults = external_default
            for external_required in cfg.get('external required'):
                settings.required = external_required
        if manager is None:
            raise ConfigurationError('no manager configured')
        return Manager(manager)


class Events(Chains):

    '''event manager'''

    def __init__(self, *patterns):
        pass

    def events(self, *events):
        return self