Skip to main content

trivial functions I like to pack along for various things

Project description

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.

reify

reify is 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 @property decorator, 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.

cached

cached is 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.

w

w is 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:
>>> with open('myfile.txt') as mf:
...     for line in mf:
...         # do something
...
>>> # you can do this:
>>> for line in w(open('myfile.txt')):
...     # do something
...

flatten

flatten is 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).

deepupdate

Updates 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.

>>> import libaaron
>>> 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 a listextend flag, which, when set to True, if the value in both dictionaries are sequences, the sequence in a will be extended with the contents of b. This function can crash if dictionary a b has a mapping somewhere that a simply has a string.

pipe

pipe is 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:

def pipe(value, *functions):
    for function in functions:
        value = function(value)
    return value

Therefore:

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.

pipeline

pipeline is 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)))

fcompose

fcompose gives math-like function composition. It’s basically identical to pipeline, 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 how pipeline and fcompose work. They aren’t classes that simulate high-order functions like functools.partial, they are just normal high order functions, and building pipelines upon pipelines isn’t going to optimize out the call stack.

pmap, pfilter and preduce

pmap(f) == functools.partial(map, f)
pfilter(f) == functools.partial(filter, f)
preduce(f) == functools.partial(functools.reduce, f)

Just convenience functions for currying map, filter and reduce, which is something which freequently helpful when using the above function composition functions.

Allows stuff like this:

import sys
from libaaron import pipe, pmap, pfilter

shout_about_dogs = pipe(
    sys.stdin,
    pfilter(lambda line: "dog" in line.lower()),
    pmap(str.upper)
)

# similar to:
shout_about_dogs = (l.upper() for l in sys.stdin if dog in l.lower())

The comprehension syntax is obviously clearer in this case. pipe is useful for longer iteration pipelines which can become unclear if factored with comprehensions.

quiteinterrupt

quiteinterrupt is 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_iter

lxml_little_iter is only available if lxml is 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 *args an **kwargs to lxml.etree.iterparse and 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.

DotDict

DotDict is a subclass of dict which allows fetching items with dot syntax. Useful as an object_hook when deserializing JSON, perhaps.

PBytes

PBytes is a subclass of int which 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.0 MiB
>>> 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 that from_str does not attempt to determine whether it is a binary or decimal format. Default is binary. Use decimal=True to explicitely change the behavior.

It also has a human_readable method 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'

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

libaaron-1.4.5.tar.gz (10.5 kB view details)

Uploaded Source

Built Distribution

libaaron-1.4.5-py3-none-any.whl (10.1 kB view details)

Uploaded Python 3

File details

Details for the file libaaron-1.4.5.tar.gz.

File metadata

  • Download URL: libaaron-1.4.5.tar.gz
  • Upload date:
  • Size: 10.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.1.4 CPython/3.8.5 Linux/5.4.0-67-lowlatency

File hashes

Hashes for libaaron-1.4.5.tar.gz
Algorithm Hash digest
SHA256 a86a9dc8e5daadbe669de9b62a859a5cf93a79dc4d7c71675605278ac66e0324
MD5 fd10d158fa08b90b5820e48f6c2bba35
BLAKE2b-256 a8058a800ef9973e79ca2fa70fe978d6e66be0728709fcf1952b25b333bd46c1

See more details on using hashes here.

File details

Details for the file libaaron-1.4.5-py3-none-any.whl.

File metadata

  • Download URL: libaaron-1.4.5-py3-none-any.whl
  • Upload date:
  • Size: 10.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.1.4 CPython/3.8.5 Linux/5.4.0-67-lowlatency

File hashes

Hashes for libaaron-1.4.5-py3-none-any.whl
Algorithm Hash digest
SHA256 fafb00117d52a38637b8bf43163fd583656ac055becab0bd53629db84c80d2dc
MD5 ef4c8ebafe5b3053833a08a5e852249d
BLAKE2b-256 ed272b015d992f62a86e1a02d276314ca4e86f1d8e222f24f72afc897eff3cbc

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page