=======
acrilib
=======

----------------------------------------------------
Independent programming idioms and utilities library
----------------------------------------------------

.. contents:: Table of Contents
   :depth: 2

Overview
========

    **acrilib** is a python library providing useful programming patterns and tools. **acrilib** started as Acrisel's internal idioms and utilities for programmers. The main key is that this library is completely independent. It does not use any external packages beside what provided by Python.
    
    It includes:
        1. programming idioms that are repeatedly used by programmers.
        #. helpers functions for logging and other utilities.
    
    We decided to contribute this library to Python community as a token of appreciation to
    what this community enables us.
    
    We hope that you will find this library useful and helpful as we find it.
    
    If you have comments or insights, please don't hesitate to contact us at support@acrisel.com
    
Programming Idoms
=================

threaded
--------

    decorator for methods that can be executed as a thread.  RetriveAsycValue callable class used in the example below provide means to access results.  One can provide their own callable to pass results. 

example
~~~~~~~

    .. code-block:: python

        from acris import threaded, RetriveAsycValue
        from time import sleep

        class ThreadedExample(object):
            @threaded
            def proc(self, id_, num, stall):
                s = num
                while num > 0:
                    print("%s: %s" % (id_, s))
                    num -= 1
                    s += stall
                    sleep(stall)
                print("%s: %s" % (id_, s))  
                return s

          
example output
~~~~~~~~~~~~~~

    .. code-block:: python

        print("starting workers")
        te1 = ThreadedExample().proc('TE1', 3, 1)
        te2 = ThreadedExample().proc('TE2', 3, 1)
    
        print("collecting results")
        te1_callback = RetriveAsycValue('te1')
        te1.addCallback(te1_callback)
        te2_callback = RetriveAsycValue('te2')
        te2.addCallback(te2_callback)
    
        print('joining t1')
        te1.join()
        print('joined t1')
        print('%s callback result: %s' % (te1_callback.name, te1_callback.result))
        result = te1.syncResult()
        print('te1 syncResult : %s' %result)
    
        result = te2.syncResult()
        print('te2 syncResult : %s' % result)
        print('%s callback result: %s' % (te2_callback.name, te2_callback.result))

    will produce:

    .. code-block:: python

        starting workers
        TE1: 3
        TE2: 3
        collecting results
        joining t1
        TE1: 4
        TE2: 4
        TE1: 5
        TE2: 5
        TE1: 6
        TE2: 6
        joined t1
        te1 callback result: 6
        te1 syncResult : 6
        te2 syncResult : 6
        te2 callback result: 6
        
Singleton and NamedSingleton
----------------------------

    meta class that creates singleton footprint of classes inheriting from it.

Singleton example
~~~~~~~~~~~~~~~~~

    .. code-block:: python

        from acris import Singleton

        class Sequence(Singleton):
            step_id=0
    
            def __call__(self):
                step_id = self.step_id
                self.step_id += 1
                return step_id  

example output
~~~~~~~~~~~~~~

    .. code-block:: python
 
        A=Sequence()
        print('A', A())
        print('A', A())
        B=Sequence()
        print('B', B()) 

    will produce:

    .. code-block:: python

        A 0
        A 1
        B 2
    
NamedSingleton example
~~~~~~~~~~~~~~~~~~~~~~

    .. code-block:: python

        from acris import Singleton

        class Sequence(NamedSingleton):
            step_id = 0
            
            def __init__(self, name=''):
                self.name = name
    
            def __call__(self,):
                step_id = self.step_id
                self.step_id += 1
                return step_id  

example output
~~~~~~~~~~~~~~

    .. code-block:: python
 
        A = Sequence('A')
        print(A.name, A())
        print(A.name, A())
        B = Sequence('B')
        print(B.name, B()) 

    will produce:

    .. code-block:: python

        A 0
        A 1
        B 0
    
