None
This library consists of various simple common routines and language constructs that are so useful they ten to be rewritten in every subsequent project I’m working on. Each function, decorator or module on its own is too simple to dedicate an entire PyPI package for it. Together however, this library represents a Swiss army knife for everyday needs (YMMV). Among the things you might find inside:
- robust memoization
- some less obvious collections (e.g.
orderedset
)- a
@synchronized
decorator (with threading or lockfile backends)- some controversial language enhancements like the Null object
- converter from ElementTree instances to dicts
- file finder (searching locations commonly used for storing app data)
The latest version can be installed via PyPI:
$ pip install lck.common
or:
$ easy_install lck.common
The source code repository and issue tracker are maintained on GitHub.
For the curious, lck
stands for LangaCore Kit. LangaCore is a one man
software development shop of mine.
Note: lck.common
requires Python 2.7 because all of its code is using
the so-called four futures (absolute_imports
, division
, print_function
and unicode_literals
). One of the virtues in the creation of this library
is to make the code beautiful. These switches give a useful transitional
state between the old Python 2.x and the new Python 3.x. You should use them as
well.
lck.git
introduced with a get_version
routinedecode_entities
added to lck.xml
lck.lang.Null
introduced, see Null Object patternlck.lang.unset
is now a Null
instancelck.xml
introduced with a etree_to_dict
routinelck.config
has been removed, use the configparser backportlck.crypto
introduced with a couple of thin wrappers over PyCryptolck.math
introduced starting with Elo rating calculation routine.lck.lang.unset
is now also False
and len(unset)
is zerolck
namespace from langacore.kit
For now the library is still quite small. Functionality gets added or refined as needed.
@synchronized
¶This decorator mimics the behaviour of the Java keyword, enabling users to treat whole functions or methods as atomic. The most simple use case involves just decorating a function:
from lck.concurrency import synchronized
@synchronized
def func():
pass
After decoration, all calls to the function are synchronized with a reentrant threading lock so that no matter how many threads invoke the function at the same time, all calls are serialized and in effect are run one after another. The default lock is reentrant so it’s okay for a synchronized function to be recursive.
In case where a whole group of functions should be serialized, the user can explicitly provide a lock object to the decorator:
from threading import Lock
from lck.concurrency import synchronized
LOCK=Lock()
@synchronized(lock=LOCK)
def func1():
pass
@synchronized(lock=LOCK)
def func2():
pass
Sharing a lock means that at any time at most one of the functions in the group is called, no matter how many threads are running. It’s also worth noting that excplicitly providing a lock enables the user to choose another lock implementation. In the above example a simple non-reentrant lock is used, in effect the performance is higher than in the reentrant case, but the functions sharing the same lock cannot call themselves.
If the application is run in a multiprocess environment, locks based on threading are not the answer. In that case the decorator can be fed with a file path instead of a lock object:
from lck.concurrency import synchronized
@synchronized(path='/tmp/example.lock')
def func():
pass
In that case upon every function call a lock file will be created on the given path to ensure serial execution across multiple processes. The implementation uses Skip Montanaro’s excellent lockfile library. It is using atomic operations available on a given platform to ensure correctness. In case of POSIX systems, hard links are created. On Windows, directories are made.
@memoize
¶This decorator enhances performance by storing the outcome of the decorated function given a specific set of arguments. Across the application the function is called as it normally would but in fact, only the first call with a concrete set of arguments is calculated. All subsequent calls with the same arguments return the stored value calculated at first.
This is particularly a win for resource or time consuming functions that are called multiple times with the same arguments.
The most typical use case for this decorator will be simply:
from time import sleep
from lck.cache import memoize
@memoize
def expensive_func(arg):
sleep(10)
print arg
expensive_func('Hello') # 10 seconds before we see 'Hello'
expensive_func('Hello') # now 'Hello' appears instantly
expensive_func('World') # 10 seconds before we see 'World'
expensive_func('World') # now 'World' appears instantly
The decorator is configurable so that the user can specify how long the outcome should be cached, or how many different sets of arguments should be stored in the cache:
from lck.cache import memoize
@memoize(update_interval=15)
def recalculation_every_15_seconds():
pass
@memoize(max_size=2)
def only_two_last_used_args_will_be_cached(arg):
pass
For more detailed view on the decorators, see the documentation below.
cache.memoization |
lck.cache.memoization |
concurrency.synchronization |
lck.concurrency.synchronization |
High-level cryptographic routines.
These are convenience routines that create Cipher
instances with the
correct algorithm implementation plugged in.
aes
([key, path, create]) → Cipher instance¶Factory creating a cipher using the AES algorithm. Arguments have the same meaning as in the raw Cipher class.
blowfish
([key, path, create]) → Cipher instance¶Factory creating a cipher using the Blowfish algorithm. Arguments have the same meaning as in the raw Cipher class.
cast
([key, path, create]) → Cipher instance¶Factory creating a cipher using the CAST algorithm. Arguments have the same meaning as in the raw Cipher class.
des
([key, path, create]) → Cipher instance¶Factory creating a cipher using the DES algorithm. Arguments have the same meaning as in the raw Cipher class.
des3
([key, path, create]) → Cipher instance¶Factory creating a cipher using the DES3 algorithm. Arguments have the same meaning as in the raw Cipher class.
lck.files
¶Filesystem based utilities.
finder
(explicit_path, envvar=None, multiple_allowed=False)¶Finds a specific file using explicitly given path (or given by an environment variable). The algorithm is as follows: for every given path from the args (explicitly given, environment variable, fallback) check whether the file exists. If it doesn’t and the path is not absolute, search the working directory, its parent directory and all child directories, the current user’s home directory and /etc.
Parameters: |
|
---|---|
Returns: | the real absolute path to the file. Raises IOError if no found. |
Holds various constructs which extend or alter behaviour of the core language.
Null
¶unset
¶NullDict
¶NullList
¶nullify
(obj)¶Various math related utilities.
rate
([winner_rank, loser_rank, penalize_loser]) -> (new_winner_rank, new_loser_rank)¶Computes the new ratings after a game. winner_rank and loser_rank must
be integers, default is 1000. If penalize_loser is True
(the default), points added to the winner are subtracted from the loser.
Various XML-related utilities.
decode_entities
(string[, encoding]) → string_with_decoded_entities¶Decodes XML entities from the given string. Supports both Unicode and bytestring arguments.
Note: when using a bytestring string argument, a bytestring will be returned. In that case however, encoding has to be specified, otherwise an UnicodeDecodeError will be raised. This is because we have to support the &#xxxx; entity which enables people to use any Unicode codepoint.
etree_to_dict
(element, [namespace]) -> ("tag_name", dict_with_children)¶element must be a valid ElementTree element. namespace is optional, must be given in Clark notation, e.g. “{ns_uri}”.
Copyright (C) 2010, 2011 by Łukasz Langa
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the Software), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Things that would be great to have but I haven’t gotten to do them yet.
configparser
and throwing out FunkyConfigParser would do much
good