-
Notifications
You must be signed in to change notification settings - Fork 1
/
model.py
51 lines (38 loc) · 1.57 KB
/
model.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
from functools import partial
from inspect import getmembers, isclass
class Meta(type):
def __new__(cls, name, bases, attrs):
try:
traits = filter(
lambda trait: not trait[0].startswith('__'),
getmembers(attrs.get('Traits'), predicate=isclass)
)
except:
raise AttributeError(f'No `Traits` meta directive')
for trait_name, trait_type in traits:
method = trait_name.lower()
field = f'_{method}'
if field in attrs or method in attrs:
continue
def getter(self, field=field):
return partial(getattr(self, field), self)
def setter(self, value, trait_name=trait_name, trait_type=trait_type, field=field):
if callable(value):
setattr(self, field, value)
elif isinstance(value, str):
value = getattr(trait_type, value)
setattr(self, field, value)
else:
raise TypeError(
f'Unexpected `{trait_name}` type {type(value)}')
attrs[method] = property(getter, setter)
return super().__new__(cls, name, bases, attrs)
class Model(object, metaclass=Meta):
class Traits:
pass
def __init__(self, *args, **kwargs):
super().__init__()
for trait, _ in getmembers(self.Traits, predicate=isclass):
trait = trait.lower().replace('-', '_')
if trait in kwargs:
setattr(self, trait, kwargs[trait])