Commits

Lynn Rees committed d45ead7

- commit point

  • Participants
  • Parent commits 37c615b
  • Branches pu

Comments (0)

Files changed (50)

File callchain/__init__.py

 # -*- coding: utf-8 -*-
 '''callchain: callables and components joined in one big happy callchain'''
 
-from callchain.call import inside, einside
+from callchain.call import internal, internal_events
 from callchain.active_auto.chain import (
     chainq as aachainq, callchain as aacallchain)
 from callchain.active_auto.event import (
 from callchain.lazy_man.event import (
     eventq as lmeventq, eventchain as lmeventchain)
 from callchain.core import ResetLocalMixin, ResetTypeMixin
-from callchain.patterns import Pathways, Branchways, Nameways
+from callchain.patterns import Chains, Branchways, Nameways
 from callchain.settings import DefaultSettings, RequiredSettings
 
 __version__ = (0, 2, 5)

File callchain/active_auto/chain.py

 
 from callchain.chain import RootMixin
 from callchain.config import Defaults
-from callchain.patterns import Pathways
-from callchain.keys.core import KThings, KResult
-from callchain.keys.base import KRoot, KCall, KChain
-from callchain.call import ChainMixin, PriorityMixin, inside
+from callchain.patterns import Chains
+from callchain.keys.core import KRootResults, KRootThings
+from callchain.call import ChainMixin, PriorityMixin, internal
 
 ###############################################################################
 ## thing chain ################################################################
 ###############################################################################
 
 
-class thingchain(Pathways):
+class thingchain(Chains, Defaults):
+    dumps = 'callchain.services.dumps.Dumps'
     loads = 'callchain.services.loads.Loads'
-    dumps = 'callchain.services.dumps.Dumps'
     logger = 'callchain.services.core.loglet'
 
 
-@appifies(KThings, KRoot, KChain, KCall)
-@inside(thingchain, defaults=Defaults)
+@appifies(KRootThings)
+@thingchain
 class callchain(RootMixin, ChainMixin, AutoResultMixin):
 
     '''active queued auto-balancing lite call chain'''
 
 
-@appifies(KThings, KRoot, KChain, KCall)
-@inside(thingchain, defaults=Defaults)
+@appifies(KRootThings)
+@thingchain
 class prioritychain(RootMixin, PriorityMixin, AutoResultMixin):
 
     '''active priority queued auto-balancing lite call chain'''
 ###############################################################################
 
 
-class chain(Pathways):
+class chain(Chains, Defaults):
+    collect = 'callchain.active_auto.chainlet.collectchain'
+    combine = 'callchain.active_auto.chainlet.combinechain'
+    delay = 'callchain.active_auto.chainlet.delaychain'
+    dumps = 'callchain.services.dumps.Dumps'
+    filter = 'callchain.active_auto.chainlet.filterchain'
     loads = 'callchain.services.loads.Loads'
-    dumps = 'callchain.services.dumps.Dumps'
     logger = 'callchain.services.core.loglet'
-    filter = 'callchain.active_auto.chainlet.filterchain'
-    collect = 'callchain.active_auto.chainlet.collectchain'
-    set = 'callchain.active_auto.chainlet.setchain'
-    slice = 'callchain.active_auto.chainlet.slicechain'
-    combine = 'callchain.active_auto.chainlet.combinechain'
     map = 'callchain.active_auto.chainlet.mapchain'
-    delay = 'callchain.active_auto.chainlet.delaychain'
-    repeat = 'callchain.active_auto.chainlet.repeatchain'
+    math = 'callchain.active_auto.chainlet.mathchain'
     order = 'callchain.active_auto.chainlet.orderchain'
     random = 'callchain.active_auto.chainlet.randomchain'
     reduce = 'callchain.active_auto.chainlet.reducechain'
-    math = 'callchain.active_auto.chainlet.mathchain'
+    repeat = 'callchain.active_auto.chainlet.repeatchain'
+    set = 'callchain.active_auto.chainlet.setchain'
+    slice = 'callchain.active_auto.chainlet.slicechain'
     truth = 'callchain.active_auto.chainlet.truthchain'
 
 
-@appifies(KResult, KRoot, KChain, KCall)
-@inside(chain, defaults=Defaults)
+@appifies(KRootResults)
+@chain
 class chainq(RootMixin, ChainMixin, AutoResultMixin):
 
     '''active queued auto-balancing call chain'''
 
 
-@appifies(KThings, KRoot, KChain, KCall)
-@inside(chain, defaults=Defaults)
+@appifies(KRootResults)
+@chain
 class priorityq(RootMixin, PriorityMixin, AutoResultMixin):
 
     '''active priority queued auto-balancing lite call chain'''

File callchain/active_auto/event.py

 from callchain.config import Defaults
 from callchain.keys.apps import events
 from callchain.chain import EventRootMixin
-from callchain.call import EventMixin, einside
+from callchain.call import EventMixin, internal_events
 from callchain.keys.core import KThings, KResult
-from callchain.patterns import Pathways
+from callchain.patterns import Chains
 from callchain.keys.base import KEvent, KEventRoot, KEventCall
 
 ###############################################################################
 ###############################################################################
 
 
-class thingevent(Pathways):
+class thingevent(Chains, Defaults):
     chain = 'callchain.active_auto.chainlet.chainlink'
     loads = 'callchain.services.loads.Loads'
     dumps = 'callchain.services.dumps.Dumps'
 
 
 @appifies(KThings, KEventRoot, KEvent, KEventCall)
-@einside(thingevent, events, defaults=Defaults)
+@internal_events(thingevent, events, defaults=Defaults)
 class eventchain(EventRootMixin, EventMixin, AutoResultMixin):
 
     '''active queued auto-balancing lite event chain'''
 ###############################################################################
 
 
-class event(Pathways):
+class event(Chains, Defaults):
     chain = 'callchain.active_auto.chainlet.chainlink'
     loads = 'callchain.services.loads.Loads'
     dumps = 'callchain.services.dumps.Dumps'
 
 
 @appifies(KResult, KEventRoot, KEvent, KEventCall)
-@einside(event, events, defaults=Defaults)
+@internal_events(event, events, defaults=Defaults)
 class eventq(EventRootMixin, EventMixin, AutoResultMixin):
 
     '''active queued auto-balancing event chain'''

File callchain/active_man/chain.py

 
 from callchain.chain import RootMixin
 from callchain.config import Defaults
-from callchain.patterns import Pathways, Nameways
+from callchain.patterns import Chains, Nameways
 from callchain.keys.core import KThings, KResult
 from callchain.keys.base import KRoot, KCall, KChain
-from callchain.call import ChainMixin, PriorityMixin, inside
+from callchain.call import ChainMixin, PriorityMixin, internal
 
 ###############################################################################
 ## thing chain ################################################################
 ###############################################################################
 
 
-class thingchain(Pathways):
+class thingchain(Chains):
     loads = 'callchain.services.loads.Loads'
     dumps = 'callchain.services.dumps.Dumps'
     logger = 'callchain.services.core.loglet'
 
 
 @appifies(KThings, KRoot, KChain, KCall)
-@inside(thingchain, defaults=Defaults)
+@internal(thingchain, defaults=Defaults)
 class callchain(RootMixin, ChainMixin, ManResultMixin):
 
     ''''active queued manually balanced lite call chain'''
 
 
 @appifies(KThings, KRoot, KChain, KCall)
-@inside(thingchain, defaults=Defaults)
+@internal(thingchain, defaults=Defaults)
 class prioritychain(RootMixin, PriorityMixin, ManResultMixin):
 
     '''active priority queued manually balanced lite call chain'''
 ###############################################################################
 
 
-class chain(Pathways):
+class chain(Chains):
     loads = 'callchain.services.loads.Loads'
     dumps = 'callchain.services.dumps.Dumps'
     logger = 'callchain.services.core.loglet'
 
 
 @appifies(KResult, KRoot, KChain, KCall)
-@inside(chain, defaults=Defaults)
+@internal(chain, defaults=Defaults)
 class chainq(RootMixin, ChainMixin, ManResultMixin):
 
     '''active queued manually balanced call chain'''
 
 
 @appifies(KThings, KRoot, KChain, KCall)
-@inside(chain, defaults=Defaults)
+@internal(chain, defaults=Defaults)
 class priorityq(RootMixin, PriorityMixin, ManResultMixin):
 
     '''active priority queued manually balanced lite call chain'''

File callchain/active_man/event.py

 from callchain.config import Defaults
 from callchain.keys.apps import events
 from callchain.chain import EventRootMixin
-from callchain.call import EventMixin, einside
+from callchain.call import EventMixin, internal_events
 from callchain.keys.core import KThings, KResult
-from callchain.patterns import Pathways
+from callchain.patterns import Chains
 from callchain.keys.base import KEvent, KEventRoot, KEventCall
 
 ###############################################################################
 ###############################################################################
 
 
-class thingevent(Pathways):
+class thingevent(Chains):
     chain = 'callchain.active_man.chainlet.chainlink'
     loads = 'callchain.services.loads.Loads'
     dumps = 'callchain.services.dumps.Dumps'
 
 
 @appifies(KThings, KEventRoot, KEvent, KEventCall)
-@einside(thingevent, events, defaults=Defaults)
+@internal_events(thingevent, events, defaults=Defaults)
 class eventchain(EventRootMixin, EventMixin, ManResultMixin):
 
     '''active queued manually balanced lite event chain'''
 ###############################################################################
 
 
-class event(Pathways):
+class event(Chains):
     chain = 'callchain.active_man.chainlet.chainlink'
     loads = 'callchain.services.loads.Loads'
     dumps = 'callchain.services.dumps.Dumps'
 
 
 @appifies(KResult, KEventRoot, KEvent, KEventCall)
-@einside(event, events, defaults=Defaults)
+@internal_events(event, events, defaults=Defaults)
 class eventq(EventRootMixin, EventMixin, ManResultMixin):
 
     '''active queued manually balanced event chain'''

File callchain/base.py

+# -*- coding: utf-8 -*-
+'''callchain core mixins'''
+
+from threading import local
+from operator import setitem
+
+from stuf.six import items
+from stuf import frozenstuf
+from appspace.keys import AppLookupError, NoAppError
+from stuf.utils import getcls, either, lazy, lazybase, exhaustmap
+
+
+class ResetTypeMixin(object):
+
+    '''`reset` descriptors that subclass `lazybase`'''
+
+    def reset(self):
+        '''reset previously accessed `lazybase` attributes'''
+        this = vars(self)
+        t = lambda x, y: x in this and isinstance(y, lazybase)
+        exhaustmap(items(vars(getcls(self))), delattr, t)
+
+
+class ResetLocalMixin(local):
+
+    '''`reset` descriptors that subclass `lazybase`'''
+
+    def reset(self):
+        '''reset previously accessed `lazybase` attributes'''
+        this = vars(self)
+        t = lambda x, y: x in this and isinstance(y, lazybase)
+        exhaustmap(items(vars(getcls(self))), delattr, t)
+
+
+class CoreMixin(ResetLocalMixin):
+
+    '''core mixin'''
+
+    def __init__(self, root):
+        '''
+        init
+
+        @param root: root chain
+        '''
+        super(CoreMixin, self).__init__()
+        self._setup(root)
+
+    def __getattr__(self, label):
+        try:
+            return object.__getattribute__(self, label)
+        except AttributeError:
+            return self._load(label)
+
+    @either
+    def G(self):
+        '''external application global settings'''
+        return self.M.settings.final if self.M is not None else frozenstuf()
+
+    @either
+    def L(self):
+        '''local settings'''
+        return self.M.localize(self) if self._M is not None else frozenstuf()
+
+    def _setup(self, root):
+        '''call chain setup'''
+
+    def _load(self, label):
+        '''
+        load thing from appspace
+
+        @param label: label of appspaced thing
+        '''
+        _M = self.M
+        try:
+            # get appspace thing
+            thing = _M.get(label, _M._current)
+        except AppLookupError:
+            try:
+                # verify namespace
+                _M.namespace(label)
+            except AppLookupError:
+                raise NoAppError(label)
+            else:
+                # temporarily swap current label
+                _M._current = label
+                return self
+        else:
+            # set current label back to root label
+            _M._current = _M._root
+            return thing
+
+
+class ConfigMixin(CoreMixin):
+
+    '''configuration access mixin'''
+
+    @lazy
+    def defaults(self):
+        '''default settings by their lonesome'''
+        return self.M.settings.defaults if self.M is not None else frozenstuf()
+
+    @lazy
+    def required(self):
+        '''required settings by their lonesome'''
+        return self.M.settings.required if self.M is not None else frozenstuf()
+
+    def _defaults(self):
+        '''reset attribute values'''
+        this = self.__dict__
+        self.exhaustitems(
+            vars(self),
+            lambda x, y: setitem(this, x.rstrip('_d'), y),
+            lambda x: x[0].endswith('_d'),
+        )
+
+    def _setdefault(self, key, value):
+        '''
+        set default value for instance attribute
+
+        @param key: attribute name
+        @param value: attribute value
+        '''
+        self.__dict__[key] = self.__dict__[key + '_d'] = value

File callchain/branch.py

+# -*- coding: utf-8 -*-
+'''root chain mixins'''
+
+from appspace import NoAppError
+
+from callchain.base import ResetLocalMixin, CoreMixin
+from callchain.mixins import BranchMixin, EventBranchMixin, ChainMixin,\
+    PriorityMixin, EventMixin
+
+
+class LinkedMixin(ResetLocalMixin):
+
+    '''linked chain mixin'''
+
+    def close(self):
+        '''close out linked chain and switch to root chain'''
+        return self.root.back(self)
+
+
+class BranchletMixin(CoreMixin):
+
+    '''chainlet mixin'''
+
+    def _setup(self, root):
+        '''
+        configure chainlet
+
+        @param root: root chain
+        '''
+        super(BranchletMixin, self)._setup(root)
+        # sync with root postitional arguments
+        self._args = root._args
+        # sync with root keyword arguments
+        self._kw = root._kw
+        # sync with root callable
+        self._call = root._call
+        # sync with root incoming things and outgoing things
+        self.inclear().extend(root.incoming).outextend(root.outgoing)
+
+
+class ChainletMixin(ResetLocalMixin):
+
+    '''chainlet mixin'''
+
+    def _load(self, label):
+        '''
+        silent internal switch back...
+
+        @param label: appspaced thing label
+        '''
+        # fetch appspaced thing...
+        try:
+            return super(ChainletMixin, self)._load(label)
+        # ...or revert to root chain
+        except NoAppError:
+            return getattr(self.back(), label)
+
+    def _syncback(self, key, value):
+        '''
+        sync chainlet with root chain
+
+        @param key: key of value
+        @param value: value of value
+        '''
+        self.__dict__[key] = self.root.__dict__[key] = value
+
+    def back(self):
+        '''switch back to root chain'''
+        return self.root.back(self)
+
+
+###############################################################################
+## chainlet ###################################################################
+###############################################################################
+
+
+class chainlet(ChainletMixin, BranchMixin, CoreMixin):
+
+    '''generic chainlet mixin'''
+
+
+class eventlet(ChainletMixin, EventBranchMixin, CoreMixin):
+
+    '''generic eventlet mixin'''
+
+
+###############################################################################
+## linked chain ###############################################################
+###############################################################################
+
+
+class chainlink(BranchMixin, LinkedMixin, ChainMixin):
+
+    '''generic linked chain'''
+
+
+class prioritylink(BranchMixin, LinkedMixin, PriorityMixin):
+
+    '''generic priority linked chain'''
+
+
+class eventlink(EventBranchMixin, LinkedMixin, EventMixin):
+
+    '''generic linked event chain'''

File callchain/chainlets.py

-# -*- coding: utf-8 -*-
-'''root chain mixins'''
-
-from appspace import NoAppError
-
-from callchain.core import ResetLocalMixin, CoreMixin
-
-
-class BranchletMixin(CoreMixin):
-
-    '''chainlet mixin'''
-
-    def _setup(self, root):
-        '''
-        configure chainlet
-
-        @param root: root chain
-        '''
-        super(BranchletMixin, self)._setup(root)
-        # sync with root postitional arguments
-        self._args = root._args
-        # sync with root keyword arguments
-        self._kw = root._kw
-        # sync with root callable
-        self._call = root._call
-        # sync with root incoming things and outgoing things
-        self.inclear().extend(root.incoming).outextend(root.outgoing)
-
-
-class ChainletMixin(ResetLocalMixin):
-
-    '''chainlet mixin'''
-
-    def _load(self, label):
-        '''
-        silent internal switch back...
-
-        @param label: appspaced thing label
-        '''
-        # fetch appspaced thing...
-        try:
-            return super(ChainletMixin, self)._load(label)
-        # ...or revert to root chain
-        except NoAppError:
-            return getattr(self.back(), label)
-
-    def _syncback(self, key, value):
-        '''
-        sync chainlet with root chain
-
-        @param key: key of value
-        @param value: value of value
-        '''
-        self.__dict__[key] = self.root.__dict__[key] = value
-
-    def back(self):
-        '''switch back to root chain'''
-        return self.root.back(self)

File callchain/chainlets/__init__.py

+# -*- coding: utf-8 -*-
+'''callchain service keys'''

File callchain/chainlets/core.py

+# -*- coding: utf-8 -*-
+'''callchain service core'''
+
+import sys
+import logging
+from logging.handlers import HTTPHandler, SysLogHandler
+from logging.handlers import TimedRotatingFileHandler, SMTPHandler
+
+from appspace import appifies
+from stuf.utils import clsname
+
+from callchain.core import CoreMixin
+from callchain import ResetLocalMixin
+from callchain.keys.core import KLogger
+from callchain.lazy_auto.chainlet import chainlet
+from callchain.chain import BranchMixin, ChainletMixin
+
+
+class _Package(ResetLocalMixin):
+
+    '''data package'''
+
+    def __init__(self, data, mime, charset=None):
+        super(_Package, self).__init__()
+        self.data = data
+        self.mime = mime
+        self.charset = charset
+
+
+class _LogStdout(object):
+
+    '''file-like object for sending stdout output to a logger.'''
+
+    def __init__(self, logger, level=logging.DEBUG):
+        '''
+        build stdout logger
+
+        @param logger: logger
+        @param level: logging level (default: `logging.DEBUG`
+        '''
+        # Set logger level
+        if level == logging.DEBUG:
+            self.logger = logger.debug
+        elif level == logging.CRITICAL:
+            self.logger = logger.critical
+        elif level == logging.ERROR:
+            self.logger = logger.error
+        elif level == logging.WARNING:
+            self.logger = logger.warning
+        elif level == logging.INFO:
+            self.logger = logger.info
+
+    def write(self, msg):
+        '''Writes non-empty strings to logger.'''
+        if msg.lstrip().rstrip() != '':
+            self.logger(msg)
+
+
+class talklet(chainlet):
+
+    '''talklet mixin'''
+
+    def _process(self, encoder, mime, charset=None):
+        with self._context():
+            self._xtend(self._map(
+                lambda x: _Package(encoder(x), mime, charset), self._iterable,
+            ))
+        return self
+
+
+@appifies(KLogger)
+class loglet(ChainletMixin, BranchMixin, CoreMixin):
+
+    '''logging chainlet'''
+
+    def _setup(self, root):
+        '''
+        build logger
+
+        @param root: root chain
+        '''
+        super(loglet, self)._setup(root)
+        settings = self._G.log
+        self.logger = logging.getLogger(settings.get('NAME', clsname(root)))
+        # set logging level
+        self.logger.setLevel(settings.LEVEL)
+        # log formatter
+        format = logging.Formatter(
+            # log entry format
+            settings.ENTRY,
+            # date format
+            settings.DATE,
+        )
+        # coroutine to setup log handlers
+        def setlog(thislog): #@IgnorePep8
+            thislog.setFormatter(format)
+            self.logger.addHandler(thislog)
+        # log to STDOUT
+        if settings.stream:
+            setlog(logging.StreamHandler())
+            # redirect STDOUT to the logger
+            if settings.stream.STDOUT:
+                # sets log level STDOUT is displayed under
+                sys.stdout = _LogStdout(self.logger, settings.stream.LEVEL)
+        # log to a rotating file that with periodic backup deletions
+        if settings.rotating.ENABLED:
+            setlog(TimedRotatingFileHandler(
+                # log file path
+                settings.rotating.PATH,
+                # interval to backup log file
+                settings.rotating.INTERVAL,
+                # number of backups to keep
+                settings.rotating.BACKUPS,
+            ))
+        # email log entries to an email address
+        if settings.email.ENABLED:
+            setlog(SMTPHandler(
+                # mail server
+                settings.email.HOST,
+                # from email address
+                settings.email.FROM,
+                # to email address
+                settings.email.TO,
+                # email subject
+                settings.email.SUBJECT,
+            ))
+        # send log entries to a web server
+        if settings.http.ENABLED:
+            setlog(HTTPHandler(
+                # web server host
+                settings.http.HOST,
+                # web url
+                settings.http.URL,
+                # http method
+                settings.http.METHOD,
+            ))
+        # send log entries to syslog
+        if settings.syslog.ENABLED:
+            setlog(SysLogHandler(
+                # syslog host
+                (settings.syslog.HOST, settings.syslog.PORT),
+                # syslog user
+                settings.syslog.FACILITY,
+            ))
+        assert self.logger.handlers, 'configure at least one logging handler'
+
+    def debug(self, msg):
+        '''log debug message'''
+        self.logger.debug(msg)
+        return self
+
+    def warning(self, msg):
+        '''log warning message'''
+        self.logger.warning(msg)
+        return self
+
+    def info(self, msg):
+        '''log info message'''
+        self.logger.info(msg)
+        return self
+
+    def error(self, msg):
+        '''log error message'''
+        self.logger.error(msg)
+        return self
+
+    def critical(self, msg):
+        '''log critical message'''
+        self.logger.critical(msg)
+        return self
+
+    def exception(self, msg):
+        '''log exception message'''
+        self.logger.exception(msg)
+        return self

File callchain/chainlets/dumps.py

+# -*- coding: utf-8 -*-
+'''callchain dumpers'''
+
+import csv
+import marshal
+
+from appspace import appifies
+
+from callchain.services import imps
+from callchain.keys.dumps import KDumps
+from callchain.services.core import talklet
+
+
+@appifies(KDumps)
+class Dumps(talklet):
+
+    '''dumper'''
+
+    def bencode(self):
+        '''
+        bencode dumper
+
+        http://en.wikipedia.org/wiki/Bencode
+        http://pypi.python.org/pypi/bencode/
+        '''
+        try:
+            return self._process(imps.bencode, 'application/x-bittorrent')
+        except AttributeError:
+            raise ImportError('requires "bencode" library')
+
+    def bson(self):
+        '''
+        binary JSON dumper
+
+        http://en.wikipedia.org/wiki/BSON
+        http://pypi.python.org/pypi/bson/
+        '''
+        try:
+            return self._process(imps.bson.dumps, 'application/x-bson')  # @UndefinedVariable @IgnorePep8
+        except AttributeError:
+            raise ImportError('requires "bson" library')
+
+    def csv(self, **kw):
+        '''comma-separated values dumper'''
+        def dumps(data, **kw):
+            dumped = imps.StringIO()
+            csvw = csv.writer(dumped, **kw)
+            for row in data:
+                csvw.writerow(row)
+            return dumped.getvalue()
+        return self._process(lambda x: dumps(x, **kw), 'text/csv')
+
+    def excel(self, **kw):
+        '''
+        M$ excel dumper
+
+        http://pypi.python.org/pypi/xlrd/
+        http://pypi.python.org/pypi/xlwt/
+        '''
+        try:
+            workbook = imps.xlwt.Workbook  # @UndefinedVariable @IgnorePep8
+        except AttributeError:
+            raise ImportError('requires the "xlrd" and "xlwt" libraries')
+        def dumps(data, **kw): #@IgnorePep8
+            wb = workbook(encoding='utf8', **kw)
+            ws = wb.add_sheet(kw.get('title', 'Worksheet 1'))
+            write = ws.write
+            for i, row in enumerate(data):
+                for j, col in enumerate(row):
+                    write(i, j, col)
+            stream = imps.StringIO()
+            wb.save(stream)
+            return stream.getvalue()
+        return self._process(
+            self._partial(dumps, **kw), 'application/vnd.ms-excel',
+        )
+
+    def html(self, **kw):
+        '''
+        html dumper
+
+        http://pypi.python.org/pypi/lxml/
+        '''
+        try:
+            return self._process(
+                lambda x: imps.html.tostring(x, **kw), 'text/html',  # @UndefinedVariable @IgnorePep8
+            )
+        except AttributeError:
+            raise ImportError('requires "lxml" library')
+
+    def json(self, **kw):
+        '''JavaScript Object Notation (JSON) dumper'''
+        return self._process(
+            lambda x: imps.json.dumps(x, use_decimal=True, **kw),
+            'application/json',
+        )
+
+    def jsonpickle(self):
+        '''JavaScript Object Notation (JSON) pickle dumper'''
+        try:
+            return self._process(imps.jsonpickle.encode, 'application/json')  # @UndefinedVariable @IgnorePep8
+        except AttributeError:
+            raise ImportError('requires the "jsonpickle" library')
+
+    def marshal(self):
+        '''
+        python marshal talker (not guaranteed to interoperate between major
+        Python releases)
+
+        ACCEPTING ARBITRARY MARSHAL DATA MAY BE UNSAFE!!!
+        '''
+        return self._process(marshal.dumps, 'application/x-python-marshal')
+
+    def message_pack(self):
+        '''
+        message pack dumper
+
+        http://msgpack.org/
+        http://wiki.msgpack.org/display/MSGPACK/QuickStart+for+Python
+
+        http://pypi.python.org/pypi/msgpack-python/
+        '''
+        try:
+            return self._process(imps.msgpack.packb, 'application/x-msgpack')  # @UndefinedVariable @IgnorePep8
+        except AttributeError:
+            raise ImportError('requires "msgpack" library')
+
+    def multipart(self):
+        '''form multipart dumper'''
+        try:
+            return self._process(
+                lambda x: imps.encode_multipart_formdata(
+                    x, boundary='----------AaB03x',
+                ),
+                'multipart/form-data; boundary=----------AaB03x',
+            )
+        except AttributeError:
+            raise ImportError('requires "requests" or "urllib3" packages')
+
+    def netstring(self):
+        '''
+        netstring dumper
+
+        http://cr.yp.to/proto/netstrings.txt
+
+        http://pypi.python.org/pypi/netstring
+        '''
+        try:
+            return self._process(
+                imps.netstring.encode, 'application/x-netstring',   # @UndefinedVariable @IgnorePep8
+            )
+        except AttributeError:
+            raise ImportError('requires "netstring" library')
+
+    def pickle(self):
+        '''
+        python pickle talker (not guaranteed to interoperate between major
+        Python releases. ACCEPTING ARBITRARY PICKLE DATA MAY BE UNSAFE!!!
+        '''
+        pickle = imps.pickle  # @UndefinedVariable
+        return self._process(
+            lambda x: pickle.dumps(x, protocol=pickle.HIGHEST_PROTOCOL), 
+            'application/python-pickle',
+        )
+
+    def plist(self):
+        '''property list dumper'''
+        return self._process(imps.plist_dumps, 'application/x-plist')
+
+    def protobuf(self):
+        '''
+        google protocol buffers dumper
+
+        http://code.google.com/p/protobuf/
+
+        http://pypi.python.org/pypi/protobuf/
+        '''
+        return self._process(
+            lambda x: x.SerializeToString(), 'application/x-protobuf',
+        )
+
+    def thrift(self):
+        '''
+        thrift dumper
+    
+        http://thrift.apache.org/
+    
+        http://pypi.python.org/pypi/thrift/
+        '''
+        try:
+            return self._process(imps.thrift.serialize, 'application/x-thrift')  # @UndefinedVariable @IgnorePep8
+        except AttributeError:
+            raise ImportError('requires "thrift" library')
+
+    def tnetstring(self):
+        '''
+        tnetstring loader
+    
+        http://pypi.python.org/pypi/tnetstring/
+        '''
+        try:
+            return self._process(
+                imps.tnetstring.dumps, 'application/x-tnetstring',  # @UndefinedVariable @IgnorePep8
+            )
+        except AttributeError:
+            raise ImportError('requires "tnetstring" library')
+
+    def urlencode(self, **kw):
+        '''urlencode dumper'''
+        return self._process(
+            lambda x: imps.urlencode(x, **kw),  # @UndefinedVariable @IgnorePep8
+            'application/x-www-form-urlencoded',
+        )
+
+    def xml(self, **kw):
+        '''
+        extensible markup language loader
+
+        http://pypi.python.org/pypi/lxml/
+        '''
+        return self._process(
+            lambda x: imps.etree.tostring(x, **kw), 'text/xml',
+        )
+
+    def xmlrpc(self, **kw):
+        '''
+        extensible markup language remote procedure call dumper
+        '''
+        return self._process(
+            lambda x: imps.xmlrpc.dumps(x, **kw), 'text/xml',   # @UndefinedVariable @IgnorePep8
+        )
+
+    def yaml(self, **kw):
+        '''
+        YAML ain't markup language dumper
+
+        http://en.wikipedia.org/wiki/YAML
+
+        http://pypi.python.org/pypi/PyYAML/
+        '''
+        try:
+            return self._process(
+                lambda x: imps.yaml.dump(x, **kw), 'application/x-yaml',  # @UndefinedVariable @IgnorePep8
+            )
+        except AttributeError:
+            raise ImportError('requires PyYaml module')

File callchain/chainlets/imps.py

+# -*- coding: utf-8 -*-
+'''callchain services imports'''
+
+from callchain.support import (
+    StringIO, xmlrpc, parse_qs, plist_loads, plist_dumps, xrange)
+try:
+    import yaml
+except ImportError:
+    pass
+try:
+    import simplejson as json
+except ImportError:
+    import json
+try:
+    from bencode import bdecode, bencode
+except ImportError:
+    pass
+try:
+    from lxml import etree
+except ImportError:
+    import xml.etree.ElementTree as etree
+try:
+    import msgpack
+except ImportError:
+    pass
+try:
+    import tnetstring
+except ImportError:
+    pass
+try:
+    import thrift.TSerialization as thrift
+except ImportError:
+    pass
+try:
+    import bson
+except ImportError:
+    pass
+try:
+    import jsonpickle
+except ImportError:
+    pass
+try:
+    import netstring
+except ImportError:
+    pass
+try:
+    import html
+except ImportError:
+    pass
+try:
+    from requests.packages.urllib3.filepost import encode_multipart_formdata
+except ImportError:
+    try:
+        from urllib3.filepost import encode_multipart_formdata
+    except ImportError:
+        pass
+try:
+    import xlwt
+    import xlrd
+except ImportError:
+    pass

File callchain/chainlets/loads.py

+# -*- coding: utf-8 -*-
+'''callchain loaders'''
+
+import csv
+import marshal
+from operator import setitem
+from cgi import parse_multipart
+
+from appspace import appifies
+from stuf.utils import exhaustmap
+
+from callchain.services import imps
+from callchain.keys.loads import KLoads
+from callchain.services.core import talklet
+
+
+@appifies(KLoads)
+class Loads(talklet):
+
+    '''loader'''
+
+    def bencode(self):
+        '''
+        bencode dumper
+
+        http://en.wikipedia.org/wiki/Bencode
+        http://pypi.python.org/pypi/bencode/
+        '''
+        try:
+            return self._process(imps.bdecode, 'application/x-bittorrent')
+        except AttributeError:
+            raise ImportError('requires "bencode" library')
+
+    def bson(self):
+        '''
+        binary JSON loader
+
+        http://en.wikipedia.org/wiki/BSON
+        http://pypi.python.org/pypi/bson/
+        '''
+        try:
+            return self._process(imps.bson.loads, 'application/x-bson')  # @UndefinedVariable @IgnorePep8
+        except AttributeError:
+            raise ImportError('requires "bson" library')
+
+    def csv(self, **kw):
+        '''comma-separated values loader'''
+        def loads(data, **kw):
+            return list(r for r in csv.reader(imps.StringIO(data), **kw))
+        return self._process(lambda x: loads(x, **kw), 'text/csv')
+
+    def excel(self, **kw):
+        '''
+        M$ excel serialization
+
+        http://pypi.python.org/pypi/xlrd/
+        http://pypi.python.org/pypi/xlwt/
+        '''
+        try:
+            workbook = imps.xlrd.open_workbook  # @UndefinedVariable @IgnorePep8
+        except AttributeError:
+            raise ImportError('requires the "xlrd" and "xlwt" libraries')
+        def loads(data, **kw): #@IgnorePep8
+            wb = workbook(file_contents=data, **kw)
+            new_workbook = list()
+            oappend = new_workbook.append
+            for sheet in wb.sheets():
+                cellvalue = sheet.cell_value
+                new_sheet = list()
+                nappend = new_sheet.append
+                for row in range(sheet.nrows):
+                    new_row = list()
+                    iappend = new_row.append
+                    for col in xrange(sheet.ncols):
+                        iappend(cellvalue(row, col))
+                    nappend(new_row)
+                oappend(new_sheet)
+            return new_workbook
+        return self._process(
+            lambda x: loads(x, **kw), 'application/vnd.ms-excel',
+        )
+
+    def html(self, **kw):
+        '''
+        html serialization
+
+        http://pypi.python.org/pypi/lxml/
+        '''
+        return self._process(
+            lambda x: imps.html.fromstring(x, **kw), 'text/html',  # @UndefinedVariable @IgnorePep8
+        )
+
+    def json(self, **kw):
+        '''JavaScript Object Notation (JSON) serialization'''
+        return self._process(
+            lambda x: imps.json.loads(x, use_decimal=True, **kw),
+            'application/json',
+        )
+
+    def jsonpickle(self):
+        '''JavaScript Object Notation (JSON) pickle serialization'''
+        try:
+            return self._process(imps.jsonpickle.decode, 'application/json')  # @UndefinedVariable @IgnorePep8
+        except AttributeError:
+            raise ImportError('requires the "jsonpickle" library')
+
+    def marshal(self):
+        '''
+        python marshal talker (not guaranteed to interoperate between major
+        Python releases)
+
+        ACCEPTING ARBITRARY MARSHAL DATA MAY BE UNSAFE!!!
+        '''
+        return self._process(marshal.loads, 'application/x-python-marshal')
+
+    def message_pack(self):
+        '''
+        message pack serialization key
+
+        http://msgpack.org/
+        http://wiki.msgpack.org/display/MSGPACK/QuickStart+for+Python
+
+        http://pypi.python.org/pypi/msgpack-python/
+        '''
+        try:
+            return self._process(imps.msgpack.unpackb, 'application/x-msgpack')  # @UndefinedVariable @IgnorePep8
+        except AttributeError:
+            raise ImportError('requires "msgpack" library')
+
+    def multipart(self):
+        '''form multipart serialization'''
+        def loads(data):
+            q = parse_multipart(
+                imps.StringIO(data), dict(boundary='----------AaB03x')
+            )
+            exhaustmap(
+                q, lambda x, y: setitem(q, x, y[0]), lambda x: len(x[1]) == 1
+            )
+            return q
+        return self._process(
+            loads, 'multipart/form-data; boundary=----------AaB03x',
+        )
+
+    def netstring(self):
+        '''
+        netstring serialization key
+
+        http://cr.yp.to/proto/netstrings.txt
+
+        http://pypi.python.org/pypi/netstring
+        '''
+        try:
+            return self._process(
+                lambda x: imps.netstring.decode(x)[0],  # @UndefinedVariable @IgnorePep8
+                'application/x-netstring',
+            )
+        except AttributeError:
+            raise ImportError('requires "netstring" library')
+
+    def pickle(self):
+        '''
+        python pickle talker (not guaranteed to interoperate between major
+        Python releases. ACCEPTING ARBITRARY PICKLE DATA MAY BE UNSAFE!!!
+        '''
+        return self._process(imps.pickle.loads, 'application/x-python-pickle')  # @UndefinedVariable @IgnorePep8
+
+    def plist(self):
+        '''property list serialization key'''
+        return self._process(imps.plist_loads, 'application/x-plist')
+
+    def protobuf(self, **kw):
+        '''
+        google protocol buffers serialization
+
+        http://code.google.com/p/protobuf/
+
+        http://pypi.python.org/pypi/protobuf/
+        '''
+        proto = kw.get('proto')
+        def load(data): #@IgnorePep8
+            p = proto()
+            p.ParseFromString(data)
+            return p
+        return self._process(load, 'application/x-protobuf')
+
+    def thrift(self, base):
+        '''
+        thrift serialization key
+    
+        http://thrift.apache.org/
+    
+        http://pypi.python.org/pypi/thrift/
+        '''
+        try:
+            return self._process(
+               lambda x: imps.thrift.deserialize(x, base),  # @UndefinedVariable @IgnorePep8
+               'application/x-thrift',
+            )
+        except AttributeError:
+            raise ImportError('requires "thrift" library')
+
+    def tnetstring(self):
+        '''
+        tnetstring loader
+    
+        http://pypi.python.org/pypi/tnetstring/
+        '''
+        try:
+            return self._process(
+                imps.tnetstring.loads, 'application/x-tnetstring',  # @UndefinedVariable @IgnorePep8
+            )
+        except AttributeError:
+            raise ImportError('requires "tnetstring" library')
+
+    def urlencode(self, **kw):
+        '''urlencode loader'''
+        def loads(data, **kw):
+            q = imps.parse_qs(data, **kw)
+            exhaustmap(
+                q, lambda x, y: setitem(q, x, y[0]), lambda x: len(x[1]) == 1,
+            )
+            return q
+        return self._process(lambda x: loads(x, **kw))
+
+    def xml(self, **kw):
+        '''
+        extensible markup language loader
+
+        http://pypi.python.org/pypi/lxml/
+        '''
+        return self._process(
+            lambda x: imps.etree.fromstring(x, **kw), 'text/xml', 'utf-8',
+        )
+
+    def xmlrpc(self, **kw):
+        '''
+        extensible markup language remote procedure call serialization key
+        '''
+        return self._process(
+            lambda x: imps.xmlrpc.loads(x, type, **kw)[0], 'text/xml',  # @UndefinedVariable @IgnorePep8
+        )
+
+    def yaml(self, **kw):
+        '''
+        YAML ain't markup language dumper
+
+        http://en.wikipedia.org/wiki/YAML
+
+        http://pypi.python.org/pypi/PyYAML/
+        '''
+        try:
+            return self._process(
+                lambda x: imps.yaml.load(x, **kw), 'application/x-yaml',  # @UndefinedVariable @IgnorePep8
+            )
+        except AttributeError:
+            raise ImportError('requires PyYaml module')

File callchain/core.py

-# -*- coding: utf-8 -*-
-'''callchain core mixins'''
-
-from threading import local
-from operator import setitem
-
-from stuf.six import items
-from stuf import frozenstuf
-from appspace.keys import AppLookupError, NoAppError
-from stuf.utils import getcls, either, lazy, lazybase, exhaustmap
-
-
-class ResetTypeMixin(object):
-
-    '''`reset` descriptors that subclass `lazybase`'''
-
-    def reset(self):
-        '''reset previously accessed `lazybase` attributes'''
-        this = vars(self)
-        t = lambda x, y: x in this and isinstance(y, lazybase)
-        exhaustmap(items(vars(getcls(self))), delattr, t)
-
-
-class ResetLocalMixin(local):
-
-    '''`reset` descriptors that subclass `lazybase`'''
-
-    def reset(self):
-        '''reset previously accessed `lazybase` attributes'''
-        this = vars(self)
-        t = lambda x, y: x in this and isinstance(y, lazybase)
-        exhaustmap(items(vars(getcls(self))), delattr, t)
-
-
-class CoreMixin(ResetLocalMixin):
-
-    '''core mixin'''
-
-    def __init__(self, root):
-        '''
-        init
-
-        @param root: root chain
-        '''
-        super(CoreMixin, self).__init__()
-        self._setup(root)
-
-    def __getattr__(self, label):
-        try:
-            return object.__getattribute__(self, label)
-        except AttributeError:
-            return self._load(label)
-
-    @either
-    def G(self):
-        '''external application global settings'''
-        return self.M.settings.final if self.M is not None else frozenstuf()
-
-    @either
-    def L(self):
-        '''local settings'''
-        return self.M.localize(self) if self._M is not None else frozenstuf()
-
-    def _setup(self, root):
-        '''call chain setup'''
-
-    def _load(self, label):
-        '''
-        load thing from appspace
-
-        @param label: label of appspaced thing
-        '''
-        _M = self.M
-        try:
-            # get appspace thing
-            thing = _M.get(label, _M._current)
-        except AppLookupError:
-            try:
-                # verify namespace
-                _M.namespace(label)
-            except AppLookupError:
-                raise NoAppError(label)
-            else:
-                # temporarily swap current label
-                _M._current = label
-                return self
-        else:
-            # set current label back to root label
-            _M._current = _M._root
-            return thing
-
-
-class ConfigMixin(CoreMixin):
-
-    '''configuration access mixin'''
-
-    @lazy
-    def defaults(self):
-        '''default settings by their lonesome'''
-        return self.M.settings.defaults if self.M is not None else frozenstuf()
-
-    @lazy
-    def required(self):
-        '''required settings by their lonesome'''
-        return self.M.settings.required if self.M is not None else frozenstuf()
-
-    def _defaults(self):
-        '''reset attribute values'''
-        this = self.__dict__
-        self.exhaustitems(
-            vars(self),
-            lambda x, y: setitem(this, x.rstrip('_d'), y),
-            lambda x: x[0].endswith('_d'),
-        )
-
-    def _setdefault(self, key, value):
-        '''
-        set default value for instance attribute
-
-        @param key: attribute name
-        @param value: attribute value
-        '''
-        self.__dict__[key] = self.__dict__[key + '_d'] = value

File callchain/generic.py

-# -*- coding: utf-8 -*-
-'''callchain generic mixins'''
-
-from callchain.core import CoreMixin
-from callchain.chain import (
-    RootMixin, EventRootMixin, BranchMixin, ChainletMixin, EventBranchMixin,
-    LinkedMixin)
-from callchain.call import ChainMixin, PriorityMixin, EventMixin
-
-###############################################################################
-## chainlet ###################################################################
-###############################################################################
-
-
-class chainlet(ChainletMixin, BranchMixin, CoreMixin):
-
-    '''generic chainlet mixin'''
-
-
-class eventlet(ChainletMixin, EventBranchMixin, CoreMixin):
-
-    '''generic eventlet mixin'''
-
-
-###############################################################################
-## linked chain ###############################################################
-###############################################################################
-
-
-class chainlink(BranchMixin, LinkedMixin, ChainMixin):
-
-    '''generic linked chain'''
-
-
-class prioritylink(BranchMixin, LinkedMixin, PriorityMixin):
-
-    '''generic priority linked chain'''
-
-
-class eventlink(EventBranchMixin, LinkedMixin, EventMixin):
-
-    '''generic linked event chain'''
-
-
-###############################################################################
-## chain ######################################################################
-###############################################################################
-
-
-class callchain(RootMixin, ChainMixin):
-
-    '''generic call chain'''
-
-
-class prioritychain(RootMixin, PriorityMixin):
-
-    '''generic priority chain generic'''
-
-
-class eventchain(EventRootMixin, EventMixin):
-
-    '''generic event chain'''

File callchain/keys/apps.py

 # -*- coding: utf-8 -*-
 '''events appconf'''
 
-from callchain.patterns import Pathways
+from callchain.patterns import Chains
 
 
-class events(Pathways):
+class events(Chains):
     key = 'callchain.keys.event.EEvent'
     # 1. before event
     before = 'callchain.keys.event.EBefore'

File callchain/keys/base.py

 # -*- coding: utf-8 -*-
 '''callchain reset keys'''
 
-from appspace.keys import AppspaceKey, Attribute
+from appspace.keys import AppspaceKey, Attribute, ConfigurationError
 
 
-class KDefaults(AppspaceKey):
+class KRoutes(AppspaceKey):
 
-    '''default settings key'''
+    '''routes key'''
 
 
-class KRequired(AppspaceKey):
+class KExternalRoutes(KRoutes):
 
-    '''required settings key'''
+    '''external routes key'''
 
 
-class KService(AppspaceKey):
+class KInternalRoutes(KRoutes):
 
-    '''service key'''
+    '''internal routes key'''
 
 
-class NoServiceError(Exception):
+class KEventRegistry(AppspaceKey):
 
-    '''no service error'''
+    '''events registry key'''
 
 
 class KResetType(AppspaceKey):
     '''reset thread local key'''
 
 
-class KSettings(KResetLocal):
-
-    '''settings key'''
-
-
 class KCore(KResetLocal):
 
     '''core key'''
     required = Attribute('required settings by their lonesome')
 
 
-class KRoot(KConfig):
+class NoService(ConfigurationError):
 
-    '''root chain key'''
-
-    def __init__(pattern=None, required=None, defaults=None, **kw):  # @NoSelf
-        '''
-        init
-
-        @param pattern: pattern configuration or appspace label (default: None)
-        @param required: required settings (default: None)
-        @param defaults: default settings (default: None)
-        '''
-
-    def __call__(*args):  # @NoSelf
-        '''new chain session'''
-
-    def back(branch):  # @NoSelf
-        '''
-        handle return from branch chain
-
-        @param branch: branch chain
-        '''
-
-
-class KEventRoot(KRoot):
-
-    '''root event key'''
-
-    def __init__(  # @NoSelf
-        patterns=None,
-        events=None,
-        required=None,
-        defaults=None,
-        *args,
-        **kw
-    ):
-        '''
-        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)
-        '''
-
-    def event(event):  # @NoSelf
-        '''
-        create or fetch `event`
-
-        @param event: event label
-        '''
-
-    def unevent(event):  # @NoSelf
-        '''
-        drop `event`
-
-        @param event: event label
-        '''
-
-
-class KChain(KResetLocal):
-
-    '''chain key'''
-
-    def chain(call, key=False, *args, **kw):  # @NoSelf
-        '''
-        add `call` or appspaced `call` to call chain, partializing it with any
-        passed arguments
-
-        @param call: call or appspaced call label
-        @param key: appspace key (default: False)
-        '''
-
-    def clear():  # @NoSelf
-        '''clear things'''
-
-    def tap(call, key=False):  # @NoSelf
-        '''
-        add call
-
-        @param call: callable or appspace label
-        @param key: link call chain key (default: False)
-        '''
-
-    def wrap(call, key=False):  # @NoSelf
-        '''build current callable from factory'''
-
-
-class KEvent(KChain):
-
-    '''event chain key'''
-
-    def on(event, call, key=False, *args, **kw):  # @NoSelf
-        '''
-        bind call to `event`
-
-        @param event: event label
-        @param call: label for call or eventspaced thing
-        @param key: key label (default: False)
-        '''
-
-    def off(event):  # @NoSelf
-        '''
-        clear calls bound to `event`
-
-        @param event: event label
-        '''
-
-    def trigger(*events):  # @NoSelf
-        '''
-        extend primary call chain with partials bound to `events`
-
-        @param *events: event labels
-        '''
-
-
-class KCall(KResetLocal):
-
-    '''call key'''
-
-    L = Attribute('local settings extracted')
-    Meta = Attribute('local settings')
-    port = Attribute('python 2.x <-> python 3.x porting helper')
-    space = Attribute('external appspace interface')
-
-    def __enter__():  # @NoSelf
-        '''enter execution context'''
-
-    def __exit__(e, t, b):  # @NoSelf
-        '''exit execution context'''
-
-    def switch(label, key=False):  # @NoSelf
-        '''
-        overt switch to linked chain configured in external appspace
-
-        @param label: linked chain label
-        @param key: linked chain chain key (default: False)
-        '''
-
-    def commit():  # @NoSelf
-        '''consume call chain'''
-
-
-class KEventCall(KCall):
-
-    '''event call key'''
-
-    def fire(*events):  # @NoSelf
-        '''
-        run calls bound to `events` **NOW**
-
-        @param *events: event labels
-        '''
-
-    def queues(*events):  # @NoSelf
-        '''
-        ordered mapping of processing queues for `events`
-
-        @param *events: event labels
-        '''
-
-
-class KBranch(KCore):
-
-    ''''branch key'''
-
-    G = Attribute('root external global settings')
-    M = Attribute('root external appspace manager')
-    _G = Attribute('root internal global settings')
-    _M = Attribute('root internal appspace manager')
-    root = Attribute('root object')
-
-
-class KEventBranch(KBranch):
-
-    '''event branch key'''
-
-    E = Attribute('local event registry')
-
-
-class KChainletKey(KBranch):
-
-    def back():  # @NoSelf
-        '''switch back to root chain'''
+    '''no service'''

File callchain/keys/chainlet.py

+# -*- coding: utf-8 -*-
+'''callchain contrib keys'''
+
+from appspace import AppspaceKey, Attribute
+
+from callchain.keys.core import KBranch
+
+
+class KChainlet(KBranch):
+
+    '''service key'''
+
+    def back():  # @NoSelf
+        '''switch back to root chain'''
+
+
+class KLogger(KChainlet):
+
+    '''logging service key'''
+
+    logger = Attribute('the logger')
+
+    def debug(msg):  # @NoSelf
+        '''log debug message'''
+
+    def warning(msg):  # @NoSelf
+        '''log warning message'''
+
+    def info(msg):  # @NoSelf
+        '''log info message'''
+
+    def error(msg):  # @NoSelf
+        '''log error message'''
+
+    def critical(msg):  # @NoSelf
+        '''log critical message'''
+
+    def exception(msg):  # @NoSelf
+        '''log exception message'''
+
+
+class KQueue(AppspaceKey):
+
+    '''queue key'''
+
+
+class KPorting(AppspaceKey):
+
+    '''porting key'''
+
+
+class KDumps(KChainlet):
+
+    '''dumping key'''
+
+    def protobuf():  # @NoSelf
+        '''
+        google protocol buffers dumps
+
+        http://code.google.com/p/protobuf/
+
+        http://pypi.python.org/pypi/protobuf/
+        '''
+
+    def thrift():  # @NoSelf
+        '''
+        thrift dumps
+
+        http://thrift.apache.org/
+
+        http://pypi.python.org/pypi/thrift/
+        '''
+
+    def bencode():  # @NoSelf
+        '''
+        bencode dumps
+
+        http://en.wikipedia.org/wiki/Bencode
+
+        http://pypi.python.org/pypi/BitTorrent-bencode/
+        '''
+
+    def bson():  # @NoSelf
+        '''
+        binary JSON dumps
+
+        http://en.wikipedia.org/wiki/BSON
+
+        http://pypi.python.org/pypi/bson/0.3.3
+        '''
+
+    def csv(**kw):  # @NoSelf
+        '''csv serialization'''
+
+    def excel(**kw):  # @NoSelf
+        '''
+        M$ excel dumps
+
+        http://pypi.python.org/pypi/xlrd/
+
+        http://pypi.python.org/pypi/xlwt/
+        '''
+
+    def html(**kw):  # @NoSelf
+        '''
+        html dumps
+
+        http://pypi.python.org/pypi/lxml/
+        '''
+
+    def json(**kw):  # @NoSelf
+        '''JavaScript Object Notation (JSON) dumps'''
+
+    def jsonpickle():  # @NoSelf
+        '''JavaScript Object Notation (JSON) pickle dumps'''
+
+    def marshal():  # @NoSelf
+        '''Python marshal dumps'''
+
+    def message_pack(**kw):  # @NoSelf
+        '''
+        message pack dumps
+
+        http://msgpack.org/
+
+        http://pypi.python.org/pypi/msgpack-python/
+        '''
+
+    def multipart():  # @NoSelf
+        '''form-multipart serialization'''
+
+    def netstring(**kw):  # @NoSelf
+        '''
+        netstring dumps
+
+        http://cr.yp.to/proto/netstrings.txt
+
+        http://pypi.python.org/pypi/netstring
+        '''
+
+    def pickle():  # @NoSelf
+        '''python pickle dumps'''
+
+    def plist():  # @NoSelf
+        '''property list dumps'''
+
+    def tnetstring():  # @NoSelf
+        '''
+        tnetstring dumps
+
+        http://pypi.python.org/pypi/tnetstring/
+        '''
+
+    def urlencode(**kw):  # @NoSelf
+        '''urlencode serialization'''
+
+    def xml(**kw):  # @NoSelf
+        '''eXtensible markup language dumps'''
+
+    def xmlrpc(**kw):  # @NoSelf
+        '''
+        eXtensible markup language remote procedure call dumps
+        '''
+
+    def yaml(**kw):  # @NoSelf
+        '''
+        YaML ain't markup language dumps
+
+        http://en.wikipedia.org/wiki/YAML
+
+        http://pypi.python.org/pypi/PyYAML/
+        '''
+
+
+class KLoads(KChainlet):
+
+    '''loading key'''
+
+    def protobuf(**kw):  # @NoSelf
+        '''
+        google protocol buffers loading
+
+        http://code.google.com/p/protobuf/
+
+        http://pypi.python.org/pypi/protobuf/
+        '''
+
+    def thrift(base):  # @NoSelf
+        '''
+        thrift loading
+
+        http://thrift.apache.org/
+
+        http://pypi.python.org/pypi/thrift/
+        '''
+
+    def bencode():  # @NoSelf
+        '''
+        bencode loading
+
+        http://en.wikipedia.org/wiki/Bencode
+
+        http://pypi.python.org/pypi/BitTorrent-bencode/
+        '''
+
+    def bson():  # @NoSelf
+        '''
+        binary JavaScript Object Notation loading
+
+        http://en.wikipedia.org/wiki/BSON
+
+        http://pypi.python.org/pypi/bson/0.3.3
+        '''
+
+    def csv(**kw):  # @NoSelf
+        '''csv serialization'''
+
+    def excel(**kw):  # @NoSelf
+        '''
+        M$ excel loading
+
+        http://pypi.python.org/pypi/xlrd/
+
+        http://pypi.python.org/pypi/xlwt/
+        '''
+
+    def html(**kw):  # @NoSelf
+        '''
+        html loading
+
+        http://pypi.python.org/pypi/lxml/
+        '''
+
+    def json(**kw):  # @NoSelf
+        '''JavaScript Object Notation (JSON) loading'''
+
+    def jsonpickle():  # @NoSelf
+        '''JavaScript Object Notation (JSON) pickle loading'''
+
+    def marshal():  # @NoSelf
+        '''Python marshal loading'''
+
+    def message_pack(**kw):  # @NoSelf
+        '''
+        message pack loading
+
+        http://msgpack.org/
+
+        http://pypi.python.org/pypi/msgpack-python/
+        '''
+
+    def multipart():  # @NoSelf
+        '''form-multipart serialization'''
+
+    def netstring(**kw):  # @NoSelf
+        '''
+        netstring loading
+
+        http://cr.yp.to/proto/netstrings.txt
+
+        http://pypi.python.org/pypi/netstring
+        '''
+
+    def pickle():  # @NoSelf
+        '''python pickle loading'''
+
+    def plist():  # @NoSelf
+        '''property list loading'''
+
+    def tnetstring():  # @NoSelf
+        '''
+        tnetstring loading
+
+        http://pypi.python.org/pypi/tnetstring/
+        '''
+
+    def urlencode(**kw):  # @NoSelf
+        '''urlencode serialization'''
+
+    def xml(**kw):  # @NoSelf
+        '''eXtensible markup language loading'''
+
+    def xmlrpc(**kw):  # @NoSelf
+        '''
+        eXtensible markup language remote procedure call loading
+        '''
+
+    def yaml(**kw):  # @NoSelf
+        '''
+        YaML ain't markup language loading