Commits

Lynn Rees committed a2f6fba

- rename

Comments (0)

Files changed (129)

 include README.rst
 include packages
 include requirements.txt
-recursive-include twoq *.py
+recursive-include thingq *.py
-*twoq* chains iterators together using a double-headed input and output queue,
+*thingq* chains iterators together using a double-headed input and output queue,
 that can be shifted or synced as needed.
 
-*twoq* exposes some useful features buried in the standard library and 
+*thingq* exposes some useful features buried in the standard library and 
 includes some Python 2 <-> 3 compatibility aids.
 
-Mirrored on https://github.com/kwarterthieves/twoq/
+Mirrored on https://github.com/kwarterthieves/thingq/
 # -*- coding: utf-8 -*-
 #
-# twoq documentation build configuration file, created by
+# thingq documentation build configuration file, created by
 # sphinx-quickstart on Mon Mar 19 15:41:40 2012.
 #
 # This file is execfile()d with the current directory set to its containing dir.
 master_doc = 'index'
 
 # General information about the project.
-project = u'twoq'
+project = u'thingq'
 copyright = u'2012, L. C. Rees'
 
 # The version info for the project you're documenting, acts as replacement for
 #html_file_suffix = None
 
 # Output file base name for HTML help builder.
-htmlhelp_basename = 'twoqdoc'
+htmlhelp_basename = 'thingqdoc'
 
 
 # -- Options for LaTeX output --------------------------------------------------
 # Grouping the document tree into LaTeX files. List of tuples
 # (source start file, target name, title, author, documentclass [howto/manual]).
 latex_documents = [
-  ('index', 'twoq.tex', u'twoq Documentation',
+  ('index', 'thingq.tex', u'thingq Documentation',
    u'L. C. Rees', 'manual'),
 ]
 
 # One entry per manual page. List of tuples
 # (source start file, name, description, authors, manual section).
 man_pages = [
-    ('index', 'twoq', u'twoq Documentation',
+    ('index', 'thingq', u'thingq Documentation',
      [u'L. C. Rees'], 1)
 ]
 
 # (source start file, target name, title, author,
 #  dir menu entry, description, category)
 texinfo_documents = [
-  ('index', 'twoq', u'twoq Documentation',
-   u'L. C. Rees', 'twoq', 'One line description of project.',
+  ('index', 'thingq', u'thingq Documentation',
+   u'L. C. Rees', 'thingq', 'One line description of project.',
    'Miscellaneous'),
 ]
 
-.. twoq documentation master file, created by
+.. thingq documentation master file, created by
    sphinx-quickstart on Mon Mar 19 15:41:40 2012.
    You can adapt this file completely to your liking, but it should at least
    contain the root `toctree` directive.
 
-Welcome to twoq's documentation!
+Welcome to thingq's documentation!
 ================================
 
 Contents:
-'''twoq fabfile'''
+'''thingq fabfile'''
 
 from fabric.api import prompt, local, settings, env
 
 
 
 def tox():
-    '''test twoq'''
+    '''test thingq'''
     local('tox')
 
 
 def tox_recreate():
-    '''recreate twoq test env'''
+    '''recreate thingq test env'''
     prompt(
         'Enter testenv: [py26, py27, py32]',
         'testenv',
 
 
 def release():
-    '''release twoq'''
+    '''release thingq'''
     local('hg update pu')
     local('hg update next')
     local('hg merge pu; hg ci -m automerge')
     prompt('Enter tag: ', 'tag')
     with settings(warn_only=True):
         local('hg tag "%(tag)s"' % env)
-        local('hg push ssh://hg@bitbucket.org/lcrees/twoq')
-        local('hg push git+ssh://git@github.com:kwarterthieves/twoq.git')
+        local('hg push ssh://hg@bitbucket.org/lcrees/thingq')
+        local('hg push git+ssh://git@github.com:kwarterthieves/thingq.git')
     local('./setup.py register sdist --format=bztar,gztar,zip upload')
     local('rm -rf dist')
 
 
 def release_next():
-    '''release twoq from next branch'''
+    '''release thingq from next branch'''
     local('hg update maint')
     local('hg merge default; hg ci -m automerge')
     local('hg update default')
     prompt('Enter tag: ', 'tag')
     with settings(warn_only=True):
         local('hg tag "%(tag)s"' % env)
-        local('hg push ssh://hg@bitbucket.org/lcrees/twoq')
-        local('hg push git+ssh://git@github.com:kwarterthieves/twoq.git')
+        local('hg push ssh://hg@bitbucket.org/lcrees/thingq')
+        local('hg push git+ssh://git@github.com:kwarterthieves/thingq.git')
     local('./setup.py register sdist --format=bztar,gztar,zip upload')
     local('rm -rf dist')
 #! /usr/bin/env python
 # -*- coding: utf-8 -*-
-'''setup for twoq'''
+'''setup for thingq'''
 
 from os import getcwd
 from os.path import join
 ).readlines())
 
 setup(
-    name='twoq',
+    name='thingq',
     version='0.5.0',
     description='iterator chaining, underscored by a two-headed queue',
     long_description=open(join(getcwd(), 'README.rst'), 'r').read(),
     license='BSD',
     author='L. C. Rees',
     author_email='lcrees@gmail.com',
-    url='https://bitbucket.org/lcrees/twoq',
+    url='https://bitbucket.org/lcrees/thingq',
     packages=[
         l.strip() for l in open(join(getcwd(), 'packages'), 'r').readlines()
     ],
-    test_suite='twoq.tests',
+    test_suite='thingq.tests',
     zip_safe=False,
     install_requires=install_requires,
     classifiers=[

thingq/__init__.py

+# -*- coding: utf-8 -*-
+'''iterator chaining, underscored by a two-headed queue'''
+
+from thingq.support import port
+from thingq.active.core import manq, autoq
+from thingq.lazy.core import autoq as lazyq
+
+thingq = autoq
+
+__all__ = ('thingq', 'manq', 'autoq', 'lazyq' 'port')
+__version__ = (0, 5, 0)

thingq/active/__init__.py

+# -*- coding: utf-8 -*-
+'''active thingqs'''

thingq/active/core.py

+# -*- coding: utf-8 -*-
+'''thingq active queues'''
+
+from thingq.core import SLOTS
+from thingq.mapping import MappingMixin as MapMixin
+from thingq.ordering import OrderingMixin as OrderMixin
+from thingq.reducing import ReducingMixin as ReduceMixin
+from thingq.filtering import FilteringMixin as FilterMixin
+
+from thingq.active.mixins import AutoResultMixin, ManResultMixin
+
+
+class autoq(AutoResultMixin, FilterMixin, MapMixin, ReduceMixin, OrderMixin):
+
+    '''auto-balancing manipulation queue'''
+
+    __slots__ = SLOTS
+
+
+class manq(ManResultMixin, FilterMixin, MapMixin, ReduceMixin, OrderMixin):
+
+    '''manually balanced manipulation queue'''
+
+    __slots__ = SLOTS

thingq/active/filtering.py

+# -*- coding: utf-8 -*-
+'''thingq active filtering queues'''
+
+from thingq.core import SLOTS
+from thingq.filtering import (
+    FilteringMixin, CollectMixin, SetMixin, SliceMixin)
+
+from thingq.active.mixins import AutoResultMixin, ManResultMixin
+
+
+class collectq(AutoResultMixin, CollectMixin):
+
+    '''auto-balanced collecting queue'''
+
+    __slots__ = SLOTS
+
+
+class mcollectq(ManResultMixin, CollectMixin):
+
+    '''manually balanced collecting queue'''
+
+    __slots__ = SLOTS
+
+
+class setq(AutoResultMixin, SetMixin):
+
+    '''auto-balanced set queue'''
+
+    __slots__ = SLOTS
+
+
+class msetq(ManResultMixin, SetMixin):
+
+    '''manually balanced set queue'''
+
+    __slots__ = SLOTS
+
+
+class sliceq(AutoResultMixin, SliceMixin):
+
+    '''auto-balanced slice queue'''
+
+    __slots__ = SLOTS
+
+
+class msliceq(ManResultMixin, SliceMixin):
+
+    '''manually balanced slice queue'''
+
+    __slots__ = SLOTS
+
+
+class filterq(AutoResultMixin, FilteringMixin):
+
+    '''auto-balanced filter queue'''
+
+    __slots__ = SLOTS
+
+
+class mfilterq(ManResultMixin, FilteringMixin):
+
+    '''manually balanced filtering queue'''
+
+    __slots__ = SLOTS

thingq/active/mapping.py

+# -*- coding: utf-8 -*-
+'''thingq active mapping queues'''
+
+from thingq.core import SLOTS
+from thingq.mapping import DelayMixin, RepeatMixin, MappingMixin
+
+from thingq.active.mixins import AutoResultMixin, ManResultMixin
+
+
+class delayq(AutoResultMixin, DelayMixin):
+
+    '''auto-balanced delayed map queue'''
+
+    __slots__ = SLOTS
+
+
+class mdelayq(ManResultMixin, DelayMixin):
+
+    '''manually balanced delayed map queue'''
+
+    __slots__ = SLOTS
+
+
+class repeatq(AutoResultMixin, RepeatMixin):
+
+    '''auto-balanced repeat queue'''
+
+    __slots__ = SLOTS
+
+
+class mrepeatq(ManResultMixin, RepeatMixin):
+
+    '''manually balanced repeat queue'''
+
+    __slots__ = SLOTS
+
+
+class mapq(AutoResultMixin, MappingMixin):
+
+    '''auto-balanced mapping queue'''
+
+    __slots__ = SLOTS
+
+
+class mmapq(ManResultMixin, MappingMixin):
+
+    '''manually balanced mapping queue'''
+
+    __slots__ = SLOTS

thingq/active/mixins.py

+# -*- coding: utf-8 -*-
+'''active thingq mixins'''
+
+from copy import copy
+from itertools import repeat
+from collections import deque
+from contextlib import contextmanager
+
+from stuf.utils import clsname
+
+from thingq.core import ThingsMixin, ResultsMixin
+
+
+class BaseMixin(ThingsMixin):
+
+    '''base active things'''
+
+    def __init__(self, *things, **kw):
+        try:
+            incoming = deque(things[0]) if len(things) == 1 else deque(things)
+        except TypeError:
+            incoming = deque()
+            incoming.extend(things)
+        super(BaseMixin, self).__init__(incoming, deque())
+        # set iterator
+        self._iterator = self._iterexcept
+        # work things
+        self._work = deque()
+        # utility things
+        self._util = deque()
+
+    ###########################################################################
+    ## mode things ############################################################
+    ###########################################################################
+
+    def ro(self):
+        '''switch to read-only mode'''
+        with self.ctx3(outq=self._UTILVAR, savepoint=False):
+            self._xtend(self._iterable)
+        with self.ctx1(hard=True, workq=self._UTILVAR, savepoint=False):
+            self.current_mode = self._RO
+            return self
+
+    ###########################################################################
+    ## context things #######################################################
+    ###########################################################################
+
+    @contextmanager
+    def ctx2(self, **kw):
+        '''swap for two-armed context'''
+        self.swap(
+            outq=kw.get(self._OUTCFG, self._INVAR), context=self.ctx2(), **kw
+        )
+        getr_ = lambda x: getattr(self, x)
+        outq = getr_(self._OUTQ)
+        utilq = getr_(self._UTILQ)
+        workq = getr_(self._WORKQ)
+        # clear all work things
+        workq.clear()
+        # extend work things with outgoing things
+        workq.extend(outq)
+        # swap iterator
+        self._iterator = self._breakcount
+        yield
+        # clear outgoing things if so configured
+        if self._clearout:
+            outq.clear()
+        # extend outgoing things with utility things
+        outq.extend(utilq)
+        # clear utility things
+        utilq.clear()
+        # return to global context
+        self.reswap()
+
+    @contextmanager
+    def ctx3(self, **kw):
+        '''swap for three-armed context'''
+        self.swap(
+            utilq=kw.get(self._WORKCFG, self._WORKVAR), context=self.ctx3, **kw
+        )
+        getr_ = lambda x: getattr(self, x)
+        outq = getr_(self._OUTQ)
+        utilq = getr_(self._UTILQ)
+        workq = getr_(self._WORKQ)
+        # clear work things
+        workq.clear()
+        # extend work things with incoming things
+        workq.extend(getr_(self._INQ))
+        # swap iterators
+        self._iterator = self._breakcount
+        yield
+        # clear outgoing things if so configured
+        if self._clearout:
+            outq.clear()
+        # extend outgoing things with utility things
+        outq.extend(utilq)
+        # clear utility things
+        utilq.clear()
+        # return to global context
+        self.reswap()
+
+    @contextmanager
+    def ctx4(self, **kw):
+        '''swap for four-armed context'''
+        self.swap(context=self.ctx4, **kw)
+        getr_ = lambda x: getattr(self, x)
+        outq = getr_(self._OUTQ)
+        utilq = getr_(self._UTILQ)
+        workq = getr_(self._WORKQ)
+        # clear work things
+        workq.clear()
+        # extend work things with incoming things
+        workq.extend(getr_(self._INQ))
+        # swap iterators
+        self._iterator = self._iterexcept
+        yield
+        # clear outgoing things if so configured
+        if self._clearout:
+            outq.clear()
+        # extend outgoing things with utility things
+        outq.extend(utilq)
+        # clear utility things
+        utilq.clear()
+        # return to global context
+        self.reswap()
+
+    @contextmanager
+    def autoctx(self, **kw):
+        '''swap for auto-synchronizing context'''
+        self.swap(context=self.autoctx, **kw)
+        getr_ = lambda x: getattr(self, x)
+        outq = getr_(self._OUTQ)
+        utilq = getr_(self._UTILQ)
+        workq = getr_(self._WORKQ)
+        inq = getr_(self._INQ)
+        # clear work things
+        workq.clear()
+        # extend work things with incoming things
+        workq.extend(inq)
+        # swap iterators
+        self._iterator = self._iterexcept
+        yield
+        # clear outgoing things if so configured
+        if self._clearout:
+            outq.clear()
+        outq.extend(utilq)
+        # clear incoming things
+        inq.clear()
+        inq.extend(utilq)
+        # clear utility things
+        utilq.clear()
+        # return to global context
+        self.reswap()
+
+    ###########################################################################
+    ## savepoint for things ###################################################
+    ###########################################################################
+
+    def _savepoint(self):
+        '''take savepoint of incoming things'''
+        self._savepoints.append(copy(getattr(self, self._INQ)))
+        return self
+
+    ###########################################################################
+    ## iterate things #########################################################
+    ###########################################################################
+
+    def __iter__(self):
+        '''yield outgoing things, clearing outgoing things as it iterates'''
+        return self._iterexcept(self._OUTQ)
+
+    @property
+    def _iterable(self):
+        '''iterable'''
+        return self._iterator(self._WORKQ)
+
+    def _breakcount(self, attr='_UTILQ'):
+        '''
+        breakcount iterator
+
+        @param attr: things to iterate over
+        '''
+        dq = getattr(self, attr)
+        length = len(dq)
+        call = dq.popleft
+        for i in repeat(None, length):  # @UnusedVariable
+            yield call()
+
+    def _iterexcept(self, attr='_UTILQ'):
+        '''
+        call a function repeatedly until an exception is raised
+
+        Converts a call-until-exception interface to an iterator interface.
+        Like `iter(call, sentinel)` but uses an exception instead of a sentinel
+        to end the loop.
+
+        Raymond Hettinger, Python Cookbook recipe # 577155
+        '''
+        call = getattr(self, attr).popleft
+        try:
+            while 1:
+                yield call()
+        except IndexError:
+            pass
+
+    ###########################################################################
+    ## extend things ##########################################################
+    ###########################################################################
+
+    def _xtend(self, things):
+        '''extend utility things with `things` wrapped'''
+        getattr(self, self._UTILQ).extend(things)
+        return self
+
+    def _xtendleft(self, things):
+        '''extend left side of utility things with `things`'''
+        getattr(self, self._UTILQ).extendleft(things)
+        return self
+
+    def _iter(self, things):
+        '''extend work things with `things` wrapped in iterator'''
+        getattr(self, self._UTILQ).extend(iter(things))
+        return self
+
+    ###########################################################################
+    ## append things ##########################################################
+    ###########################################################################
+
+    def _append(self, things):
+        '''append `things` to utility things'''
+        getattr(self, self._UTILQ).append(things)
+        return self
+
+    def _appendleft(self, things):
+        '''append `things` to left side of utility things'''
+        getattr(self, self._UTILQ).appendleft(things)
+        return self
+
+    ###########################################################################
+    ## know things ############################################################
+    ###########################################################################
+
+    def __len__(self):
+        '''number of incoming things'''
+        return len(self.incoming)
+
+    def __repr__(self):
+        getr_, list_ = lambda x: getattr(self, x), list
+        return self._repr(
+            self.__module__,
+            clsname(self),
+            self.current_mode.upper(),
+            self._INQ,
+            list_(getr_(self._INQ)),
+            self._WORKQ,
+            list_(getr_(self._WORKQ)),
+            self._UTILQ,
+            list_(getr_(self._UTILQ)),
+            self._OUTQ,
+            list_(getr_(self._OUTQ)),
+            id(self),
+        )
+
+    def countout(self):
+        '''number of outgoing things'''
+        return len(self.outgoing)
+
+    ###########################################################################
+    ## clear things ###########################################################
+    ###########################################################################
+
+    def _clearu(self):
+        '''clear utility things'''
+        self._util.clear()
+        return self
+
+    def _clearw(self):
+        '''clear work things'''
+        self._work.clear()
+        return self
+
+    def clearin(self):
+        '''clear incoming things'''
+        self.incoming.clear()
+        return self
+
+    def clearout(self):
+        '''clear outgoing things'''
+        self.outgoing.clear()
+        return self
+
+
+class AutoMixin(BaseMixin):
+
+    '''auto-balancing queue mixin'''
+
+    _DEFAULT_CONTEXT = 'autoctx'
+
+
+class ManMixin(BaseMixin):
+
+    '''manually balanced queue mixin'''
+
+    _DEFAULT_CONTEXT = 'ctx4'
+
+
+class EndMixin(ResultsMixin):
+
+    '''result things mixin'''
+
+    def end(self):
+        '''return outgoing things then clear out everything'''
+        # return to default context
+        self.unswap()
+        wrap, outgoing = self._wrapper, self.outgoing
+        out = self.outgoing.pop() if len(outgoing) == 1 else wrap(outgoing)
+        # clear every last thing
+        self.clear()._clearsp()
+        return out
+
+    def snapshot(self):
+        '''snapshot of current outgoing things'''
+        out = copy(getattr(self, self._OUTQ))
+        return out.pop() if len(out) == 1 else self._wrapper(out)
+
+    def value(self):
+        '''return outgoing things and clear outgoing things'''
+        # return to default context
+        self.unswap()
+        wrap, outgoing = self._wrapper, self.outgoing
+        out = self.outgoing.pop() if len(outgoing) == 1 else wrap(outgoing)
+        # clear outgoing things
+        self.clearout()
+        return out
+
+
+class AutoResultMixin(AutoMixin, EndMixin):
+
+    '''auto-balancing manipulation things (with results extractor) mixin'''
+
+
+class ManResultMixin(ManMixin, EndMixin):
+
+    '''manually balanced things (with results extractor) mixin'''

thingq/active/ordering.py

+# -*- coding: utf-8 -*-
+'''thingq active ordering queues'''
+
+from thingq.core import SLOTS
+from thingq.ordering import RandomMixin, OrderingMixin
+
+from thingq.active.mixins import AutoResultMixin, ManResultMixin
+
+
+class randomq(AutoResultMixin, RandomMixin):
+
+    '''auto-balanced randomizing queue'''
+
+    __slots__ = SLOTS
+
+
+class mrandomq(ManResultMixin, RandomMixin):
+
+    '''manually balanced randomizing queue'''
+
+    __slots__ = SLOTS
+
+
+class orderq(AutoResultMixin, OrderingMixin):
+
+    '''auto-balanced ordering queue'''
+
+    __slots__ = SLOTS
+
+
+class morderq(ManResultMixin, OrderingMixin):
+
+    '''manually balanced order queue'''
+
+    __slots__ = SLOTS

thingq/active/reducing.py

+# -*- coding: utf-8 -*-
+'''thingq active reducing queues'''
+
+from thingq.core import SLOTS
+from thingq.reducing import MathMixin, TruthMixin, ReducingMixin
+
+from thingq.active.mixins import AutoResultMixin, ManResultMixin
+
+
+class mathq(AutoResultMixin, MathMixin):
+
+    '''auto-balancing math queue'''
+
+    __slots__ = SLOTS
+
+
+class mmathq(ManResultMixin, MathMixin):
+
+    '''manually balanced math queue'''
+
+    __slots__ = SLOTS
+
+
+class truthq(AutoResultMixin, TruthMixin):
+
+    '''auto-balancing truth queue'''
+
+    __slots__ = SLOTS
+
+
+class mtruthq(ManResultMixin, TruthMixin):
+
+    '''manually balanced truth queue'''
+
+    __slots__ = SLOTS
+
+
+class reduceq(AutoResultMixin, ReducingMixin):
+
+    '''auto-balancing reduce queue'''
+
+    __slots__ = SLOTS
+
+
+class mreduceq(ManResultMixin, ReducingMixin):
+
+    '''manually balanced reduce queue'''
+
+    __slots__ = SLOTS
+# -*- coding: utf-8 -*-
+'''thingq queuing mixins'''
+
+from threading import local
+from collections import deque
+from contextlib import contextmanager
+
+from stuf.utils import OrderedDict
+from stuf.core import stuf, frozenstuf, orderedstuf
+
+SLOTS = [
+    '_work', 'outgoing', '_util', 'incoming', '_call', '_alt', '_wrapper',
+    '_args', '_kw', '_clearout', '_context', '_CONFIG', '_INQ', '_WORKQ',
+    '_UTILQ', '_OUTQ', '_iterator', 'current_mode', '_savepoints', '_start',
+]
+
+
+class ThingsMixin(local):
+
+    '''things management mixin'''
+
+    def __init__(self, incoming, outgoing, **kw):
+        '''
+        init
+
+        @param incoming: incoming things
+        @param outgoing: outgoing things
+        '''
+        super(ThingsMixin, self).__init__()
+        # incoming things
+        self.incoming = incoming
+        # outgoing things
+        self.outgoing = outgoing
+        # preferred mode
+        self.current_mode = self._RW
+        #######################################################################
+        ## context defaults ###################################################
+        #######################################################################
+        # preferred context
+        self._context = getattr(self, self._DEFAULT_CONTEXT)
+        # default context settings
+        self._CONFIG = {}
+        # 1. default incoming things
+        self._INQ = self._INVAR
+        # 2. default work things
+        self._WORKQ = self._WORKVAR
+        # 3. default utility things
+        self._UTILQ = self._UTILVAR
+        # 4. default outgoing things
+        self._OUTQ = self._OUTVAR
+        # clear outgoing things before extending/appending to them?
+        self._clearout = True
+        #######################################################################
+        ## snapshotting defaults ##############################################
+        #######################################################################
+        # number of savepoints to keep (default: 5)
+        maxlen = kw.pop('savepoints', 5)
+        # create stack for savepoint things
+        self._savepoints = deque(maxlen=maxlen) if maxlen is not None else None
+        # savepoint of original incoming things
+        if self._savepoints is not None:
+            self._original()
+        #######################################################################
+        ## callable defaults ##################################################
+        #######################################################################
+        # current callable (default: identity)
+        self._call = lambda x: x
+        # current alternate callable (default: identity)
+        self._alt = lambda x: x
+        # iterable export wrapper (default: `list`)
+        self._wrapper = list
+        # postition arguments (default: `tuple`)
+        self._args = ()
+        # keyword arguments (default: `dict`)
+        self._kw = {}
+
+    ###########################################################################
+    ## mode things ############################################################
+    ###########################################################################
+
+    # read/write mode
+    _RW = 'read/write'
+    # read-only mode
+    _RO = 'read-only'
+
+    def rw(self):
+        '''switch to read/write mode'''
+        self.current_mode = self._RW
+        return self._clearu().unswap()
+
+    ###########################################################################
+    ## context things #EE######################################################
+    ###########################################################################
+
+    # 1. incoming things
+    _INCFG = 'inq'
+    _INVAR = 'incoming'
+    # 2. utility things
+    _UTILCFG = 'utilq'
+    _UTILVAR = '_util'
+    # 3. work things
+    _WORKCFG = 'workq'
+    _WORKVAR = '_work'
+    # 4. outgoing things
+    _OUTCFG = 'outq'
+    _OUTVAR = 'outgoing'
+
+    def swap(self, **kw):
+        '''swap context'''
+        # savepoint
+        savepoint = kw.pop('savepoint', True)
+        if savepoint:
+            self._savepoint()
+        # keep context-specific settings between context swaps
+        self._CONFIG = kw if kw.get('hard', False) else {}
+        # set context
+        self._context = kw.get('context', getattr(self, self._DEFAULT_CONTEXT))
+        # clear out outgoing things before extending them?
+        self._clearout = kw.get('clearout', True)
+        # 1. incoming things
+        self._INQ = kw.get(self._INCFG, self._INVAR)
+        # 2. work things
+        self._WORKQ = kw.get(self._WORKCFG, self._WORKVAR)
+        # 3. utility things
+        self._UTILQ = kw.get(self._UTILCFG, self._UTILVAR)
+        # 4. outgoing things
+        self._OUTQ = kw.get(self._OUTCFG, self._OUTVAR)
+        return self
+
+    def reswap(self):
+        '''swap for preferred context'''
+        return self.swap(savepoint=False, **self._CONFIG)
+
+    def unswap(self):
+        '''swap for current default context'''
+        return self.swap(savepoint=False)
+
+    @contextmanager
+    def ctx1(self, **kw):
+        '''swap for one-armed context'''
+        q = kw.pop(self._WORKCFG, self._INVAR)
+        self.swap(workq=q, utilq=q, context=self.ctx1, **kw)
+        yield
+        self.reswap()
+
+    ###########################################################################
+    ## savepoint for things ##################################################
+    ###########################################################################
+
+    def _original(self):
+        '''preserve original incoming things'''
+        self._savepoint()
+        # preserve from savepoint stack
+        self._start = self._savepoints.pop()
+        return self
+
+    def undo(self, index=0, everything=False):
+        '''
+        revert to previous savepoint
+
+        @param index: index of savepoint (default: 0)
+        @param everything: undo everything and return things to original state
+        '''
+        if everything:
+            self.clear()._clearsp()
+            self.incoming = self._start
+            self._original()
+            return self
+        self.clear()
+        if not index:
+            self.incoming = self._savepoints.pop()
+        else:
+            self.incoming = deque(reversed(self._savepoints))[index]
+        return self._savepoint()
+
+    ###########################################################################
+    ## rotate things ##########################################################
+    ###########################################################################
+
+    def reup(self):
+        '''put incoming things in incoming things as one incoming thing'''
+        with self.ctx2(savepoint=False):
+            return self._append(list(self._iterable))
+
+    def sync(self):
+        '''shift outgoing things to incoming things'''
+        with self.autoctx(inq=self._OUTVAR, outq=self._INVAR, savepoint=False):
+            return self._xtend(self._iterable)
+
+    def syncout(self):
+        '''shift incoming things to outgoing things'''
+        with self.autoctx(savepoint=False):
+            return self._xtend(self._iterable)
+
+    ###########################################################################
+    ## extend incoming things #################################################
+    ###########################################################################
+
+    def extend(self, things):
+        '''
+        extend after incoming things
+
+        @param thing: some things
+        '''
+        with self.ctx1():
+            return self._xtend(things)
+
+    def extendleft(self, things):
+        '''
+        extend before incoming things
+
+        @param thing: some things
+        '''
+        with self.ctx1():
+            return self._xtendleft(things)
+
+    def outextend(self, things):
+        '''
+        extend right side of outgoing things
+
+        @param thing: some things
+        '''
+        with self.ctx1(workq=self._OUTVAR):
+            return self._xtend(things)
+
+    ###########################################################################
+    ## append incoming things #################################################
+    ###########################################################################
+
+    def append(self, thing):
+        '''
+        append after incoming things
+
+        @param thing: some thing
+        '''
+        with self.ctx1():
+            return self._append(thing)
+
+    def prepend(self, thing):
+        '''
+        append before incoming things
+
+        @param thing: some thing
+        '''
+        with self.ctx1():
+            return self._appendleft(thing)
+
+    ###########################################################################
+    ## call things ############################################################
+    ###########################################################################
+
+    def args(self, *args, **kw):
+        '''set arguments for current or alternative callable'''
+        # set position arguments
+        self._args = args
+        # set keyword arguemnts
+        self._kw = kw
+        return self
+
+    def tap(self, call, alt=None, factory=False):
+        '''
+        set current callable
+
+        @param call: a callable
+        @param alt: an alternative callable (default: None)
+        @param factor: call is a factory? (default: False)
+        '''
+        # reset postition arguments
+        self._args = ()
+        # reset keyword arguments
+        self._kw = {}
+        # set factory for building current callable
+        if factory:
+            def factory(*args, **kw):
+                return call(*args, **kw)
+            self._call = factory
+        else:
+            # set current callable
+            self._call = call
+        # set alternative callable
+        self._alt = alt if alt is not None else lambda x: x
+        return self
+
+    def untap(self):
+        '''clear current callable'''
+        # reset postition arguments
+        self._args = ()
+        # reset keyword arguments
+        self._kw = {}
+        # reset current callable (default is identity)
+        self._call = lambda x: x
+        # reset alternative callable
+        self._alt = lambda x: x
+        return self
+
+    ###########################################################################
+    ## know things ############################################################
+    ###########################################################################
+
+    @staticmethod
+    def _repr(*args):
+        '''queue representation'''
+        return (
+            '<{0}.{1}<<{2}>>([IN: {3}({4}) => WORK: {5}({6}) => UTIL: {7}({8})'
+            ' => OUT: {9}: ({10})]) at {11}>'
+        ).format(*args)
+
+    @property
+    def balanced(self):
+        '''queues are balanced?'''
+        return self.countout() == self.__len__()
+
+    ###########################################################################
+    ## clear things ###########################################################
+    ###########################################################################
+
+    def _clearsp(self):
+        '''clear savepoints'''
+        self._savepoints.clear()
+        return self
+
+    def clear(self):
+        '''clear anything'''
+        return self.untap().unwrap().clearout().clearin()._clearw()._clearu()
+
+
+class ResultsMixin(local):
+
+    '''result of things mixin'''
+
+    ###########################################################################
+    ## outgoing things export #################################################
+    ###########################################################################
+
+    def peek(self):
+        '''results from read-only context'''
+        self.ro()
+        out = self._wrapper(self._util)
+        results = out[0] if len(out) == 1 else out
+        self.rw()
+        return results
+
+    def results(self):
+        '''yield outgoing things, clearing outgoing things as it iterates'''
+        return self.__iter__()
+
+    ###########################################################################
+    ## wrap outgoing things ###################################################
+    ###########################################################################
+
+    def wrap(self, wrapper):
+        '''
+        wrapper for outgoing things
+
+        @param wrapper: an iterator class
+        '''
+        self._wrapper = wrapper
+        return self
+
+    def tuple_wrap(self):
+        '''set wrapper to `tuple`'''
+        return self.wrap(tuple)
+
+    def set_wrap(self):
+        '''set wrapper to `set`'''
+        return self.wrap(set)
+
+    def deque_wrap(self):
+        '''set wrapper to `deque`'''
+        return self.wrap(deque)
+
+    def dict_wrap(self):
+        '''set wrapper to `dict`'''
+        return self.wrap(dict)
+
+    def frozenset_wrap(self):
+        '''set wrapper to `frozenset`'''
+        return self.wrap(frozenset)
+
+    def frozenstuf_wrap(self):
+        '''set wrapper to `frozenstuf`'''
+        return self.wrap(frozenstuf)
+
+    def ordereddict_wrap(self):
+        '''set wrapper to `OrderedDict`'''
+        return self.wrap(OrderedDict)
+
+    def orderedstuf_wrap(self):
+        '''set wrapper to `orderedstuf`'''
+        return self.wrap(orderedstuf)
+
+    def stuf_wrap(self):
+        '''set wrapper to `stuf`'''
+        return self.wrap(stuf)
+
+    def list_wrap(self):
+        '''clear current wrapper'''
+        return self.wrap(list)
+
+    unwrap = list_wrap

thingq/filtering.py

+# -*- coding: utf-8 -*-
+'''thingq filtering mixins'''
+
+from inspect import getmro
+from threading import local
+from functools import reduce
+from collections import deque
+from itertools import tee, islice
+from operator import attrgetter, itemgetter, truth
+
+from thingq.support import ifilter, ichain, imap, filterfalse
+
+
+class CollectMixin(local):
+
+    '''collecting mixin'''
+
+    def members(self):
+        '''extract object members from incoming things'''
+        call_, alt_, wrap_ = self._call, self._alt, self._wrapper
+        def members(truth, iterable): #@IgnorePep8
+            f, s, t, i = truth, alt_, wrap_, iterable
+            d, w, g, e = dir, extract, getattr, AttributeError
+            test = lambda x: x.startswith('__') or x.startswith('mro')
+            for k in filterfalse(test, d(i)):
+                try:
+                    v = g(i, k)
+                except e:
+                    pass
+                else:
+                    if s(v):
+                        yield k, t(w(f, v))
+                    else:
+                        yield k, v
+        def extract(truth, iterable, ifilter_=ifilter, members_=members):
+            for member in ifilter_(truth, members_(truth, iterable)):
+                yield member
+        with self._context():
+            return self._xtend(ichain(imap(
+                lambda x: extract(call_, x), self._iterable,
+            )))
+
+    def mro(self):
+        '''extract ancestors of things by method resolution order'''
+        with self._context():
+            return self._xtend(ichain(getmro(i) for i in self._iterable))
+
+    def pick(self, *names):
+        '''collect object attributes from incoming things by their `*names`'''
+        def pick(names, iterable):
+            '''
+            collect attributes of things in iterable
+    
+            @param names: sequence of names
+            @param iterable: an iterable
+            '''
+            attrfind = attrgetter(*names)
+            for thing in iterable:
+                try:
+                    yield attrfind(thing)
+                except AttributeError:
+                    pass
+        with self._context():
+            return self._xtend(pick(names, self._iterable))
+
+    def pluck(self, *keys):
+        '''collect object items from incoming things by item `*keys`'''
+        def pluck(keys, iterable, _itemgetter=itemgetter):
+            '''
+            collect values of things in iterable
+    
+            @param keys: sequence of keys
+            @param iterable: an iterable
+            '''
+            itemfind = _itemgetter(*keys)
+            IndexErr_, KeyErr_, TypeErr_ = IndexError, KeyError, TypeError
+            for thing in iterable:
+                try:
+                    yield itemfind(thing)
+                except (IndexErr_, KeyErr_, TypeErr_):
+                    pass
+        with self._context():
+            return self._xtend(pluck(keys, self._iterable))
+
+
+class SetMixin(local):
+
+    '''set and uniqueness mixin'''
+
+    def difference(self):
+        '''difference between incoming things'''
+        with self._context():
+            return self._xtend(reduce(
+                lambda x, y: set(x).difference(y), self._iterable,
+            ))
+
+    def symmetric_difference(self):
+        '''symmetric difference between incoming things'''
+        with self._context():
+            return self._xtend(reduce(
+                lambda x, y: set(x).symmetric_difference(y), self._iterable,
+            ))
+
+    def disjointed(self):
+        '''disjoint between incoming things'''
+        with self._context():
+            return self._append(reduce(
+                lambda x, y: set(x).isdisjoint(y), self._iterable,
+            ))
+
+    def intersection(self):
+        '''intersection between incoming things'''
+        with self._context():
+            return self._xtend(reduce(
+                lambda x, y: set(x).intersection(y), self._iterable,
+            ))
+
+    def subset(self):
+        '''incoming things that are subsets of incoming things'''
+        with self._context():
+            return self._append(reduce(
+                lambda x, y: set(x).issubset(y), self._iterable,
+            ))
+
+    def superset(self):
+        '''incoming things that are supersets of incoming things'''
+        with self._context():
+            return self._append(reduce(
+                lambda x, y: set(x).issubset(y), self._iterable
+            ))
+
+    def union(self):
+        '''union between incoming things'''
+        with self._context():
+            return self._xtend(
+                reduce(lambda x, y: set(x).union(y), self._iterable)
+            )
+
+    def unique(self):
+        '''
+        list unique incoming things, preserving order and remember all incoming
+        things ever seen
+        '''
+        def unique(iterable, key=None):
+            seen = set()
+            seen_add_, key_ = seen.add, key
+            for element in iterable:
+                k = key_(element)
+                if k not in seen:
+                    seen_add_(k)
+                    yield element
+        with self._context():
+            return self._iter(unique(self._iterable, self._call))
+
+
+class SliceMixin(local):
+
+    '''slicing mixin'''
+
+    def first(self):
+        '''first incoming thing'''
+        with self._context():
+            return self._append(next(self._iterable))
+
+    def last(self):
+        '''last incoming thing'''
+        with self._context():
+            i1, _ = tee(self._iterable)
+            return self._append(deque(i1, maxlen=1).pop())
+
+    def nth(self, n, default=None):
+        '''
+        `nth` incoming thing or default thing
+
+        @param n: number of things
+        @param default: default thing (default: None)
+        '''
+        with self._context():
+            return self._append(
+                next(islice(self._iterable, n, None), default)
+            )
+
+    def initial(self):
+        '''all incoming things except the last thing'''
+        with self._context():
+            i1, i2 = tee(self._iterable)
+            return self._xtend(islice(i1, len(list(i2)) - 1))
+
+    def partition(self):
+        '''
+        split incoming things into `True` and `False` things based on results
+        of call
+        '''
+        list_, call_ = list, self._call
+        with self._context():
+            falsy, truey = tee(self._iterable)
+            return self._xtend(iter([
+                list_(filterfalse(call_, falsy)), list_(ifilter(call_, truey)),
+            ]))
+
+    def rest(self):
+        '''all incoming things except the first thing'''
+        with self._context():
+            return self._xtend(islice(self._iterable, 1, None))
+
+    def snatch(self, n):
+        '''
+        last `n` things of incoming things
+
+        @param n: number of things
+        '''
+        with self._context():
+            i1, i2 = tee(self._iterable)
+            return self._xtend(islice(i1, len(list(i2)) - n, None))
+
+    def take(self, n):
+        '''
+        first `n` things of incoming things
+
+        @param n: number of things
+        '''
+        with self._context():
+            return self._xtend(islice(self._iterable, n))
+
+
+class FilterMixin(local):
+
+    '''filters mixin'''
+
+    def compact(self):
+        '''strip "untrue" things from incoming things'''
+        with self._context():
+            return self._iter(ifilter(truth, self._iterable))
+
+    def filter(self):
+        '''incoming things for which call is `True`'''
+        with self._context():
+            return self._xtend(ifilter(self._call, self._iterable))
+
+    def find(self):
+        '''first incoming thing for which call is `True`'''
+        with self._context():
+            return self._append(
+                next(ifilter(self._call, self._iterable))
+            )
+
+    def reject(self):
+        '''incoming things for which call is `False`'''
+        with self._context():
+            return self._xtend(filterfalse(self._call, self._iterable))
+
+    def without(self, *things):
+        '''strip things from incoming things'''
+        with self._context():
+            return self._xtend(
+                filterfalse(lambda y: y in things, self._iterable)
+            )
+
+
+class FilteringMixin(CollectMixin, SetMixin, SliceMixin, FilterMixin):
+
+    '''filtering mixin'''

thingq/lazy/__init__.py

+# -*- coding: utf-8 -*-
+'''lazy thingqs'''

thingq/lazy/core.py

+# -*- coding: utf-8 -*-
+'''thingq lazy queues'''
+
+from thingq.core import SLOTS
+from thingq.mapping import MappingMixin as MapMixin
+from thingq.ordering import OrderingMixin as OrderMixin
+from thingq.reducing import ReducingMixin as ReduceMixin
+from thingq.filtering import FilteringMixin as FilterMixin
+
+from thingq.lazy.mixins import AutoResultMixin, ManResultMixin
+
+
+class autoq(AutoResultMixin, FilterMixin, MapMixin, ReduceMixin, OrderMixin):
+
+    '''auto-balancing manipulation queue'''
+
+    __slots__ = SLOTS
+
+
+class manq(ManResultMixin, FilterMixin, MapMixin, ReduceMixin, OrderMixin):
+
+    '''manually balanced manipulation queue'''
+
+    __slots__ = SLOTS
+
+
+lazyq = autoq

thingq/lazy/filtering.py

+# -*- coding: utf-8 -*-
+'''thingq lazy filtering queues'''
+
+from thingq.core import SLOTS
+from thingq.filtering import (
+    FilteringMixin, CollectMixin, SetMixin, SliceMixin)
+
+from thingq.lazy.mixins import AutoResultMixin, ManResultMixin
+
+
+class collectq(AutoResultMixin, CollectMixin):
+
+    '''auto-balanced collecting queue'''
+
+    __slots__ = SLOTS
+
+
+class mcollectq(ManResultMixin, CollectMixin):
+
+    '''manually balanced collecting queue'''
+
+    __slots__ = SLOTS
+
+
+class setq(AutoResultMixin, SetMixin):
+
+    '''auto-balanced set queue'''
+
+    __slots__ = SLOTS
+
+
+class msetq(ManResultMixin, SetMixin):
+
+    '''manually balanced set queue'''
+
+    __slots__ = SLOTS
+
+
+class sliceq(AutoResultMixin, SliceMixin):
+
+    '''auto-balanced slice queue'''
+
+    __slots__ = SLOTS
+
+
+class msliceq(ManResultMixin, SliceMixin):
+
+    '''manually balanced slice queue'''
+
+    __slots__ = SLOTS
+
+
+class filterq(AutoResultMixin, FilteringMixin):
+
+    '''auto-balanced filter queue'''
+
+    __slots__ = SLOTS
+
+
+class mfilterq(ManResultMixin, FilteringMixin):
+
+    '''manually balanced filtering queue'''
+
+    __slots__ = SLOTS

thingq/lazy/mapping.py

+# -*- coding: utf-8 -*-
+'''thingq lazy mapping queues'''
+
+from thingq.core import SLOTS
+from thingq.mapping import DelayMixin, RepeatMixin, MappingMixin
+
+from thingq.lazy.mixins import AutoResultMixin, ManResultMixin
+
+
+class delayq(AutoResultMixin, DelayMixin):
+
+    '''auto-balanced delayed map queue'''
+
+    __slots__ = SLOTS
+
+
+class mdelayq(ManResultMixin, DelayMixin):
+
+    '''manually balanced delayed map queue'''
+
+    __slots__ = SLOTS
+
+
+class repeatq(AutoResultMixin, RepeatMixin):
+
+    '''auto-balanced repeat queue'''
+
+    __slots__ = SLOTS
+
+
+class mrepeatq(ManResultMixin, RepeatMixin):
+
+    '''manually balanced repeat queue'''
+
+    __slots__ = SLOTS
+
+
+class mapq(AutoResultMixin, MappingMixin):
+
+    '''auto-balanced map queue'''
+
+    __slots__ = SLOTS
+
+
+class mmapq(ManResultMixin, MappingMixin):
+
+    '''manually balanced map queue'''
+
+    __slots__ = SLOTS

thingq/lazy/mixins.py

+# -*- coding: utf-8 -*-
+'''lazy thingq mixins'''
+
+from itertools import tee, chain
+from contextlib import contextmanager
+
+from stuf.utils import clsname
+
+from thingq.core import ResultsMixin, ThingsMixin
+
+
+class BaseMixin(ThingsMixin):
+
+    '''base lazy things'''
+
+    def __init__(self, *things, **kw):
+        incoming = iter([things[0]]) if len(things) == 1 else iter(things)
+        super(BaseMixin, self).__init__(incoming, iter([]))
+        # work things
+        self._work = iter([])
+        # utility things
+        self._util = iter([])
+
+    def __repr__(self):
+        list_, tee_ = list, tee
+        setr_ = lambda x, y: setattr(self, x, y)
+        getr_ = lambda x: getattr(self, x)
+        in1, in2 = tee_(getr_(self._INQ))
+        setr_(self._INQ, in1)
+        out1, out2 = tee_(getr_(self._OUTQ))
+        setr_(self._OUTQ, out1)
+        work1, work2 = tee_(getr_(self._WORKQ))
+        setr_(self._WORKQ, work1)
+        util1, util2 = tee_(getr_(self._UTILQ))
+        setr_(self._UTILQ, util1)
+        return self._repr(
+            self.__module__,
+            clsname(self),
+            self.current_mode.upper(),
+            self._INQ,
+            list_(in2),
+            self._WORKQ,
+            list_(work2),
+            self._UTILQ,
+            list_(util2),
+            self._OUTQ,
+            list_(out2),
+            id(self),
+        )
+
+    ###########################################################################
+    ## mode things ############################################################
+    ###########################################################################
+
+    def ro(self):
+        '''switch to read-only mode'''
+        with self.ctx3(outq=self._UTILVAR, savepoint=False):
+            self._xreplace(self._iterable)
+        with self.ctx1(hard=True, workq=self._UTILVAR, savepoint=False):
+            self.current_mode = self._RO
+            return self
+
+    ###########################################################################
+    ## context things #########################################################
+    ###########################################################################
+
+    @contextmanager
+    def ctx2(self, **kw):
+        '''swap for two-armed context'''
+        self.swap(
+            context=self.ctx2, outq=kw.get(self._OUTCFG, self._INVAR), **kw
+        )._clearworking()
+        setr_ = lambda x, y: setattr(self, x, y)
+        getr_ = lambda x: getattr(self, x)
+        OUTQ = self._OUTQ
+        # extend work things with outgoing things
+        work, out = tee(getr_(OUTQ))
+        setr_(self._WORKQ, work)
+        setr_(OUTQ, out)
+        yield
+        # extend outgoing things with utility things
+        util = getr_(self._UTILQ)
+        setr_(
+            self._OUTQ,
+            util if self._clearout else chain(util, getr_(self._OUTQ)),
+        )
+        self._clearworking()
+        # return to global context
+        self.reswap()
+
+    @contextmanager
+    def ctx3(self, **kw):
+        '''swap for three-armed context'''
+        self.swap(
+            utilq=kw.get(self._WORKCFG, self._WORKVAR), context=self.ctx3, **kw
+        )._clearworking()
+        setr_ = lambda x, y: setattr(self, x, y)
+        getr_ = lambda x: getattr(self, x)
+        INQ = self._INQ
+        # extend work things with incoming things
+        work, inq = tee(getr_(INQ))
+        setr_(self._WORKQ, work)
+        setr_(INQ, inq)
+        yield
+        # extend outgoing things with utility things
+        util = getr_(self._UTILQ)
+        setr_(
+            self._OUTQ,
+            util if self._clearout else chain(util, getr_(self._OUTQ)),
+        )
+        self._clearworking()
+        # return to global context
+        self.reswap()
+
+    @contextmanager
+    def ctx4(self, **kw):
+        '''swap for four-armed context'''
+        self.swap(context=self.ctx4, **kw)._clearworking()
+        setr_ = lambda x, y: setattr(self, x, y)
+        getr_ = lambda x: getattr(self, x)
+        INQ = self._INQ
+        # extend work things with incoming things
+        work, inq = tee(getr_(INQ))
+        setr_(self._WORKQ, work)
+        setr_(INQ, inq)
+        yield
+        # extend outgoing things with utility things
+        util = getr_(self._UTILQ)
+        setr_(
+            self._OUTQ,
+            util if self._clearout else chain(util, getr_(self._OUTQ)),
+        )
+        self._clearworking()
+        # return to global context
+        self.reswap()
+
+    @contextmanager
+    def autoctx(self, **kw):
+        '''swap for auto-synchronizing context'''
+        self.swap(context=self.autoctx, **kw)._clearworking()
+        setr_ = lambda x, y: setattr(self, x, y)
+        getr_ = lambda x: getattr(self, x)
+        INQ = self._INQ
+        # extend work things with incoming things
+        work, inq = tee(getr_(INQ))
+        setr_(self._WORKQ, work)
+        setr_(INQ, inq)
+        yield
+        # extend incoming things and outgoing things with utility things
+        inq, out = tee(getr_(self._UTILQ))
+        setr_(
+            self._OUTQ,
+            out if self._clearout else chain(out, getr_(self._OUTQ)),
+        )
+        setr_(INQ, inq)
+        self._clearworking()
+        # return to global context
+        self.reswap()
+
+    ###########################################################################
+    ## savepoint for things ###################################################
+    ###########################################################################
+
+    def _savepoint(self):
+        '''take savepoint of incoming'''
+        savepoint, self.incoming = tee(getattr(self, self._INQ))
+        self._savepoints.append(savepoint)
+        return self
+
+    ###########################################################################
+    ## iterate things #########################################################
+    ###########################################################################
+
+    def __iter__(self):
+        '''yield outgoing things, clearing outgoing things as it iterates'''
+        return getattr(self, self._OUTQ)
+
+    @property
+    def _iterable(self):
+        '''iterable'''
+        return getattr(self, self._WORKQ)
+
+    ###########################################################################
+    ## extend things ##########################################################
+    ###########################################################################
+
+    def _xtend(self, thing):
+        '''build chain'''
+        UTILQ = self._UTILQ
+        setattr(self, UTILQ, chain(thing, getattr(self, UTILQ)))
+        return self
+
+    __buildchain = _xtend
+
+    def _xtendleft(self, things):
+        '''extend left side of work things with `things`'''
+        return self.__buildchain(reversed(things))
+
+    def _xreplace(self, thing):
+        '''build chain'''
+        setattr(self, self._UTILQ, thing)
+        return self
+
+    def _iter(self, things):
+        '''extend work things with `things` wrapped in iterator'''
+        return self.__buildchain(iter(things))
+
+    ###########################################################################
+    ## append things ##########################################################
+    ###########################################################################
+
+    def _append(self, things):
+        '''append `things` to work things'''
+        UTILQ = self._UTILQ
+        setattr(self, UTILQ, chain(getattr(self, UTILQ), iter([things])))
+        return self
+
+    def _appendleft(self, things):
+        '''append `things` to left side of work things'''
+        return self.__buildchain(iter([things]))
+
+    ###########################################################################
+    ## know things ############################################################
+    ###########################################################################
+
+    def __len__(self):
+        '''number of incoming things'''
+        self.incoming, incoming = tee(self.incoming)
+        return len(list(incoming))
+
+    def countout(self):
+        '''number of outgoing things'''
+        self.outgoing, outgoing = tee(self.outgoing)
+        return len(list(outgoing))
+
+    ###########################################################################
+    ## clear things ###########################################################
+    ###########################################################################
+
+    def _clearworking(self):
+        '''clear work things and utility things'''
+        iter_ = iter
+        setr_ = lambda x, y: setattr(self, x, y)
+        delr_ = lambda x: delattr(self, x)
+        WORKQ, UTILQ = self._WORKQ, self._UTILQ
+        # clear work things
+        delr_(WORKQ)
+        setr_(WORKQ, iter_([]))
+        # clear utility things
+        delr_(UTILQ)
+        setr_(UTILQ, iter_([]))
+        return self
+
+    def _clearu(self):
+        '''clear utility things'''
+        UTILQ = self._UTILQ
+        delattr(self, UTILQ)
+        setattr(self, UTILQ, iter([]))
+        return self
+
+    def _clearw(self):
+        '''clear work things'''
+        WORKQ = self._WORKQ
+        delattr(self, WORKQ)
+        setattr(self, WORKQ, iter([]))
+        return self
+
+    def clearin(self):
+        '''clear incoming things'''
+        INQ = self._INQ
+        delattr(self, INQ)
+        setattr(self, INQ, iter([]))
+        return self
+
+    def clearout(self):
+        '''clear outgoing things'''
+        OUTQ = self._OUTQ
+        delattr(self, OUTQ)
+        setattr(self, OUTQ, iter([]))
+        return self
+
+
+class AutoMixin(BaseMixin):
+
+    '''auto-balancing things mixin'''
+
+    _DEFAULT_CONTEXT = 'autoctx'
+
+
+class ManMixin(BaseMixin):
+
+    '''manually balanced things mixin'''
+
+    _DEFAULT_CONTEXT = 'ctx4'
+
+
+class EndMixin(ResultsMixin):
+
+    '''result things mixin'''
+
+    def end(self):
+        '''return outgoing things then clear out everything'''
+        # swap for default context
+        self.unswap()
+        out, tell = tee(self.outgoing)
+        wrap = self._wrapper
+        out = next(out) if len(wrap(tell)) == 1 else wrap(out)
+        # clear every last thing
+        self.clear()
+        return out
+
+    def snapshot(self):
+        '''snapshot of current outgoing things'''
+        out, tell, self.outgoing = tee(getattr(self, self._OUTQ), 3)
+        wrap = self._wrapper
+        return out.pop() if len(wrap(tell)) == 1 else wrap(out)
+
+    def value(self):
+        '''return outgoing things and clear outgoing things'''
+        # swap for default context
+        self.unswap()
+        out, tell = tee(self.outgoing)
+        wrap = self._wrapper
+        out = next(out) if len(wrap(tell)) == 1 else wrap(out)
+        # clear outgoing things
+        self.clearout()
+        return out
+
+
+class AutoResultMixin(EndMixin, AutoMixin):
+
+    '''auto-balancing things (with results extraction) mixin'''
+
+
+class ManResultMixin(EndMixin, ManMixin):
+
+    '''manually balanced things (with results extraction) mixin'''

thingq/lazy/ordering.py

+# -*- coding: utf-8 -*-
+'''thingq lazy ordering queues'''
+
+from thingq.core import SLOTS
+from thingq.ordering import RandomMixin, OrderingMixin
+
+from thingq.lazy.mixins import AutoResultMixin, ManResultMixin
+
+
+class randomq(AutoResultMixin, RandomMixin):
+
+    '''auto-balanced random queue'''
+
+    __slots__ = SLOTS
+
+
+class mrandomq(ManResultMixin, RandomMixin):
+
+    '''manually balanced random queue'''
+
+    __slots__ = SLOTS
+
+
+class orderq(AutoResultMixin, OrderingMixin):
+
+    '''auto-balanced order queue'''
+
+    __slots__ = SLOTS
+
+
+class morderq(ManResultMixin, OrderingMixin):
+
+    '''manually balanced order queue'''
+
+    __slots__ = SLOTS

thingq/lazy/reducing.py

+# -*- coding: utf-8 -*-
+'''thingq lazy reducing queues'''
+
+from thingq.core import SLOTS
+from thingq.reducing import MathMixin, TruthMixin, ReducingMixin
+
+from thingq.lazy.mixins import AutoResultMixin, ManResultMixin
+
+
+class mathq(AutoResultMixin, MathMixin):
+
+    '''auto-balancing math queue'''
+
+    __slots__ = SLOTS
+
+
+class mmathq(ManResultMixin, MathMixin):
+
+    '''manually balanced math queue'''
+
+    __slots__ = SLOTS
+
+
+class truthq(AutoResultMixin, TruthMixin):
+
+    '''auto-balancing truth queue'''
+
+    __slots__ = SLOTS
+
+