Collection of lower-level utilities that enhance code compatibility and validation.
Project description
Motivation
While developing Python software for Visual Effects pipelines, I found myself having to write the same boiler-plate code over and over again, as well as struggling with compatibility issues and feature gaps between Python 2.7 and Python 3.7+.
So I decided to implement solutions for those issues at the base, and basicco was born.
Overview
Basicco provides a collection of lower-level Utilities that enhance code readability and validation.
Utilities
caller_module
Retrieve the caller’s module name.
>>> from basicco.caller_module import caller_module
>>> def do_something():
... return "I was called by {}".format(caller_module())
...
>>> do_something()
'I was called by __main__'
context_vars
Backport of contextvars for Python 2.7 based on MagicStack/contextvars.
>>> from basicco.context_vars import ContextVar
>>> my_var = ContextVar("my_var", default="bar")
>>> token = my_var.set("foo")
>>> my_var.get()
'foo'
>>> my_var.reset(token)
>>> my_var.get()
'bar'
custom_repr
Custom representation functions.
>>> from basicco.custom_repr import mapping_repr
>>> dct = {"a": 1, "b": 2}
>>> mapping_repr(dct, prefix="<", suffix=">", template="{key}={value}", sorting=True)
"<'a'=1, 'b'=2>"
>>> from basicco.custom_repr import iterable_repr
>>> tup = ("a", "b", "c", 1, 2, 3)
>>> iterable_repr(tup, prefix="<", suffix=">", value_repr=str)
'<a, b, c, 1, 2, 3>'
explicit_hash
Metaclass that forces __hash__ to be declared when __eq__ is declared.
>>> import six
>>> from basicco.explicit_hash import ExplicitHashMeta
>>> class Asset(six.with_metaclass(ExplicitHashMeta, object)):
... def __eq__(self, other):
... pass
...
Traceback (most recent call last):
TypeError: declared '__eq__' in 'Asset' but didn't declare '__hash__'
fabricate_value
Run a value through a callable factory (or None).
>>> from basicco.fabricate_value import fabricate_value
>>> fabricate_value(None, 3)
3
>>> fabricate_value(str, 3)
'3'
>>> fabricate_value("str", 3) # use an import path
'3'
get_mro
Get consistent MRO amongst different python versions. This works even with generic classes in Python 2.7.
>>> from six import with_metaclass
>>> from tippo import Generic, TypeVar
>>> from basicco.get_mro import get_mro
>>> T = TypeVar("T")
>>> class MyGeneric(Generic[T]):
... pass
...
>>> class SubClass(MyGeneric[T]):
... pass
...
>>> class Mixed(SubClass[T], MyGeneric[T]):
... pass
...
>>> [c.__name__ for c in get_mro(Mixed)]
['Mixed', 'SubClass', 'MyGeneric', 'Generic', 'object']
import_path
Generate importable dot paths and import from them.
>>> import itertools
>>> from basicco.import_path import get_path, import_path
>>> get_path(itertools.chain)
'itertools.chain'
>>> import_path("itertools.chain")
<... 'itertools.chain'>
>>> from basicco.import_path import extract_generic_paths
>>> extract_generic_paths("Tuple[int, str]")
('Tuple', ('int', 'str'))
mangling
Functions to mangle/unmangle/extract private names.
>>> from basicco.mangling import mangle, unmangle, extract
>>> mangle("__member", "Foo")
'_Foo__member'
>>> unmangle("_Foo__member", "Foo")
'__member'
>>> extract("_Foo__member")
('__member', 'Foo')
mapping_proxy
Mapping Proxy type (read-only) for older Python versions.
>>> from basicco.mapping_proxy import MappingProxyType
>>> internal_dict = {"foo": "bar"}
>>> proxy_dict = MappingProxyType(internal_dict)
>>> proxy_dict["foo"]
'bar'
namespace
Wraps a dictionary/mapping and provides attribute-style access to it.
>>> from basicco.namespace import Namespace
>>> ns = Namespace({"bar": "foo"})
>>> ns.bar
'foo'
>>> from basicco.namespace import MutableNamespace
>>> ns = MutableNamespace({"bar": "foo"})
>>> ns.foo = "bar"
>>> ns.foo
'bar'
>>> ns.bar
'foo'
Also provides a NamespacedMeta metaclass for adding a __namespace__ private property that is unique to each class.
>>> from six import with_metaclass
>>> from basicco.namespace import NamespacedMeta
>>> class Asset(with_metaclass(NamespacedMeta, object)):
... pass
...
>>> Asset.__namespace__.foo = "bar"
qualname
Python 2.7 compatible way of getting the qualified name. Inspired by wbolster/qualname.
recursive_repr
Decorator that prevents infinite recursion for __repr__ methods.
>>> from basicco.recursive_repr import recursive_repr
>>> class MyClass(object):
...
... @recursive_repr
... def __repr__(self):
... return "MyClass<{!r}>".format(self)
...
>>> my_obj = MyClass()
>>> repr(my_obj)
'MyClass<...>'
runtime_final
Runtime-checked version of the typing.final decorator.
Can be used on methods, properties, classmethods, staticmethods, and classes that have FinalizedMeta as a metaclass. It is also recognized by static type checkers and prevents subclassing and/or member overriding during runtime:
>>> import six
>>> from basicco.runtime_final import FinalizedMeta, final
>>> @final
... class Asset(six.with_metaclass(FinalizedMeta, object)):
... pass
...
>>> class SubAsset(Asset):
... pass
...
Traceback (most recent call last):
TypeError: can't subclass final class 'Asset'
>>> import six
>>> from basicco.runtime_final import FinalizedMeta, final
>>> class Asset(six.with_metaclass(FinalizedMeta, object)):
... @final
... def method(self):
... pass
...
>>> class SubAsset(Asset):
... def method(self):
... pass
Traceback (most recent call last):
TypeError: 'SubAsset' overrides final member 'method' defined by 'Asset'
>>> import six
>>> from basicco.runtime_final import FinalizedMeta, final
>>> class Asset(six.with_metaclass(FinalizedMeta, object)):
... @property
... @final
... def prop(self):
... pass
...
>>> class SubAsset(Asset):
... @property
... def prop(self):
... pass
Traceback (most recent call last):
TypeError: 'SubAsset' overrides final member 'prop' defined by 'Asset'
state
Get/update the state of an object, slotted or not (works even in Python 2.7).
>>> from basicco.state import get_state
>>> class Slotted(object):
... __slots__ = ("foo", "bar")
... def __init__(self, foo, bar):
... self.foo = foo
... self.bar = bar
...
>>> slotted = Slotted("a", "b")
>>> sorted(get_state(slotted).items())
[('bar', 'b'), ('foo', 'a')]
type_checking
Runtime type checking with support for import paths and type hints.
>>> from tippo import Mapping
>>> from itertools import chain
>>> from basicco.type_checking import is_instance
>>> class SubChain(chain):
... pass
...
>>> is_instance(3, int)
True
>>> is_instance(3, (chain, int))
True
>>> is_instance(3, ())
False
>>> is_instance(SubChain(), "itertools.chain")
True
>>> is_instance(chain(), "itertools.chain", subtypes=False)
True
>>> is_instance(SubChain(), "itertools.chain", subtypes=False)
False
>>> is_instance({"a": 1, "b": 2}, Mapping[str, int])
True
unique_iterator
Iterator that yields unique values.
>>> from basicco.unique_iterator import unique_iterator
>>> list(unique_iterator([1, 2, 3, 3, 4, 4, 5]))
[1, 2, 3, 4, 5]
weak_reference
Weak Reference-like object that supports pickling.
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
Built Distribution
Hashes for basicco-7.0.1-py2.py3-none-any.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 15d06462f967a9e212464dc3e08dcfeb515d057155ed5bc1d9591fa999dcc90d |
|
MD5 | 19308ffb52c03e067be7a77620d48f50 |
|
BLAKE2b-256 | 2a32dcae1229c8be719013f61be1e1dcc966ab1871f80596be20361e6b2f95f8 |