tri.declarative contains class decorators to define classes with subclass semantics in the style of django Model classes.
Project description
.. image:: https://travis-ci.org/TriOptima/tri.declarative.svg?branch=master
:target: https://travis-ci.org/TriOptima/tri.declarative
.. image:: http://codecov.io/github/TriOptima/tri.declarative/coverage.svg?branch=master
:target: http://codecov.io/github/TriOptima/tri.declarative?branch=master
tri.declarative
===============
tri.declarative contains class decorators to define classes with subclass semantics in the style of django Model classes.
Running tests
-------------
You need tox installed then just `make test`.
License
-------
BSD
Documentation
-------------
http://declarative.readthedocs.org.
Usage
=====
@declarative
------------
In example below, the :code:`@declarative(str)` decorator will ensure that all :code:`str` members of class Foo will be
collected and sent as :code:`members` constructor keyword argument.
.. code:: python
from tri.declarative import declarative
@declarative(str)
class Foo(object):
bar = 'barbar'
baz = 'bazbaz'
boink = 17
def __init__(self, members):
assert members['bar'] == 'barbar'
assert members['baz'] == 'bazbaz'
assert 'boink' not in members
f = Foo()
The value of the :code:`members` argument will also be collected from sub-classes:
.. code:: python
from tri.declarative import declarative
@declarative(str)
class Foo(object):
def __init__(self, members):
assert members['bar'] == 'barbar'
assert members['baz'] == 'bazbaz'
class MyFoo(Foo):
bar = 'barbar'
baz = 'bazbaz'
def __init__(self):
super(MyFoo, self).__init__()
f = MyFoo()
The :code:`members` argument can be given another name (:code:`things` in the example below).
.. code:: python
from tri.declarative.declarative import declarative
@declarative(str, 'things')
class Foo(object):
bar = 'barbar'
def __init__(self, **kwargs):
assert 'things' in kwargs
assert kwargs['things']['bar'] == 'barbar'
f = Foo()
Note that the collected dict is an :code:`OrderedDict` and will be ordered by class inheritance and by using
:code:`sorted` of the values within each class. (In the 'str' example, :code:`sorted` yields in alphabetical order).
Also note that the collection of *class* members based on their class does *not* interfere with *instance* constructor
argument of the same type.
.. code:: python
from tri.declarative import declarative
@declarative(str)
class Foo(object):
charlie = '3'
alice = '1'
def __init__(self, members):
assert members == OrderedDict([('alice', '1'), ('charlie', '3'),
('bob, '2'), ('dave', '4'),
('eric', '5')])
assert 'animal' not in members
class MyFoo(Foo):
dave = '4'
bob = '2'
class MyOtherFoo(MyFoo):
eric = '5'
def __init__(self, animal)
assert animal == 'elephant'
f = MyOtherFoo('elephant')
@creation_ordered
-----------------
Class decorator that ensures that instances will be ordered after creation order when sorted.
This is useful for classes intended to be used as members of a :code:`@declarative` class when member order matters.
.. code:: python
from tri.declarative import creation_ordered
@creation_ordered
class Thing(object):
pass
t1 = Thing()
t2 = Thing()
t3 = Thing()
assert sorted([t2, t3, t1]) == [t1, t2, t3]
Real world use-case
-------------------
Below is a more complete example of using @declarative:
.. code:: python
from tri.declarative import declarative, creation_ordered
@creation_ordered
class Field(object):
pass
class IntField(Field):
def render(self, value):
return '%s' % value
class StringField(Field):
def render(self, value):
return "'%s'" % value
@declarative(Field, 'table_fields')
class SimpleSQLModel(object):
def __init__(self, **kwargs):
self.table_fields = kwargs.pop('table_fields')
for name in kwargs:
assert name in self.table_fields
setattr(self, name, kwargs[name])
def insert_statement(self):
return 'INSERT INTO %s(%s) VALUES (%s)' % (self.__class__.__name__,
', '.join(self.table_fields.keys()),
', '.join([field.render(getattr(self, name))
for name, field in self.table_fields.items()]))
class User(SimpleSQLModel):
username = StringField()
password = StringField()
age = IntField()
my_user = User(username='Bruce_Wayne', password='Batman', age=42)
assert my_user.username == 'Bruce_Wayne'
assert my_user.password == 'Batman'
assert my_user.insert_statement() == "INSERT INTO User(username, password, age) VALUES ('Bruce_Wayne', 'Batman', 42)"
# Fields are ordered by creation time (due to having used the @creation_ordered decorator)
assert my_user.get_meta().table_fields.keys() == ['username', 'password', 'age']
@with_meta
----------
Class decorator to enable a class (and it's sub-classes) to have a 'Meta' class attribute.
The members of the Meta class will be injected as arguments to constructor calls. e.g.:
.. code:: python
from tri.declarative import with_meta
@with_meta
class Foo(object):
class Meta:
foo = 'bar'
def __init__(self, foo, buz):
assert foo == 'bar'
assert buz == 'buz'
foo = Foo(buz='buz')
# Members of the 'Meta' class can be accessed thru the get_meta() class method.
assert foo.get_meta() == {'foo': 'bar'}
assert Foo.get_meta() == {'foo': 'bar'}
Foo() # Crashes, has 'foo' parameter, but no has no 'buz' parameter.
The passing of the merged name space to the constructor is optional.
It can be disabled by passing :code:`add_init_kwargs=False` to the decorator.
.. code:: python
from tri.declarative import with_meta
@with_meta(add_init_kwargs=False)
class Foo(object):
class Meta:
foo = 'bar'
Foo() # No longer crashes
assert Foo().get_meta() == {'foo': 'bar'}
Another example:
.. code:: python
from tri.declarative import with_meta
class Foo(object):
class Meta:
foo = 'bar'
bar = 'bar'
@with_meta
class Bar(Foo):
class Meta:
foo = 'foo'
buz = 'buz'
def __init__(self, *args, **kwargs):
assert kwargs['foo'] == 'foo' # from Bar (overrides Foo)
assert kwargs['bar'] == 'bar' # from Foo
assert kwargs['buz'] == 'buz' # from Bar
This can be used e.g to enable sub-classes to modify constructor default arguments.
=========
Changelog
=========
Here's the recent changes to tri.declarative.
.. changelog::
:version: dev
:released: Ongoing
.. change::
:tags: docs
Updated CHANGES.
:target: https://travis-ci.org/TriOptima/tri.declarative
.. image:: http://codecov.io/github/TriOptima/tri.declarative/coverage.svg?branch=master
:target: http://codecov.io/github/TriOptima/tri.declarative?branch=master
tri.declarative
===============
tri.declarative contains class decorators to define classes with subclass semantics in the style of django Model classes.
Running tests
-------------
You need tox installed then just `make test`.
License
-------
BSD
Documentation
-------------
http://declarative.readthedocs.org.
Usage
=====
@declarative
------------
In example below, the :code:`@declarative(str)` decorator will ensure that all :code:`str` members of class Foo will be
collected and sent as :code:`members` constructor keyword argument.
.. code:: python
from tri.declarative import declarative
@declarative(str)
class Foo(object):
bar = 'barbar'
baz = 'bazbaz'
boink = 17
def __init__(self, members):
assert members['bar'] == 'barbar'
assert members['baz'] == 'bazbaz'
assert 'boink' not in members
f = Foo()
The value of the :code:`members` argument will also be collected from sub-classes:
.. code:: python
from tri.declarative import declarative
@declarative(str)
class Foo(object):
def __init__(self, members):
assert members['bar'] == 'barbar'
assert members['baz'] == 'bazbaz'
class MyFoo(Foo):
bar = 'barbar'
baz = 'bazbaz'
def __init__(self):
super(MyFoo, self).__init__()
f = MyFoo()
The :code:`members` argument can be given another name (:code:`things` in the example below).
.. code:: python
from tri.declarative.declarative import declarative
@declarative(str, 'things')
class Foo(object):
bar = 'barbar'
def __init__(self, **kwargs):
assert 'things' in kwargs
assert kwargs['things']['bar'] == 'barbar'
f = Foo()
Note that the collected dict is an :code:`OrderedDict` and will be ordered by class inheritance and by using
:code:`sorted` of the values within each class. (In the 'str' example, :code:`sorted` yields in alphabetical order).
Also note that the collection of *class* members based on their class does *not* interfere with *instance* constructor
argument of the same type.
.. code:: python
from tri.declarative import declarative
@declarative(str)
class Foo(object):
charlie = '3'
alice = '1'
def __init__(self, members):
assert members == OrderedDict([('alice', '1'), ('charlie', '3'),
('bob, '2'), ('dave', '4'),
('eric', '5')])
assert 'animal' not in members
class MyFoo(Foo):
dave = '4'
bob = '2'
class MyOtherFoo(MyFoo):
eric = '5'
def __init__(self, animal)
assert animal == 'elephant'
f = MyOtherFoo('elephant')
@creation_ordered
-----------------
Class decorator that ensures that instances will be ordered after creation order when sorted.
This is useful for classes intended to be used as members of a :code:`@declarative` class when member order matters.
.. code:: python
from tri.declarative import creation_ordered
@creation_ordered
class Thing(object):
pass
t1 = Thing()
t2 = Thing()
t3 = Thing()
assert sorted([t2, t3, t1]) == [t1, t2, t3]
Real world use-case
-------------------
Below is a more complete example of using @declarative:
.. code:: python
from tri.declarative import declarative, creation_ordered
@creation_ordered
class Field(object):
pass
class IntField(Field):
def render(self, value):
return '%s' % value
class StringField(Field):
def render(self, value):
return "'%s'" % value
@declarative(Field, 'table_fields')
class SimpleSQLModel(object):
def __init__(self, **kwargs):
self.table_fields = kwargs.pop('table_fields')
for name in kwargs:
assert name in self.table_fields
setattr(self, name, kwargs[name])
def insert_statement(self):
return 'INSERT INTO %s(%s) VALUES (%s)' % (self.__class__.__name__,
', '.join(self.table_fields.keys()),
', '.join([field.render(getattr(self, name))
for name, field in self.table_fields.items()]))
class User(SimpleSQLModel):
username = StringField()
password = StringField()
age = IntField()
my_user = User(username='Bruce_Wayne', password='Batman', age=42)
assert my_user.username == 'Bruce_Wayne'
assert my_user.password == 'Batman'
assert my_user.insert_statement() == "INSERT INTO User(username, password, age) VALUES ('Bruce_Wayne', 'Batman', 42)"
# Fields are ordered by creation time (due to having used the @creation_ordered decorator)
assert my_user.get_meta().table_fields.keys() == ['username', 'password', 'age']
@with_meta
----------
Class decorator to enable a class (and it's sub-classes) to have a 'Meta' class attribute.
The members of the Meta class will be injected as arguments to constructor calls. e.g.:
.. code:: python
from tri.declarative import with_meta
@with_meta
class Foo(object):
class Meta:
foo = 'bar'
def __init__(self, foo, buz):
assert foo == 'bar'
assert buz == 'buz'
foo = Foo(buz='buz')
# Members of the 'Meta' class can be accessed thru the get_meta() class method.
assert foo.get_meta() == {'foo': 'bar'}
assert Foo.get_meta() == {'foo': 'bar'}
Foo() # Crashes, has 'foo' parameter, but no has no 'buz' parameter.
The passing of the merged name space to the constructor is optional.
It can be disabled by passing :code:`add_init_kwargs=False` to the decorator.
.. code:: python
from tri.declarative import with_meta
@with_meta(add_init_kwargs=False)
class Foo(object):
class Meta:
foo = 'bar'
Foo() # No longer crashes
assert Foo().get_meta() == {'foo': 'bar'}
Another example:
.. code:: python
from tri.declarative import with_meta
class Foo(object):
class Meta:
foo = 'bar'
bar = 'bar'
@with_meta
class Bar(Foo):
class Meta:
foo = 'foo'
buz = 'buz'
def __init__(self, *args, **kwargs):
assert kwargs['foo'] == 'foo' # from Bar (overrides Foo)
assert kwargs['bar'] == 'bar' # from Foo
assert kwargs['buz'] == 'buz' # from Bar
This can be used e.g to enable sub-classes to modify constructor default arguments.
=========
Changelog
=========
Here's the recent changes to tri.declarative.
.. changelog::
:version: dev
:released: Ongoing
.. change::
:tags: docs
Updated CHANGES.
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
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file tri.declarative-0.17.0.tar.gz.
File metadata
- Download URL: tri.declarative-0.17.0.tar.gz
- Upload date:
- Size: 9.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4548f86239e6fffbfed188c6bea42a8febf30d239488b529c3f5375b2e1531b2
|
|
| MD5 |
3dab4cee4b90281f7369edb202b94951
|
|
| BLAKE2b-256 |
7056fd4f34443b237c40133fc3fe69ef86ed624e672d02e344f87abd2b1bf755
|
File details
Details for the file tri.declarative-0.17.0-py2.py3-none-any.whl.
File metadata
- Download URL: tri.declarative-0.17.0-py2.py3-none-any.whl
- Upload date:
- Size: 10.8 kB
- Tags: Python 2, Python 3
- Uploaded using Trusted Publishing? No
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f5ab5a9dbdc94ac10b251cecea78ff5b61849ffcfed82f5a7e7a41f65c798a45
|
|
| MD5 |
c2068ff9a2721c2621ca763117912126
|
|
| BLAKE2b-256 |
3732dbd44cfbaf2864ce997992b1df16ae480038003d63d69f06e5de8232384a
|