Repository navigation
Expand file tree
/
Copy pathmaker.py
More file actions
247 lines (198 loc) · 8.97 KB
/
Copy pathmaker.py
File metadata and controls
247 lines (198 loc) · 8.97 KB
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
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
import inspect
import json
import re
import traceback
from bson import json_util, ObjectId
from datetime import datetime, date
#### CONSTANTS
TYPE_FIELD = '_type'
###############################################################################
# Maker Exception class
###############################################################################
class MakerException(Exception):
def __init__(self, message,cause=None):
self.message = message
self.cause = cause
def __str__(self):
return self.message
###############################################################################
def resolve_class(kls):
if kls == "dict":
return dict
try:
parts = kls.split('.')
module = ".".join(parts[:-1])
m = __import__( module )
for comp in parts[1:]:
m = getattr(m, comp)
return m
except Exception, e:
raise MakerException("Cannot resolve class '%s'. Cause: %s" % (kls, e))
###############################################################################
class Maker():
###########################################################################
def __init__(self,
type_bindings=None,
default_type=None,
object_descriptor_resolver=None):
self.type_bindings = type_bindings
self.default_type = default_type or dict
self.object_descriptor_resolver = object_descriptor_resolver
self.ignore_fields = []
###########################################################################
def make(self, datum):
if datum is None:
return None
# primitive types
if isinstance(datum, (str, unicode, bool,
int, long, float, complex,
date, datetime, ObjectId)):
return datum
if (inspect.isroutine(datum) or
inspect.isclass(datum) or
inspect.ismodule(datum)):
return datum
# lists
if isinstance(datum, list):
return self._make_list(datum)
return self._make_object(datum)
###########################################################################
def _make_list(self, datum):
return map(lambda elem: self.make(elem), datum)
###########################################################################
def _make_object(self, datum):
desc_resolver = self.object_descriptor_resolver
if desc_resolver and desc_resolver.is_datum_descriptor(datum):
datum = desc_resolver.resolve_datum_descriptor(datum)
# instantiate object
result = self.instantiate(datum)
# define properties
for key, value in datum.items():
# Include _type field for dict types only
if (key not in self.ignore_fields and
(key != TYPE_FIELD or isinstance(result, dict))):
prop_name = self.resolve_property_name(result, key)
prop_val = self.make(value)
self._set_object_property(result, prop_name, prop_val)
return result
###########################################################################
def instantiate(self, datum):
obj_type = dict
if TYPE_FIELD in datum :
type_name = datum[TYPE_FIELD]
if isinstance(type_name, (str, unicode)):
obj_type = self.resolve_type(type_name)
if not obj_type:
raise MakerException("Could not resolve _type %s" %
type_name)
elif inspect.isclass(type_name):
obj_type = type_name
else:
raise MakerException("Invalid _type value '%s'. _type can "
"be a string or a class" % type_name)
return obj_type()
###########################################################################
def _set_object_property(self, obj, prop, value):
try:
if isinstance(obj, dict):
obj[prop] = value
else:
setattr(obj, prop, value)
except Exception, e:
msg = ("Error while trying to set property %s for object %s."
" Cause: %s, Trace: %s" % (prop, obj, e,
traceback.format_exc()))
raise Exception(msg)
###########################################################################
def resolve_type(self, type_name):
if self.type_bindings and type_name in self.type_bindings:
return resolve_class(self.type_bindings[type_name])
else:
return resolve_class(type_name)
###########################################################################
def resolve_property_name(self, obj, datum_prop_name):
"""
Resolves the property name of the specified obj. If the obj has an
un-cameled property of the specified property ==> returns un-cameled
ELSE: return property as is
"""
# TODO use a mapping
try:
datum_prop_name = datum_prop_name.encode('ascii', 'ignore')
uncameled_prop = un_camelcase(datum_prop_name)
if (hasattr(obj, uncameled_prop) and
not hasattr(obj, datum_prop_name)):
return uncameled_prop
else:
return datum_prop_name
except Exception, e:
msg = ("Error while trying to resolve property name '%s' for "
"object %s."
" Cause: %s, Trace: %s" % (datum_prop_name, obj, e,
traceback.format_exc()))
raise Exception(msg)
###############################################################################
def un_camelcase(property_name):
s1 = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', property_name)
return re.sub('([a-z0-9])([A-Z])', r'\1_\2', s1).lower()
###############################################################################
# GenericDocObject
###############################################################################
class GenericDocObject(object):
###########################################################################
def __init__(self, document=None):
document = document or {}
self.__dict__['_document'] = document
###########################################################################
@property
def document(self):
return self.__dict__['_document']
###########################################################################
def __getattr__(self, name):
if self._document.has_key(name):
return self._document[name]
###########################################################################
def has_key(self, name):
return self._document.has_key(name)
###########################################################################
def __setattr__(self, name, value):
if hasattr(getattr(self.__class__, name, None), '__set__'):
# THANK YOU http://bit.ly/HOTMsT
return object.__setattr__(self, name, value)
self._document[name] = value
###########################################################################
def __delattr__(self, name):
if hasattr(getattr(self.__class__, name, None), '__delete__'):
# THANKS AGAIN http://bit.ly/HOTMsT
return object.__delattr__(self, name)
del self._document[name]
###########################################################################
def __getitem__(self, name):
return self.__getattr__(name)
###########################################################################
def __setitem__(self, name, value):
return self.__setattr__(name, value)
###########################################################################
def __delitem__(self, name):
return self.__delattr__(name)
###########################################################################
def __contains__(self, name):
return self.has_key(name)
###########################################################################
def __str__(self):
return document_pretty_string(self._document)
###########################################################################
def __repr__(self):
return self._document.__repr__()
###########################################################################
def items(self):
return dict((key, self[key]) for key in self._document.keys()).items()
###############################################################################
# other helpful utilities... okay, just document_pretty_string()
###############################################################################
def document_pretty_string(document):
return json.dumps(document, indent=4, default=json_util.default)
###############################################################################
MAKER = Maker()
def o(datum):
return MAKER.make(datum)