-
Notifications
You must be signed in to change notification settings - Fork 0
/
datarows.py
216 lines (153 loc) · 5.58 KB
/
datarows.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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
# -*- coding: utf-8 -*-
"""Module for create DataRows objects.
A 'DataRow' object is a mutable data container with the ability to consume
less memory that dicts or class instances. In essence is like 'namedtuple' but
mutable.
Inspired by 'namedlist' package.
"""
import sys
import json
import collections
__version__ = '0.0.1a1'
__all__ = ['datarow_factory']
###############################################################################
# Blocks of the Class
###############################################################################
def __init__(self, *args, **kwargs):
self.update(*args, **kwargs)
def __len__(self):
return self.slots_length
def __getitem__(self, item):
if isinstance(item, slice):
return [getattr(self, x) for x in self.__slots__[item]]
else:
return getattr(self, self.__slots__[item])
def __iter__(self):
for item in self.__slots__:
if hasattr(self, item):
yield item, getattr(self, item)
def __eq__(self, other):
try:
return tuple(self) == tuple(other)
except TypeError:
return False
def __ne__(self, other):
return not self.__eq__(other)
def __contains__(self, attr):
return attr in self.__slots__
def __hash__(self):
return hash(tuple(self))
def __repr__(self):
attr = ("%s=%r" % (k, v) for k, v in self)
return u"%s(%s)" % (self.__class__.__name__, ', '.join(attr))
def __getstate__(self):
return dict((slot, getattr(self, slot))
for slot in self.__slots__ if hasattr(self, slot))
def __setstate__(self, state):
for slot, value in state.items():
setattr(self, slot, value)
def __dict__(self):
return self.todict()
def _hash(self):
# hash() only work with strings
return hash(self.json())
def _get(self, attr, default=None):
return getattr(self, attr, default)
def _attrget(self, *attr):
u"""Recreate object with selected attributes."""
return datarow_factory(*attr)(*[self.get(x) for x in attr])
def _todict(self):
u"""Return unordered dict."""
return dict(tuple(self))
def _keys(self):
u"""Get keys from object."""
return tuple(self.__slots__)
def _values(self):
u"""Get values from object."""
return tuple(v for k, v in self)
def _find(self, attr):
return self.__slots__.index(attr)
def _json(self):
""""""
return json.dumps(vars(self))
###############################################################################
# Class factory
###############################################################################
def datarow_factory(*fields, **factory_kwargs):
u"""Factory function that generate a *DataRow* class.
Generate *DataRow* class with the given fields. Default value can be
passed for attributes.
Args:
*fields: list of named fields. Only permited regular attribute names.
**factory_kwargs: variable keyword. Now, only for pass *default_value*.
Returns:
*DataRow*: Returns a *DataRow* class with the attribute names specified
in the factory (*fields argument).
"""
if not fields:
raise ValueError(u"Param 'fields' not found")
# **factory_kwargs
default_value = factory_kwargs.pop('default_value', None)
name = factory_kwargs.pop('name', 'DataRow')
if factory_kwargs:
raise ValueError(
"Unexpected keyword arguments: '{}'".format(factory_kwargs))
def _update(self, *args, **kwargs):
total_args = len(args) + len(kwargs)
if total_args > self.slots_length:
raise ValueError(u"Number of fields incorrect ('{}' > '{}')."
.format(total_args, self.slots_length))
slots = list(self.__slots__)
for slot, arg in zip(self.__slots__, args):
setattr(self, slot, arg)
slots.remove(slot)
for attr in slots:
try:
setattr(self, attr, kwargs[attr])
except KeyError:
value = getattr(self, attr, default_value)
setattr(self, attr, value)
def _clear(self):
for k in self.__slots__:
setattr(self, k, default_value)
def from_json(cls, json_data):
u"""Create *DataRow* object from json data."""
init_data = json.loads(json_data)
return cls(**init_data)
cls = {
'from_json': classmethod(from_json),
'__slots__': fields,
'slots_length': len(fields),
'__init__': __init__,
'__len__': __len__,
'__getitem__': __getitem__,
'__iter__': __iter__,
'__eq__': __eq__,
'__ne__': __ne__,
'__contains__': __contains__,
'__hash__': __hash__,
'__repr__': __repr__,
'__getstate__': __getstate__,
'__setstate__': __setstate__,
'__dict__': property(__dict__),
'clear': _clear,
'hash': property(_hash),
'update': _update,
'get': _get,
'attrget': _attrget,
'todict': _todict,
'keys': _keys,
'_fields': fields,
'values': _values,
'find': _find,
'json': _json
}
# Code from namedtuple
try:
cls['__module__'] = sys._getframe(1).f_globals.get('__name__',
'__main__')
except (AttributeError, ValueError):
pass
cls = type(name, (object,), cls)
collections.MutableSequence.register(cls)
return cls