Toolbox with useful Python classes and type magic.
Project description
nr.types
The nr.types
package provides a number os useful data types for day-to-day
Python programming. It is compatible with Python 2.7 and modern versions of
Python 3.
Installation
pip install nr.types
Run Tests
pip install -e .[test]
pytest --cov=./src/nr
API
nr.types.NotSet
The NotSet
singleton is useful in cases where None
is an acceptable value
for a parameter so there needs to be an additional state that defines the
parameter as "not set".
nr.types.abc
An alias for collections.abc
or collections
(the six
module does not
provide a move for these modules).
nr.types.functools
Tools to help with Python function internals such as closures, code and function objects.
Example:
import nr.types.functools as ft
def test(value):
def x():
return value
return x
x = test(42)
assert x() == 42
y = ft.copy_function(x, closure={'value': 99})
assert y() == 99
nr.types.generic
Allows you to implement generic types, ie. classes with parameters.
Example:
from nr.types import generic
class HashDict(generic.Generic['key_hash']):
def __init__(self):
generic.assert_initialized(self)
self.data = {}
def __getitem__(self, key):
return self.data[self.key_hash(key)]
def __setitem__(self, key, value):
self.data[self.key_hash(key)] = value
UnsafeHashDict = HashDict[hash]
nr.types.interface
Similar to zope.interface
, but Python 3 compatible and less magical.
Example:
from nr.types.interface import Interface, Implementation, implements, attr
class IFoo(Interface):
""" The foo interface. """
x = attr("""Some attribute.""")
def bar(self, q, r=None):
""" The bar function. """
assert set(IFoo) == set(['x', 'bar'])
assert not hasattr(IFoo, 'x')
assert not hasattr(IFoo, 'bar')
assert IFoo['x'].name == 'x'
assert IFoo['bar'].name == 'bar'
@implements(IFoo)
class Foo(object):
def __init__(self, x=None):
self.x = x
def bar(self, q, r=None):
return q, r, self.x
assert issubclass(Foo, Implementation)
assert IFoo.implemented_by(Foo)
assert IFoo.provided_by(Foo())
assert list(IFoo.implementations()) == [Foo]
assert Foo(42).x == 42
nr.types.maps
Provides the following mapping (and mapping-related) implementations:
OrderedDict
ObjectAsDict
ObjectFromDict
ChainDict
(usemaps.chain()
)HashDict[hash_func]
ValueIterableDict
nr.types.meta
Provides useful metaclasses, such as InlineMetaclass
.
Example:
from nr.types.meta import InlineMetaclassBase
class MyClass(InlineMetaclassBase):
def __metainit__(self, name, bases, attr):
print('MyClass constructed!')
self.value = 'foo'
assert MyClass.value == 'foo'
nr.types.moduletools
Provides some tools for working with modules. Currently only provides the
make_inheritable()
function which can be used from within your module to
make the module object itself usable as a parent class.
# myclass.py
class MyClass(object): pass
make_inheritable(__name__)
# test.py
import myclass
class MySubclass(myclass): pass
assert issubclass(MySubclass, myclass.MyClass)
nr.types.proxy
Provides the proxy
class which is a wrapper for a callable. Any kind of
access to the proxy object is redirected to the object returned by the
callable.
Example for `proxy` class:
from nr.types import proxy
count = 0
@proxy
def auto_increment():
global count
count += 1
return count
assert auto_increment == 1
assert auto_increment == 2
assert auto_increment + 10 == 13
Example for `proxy` class:
from nr.types.proxy import lazy_proxy
count = 0
@lazy_proxy
def not_incrementing():
global count
count += 1
return count
assert not_incrementing == 1
assert not_incrementing == 1
assert not_incrementing == 1
nr.types.record
Similar to namedtuple
but mutable, with support for keyword arguments,
type declarations and default values. Supports multiple forms of declaring
a record, eg. via Python 3.6+ class-level annotations, specifying a class-level
__fields__
member or declaring attributes by creating record.Field()
objects.
Example:
import random
from nr.types import record
class Person(record.Record):
name: str
mail: str = None
age: int = lambda: random.randint(10, 50)
p = Person('John Smith')
assert p.name == 'John Smith'
assert p.mail is None
assert 10 <= p.age <= 50
Alternatives:
import random
from nr.types import record
class Person(record.Record):
name = record.Field(str)
mail = record.Field(str, None)
age = record.Field(str, lambda: random.randint(10, 50))
class Person(record.Record):
__fields__ = [
('name', str),
('mail', str, None),
('age', str, lambda: random.randint(10, 50)),
]
Person = record.create_record('Person', [
('name', str),
record.Field.with_name('mail', str, None),
('age', str, lambda: random.randint(10, 50))
])
Person = record.create_record('Person', {
'name': record.Field(str),
'mail': record.Field(str, None),
'age': record.Field(str, lambda: random.randint(10, 50))
})
assert list(Person.__fields__.keys()) == ['name', 'mail', 'age']
nr.types.sets
Currently only provides an OrderedSet
implementation.
nr.types.stream
Example:
from nr.types import stream
stream(range(10)).map(lambda x: x*2)
stream.map(range(10), lambda x: x*2)
nr.types.structured
Example:
from nr.types import structured
Person = structured.ForwardDecl('Person')
People = structured.translate_field_type({Person})
class Person(structured.Object):
name = structured.ObjectKeyField()
age = structured.Field(int)
numbers = structured.Field([str])
data = {
'John': {'age': 52, 'numbers': ['+1 123 5423435']},
'Barbara': {'age': 29, 'numbers': ['+44 1523/5325323']}
}
people = structured.extract(data, People)
assert people['John'] == Person('John', 52, ['+1 123 5423435'])
assert people['Barbara'] == Person('Barbara', 29, ['+44 1523/5325323'])
nr.types.sumtype
Example:
from nr.types import record, sumtype
class Filter(sumtype):
# Three ways to define constructors.
# 1)
Date = sumtype.constructor(record.create_record('Date', 'min,max'))
# 2)
Keyword = sumtype.constructor('text')
# 3)
@sumtype.constructor
class Duration(sumtype.record):
value = sumtype.field(int, default=3600)
def to_hours(self):
return self.value / 3600.0
# Enrich constructors with members.
@sumtype.member_of([Date, Keyword])
def only_on_date_or_keyword(self):
return 'The answer is 42'
f = Filter.Keyword('building')
assert isinstance(f, Filter)
assert f.is_keyword()
assert f.text == 'building'
assert hasattr(f, 'only_on_date_or_keyword')
assert f.only_on_date_or_keyword() == 'The answer is 42'
f = Filter.Date(10, 42)
assert isinstance(f, Filter)
assert f.is_date()
assert (f.min, f.max) == (10, 42)
assert hasattr(f, 'only_on_date_or_keyword')
assert f.only_on_date_or_keyword() == 'The answer is 42'
f = Filter.Duration()
assert isinstance(f, Filter)
assert f.is_duration()
assert f.value == 3600
assert not hasattr(f, 'only_on_date_or_keyword')
f = Filter.Duration(value=4759)
assert f.value == 4759
assert f.to_hours() == (4759 / 3600.0)
Copyright © Niklas Rosenstein 2019
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
File details
Details for the file nr.types-2.5.5.tar.gz
.
File metadata
- Download URL: nr.types-2.5.5.tar.gz
- Upload date:
- Size: 41.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/1.13.0 pkginfo/1.5.0.1 requests/2.22.0 setuptools/41.0.1 requests-toolbelt/0.9.1 tqdm/4.32.2 CPython/3.6.8
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | e54e390ac7497a43f44c3a7b68241645c0d116fdf79f213a20345210fcd0af5f |
|
MD5 | 9175e06679d18abcbf62129eca7b5c53 |
|
BLAKE2b-256 | 9325f5818f4a5faabed3adfcbca98e89fb68f88285904170ef0ccc1895476cda |