Changeset 668 for branches


Ignore:
Timestamp:
05/29/13 13:10:35 (3 years ago)
Author:
mmckerns
Message:

added docstrings for caching and rounding functions, methods, etc

Location:
branches/decorate
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • branches/decorate/archives.py

    r665 r668  
     1#!/usr/bin/env python 
    12""" 
    23custom caching dict, which archives results to memory, file, or database 
     
    7980        return 
    8081    def __asdict__(self): 
     82        """build a dictionary containing the archive contents""" 
    8183        return self 
    8284    def __setitem__(self, key, value): 
    8385        pass 
     86    __setitem__.__doc__ = dict.__setitem__.__doc__ 
    8487    def update(self, adict, **kwds): 
    8588        pass 
     89    update.__doc__ = dict.update.__doc__ 
    8690    def setdefault(self, key, *value): 
    8791        return self.get(key, *value) 
     92    setdefault.__doc__ = dict.setdefault.__doc__ 
    8893    def __repr__(self): 
    8994        return "archive(NULL)" 
     95    __repr__.__doc__ = dict.__repr__.__doc__ 
    9096    pass 
    9197 
     
    111117        return 
    112118    def __asdict__(self): 
     119        """build a dictionary containing the archive contents""" 
    113120        if self._serialized: 
    114121            try: 
     
    131138        return memo 
    132139    def __save__(self, memo=None): 
     140        """create an archive from the given dictionary""" 
    133141        if memo == None: return 
    134142        if self._serialized: 
     
    147155        memo = self.__asdict__() 
    148156        return memo[key] 
     157    __getitem__.__doc__ = dict.__getitem__.__doc__ 
    149158    def __iter__(self): 
    150159        return self.__asdict__().iterkeys() 
     160    __iter__.__doc__ = dict.__iter__.__doc__ 
    151161    def __repr__(self): 
    152162        return "archive(%s: %s)" % (self._filename, self.__asdict__()) 
     163    __repr__.__doc__ = dict.__repr__.__doc__ 
    153164    def __setitem__(self, key, value): 
    154165        memo = self.__asdict__() 
     
    156167        self.__save__(memo) 
    157168        return 
     169    __setitem__.__doc__ = dict.__setitem__.__doc__ 
    158170    def clear(self): 
    159171        self.__save__({}) 
    160172        return 
     173    clear.__doc__ = dict.clear.__doc__ 
    161174    #FIXME: copy, fromkeys 
    162175    def get(self, key, value=None): 
    163176        memo = self.__asdict__() 
    164177        return memo.get(key, value) 
     178    get.__doc__ = dict.get.__doc__ 
    165179    def has_key(self, key): 
    166180        return key in self.__asdict__() 
     181    has_key.__doc__ = dict.has_key.__doc__ 
    167182    def items(self): 
    168183        return list(self.iteritems()) 
     184    items.__doc__ = dict.items.__doc__ 
    169185    def iteritems(self): 
    170186        return self.__asdict__().iteritems() 
     187    iteritems.__doc__ = dict.iteritems.__doc__ 
    171188    iterkeys = __iter__ 
    172189    def itervalues(self): 
    173190        return self.__asdict__().itervalues() 
     191    itervalues.__doc__ = dict.itervalues.__doc__ 
    174192    def keys(self): 
    175193        return list(self.__iter__()) 
     194    keys.__doc__ = dict.keys.__doc__ 
    176195    def pop(self, key, *value): 
    177196        memo = self.__asdict__() 
     
    179198        self.__save__(memo) 
    180199        return res 
     200    pop.__doc__ = dict.pop.__doc__ 
    181201    #FIXME: popitem 
    182202    def setdefault(self, key, *value): 
     
    184204        self.__setitem__(key, res) 
    185205        return res 
     206    setdefault.__doc__ = dict.setdefault.__doc__ 
    186207    def update(self, adict, **kwds): 
    187208        memo = self.__asdict__() 
     
    189210        self.__save__(memo) 
    190211        return 
     212    update.__doc__ = dict.update.__doc__ 
    191213    def values(self): 
    192214        return list(self.itervalues()) 
     215    values.__doc__ = dict.values.__doc__ 
    193216    pass 
    194217 
     
    215238        return 
    216239    def __asdict__(self): 
     240        """build a dictionary containing the archive contents""" 
    217241        sql = "select * from %s" % self._table 
    218242        res = self._curs.execute(sql) 
     
    225249        if res: return res[-1][-1] # always get the last one 
    226250        raise KeyError, key 
     251    __getitem__.__doc__ = dict.__getitem__.__doc__ 
    227252    def __iter__(self): 
    228253        sql = "select argstr from %s" % self._table 
    229254        return (k[-1] for k in set(self._curs.execute(sql))) 
     255    __iter__.__doc__ = dict.__iter__.__doc__ 
    230256    def __repr__(self): 
    231257        return "archive(%s: %s)" % (self._table, self.__asdict__()) 
     258    __repr__.__doc__ = dict.__repr__.__doc__ 
    232259    def __setitem__(self, key, value): #XXX: maintains 'history' of values 
    233260        sql = "insert into %s values(?,?)" % self._table 
     
    235262        self._conn.commit() 
    236263        return 
     264    __setitem__.__doc__ = dict.__setitem__.__doc__ 
    237265    def clear(self): 
    238266        [self.pop(k) for k in self.keys()] # better delete table, add empty ? 
    239267        return 
     268    clear.__doc__ = dict.clear.__doc__ 
    240269    #FIXME: copy, fromkeys 
    241270    def get(self, key, value=None): 
     
    243272        if res: value = res[-1][-1] 
    244273        return value 
     274    get.__doc__ = dict.get.__doc__ 
    245275    def has_key(self, key): 
    246276        return bool(self._select_key_items(key)) 
     277    has_key.__doc__ = dict.has_key.__doc__ 
    247278    def items(self): 
    248279       #return self.__asdict__().items() 
    249280        return list(self.iteritems()) 
     281    items.__doc__ = dict.items.__doc__ 
    250282    def iteritems(self): 
    251283        return ((k,self.__getitem__(k)) for k in self.__iter__()) 
     284    iteritems.__doc__ = dict.iteritems.__doc__ 
    252285    iterkeys = __iter__ 
    253286    def itervalues(self): 
    254287        return (self.__getitem__(k) for k in self.__iter__()) 
     288    itervalues.__doc__ = dict.itervalues.__doc__ 
    255289    def keys(self): 
    256290       #return self.__asdict__().keys() 
    257291        return list(self.__iter__()) 
     292    keys.__doc__ = dict.keys.__doc__ 
    258293    def pop(self, key, *value): 
    259294        L = len(value) 
     
    270305        self._conn.commit() 
    271306        return _value  
     307    pop.__doc__ = dict.pop.__doc__ 
    272308    #FIXME: popitem 
    273309    def setdefault(self, key, *value): 
     
    283319            self.__setitem__(key, _value) 
    284320        return _value 
     321    setdefault.__doc__ = dict.setdefault.__doc__ 
    285322    def update(self, adict, **kwds): 
    286323        _dict = adict.copy() 
     
    288325        [self.__setitem__(k,v) for (k,v) in _dict.items()] 
    289326        return 
     327    update.__doc__ = dict.update.__doc__ 
    290328    def values(self): 
    291329       #return self.__asdict__().values() 
    292330        return list(self.itervalues()) 
     331    values.__doc__ = dict.values.__doc__ 
    293332    def _select_key_items(self, key): 
    294         '''Return a tuple of (key, value) pairs that match the specified key. 
    295         ''' 
     333        '''Return a tuple of (key, value) pairs that match the specified key''' 
    296334        sql = "select * from %s where argstr = ?" % self._table 
    297335        return tuple(self._curs.execute(sql, (key,))) 
  • branches/decorate/cache.py

    r667 r668  
    1 #  
     1#!/usr/bin/env python 
     2# code inspired by Raymond Hettinger's LFU and LRU cache decorators 
     3# on http://code.activestate.com/recipes/498245-lru-and-lfu-cache-decorators 
     4# and subsequent forks as well as the version available in python3.3 
     5""" 
     6a selection of caching decorators 
     7""" 
    28 
    39try: 
     
    1521from archives import archive_dict 
    1622from keymaps import hashmap 
     23 
     24__all__ = ['_CacheInfo','Counter','no_cache','inf_cache',\ 
     25           'lfu_cache','lru_cache','mru_cache','rr_cache'] 
    1726 
    1827_CacheInfo = namedtuple("CacheInfo", ['hit','miss','load','maxsize','size']) 
  • branches/decorate/keymaps.py

    r663 r668  
    1 # 
     1#!/usr/bin/env python 
     2""" 
     3custom 'keymaps' for generating dictionary keys from function input signatures 
     4""" 
     5 
     6__all__ = ['SENTINEL','NOSENTINEL','keymap','hashmap','stringmap','picklemap'] 
    27 
    38class _Sentinel(object): 
     9    """build a sentinel object for the SENTINEL singleton""" 
    410    def __repr__(self): 
    511        return "<SENTINEL>" 
    612class _NoSentinel(object): 
     13    """build a sentinel object for the NOSENTINEL singleton""" 
    714    def __repr__(self): 
    815        return "<NOSENTINEL>" 
     
    1522 
    1623class keymap(object): 
     24    """tool for converting a function's input signature to an unique key 
    1725 
     26    This keymap does not serialize objects, but does do some formatting. 
     27    Since the keys are stored as raw objects, there is no information loss, 
     28    and thus it is easy to recover the original input signature.  However, 
     29    to use an object as a key, the object must be hashable. 
     30    """ 
    1831    def __init__(self, typed=False, flat=True, sentinel=NOSENTINEL, **kwds): 
    1932        '''initialize the key builder 
     
    2235        flat: if True, flatten the key to a sequence; if False, use (args, kwds) 
    2336        sentinel: marker for separating args and kwds in flattened keys 
     37 
     38        This keymap stores function args and kwds as (args, kwds) if flat=False, 
     39        or a flattened (*args, zip(**kwds)) if flat=True.  If typed, then 
     40        include a tuple of type information (args, kwds, argstypes, kwdstypes) 
     41        in the generated key.  If a sentinel is given, the sentinel will be 
     42        added to a flattened key to indicate the boundary between args, keys, 
     43        argstypes, and kwdstypes.  
    2444        ''' 
    2545        self.typed = typed 
     
    4565 
    4666    def __call__(self, *args, **kwds): 
    47         'Make cache key from optionally typed positional and keyword arguments' 
     67        'generate a key from optionally typed positional and keyword arguments' 
    4868        if self.flat: 
    4969            return self.encode(*args, **kwds) 
     
    5171 
    5272    def encrypt(self, *args, **kwds): 
    53         """use a non-flat scheme for producing a key""" 
     73        """use a non-flat scheme for generating a key""" 
    5474        key = (args, kwds) #XXX: pickles larger, but is simpler to unpack 
    5575        if self.typed: 
     
    6080 
    6181    def encode(self, *args, **kwds): 
    62         """use a flattened scheme for producing a key""" 
     82        """use a flattened scheme for generating a key""" 
    6383        key = args 
    6484        if kwds: 
     
    7898 
    7999    def decrypt(self, key): 
     100        """recover the stored value directly from a generated (non-flat) key""" 
    80101        raise NotImplementedError, "Key decryption is not implemented" 
    81102 
    82103    def decode(self, key): 
     104        """recover the stored value directly from a generated (flattened) key""" 
    83105        raise NotImplementedError, "Key decoding is not implemented" 
    84106 
     
    97119 
    98120class hashmap(keymap): 
     121    """tool for converting a function's input signature to an unique key 
     122 
     123    This keymap generates a hash for the given object.  Not all objects are 
     124    hashable, and generating a hash incurrs some information loss.  Hashing 
     125    is fast, however there is not a method to recover the input signature 
     126    from a hash. 
     127    """ 
    99128    def encode(self, *args, **kwds): 
     129        """use a flattened scheme for generating a key""" 
    100130        return hash(keymap.encode(self, *args, **kwds)) 
    101131    def encrypt(self, *args, **kwds): 
     132        """use a non-flat scheme for generating a key""" 
    102133        return hash(keymap.encrypt(self, *args, **kwds)) 
    103134 
    104135class stringmap(keymap): 
     136    """tool for converting a function's input signature to an unique key 
     137 
     138    This keymap serializes objects by converting __repr__ to a string. 
     139    Converting to a string is slower than hashing, however will produce a 
     140    key in all cases.  Some forms of archival storage, like a database, 
     141    may require string keys.  There is not a method to recover the input 
     142    signature from a string key that works in all cases, however this is 
     143    possibe for any object where __repr__ effectively mimics __init__. 
     144    """ 
    105145   #def __init__(self, *args, **kwds): 
    106146   #    keymap.__init__(self, *args, **kwds) 
    107147   #    self.typed = False  #XXX: is always typed, so set typed=False 
    108148    def encode(self, *args, **kwds): 
     149        """use a flattened scheme for generating a key""" 
    109150        return str(keymap.encode(self, *args, **kwds)) 
    110151    def encrypt(self, *args, **kwds): 
     152        """use a non-flat scheme for generating a key""" 
    111153        return str(keymap.encrypt(self, *args, **kwds)) 
    112154 
    113155import dill as pickle 
    114156class picklemap(keymap): 
     157    """tool for converting a function's input signature to an unique key 
     158 
     159    This keymap serializes objects by pickling the object.  Serializing an 
     160    object with pickle is relatively slower, however will reliably produce a 
     161    unique key for all picklable objects.  Also, pickling is a reversible 
     162    operation, where the original input signature can be recovered from the 
     163    generated key. 
     164    """ 
    115165   #def __init__(self, *args, **kwds): 
    116166   #    keymap.__init__(self, *args, **kwds) 
    117167   #    self.typed = False  #XXX: is always typed, so set typed=False 
    118168    def encode(self, *args, **kwds): 
     169        """use a flattened scheme for generating a key""" 
    119170        return pickle.dumps(keymap.encode(self, *args, **kwds)) 
    120171    def encrypt(self, *args, **kwds): 
     172        """use a non-flat scheme for generating a key""" 
    121173        return pickle.dumps(keymap.encrypt(self, *args, **kwds)) 
    122174 
  • branches/decorate/namedtuple.py

    r660 r668  
     1#!/usr/bin/env python 
     2# this code was written by Raymond Hettinger 
     3# available at http://code.activestate.com/recipes/500261-named-tuples 
     4""" 
     5named tuple: a subclass of tuple with named fields 
     6""" 
    17from operator import itemgetter as _itemgetter 
    28from keyword import iskeyword as _iskeyword 
  • branches/decorate/rounding.py

    r665 r668  
     1#!/usr/bin/env python 
    12""" 
    23decorators that provide rounding 
     
    67 
    78def isiterable(x): 
     9  """check if an object is iterable""" 
    810 #try: 
    911 #    from collections import Iterable 
     
    1618 #return hasattr(x, '__len__') or hasattr(x, '__iter__') 
    1719 
     20#FIXME: these seem *slow*... and a bit convoluted.  Maybe rewrite as classes? 
    1821 
    1922def deep_round_factory(tol): 
     23  """helper function for deep_round (a factory for deep_round functions)""" 
    2024  def deep_round(*args, **kwds): 
    2125    argstype = type(args)  
     
    4650 
    4751def deep_round(tol=0): 
     52  """decorator for rounding a function's input argument and keywords to the 
     53  given precision *tol*.  This decorator always rounds to a floating point 
     54  number. 
     55 
     56  Rounding is done recursively for each element of all arguments and keywords. 
     57 
     58  For example: 
     59  >>> @deep_round(tol=1) 
     60  ... def add(x,y): 
     61  ...   return x+y 
     62  ... 
     63  >>> add(2.54, 5.47) 
     64  8.0 
     65  >>> 
     66  >>> # rounds each float, regardless of depth in an object 
     67  >>> add([2.54, 5.47],['x','y']) 
     68  [2.5, 5.5, 'x', 'y'] 
     69  >>> 
     70  >>> # rounds each float, regardless of depth in an object 
     71  >>> add([2.54, 5.47],['x',[8.99, 'y']]) 
     72  [2.5, 5.5, 'x', [9.0, 'y']] 
     73  """ 
    4874  def dec(f): 
    4975    def func(*args, **kwds): 
     
    5985 
    6086def simple_round_factory(tol): 
     87  """helper function for simple_round (a factory for simple_round functions)""" 
    6188  def simple_round(*args, **kwds): 
    6289    argstype = type(args)  
     
    7198 
    7299def simple_round(tol=0): #NOTE: only rounds floats, nothing else 
     100  """decorator for rounding a function's input argument and keywords to the 
     101  given precision *tol*.  This decorator always rounds to a floating point 
     102  number. 
     103 
     104  Rounding is only done for arguments or keywords that are floats. 
     105 
     106  For example: 
     107  >>> @simple_round(tol=1) 
     108  ... def add(x,y): 
     109  ...   return x+y 
     110  ...  
     111  >>> add(2.54, 5.47) 
     112  8.0 
     113  >>> 
     114  >>> # does not round elements of iterables, only rounds at the top-level 
     115  >>> add([2.54, 5.47],['x','y']) 
     116  [2.54, 5.4699999999999998, 'x', 'y'] 
     117  >>> 
     118  >>> # does not round elements of iterables, only rounds at the top-level 
     119  >>> add([2.54, 5.47],['x',[8.99, 'y']]) 
     120  [2.54, 5.4699999999999998, 'x', [8.9900000000000002, 'y']] 
     121  """ 
    73122  def dec(f): 
    74123    def func(*args, **kwds): 
     
    84133 
    85134def shallow_round_factory(tol): 
     135  """helper function for shallow_round (a factory for shallow_round functions)""" 
    86136  from numpy import round as around #XXX: try or numpy makes this slow 
    87137  def shallow_round(*args, **kwds): 
     
    103153 
    104154def shallow_round(tol=0): #NOTE: rounds floats, lists, arrays one level deep 
     155  """decorator for rounding a function's input argument and keywords to the 
     156  given precision *tol*.  This decorator always rounds to a floating point 
     157  number. 
     158 
     159  Rounding is done recursively for each element of all arguments and keywords, 
     160  however the rounding is shallow (a max of one level deep into each object). 
     161 
     162  For example: 
     163  >>> @shallow_round(tol=1) 
     164  ... def add(x,y): 
     165  ...   return x+y 
     166  ...  
     167  >>> add(2.54, 5.47) 
     168  8.0 
     169  >>> 
     170  >>> # rounds each float, at the top-level or first-level of each object. 
     171  >>> add([2.54, 5.47],['x','y']) 
     172  [2.5, 5.5, 'x', 'y'] 
     173  >>> 
     174  >>> # rounds each float, at the top-level or first-level of each object. 
     175  >>> add([2.54, 5.47],['x',[8.99, 'y']]) 
     176  [2.5, 5.5, 'x', [8.9900000000000002, 'y']] 
     177  """ 
    105178  def dec(f): 
    106179    def func(*args, **kwds): 
  • branches/decorate/safecache.py

    r667 r668  
    1 #  
     1#!/usr/bin/env python 
     2# code inspired by Raymond Hettinger's LFU and LRU cache decorators 
     3# on http://code.activestate.com/recipes/498245-lru-and-lfu-cache-decorators 
     4# and subsequent forks as well as the version available in python3.3 
     5""" 
     6'safe' versions of selected caching decorators 
     7 
     8If a hashing error occurs, the cached function will be evaluated. 
     9""" 
    210 
    311try: 
     
    1523from archives import archive_dict 
    1624from keymaps import stringmap 
    17 from cache import Counter 
    18  
    19 _CacheInfo = namedtuple("CacheInfo", ['hit','miss','load','maxsize','size']) 
     25from cache import _CacheInfo, Counter 
     26 
     27__all__ = ['no_cache','inf_cache','lfu_cache',\ 
     28           'lru_cache','mru_cache','rr_cache'] 
    2029 
    2130#XXX: what about caches that expire due to time, calls, etc... 
     
    825834    if archived: 
    826835        from archives import file_archive 
    827         f.archive(file_archive('cache.pkl')) 
     836        f.archive(file_archive('safecache.pkl')) 
    828837 
    829838    domain = range(rangelimit) 
Note: See TracChangeset for help on using the changeset viewer.