Package: libaaron
Just my library of handy functions I like to bring along. Other people
may feel free to copy this library, but they should not depend on it.
The content and APIs are subject to change without notice.Contentsreifycachedwflattendeepupdatepipepipelinefcomposepmap,pfilterandpreducequiteinterruptlxml_little_iterDotDictPBytesreifyreifyis a decorator I stole from the Pylons project that I like to
use frequently.from the docstring:Use as a class method decorator.  It operates almost exactly like the
Python@propertydecorator, but it puts the result of the method it
decorates into the instance dict after the first call, effectively
replacing the function it decorates with an instance variable.  It is, in
Python parlance, a non-data descriptor.cachedcachedis a decorator that makes a property but caches its results.
It’s functionally similar to reify, but it dynamically creates a
“private” attribute to cache the result instead of messing with
descriptors. This approach is comppatible with slots. I love slots.wwis a function that takes an iterable with a context manager (like
a file object) and yields from that iterable inside its context manager.>>># instead of this:>>>withopen('myfile.txt')asmf:...forlineinmf:...# do something...>>># you can do this:>>>forlineinw(open('myfile.txt')):...# do something...flattenflattenis a function that takes an iterable as an arguments and
recursively yields all contents from nested iterables (except strings,
which are yielded as strings). The optional second argument is a
function that will be used to convert any mappings into iterables before
yielding from them (in the event you want to yield from their values or
something else).deepupdateUpdates a dictionary from another dictionary, but doesn’t overwrite
entire branches of a tree in the case of nested dictionaries. I use it
to combine the content from the system configuration file with a user
configuration file.>>>importlibaaron>>>a={..."type":"foo",..."content":{..."bar":"baz",..."eggs":"spam"...}...}>>>b={..."content":{..."ham":"sausage",..."bar":"lol"...}...}>>>libaaron.deepupdate(a,b)>>>a{'type':'foo','content':{'bar':'lol','eggs':'spam','ham':'sausage'}}There’s also alistextendflag, which, when set toTrue, if
the value in both dictionaries are sequences, the sequence inawill be extended with the contents ofb. This function can crash
if dictionary abhas a mapping somewhere thatasimply has
a string.pipepipeis a trivial function that takes an initial value and any
number of functions as arguments applies them in a compositional manner.
It is defined thusly:defpipe(value,*functions):forfunctioninfunctions:value=function(value)returnvalueTherefore:pipe(value,f,g,h)==h(g(f(value)))This is to avoid having to come up with a lot of intermediate variable
names on the one hand, or deeply nested function calls on the other.pipelinepipelineis a wrapper on pipe that curries the functions and lets
you apply the initial arguments later.pipline(f,g,h)(*args,**kwargs)==h(g(f(*args,**kwargs)))fcomposefcomposegives math-like function composition. It’s basically
identical topipeline, but with reverse application order.# in math, this would look like `f ∘ g ∘ h`fcompose(f,g,h)(*args,**kwargs)==f(g(h(*args,**kwargs)Note that there is nothing clever about howpipelineandfcomposework. They aren’t classes that simulate high-order
functions likefunctools.partial, they are just normal high order
functions, and building pipelines upon pipelines isn’t going to optimize
out the call stack.pmap,pfilterandpreducepmap(f)==functools.partial(map,f)pfilter(f)==functools.partial(filter,f)preduce(f)==functools.partial(functools.reduce,f)Just convenience functions for curryingmap,filterandreduce, which is something which freequently helpful when using the
above function composition functions.Allows stuff like this:importsysfromlibaaronimportpipe,pmap,pfiltershout_about_dogs=pipe(sys.stdin,pfilter(lambdaline:"dog"inline.lower()),pmap(str.upper))# similar to:shout_about_dogs=(l.upper()forlinsys.stdinifdoginl.lower())The comprehension syntax is obviously clearer in this case.pipeis
useful for longer iteration pipelines which can become unclear if
factored with comprehensions.quiteinterruptquiteinterruptis a function that adds a signal handler which
silences the stacktrace when the a script is stopped with a keyboard
interrupt. It can optionally print a message on interrupt.lxml_little_iterlxml_little_iteris only available iflxmlis in the
environment. It’s for iterating over very large xml files with many of
the same kinds of records at the top level (something that would be an
array in JSON). It is for iterating on data that is too large to fit in
memory.This generator function passes all*argsan**kwargstolxml.etree.iterparseand yields the same(even, element)tuple.
However, when the next item is retrieved, the previous element will be
cleared and all previous nodes are deleted. Thus, the ram is saved.DotDictDotDictis a subclass of dict which allows fetching items with dot
syntax. Useful as anobject_hookwhen deserializing JSON, perhaps.PBytesPBytesis a subclass ofintwhich has a__str__that shows
interprets it as a number of bytes and make a human readable format. It
can also parse a number of bytes from a string.>>>print(PBytes(2134963))2.0MiB>>>PBytes.from_str('35.8 KB')PBytes(36659)>>>PBytes.from_str('35.8 KB',decimal=True)PBytes(35800)Internally, it’s just an integer, so you can do any integer operations
with it. Note thatfrom_strdoes not attempt to determine whether it
is a binary or decimal format. Default is binary. Usedecimal=Trueto explicitely change the behavior.It also has ahuman_readablemethod which returns a number and the
units for easily constructing alterative representations:>>>PBytes(83629).human_readable()(81.6689453125,'K')>>>'%d%s'%PBytes(83629).human_readable()'81K'>>>'%d%s'%PBytes(83629).human_readable(decimal=True)'83K'