Python shredded utilities
Project description
pymince
About
pymince is a collection of useful tools that are "missing" from the Python standard library.
Installation (via pip)
pip install pymince
Tests
(env)$ pip install -r requirements.txt # Ignore this command if it has already been executed
(env)$ pytest tests/
(env)$ pytest --cov pymince # Tests with coverge
Usage
PyModules | Tools |
---|---|
boolean.py | string2bool |
dates.py | irange, string2year |
dictionary.py | DigestGetter, all_true_values, find_leaf_value, from_objects, frozendict |
file.py | ensure_directory, is_empty_directory, match_on_zip, open_on_zip, replace_extension |
functional.py | classproperty |
iterator.py | all_distinct, all_equal, all_equals, all_identical, consume, contains, grouper, has_only_one, ibool, in_all, in_any, pad_end, pad_start, replacer, splitter, uniquer, uniques |
json.py | dump_into, load_from |
logging.py | StructuredFormatter, timed_block |
retry.py | retry_if_errors, retry_if_none |
std.py | bind_json_std |
text.py | remove_decimal_zeros, remove_number_commas, replace |
xml.py | iterparse |
boolean.py
string2bool
string2bool(value, ignorecase=False)
Function to convert a string representation of
truth to True or False.
:param str value: value to convert.
:param bool ignorecase: Uppercase/lowercase letters of given "value" are ignored.
:raise: "ValueError" if "value" is anything else.
:rtype: bool
Examples:
from pymince.boolean import string2bool
string2bool("true") # --> True
string2bool("false") # --> False
string2bool("TRUE") # --> ValueError
string2bool("TRUE", ignorecase=True) # --> True
string2bool("FALSE") # --> ValueError
string2bool("FALSE", ignorecase=True) # --> False
dates.py
irange
irange(start_date, stop_date=None, time_step=None)
Returns a generator that produces a sequence of datetime's from "start_date" (inclusive)
to "stop_date" (exclusive) by "time_step".
:param datetime.datetime start_date: Inclusive.
:param datetime.datetime stop_date: Exclusive. `utcnow` is used by default.
:param datetime.delta time_step: one-day `timedelta` is used by default.
Examples:
import datetime
from pymince.dates import irange
ini = datetime.datetime.fromisoformat("2022-10-31")
end = datetime.datetime.fromisoformat("2022-11-02")
day = datetime.timedelta(days=1)
it = irange(ini, stop_date=end, time_step=day)
next(it) # --> datetime.datetime(2022, 10, 31, 0, 0)
next(it) # --> datetime.datetime(2022, 11, 1, 0, 0)
next(it) # --> raise StopIteration
string2year
string2year(value, gte=None, lte=None, shift=None)
Function to convert a string year representation to integer year.
:param str value: Value to convert.
:param Optional[int] gte: if it is specified is required that: year >= gte
:param Optional[int] lte: if it is specified is required that: year <= lte
:param Optional[int] shift: use a two-digit year on shift
:raise: "ValueError" if "value" cannot be converted.
:rtype: int
Examples:
from pymince.dates import string2year
string2year("53", shift=None) # --> 2053
string2year("53", shift=1953) # --> 1953
string2year("52", shift=1953) # --> 2052
string2year("54", shift=1953) # --> 1954
string2year("1954") # --> 1954
string2year("123") # --> ValueError
string2year("1955", gte=1956) # --> ValueError
string2year("1955", lte=1954) # --> ValueError
dictionary.py
Useful functions that use dictionaries
DigestGetter
DigestGetter(include_keys=None, exclude_keys=None)
Calculate a digest of a "jsonified" python dictionary.
:param include_keys: dictionary keys to exclude
:param exclude_keys: dictionary keys to include
:rtype: str
Examples:
from pymince.dictionary import DigestGetter
getter = DigestGetter(include_keys=("a",))
getter({"a": 1, "b": 1}) # --> bb6cb5c68df4652941caf652a366f2d8
getter({"a": 1}) # --> bb6cb5c68df4652941caf652a366f2d8
all_true_values
all_true_values(dictionary, keys)
Check if an dictionary has all specified keys and
key-related values as True.
:param dict dictionary:
:param keys: keys sequence
:rtype: bool
Examples:
from pymince.dictionary import all_true_values
all_true_values({"a": 1, "b": 2}, ("a", "b")) # --> True
all_true_values({"a": 1, "b": 0}, ("a", "b")) # --> False
all_true_values({"a": 1, "b": 0}, ("a",)) # --> True
find_leaf_value
find_leaf_value(key, dictionary)
Find leaf value in mapping.
:param str key:
:param dict dictionary:
Examples:
from pymince.dictionary import find_leaf_value
find_leaf_value('a', {}) # --> 'a'
find_leaf_value('a', {'a': 'b', 'b': 'c'}) # --> 'c'
find_leaf_value('a', {'a': 'a'}) # --> 'a'
from_objects
from_objects(iterable, key_getter, value_getter)
Create a new dictionary with elements generated from
the "key_getter" and "value_getter" callbacks applied to each element of the iterable.
:param Iterable[any] iterable:
:param Callable key_getter:
Dictionary keys getter.
It is called with each element of "iterable" passing it as an argument.
:param Callable value_getter:
Dictionary values getter.
It is called with each element of "iterable" passing it as an argument.
:raise: ValueError if any generated key is duplicate.
:rtype: dict
Examples:
from pymince.dictionary import from_objects
keygetter = operator.itemgetter(0)
valgetter = operator.itemgetter(1, 2)
values = iter([(1, "a", "b"), (2, "a", "b")])
from_objects(values, keygetter, valgetter) # --> {1: ('a', 'b'), 2: ('a', 'b')}
frozendict
frozendict(*args, **kwargs)
Returns a "MappingProxyType" from a dictionary built according to given parameters.
Add immutability only on a first level.
Examples:
from pymince.dictionary import frozendict
my_dict = frozendict(a=1, b=2)
my_dict["a"] # --> 1
list(my_dict.items()) # --> [("a", 1), ("b", 2)]
file.py
ensure_directory
ensure_directory(path, cleaning=False)
Make sure the given file path is an existing directory.
If it does not exist, a new directory will be created.
:param str path:
:param bool cleaning:
If "cleaning" is True and a directory already exists,
this directory and the files contained in it will be deleted.
If "cleaning" is True and a file already exists,
this file will be deleted.
is_empty_directory
is_empty_directory(path)
Function to check if the given path is an empty directory.
:param str path:
:rtype: bool
match_on_zip
match_on_zip(zip_file, pattern)
Make an iterator that returns file names in the zip file that
match the given pattern.
Uppercase/lowercase letters are ignored.
:param zip_file: instance of ZipFile class
:param pattern: "re.Pattern" to filter filename list
:return: Iterator with the filenames found
Examples:
import pymince.file
pymince.file.match_on_zip(zip_file, "^file") # --> file1.log file2.txt
open_on_zip
open_on_zip(zip_file, filename)
Open a file that is inside a zip file.
:param zip_file: instance of ZipFile class
:param str filename:
Examples:
-------------------------------------------------
import zipfile
from pymince.file import open_on_zip
with zipfile.ZipFile(zip_filename) as zf:
# example1
with open_on_zip(zf, "foo1.txt") as fd1:
foo1_string = fd1.read()
# example2
with open_on_zip(zf, "foo2.txt") as fd2:
foo2_string = fd2.read()
-------------------------------------------------
replace_extension
replace_extension(filename, old_ext=None, new_ext=None)
Replace filename "old_ext" with "new_ext"
:param str filename:
:param Optional[str] old_ext:
:param Optional[str] new_ext:
Examples:
from pymince.file import replace_extension
# remove extensions
replace_extension("/home/user/file.old") # --> "/home/user/file"
replace_extension("/home/user/file.old", old_ext=".old") # --> "/home/user/file"
replace_extension("/home/user/file.old", old_ext=".new") # --> "/home/user/file.old"
# replace extensions
replace_extension("/home/user/file.old", new_ext=".new") # --> "/home/user/file.new"
replace_extension("/home/user/file.old", old_ext=".old", new_ext=".new") # --> "/home/user/file.new"
replace_extension("/home/user/file.old", old_ext=".new", new_ext=".new") # --> "/home/user/file.old"
functional.py
classproperty
classproperty(method=None)
Decorator that converts a method with a single cls argument into a property
that can be accessed directly from the class.
Examples:
from pymince.functional import classproperty
class MyClass:
__foo = "var"
@classproperty
def foo(cls):
return cls.__foo
iterator.py
Functions that use iterators for efficient loops
all_distinct
all_distinct(iterable, key=None)
Check if all the elements of a key-based iterable are distinct.
:param iterable:
:param key: None or "Callable" to compare if iterable items.
:rtype: bool
Examples:
from pymince.iterator import all_distinct
all_distinct([1, 1]) # --> False
all_distinct([1, 2]) # --> True
all_equal
all_equal(iterable, key=None)
Check if all the elements of a key-based iterable are equals.
:param iterable:
:param key: None or "Callable" to compare if iterable items.
:rtype: bool
Examples:
from pymince.iterator import all_equal
all_equal([1, 1]) # --> True
all_equal([1, 2]) # --> False
all_equals
all_equals(*iterables, key=None)
Check if the iterables are equal.
If the "iterables" are empty, it returns True.
:param iterables:
:param key: None or "Callable" to compare if iterable items.
:rtype: bool
Examples:
from pymince.iterator import all_equals
all_equals() # --> True
all_equals(range(1, 4), (1, 2, 3), {1, 2, 3}) # --> True
all_equals((1, 2), (1, 2, 3)) # --> False
all_identical
all_identical(left, right)
Check that the items of `left` are the same objects
as those in `right`.
:param Iterable[Any] left:
:param Iterable[Any] right:
:rtype: bool
Examples:
from pymince.iterator import all_identical
a, b = object(), object()
all_identical([a, b, a], [a, b, a]) # --> True
all_identical([a, b, [a]], [a, b, [a]]) # --> False *new list object, while "equal" is not "identical"*
consume
consume(iterator, n=None)
Advance *iterator* by *n* steps. If *n* is ``None``, consume it
entirely.
Examples:
from pymince.iterator import consume
it = iter([1, 2])
consume(it)
next(it) # --> StopIteration
contains
contains(iterable, obj)
Check if the object is contained in given iterable.
:param Any obj:
:param iterable:
:rtype: bool
grouper
grouper(iterable, size)
Make an iterator that returns each element being iterable
with "size" as the maximum number of elements.
:param iterable:
:param int size: maximum size of element groups.
Examples:
from pymince.iterator import grouper
groups = grouper([1, 2, 3, 4, 5], 2)
list(list(g) for g in groups) # --> [[1, 2], [3, 4], [5]]
has_only_one
has_only_one(iterable)
Check if given iterable has only one element.
:param iterable:
:rtype: bool
Examples:
from pymince.iterator import has_only_one
has_only_one([1]) # --> True
has_only_one([1, 2]) # --> False
has_only_one([]) # --> False
ibool
ibool(iterable)
Iterator class supporting __bool__.
Examples:
from pymince.iterator import ibool
it = ibool((1, 2, 3))
bool(it) # --> True
list(it) # --> [1, 2, 3]
in_all
in_all(obj, iterables)
Check if the object is contained in all the given iterables.
If the "iterables" are empty, return True.
:param Any obj:
:param iterables: iterable of iterables
:rtype: bool
Examples:
from pymince.iterator import in_all
in_all("a", (("a", "b"), "bcd")) # --> False
in_all("a", (("a", "b"), "abc")) # --> True
in_all("a", ()) # --> True
in_any
in_any(obj, iterables)
Check if the object is contained in any of the given iterables.
:param Any obj:
:param iterables: iterable of iterables
:rtype: bool
Examples:
from pymince.iterator import in_any
in_any("a", (("a", "b"), "bcd")) # --> True
in_any("a", (("b", "b"), "def")) # --> False
in_any("a", ()) # --> False
pad_end
pad_end(iterable, length, fill_value=None)
The function adds "fill_value" at the finishing of the iterable,
until it reaches the specified length.
If the value of the "length" param is less than the length of
the given "iterable", no filling is done.
:param iterable:
:param int length: A number specifying the desired length of the resulting iterable.
:param Any fill_value: Any value to fill the given iterable.
:rtype: Generator
Examples:
from pymince.iterator import pad_end
pad_end(("a", "b"), 3, fill_value="1") # --> "a" "b" "1"
pad_end(("a", "b"), 3) # --> "a" "b" None
pad_end(("a", "b", "c"), 3) # --> "a" "b" "c"
pad_start
pad_start(iterable, length, fill_value=None)
The function adds "fill_value" at the beginning of the iterable,
until it reaches the specified length.
If the value of the "length" param is less than the length of
the given "iterable", no filling is done.
:param iterable:
:param int length: A number specifying the desired length of the resulting iterable.
:param Any fill_value: Any value to fill the given iterable.
:rtype: Generator
Examples:
from pymince.iterator import pad_start
pad_start(("a", "b"), 3, fill_value="1") # --> "1" "a" "b"
pad_start(("a", "b"), 3) # --> None "a" "b"
pad_start(("a", "b", "c"), 3) # --> "a" "b" "c"
replacer
replacer(iterable, matcher, new_value, count=-1)
Make an iterator that returns all occurrences of the old "iterable"
replaced by "new_value".
:param iterable:
:param matcher: Callable to find occurrences. It is an occurrence if the matcher returns True.
:param new_value: Any value to replace found occurrences.
:param int count:
Maximum number of occurrences to replace.
-1 (the default value) means replace all occurrences.
Examples:
from pymince.iterator import replacer
replacer([1,2,3,1,2,3], lambda n: n == 1, None) # --> None 2 3 None 2 3
replacer([1,2,3,1,2,3], lambda n: n == 1, None, count=1) # --> None 2 3 1 2 3
splitter
splitter(iterable, sep, key=None, maxsplit=-1)
Split iterable into groups of iterators according
to given delimiter.
:param iterable:
:param sep: The delimiter to split the iterable.
:param key
A function to compare the equality of each element with the given delimiter.
If the key function is not specified or is None, the element itself is used for compare.
:param maxsplit:
Maximum number of splits to do.
-1 (the default value) means no limit.
:return: Generator with consecutive groups from "iterable" without the delimiter element.
Examples:
from pymince.iterator import splitter
data = ["a", "b", "c", "d", "b", "e"]
undefined_split = splitter(data, "b")
one_split = splitter(data, "b", maxsplit=1)
list(list(s) for s in undefined_split) # --> [["a"], ["c", "d"], ["e"]]
list(list(s) for s in one_split) # --> [["a"], ["c", "d", "b", "e"]]
uniquer
uniquer(iterable, key=None)
Make an iterator that returns each element from iterable only once
respecting the input order.
Examples:
from pymince.iterator import uniquer
uniquer([1, 2, 3, 2]) # --> 1 2 3
uniques
uniques(iterable, key=None)
Check if all the elements of a key-based iterable are unique.
:param iterable:
:param key: None or "Callable" to compare if iterable items.
:rtype: bool
Examples:
from pymince.iterator import uniques
uniques([1,2]) # --> True
uniques([1,1]) # --> False
json.py
dump_into
dump_into(filename, payload, indent=2)
Dump JSON to a file.
Examples:
from pymince.json import dump_into
dump_into("foo.json", {"key": "value"})
load_from
load_from(filename)
Load JSON from a file.
Examples:
from pymince.json import load_from
dictionary = load_from("foo.json")
logging.py
StructuredFormatter
StructuredFormatter(fmt=None, datefmt=None, style='%', validate=True)
Implementation of JSON structured logging that works
for most handlers.
Examples:
import logging
import sys
from pymince.logging import StructuredFormatter
# Config
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)
formatter = StructuredFormatter('%(message)s')
handler = logging.StreamHandler(sys.stdout)
handler.setLevel(logging.DEBUG)
handler.setFormatter(formatter)
logger.addHandler(handler)
# Usage
logger.debug('', {"string": "value1", "number": 1})
logger.debug('', {"string": "value2", "number": 2})
>>Output<<
{"timestamp":"2022-06-17 18:37:48,789","level":"DEBUG","payload":{"string":"value1","number":1}}
{"timestamp":"2022-06-17 18:37:48,789","level":"DEBUG","payload":{"string":"value2","number":2}}
timed_block
timed_block(name, logger=None)
Logger the duration of the handled context.
Examples:
import logging
from pymince.logging import timed_block
logging.basicConfig(level=logging.DEBUG)
with timed_block("sleeping"):
time.sleep(1)
>>Output<<
INFO:root:Generating [sleeping]
DEBUG:root:Finished [sleeping in 1.002 ms.]
retry.py
retry_if_errors
retry_if_errors(*exceptions, delay=0, tries=1)
Decorator that retries to call the wrapped function
if any of given exceptions are thrown.
:param exceptions: Lists of exceptions that trigger a retry attempt.
:param int delay: seconds delay between attempts. default: 0.
:param int tries: number of attempts. default: 1
Examples:
@retry_if_errors(ValueError, TypeError, delay=0, tries=1)
def foo():
return 1
retry_if_none
retry_if_none(delay=0, tries=1)
Decorator that retries to call the wrapped function
if it returns None.
:param int delay: seconds delay between attempts. default: 0.
:param int tries: number of attempts. default: 1
Examples:
@retry_if_none(delay=0, tries=1)
def foo():
return 1
std.py
bind_json_std
bind_json_std(encoding='utf-8')
Decorator to call "function" passing the json read from
"stdin" in the keyword parameter "data" and dump the json that the callback returns
to "stdout".
Examples:
from pymince.std import bind_json_std
@bind_json_std()
def foo(data=None):
print("Processing data from sys.stdin", data)
result = data and {**data, "new": "value"}
print("Result to write in sys.stdout", result)
return result
text.py
Useful functions for working with strings.
remove_decimal_zeros
remove_decimal_zeros(value, decimal_sep='.', min_decimals=None)
Removes non-significant decimal zeros from a formatted text number.
Examples:
from pymince.text import remove_decimal_zeros
remove_decimal_zeros("2.000100", ".") # --> "2.0001"
remove_decimal_zeros("2.000000", ".") # --> "2"
remove_decimal_zeros("2.000000", ".", min_decimals=2) # --> "2.00"
remove_number_commas
remove_number_commas(string)
Removes commas from a formatted text number having commas
as group separator.
:param str string:
:rtype str
Examples:
from pymince.text import remove_number_commas
remove_number_commas('1,234,567.8') # --> '1234567.8'
replace
replace(value, old_values, new_value, count=-1)
Replace matching values in the given string with new_value.
:param str value:
:param old_values: iterable of values to replace.
:param str new_value: replacement value.
:param int count:
Maximum number of occurrences to replace.
-1 (the default value) means replace all occurrences.
:rtype: str
Examples:
from pymince.text import replace
replace("No, woman, no cry", [","], ";") # --> "No; woman; no cry"
replace("No, woman, no cry", [","], ";", count=1) # --> "No; woman, no cry"
xml.py
iterparse
iterparse(filename)
Incrementally parse XML document into ElementTree.
This function is based on: https://github.com/python/cpython/issues/93618
'Fix misleading hint for original ElementTree.iterparse.'
'''
The code below deletes a root child once it is completed, then processes and removes
it from the memory (if nothing more references to it ofc).
This allows to process 7GB XML with with a memory usage up to 10MB (in case of great number of root children).
'''
:param str filename: XML filename
:rtype: Generator
Examples:
from pymince.xml import iterparse
for event, obj in iterparse("countries.xml")
if event == 'start'
print(obj, obj.tag, obj.attrib, obj.text)
>>Output<<
<Element 'country' at 0x0000018ADF9D0CC0> country {'code': 'as', 'iso': '16'} American Samoa
<Element 'country' at 0x0000018ADF9D0C70> country {'code': 'ad', 'iso': '20'} Andorra
Upgrade README.md
Upgrade README.md Usage
section according to current pymince code.
(env) python upgrade_readme_usage.py
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
pymince-1.0.13.tar.gz
(23.3 kB
view hashes)
Built Distribution
pymince-1.0.13-py3-none-any.whl
(21.3 kB
view hashes)