Sequence
--------

    meta class to produce sequences.  Sequence allows creating different sequences using name tags.

example
~~~~~~~

    .. code-block:: python

        from acris import Sequence

        A = Sequence('A')
        print('A', A())
        print('A', A())
        B = Sequence('B')
        print('B', B()) 
    
        A = Sequence('A')
        print('A', A())
        print('A', A())
        B = Sequence('B')
        print('B', B()) 

example output
~~~~~~~~~~~~~~

    .. code-block:: python
     
        A 0
        A 1
        B 0
        A 2
        A 3
        B 1

TimedSizedRotatingHandler
-------------------------
	
    TBD

        
Decorators
----------

    Useful decorators for production and debug.
    
traced_method
~~~~~~~~~~~~~

    logs entry and exit of function or method.
    
    .. code-block :: python
    
        from acris import traced_method

        traced = traced_method(print, print_args=True, print_result=True)

        class Oper(object):
            def __init__(self, value):
                self.value = value
        
            def __repr__(self):
                return str(self.value)
        
            @traced
            def mul(self, value):
                self.value *= value 
                return self   
    
            @traced
            def add(self, value):
                self.value += value
                return self
    
        o=Oper(3)
        print(o.add(2).mul(5).add(7).mul(8))
        
    would result with the following output:
    
    .. code-block :: python
        
        [ add ][ entering][ args: (2) ][ kwargs: {} ][ trace_methods.py.Oper(39) ]
        [ add ][ exiting ] [ time span: 0:00:00.000056][ result: 5 ][ trace_methods.py.Oper(39) ]
        [ mul ][ entering][ args: (5) ][ kwargs: {} ][ trace_methods.py.Oper(34) ]
        [ mul ][ exiting ] [ time span: 0:00:00.000010][ result: 25 ][ trace_methods.py.Oper(34) ]
        [ add ][ entering][ args: (7) ][ kwargs: {} ][ trace_methods.py.Oper(39) ]
        [ add ][ exiting ] [ time span: 0:00:00.000007][ result: 32 ][ trace_methods.py.Oper(39) ]
        [ mul ][ entering][ args: (8) ][ kwargs: {} ][ trace_methods.py.Oper(34) ]
        [ mul ][ exiting ] [ time span: 0:00:00.000008][ result: 256 ][ trace_methods.py.Oper(34) ]
        256
	
Data Types
----------

    varies derivative of Python data types

MergeChainedDict
~~~~~~~~~~~~~~~~

    Similar to ChainedDict, but merged the keys and is actually derivative of dict.

    .. code-block:: python

        a={1:11, 2:22}
        b={3:33, 4:44}
        c={1:55, 4:66}
        d=MergedChainedDict(c, b, a)
        print(d) 

    Will output:

    .. code-block:: python

    	{1: 55, 2: 22, 3: 33, 4: 66}

        
Mediator
--------
    
    Class interface to generator allowing query of has_next()
    
Example 
~~~~~~~

    .. code-block:: python

        from acris import Mediator

        def yrange(n):
            i = 0
            while i < n:
                yield i
                i += 1

        n = 10
        m = Mediator(yrange(n))
        for i in range(n):
            print(i, m.has_next(3), next(m))
        print(i, m.has_next(), next(m))

Example Output
~~~~~~~~~~~~~~

    .. code-block:: python

        0 True 0
        1 True 1
        2 True 2
        3 True 3
        4 True 4
        5 True 5
        6 True 6
        7 True 7
        8 False 8
        9 False 9
        Traceback (most recent call last):
          File "/private/var/acrisel/sand/acris/acris/acris/example/mediator.py", line 19, in <module>
            print(i, m.has_next(), next(m))
          File "/private/var/acrisel/sand/acris/acris/acris/acris/mediator.py", line 38, in __next__
            value=next(self.generator)
        StopIteration       
        
     
Change History
==============

Version 1.0.2
-------------

    1. Initial publication to open source



    