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.