Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/sametmax/Bat-belt

A collection of gagdets make Python even more powerful
https://github.com/sametmax/Bat-belt

Last synced: 3 months ago
JSON representation

A collection of gagdets make Python even more powerful

Awesome Lists containing this project

README

        

*************************************************************
A collection of gagdets that makes Python even more powerful
*************************************************************

There is not real structure for this lib, it's just a bunch of snippets I put together because I use them often.

Not all of them are documented here, few of them have tests, it's zlib licence, you know the drill...

To timestamp
=============

datetime.fromtimestamp exists but not the other away around, and it's not likely to change anytime soon (see: http://bugs.python.org/issue2736). In the meantime::

>>> from datetime import datetime
>>> to_timestamp(datetime(2000, 1, 1, 2, 1, 1))
946692061
>>> datetime.fromtimestamp(946688461) # tu as codé celle là et pas l'autre connard !
datetime.datetime(2000, 1, 1, 2, 1, 1)

Get this nest value or a default
=================================

Don't::

try:
res = data['key'][0]['other key'][1]
except (KeyError, IndexError):
res = "value"

Do::

get(data, 'key', 0, 'other key, 1, default="value")

For attributes::

devise = attr(car, 'insurance', 'expiration_date', 'timezone')

Iteration tools missing in itertools
===================================================================================

Iteration by chunk or with a sliding window::

>>> for chunk in chunks(l, 3):
... print list(chunk)
...
[0, 1, 2]
[3, 4, 5]
[6, 7, 8]
[9]
>>> for slide in window(l, 3):
... print list(slide)
...
[0, 1, 2]
[1, 2, 3]
[2, 3, 4]
[3, 4, 5]
[4, 5, 6]
[5, 6, 7]
[6, 7, 8]
[7, 8, 9]

Get the first element an any iterable (not just indexable) or the first one to be True::

>>> first(xrange(10))
0
>>> first_true(xrange(10))
1
>>> first([], default="What the one thing we say to the God of Death ?")
'What the one thing we say to the God of Death ?'

Sorted Set
===================================================================================

Slow but useful data structure::

>>> for x in sset((3, 2, 2, 2, 1, 2)):
... print x
...
3
2
1

Dictionaries one liners
===================================================================================

I wish + was overloaded for dicts::

>>> dmerge({"a": 1, "b": 2}, {"b": 2, "c": 3})
{'a': 1, 'c': 3, 'b': 2}

Sometimes you do not want to simply overwrite the values inside the original dict, but merge them in custom fashion::

>>> def my_merge(v1, v2):
... if isinstance(v1, dict) and isinstance(v2, dict):
... return dmerge(v1, v2)
... return v2
>>> dmerge({"a": 1, "b": {'ok': 5}}, {"b": {'ko': 5 }, "c": 3}, my_merge)
{'a': 1, 'c': 3, 'b': {'ko': 5, 'ok': 5}}

Original dicts are not modified, but this will modify them::

>>> from batbelt.structs import rename
>>> rename({"a": 1, "b": 2})
>>> rename({"a": 1, "b": 2}, 'b', 'z')
{u'a': 1, u'z': 2}

(not thread safe).

Twited but satisfying::

>>> from batbelt.structs import unpack
>>> dct = {'a': 2, 'b': 4, 'z': 42}
>>> a, b, c = unpack(dct, 'a', 'b', 'c', default=1)
>>> a
2
>>> b
4
>>> c
1

String tools
===================================================================================

The mandatory "slufigy"::

>>> slugify(u"Hélo Whorde")
helo-whorde

You get better slugification if you install the `unidecode` lib, but it's optional. You can specify `separator` if you don't like `-` or call directly `normalize()` (the underlying function) if you wish more control.

The module also feature html_escape/unescape that is not useless and json_dumps/loads that understand datetime by default. Look at the source for these, I'm lazy (PL for documentation are welcome).

There is also a poor man template system using the `format()` string method on a file content. No loop, but still nice for quick and dirty file generation :

from batbelt.strings import render

render('stuff.conf.tpl', {"var": "value"}, "/etc/stuff.conf")

Import this
===================================================================================

`__import__` is weird. Let's abstract that ::

TaClasse = import_from_path('foo.bar.TaClasse')
ton_obj = TaClasse()

Catpure prints
===================================================================================

A context manager to deal with this libs that print the result instead of returning it :

>>> with capture_ouput() as (stdout, stderr):
... print "hello",
...
>>> print stdout.read()
hello
>>> stdout.close()

Create a decorator that accept arguments
===================================================================================

I never remember how to do this. And I don't have to anymore.

First, write the decorator::

# all arguments after 'func' are your decorator argument
@decorator_with_args()
def your_decorator(func, arg1, arg2=None):

if arg1:
# do stuff here

# do your usual decorator jimbo jumbo, wrapping, calling, returning...
def wrapper():
return func(arg2)

return wrapper

Enjoy :

@your_decorator(False, 1)
def hop(un_arg):
# do stuff in the decorated function

Add a any directory to the PYTHON PATH
===========================================

Accepts shell variables and relative paths :

from batbelt.utils import add_to_pythonpath
add_to_pythonpath("~/..")

You can (and probably wants) specify a starting point if you pass a relative path. The default starting point is the result is `os.getcwd()` while you probably wants the directory containing you script. To to so, pass `__file__`:

add_to_pythonpath("../..", starting_point=__file__)

`starting_point` can be a file path (basename will be stripped) or a directory name. If will be from there that the reltive path will be calculated.

You can also choose where in the `sys.path` list the your path will be added by passing `insertion_index`, which default to the after the last existing item.

Poor man task queue
===================================================================================================

You don't always need the guaranty of a big lib, you just need a little worker to do the job outside of the main thread::

from batbelt.parallel import worker

@worker()
def task(arg):
arg = arg + 10
return arg

# start the worker
process = task.start()

# send tasks
for x in range(10):
process.put(x)

# (optionaly) get results
for x in range(10):
print process.get()

## 10
## 11
## 12
## 13
## 14
## 15
## 16
## 17
## 18
## 19

# stop the worker
process.stop()

The worker use multiprocessing by default, but if you prefer threads: `@worker(method="tread")`.

If you look for it in the source code, you'll see goodies such as Singletong, Null Pattern implementation and other things you don't use that often.