Source

callchain / callchain / tests / descriptors.py

# -*- coding: utf-8 -*-
'''context descriptors'''

from inspect import isclass
from functools import update_wrapper

from stuf.utils import lazybase
from appspace.keys import key

from spine.keys.core import (
    KDirect, KFactory, KExtend, KCall, KMethod, KRefactory, KReextend, KJoin)

###############################################################################
## base descriptor classes ####################################################
###############################################################################


class _readonly(lazybase):

    '''read-only descriptor'''

    def __set__(self, this, value):
        raise AttributeError('attribute is read-only')

    def __delete__(self, this):
        raise AttributeError('attribute is read-only')


class _appbase(_readonly):

    def __init__(self, label, branch=False):
        '''
        init

        @param label: application label
        @param branch: branch label (default: False)
        '''
        super(_appbase, self).__init__()
        self.label = label
        self.branch = branch


class _configurable(_appbase):

    def __init__(self, label, branch=False, *args, **kw):
        '''
        init

        @param label: application label
        @param branch: branch label (default: False)
        '''
        super(_configurable, self).__init__(label, branch)
        # method attributes
        self.attrs = args
        # method keywords
        self.extra = kw


class _factory(_configurable):

    def __get__(self, this, that):
        new_app = this.M.get(self.label, self.branch)
        if isclass(new_app):
            # build application
            new_app = self._factory(new_app, this)
        return new_app


###############################################################################
## direct invocation descriptor classes #######################################
###############################################################################


@key(KDirect)
class app(_appbase):

    '''passes application from appspace directly to host'''

    def __get__(self, this, that):
        return this.M.get(self.label, self.branch)


@key(KJoin)
class join(_configurable):

    '''
    pass appspaced application directly to host after assigning current
    session to it
    '''

    def __get__(self, this, that):
        new_app = this.M.get(self.label, self.branch)
        new_app.session = this.session
        return new_app


@key(KCall)
class call(_configurable):

    '''calls application from appspace when accessed on object/class'''

    def __get__(self, this, that):
        return this.M.apply(
            self.label,
            self.branch,
            *(getattr(this, attr) for attr in self.attrs),
            **self.extra
        )


@key(KMethod)
class method(_configurable):

    '''adds method from appspace when accessed on object/class'''

    def __get__(self, this, that):
        return this.M.partial(
            self.label,
            self.branch,
            *(getattr(this, attr) for attr in self.attrs),
            **self.extra
        )


###############################################################################
## factory descriptor classes #################################################
###############################################################################


@key(KFactory)
class factory(_factory):

    '''
    builds object from appspaced factory once, adds it to appspace, and
    passes it to host
    '''

    def _factory(self, new_app, this):
        new_app = new_app(
            *(getattr(this, attr) for attr in self.attrs), **self.extra
        )
        return this.M.set(new_app, self.label, self.branch)


@key(KExtend)
class extend(_factory):

    '''
    builds object hat extends host functionality from appspaced factory once,
    adds it to appspace, and passes it to host
    '''

    def _factory(self, new_app, this):
        new_app = new_app(
            this, *(getattr(this, attr) for attr in self.attrs), **self.extra
        )
        return this.M.set(new_app, self.label, self.branch)


@key(KRefactory)
class refactory(_factory):

    '''builds new object from appspaced factory and passes it to host'''

    def _factory(self, new_app, this):
        new_app = new_app(
            *(getattr(this, attr) for attr in self.attrs), **self.extra
        )
        return new_app


@key(KReextend)
class reextend(_factory):

    '''
    builds new object from appspaced factory that extends host functionality
    '''

    def _factory(self, new_app, this):
        new_app = new_app(
            this, *(getattr(this, attr) for attr in self.attrs), **self.extra
        )
        return new_app

###############################################################################
## defer descriptor classes ###################################################
###############################################################################


class defer(_readonly):

    '''defer method call'''

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

        @param method: method to defer
        '''
        super(defer, self).__init__()
        self.method = method

    def __get__(self, this, that):
        return self._factory(that) if this is None else self._factory(this)

    def _factory(self, this):
        method = self.method
        def coroutine(*args, **kw): #@IgnorePep8
            # pack object reference into arguments
            args = (this,) + args
            # chain method
            this.session.chain(method, *args, **kw)
            return this
        update_wrapper(coroutine, method)
        return coroutine
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.