Source

appspace / appspace / utils.py

from functools import partial
from itertools import starmap
from keyword import iskeyword

#from knife import __
#from stuf import stuf
from stuf.six import strings

from appspace.support import appifies
from appspace.keys import ABranch, ANamespace, AApp
from appspace.registry import Manager, StrictManager
from stuf.iterable import exhaustmap, exhaust
from stuf.desc import twoway
from stuf.utils import lazyimport
from stuf.deep import selfname


class key(appifies):

    '''appifier'''

    def __init__(self, key, **metadata):
        exhaustmap(metadata, key.setTaggedValue)
        appifies.__init__(self, key)


class _Filter(object):

    @classmethod
    def _filter(self, x):
        return not x[0].startswith('_')


class Patterns(_Filter):

    '''patterns for manager configured by class'''

    key = AApp
    strict = False

    @twoway
    def _manager(self):
        '''manager class'''
        return StrictManager if self.strict else Manager

    @classmethod
    def build(cls):
        '''build manager configuration from class'''
        l = selfname(cls)
        # set key
        key = cls.key
        if isinstance(key, strings):
            # load key if string
            key = lazyimport(key)
        manager = cls._manager(l, key)  # pylint: disable-msg=e1121
        b = partial(manager.keyed, ABranch)
        m, n = manager.set, partial(manager.keyed, ANamespace)
        t = lambda x, y: y.build(manager) if (n(y) or b(y)) else m(y, x, l)
        exhaustmap(vars(cls), t, cls._filter)
        return manager

    @staticmethod
    def factory(label, manager, *args):
        '''
        factory for manager

        @param label: label for manager
        '''
        # build manager
        manager = manager(label)
        # register things in manager
        exhaust(starmap(lambda x, y: manager.set(y, x), iter(args)))
        return manager

    @classmethod
    def patterns(cls, label, *args):
        '''
        configure appspace

        @param label: name of branch appspace
        @param *args: tuple of module paths or component inclusions
        '''
        return cls.factory(label, cls._manager, *args)


class _PatternsMixin(object):

    @classmethod
    def _key(cls, label, manager):
        try:
            # lazily load key
            key = cls.key
            if isinstance(key, strings):
                key = lazyimport(key)
            # register class key

        except AttributeError:
            key = manager.key(ANamespace, label)


class _PatternMixin(_Filter):

    @classmethod
    def _key(cls, label, manager):
        try:
            # lazily load key
            key = cls.key
            if isinstance(key, strings):
                key = lazyimport(key)
            # register class key
            manager.ez_register(ANamespace, label, key)
        except AttributeError:
            key = manager.key(ANamespace, label)


@appifies(ANamespace)
class Branch(_PatternMixin):

    '''branch configuration'''

    @classmethod
    def build(cls, manager):
        '''gather branch configuration'''
        cls._key(selfname(cls), manager)
        i, m = cls.include, manager.set
        t = lambda x: not x[0].startswith('_') or isinstance(x[1], strings)
        exhaustmap(vars(cls), lambda x, y: m(i(y), x), t)

    @staticmethod
    def include(module):
        '''
        configure branch appspace

        @param module: module import path
        '''
        return ('include', module)


@appifies(ANamespace)
class Namespace(_PatternMixin):

    '''configuration namespace'''

    @classmethod
    def build(cls, manager):
        '''gather namespace configuration'''
        label = selfname(cls)
        cls._key(label, manager)
        m, n = manager.set, partial(manager.keyed, ANamespace)
        t = lambda k, v: v.build(manager) if n(v) else m(v, k, label)
        exhaustmap(vars(cls), t, cls._filter)


#def localize(self, thing, *args, **kw):
#    '''
#    local settings from thing and its base classes plus any custom settings
#
#    @param thing: some thing with local settings
#    '''
#    return (twoq([type.mro(getcls(thing)), [thing]]).smash().pick('Meta')
#    .tap(lambda x: not x[0].startswith('__')).members()
#    .reup().wrap(stuf).map().invoke('update', *args, **kw).value())