Skip to content

Commit 3f696c3

Browse files
committed
Build prototype
1 parent 841250f commit 3f696c3

1 file changed

Lines changed: 134 additions & 5 deletions

File tree

adapter/adapter.py

Lines changed: 134 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,155 @@
22

33
from __future__ import unicode_literals
44

5+
import collections
6+
import copy
7+
import six
58

6-
__all__ = ['Adapter', 'CharField']
9+
10+
__all__ = ['Adapter', 'Field']
711

812

913
class undefined:
1014
pass
1115

1216

17+
class Struct(object):
18+
def __init__(self, **data):
19+
self.__dict__.update(data)
20+
21+
def __eq__(self, other):
22+
return self.__dict__ == other.__dict__
23+
24+
25+
class BindingDict(collections.MutableMapping):
26+
def __init__(self, adapter):
27+
self.adapter = adapter
28+
self.fields = collections.OrderedDict()
29+
30+
def __setitem__(self, key, field):
31+
self.fields[key] = field
32+
field.bind(key, self.adapter)
33+
34+
def __getitem__(self, key):
35+
return self.fields[key]
36+
37+
def __delitem__(self, key):
38+
del self.fields[key]
39+
40+
def __iter__(self):
41+
return iter(self.fields)
42+
43+
def __len__(self):
44+
return len(self.fields)
45+
46+
def __repr__(self):
47+
return dict.__repr__(self.fields)
48+
49+
50+
def get_attribute(obj, attrs):
51+
for attr in attrs:
52+
if obj is None:
53+
return undefined
54+
55+
try:
56+
if isinstance(obj, collections.Mapping):
57+
obj = obj[attr]
58+
elif isinstance(obj, (list, tuple)):
59+
obj = obj[int(attr)]
60+
else:
61+
obj = getattr(obj, attr)
62+
except Exception:
63+
return undefined
64+
65+
if callable(obj):
66+
obj = obj()
67+
68+
return obj
69+
70+
1371
class BaseField(object):
1472
def __init__(self, source=None, default=undefined):
15-
pass
73+
self.source = source
74+
self.default = default
75+
76+
def bind(self, field_name, adapter):
77+
if field_name == self.source:
78+
raise ValueError((
79+
"The `source='{field_name}'` kwarg is redundant on "
80+
"adapter `{adapter_name}. Remove the `source` kwarg."
81+
).format({
82+
'field_name': field_name,
83+
'adapter_name': adapter.__class__.__name__
84+
}))
85+
86+
self.field_name = field_name
87+
self.adapter = adapter
88+
89+
if self.source is None:
90+
self.source = self.field_name
91+
92+
if self.source == '*':
93+
self.lookup_attrs = []
94+
else:
95+
self.lookup_attrs = self.source.split('.')
96+
97+
def get_attribute(self, obj):
98+
value = get_attribute(obj, self.lookup_attrs)
99+
if value is not undefined:
100+
return value
101+
else:
102+
return self.default
103+
104+
def adapt(self, data):
105+
return data
106+
16107

17-
def adapt(self):
18-
pass
108+
class AdapterMetaClass(type):
109+
def __new__(meta, name, bases, attrs):
110+
fields = [
111+
(key, attrs.pop(key))
112+
for key in attrs.keys() if isinstance(attrs[key], BaseField)
113+
]
19114

115+
for base in reversed(bases):
116+
if hasattr(base, 'declared_fields'):
117+
fields = list(base.declared_fields.items()) + fields
20118

21-
class CharField(BaseField):
119+
attrs['declared_fields'] = collections.OrderedDict(fields)
120+
121+
cls = super(AdapterMetaClass, meta).__new__(meta, name, bases, attrs)
122+
123+
return cls
124+
125+
126+
class Field(BaseField):
22127
pass
23128

24129

130+
@six.add_metaclass(AdapterMetaClass)
25131
class Adapter(BaseField):
26132
def __init__(self, data=None, *args, **kwargs):
133+
self.data = data
134+
27135
super(Adapter, self).__init__(*args, **kwargs)
136+
137+
@property
138+
def fields(self):
139+
if not hasattr(self, '_fields'):
140+
self._fields = BindingDict(self)
141+
for key, value in self.get_fields().iteritems():
142+
self._fields[key] = value
143+
return self._fields
144+
145+
def get_fields(self):
146+
return copy.deepcopy(self.declared_fields)
147+
148+
def adapt(self, data=None):
149+
meta = getattr(self, 'Meta', None)
150+
model_cls = getattr(meta, 'model', Struct)
151+
obj = model_cls()
152+
for field_name, field in self.fields.iteritems():
153+
value = field.get_attribute(data or self.data)
154+
adapted_value = field.adapt(value)
155+
setattr(obj, field_name, adapted_value)
156+
return obj

0 commit comments

Comments
 (0)