-
Notifications
You must be signed in to change notification settings - Fork 7
/
basemodel.py
260 lines (221 loc) · 9 KB
/
basemodel.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
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
248
249
250
251
252
253
254
255
256
257
258
259
# -*- coding: utf-8 -*-
import functions
import numpy
import sys
NAMESPACE='http://vamdc.org/xml/xsams/1.0'
# some usefull functions
def split_datalist(datalist):
"""
"""
return datalist.text.split(" ")
def get_value(element):
"""
Just returns the value of an element
"""
return element.text
def get_attributes(element):
"""
Returns a list of attributes-tuples (attribute, value)
"""
return element.items()
def convert_tabulateddata(item):
"""
Converts an element of type {..xsams..}TabulatedData into a dictionary
with elements from X as key and elements from Y as values
Returns:
datadict = (dictionary) with datapoints
xunits = (string) unit of key elements
yunits = (string) containing unit of value elements
comment = (string)
"""
x = item.find("{%s}X/{%s}DataList" % (NAMESPACE, NAMESPACE) ).text.split(" ")
y = item.find("{%s}Y/{%s}DataList" % (NAMESPACE, NAMESPACE) ).text.split(" ")
xunits = item.find("{%s}X" % (NAMESPACE) ).get('units')
yunits = item.find("{%s}Y" % (NAMESPACE) ).get('units')
comment = item.find("{%s}Comments" % (NAMESPACE)).text
datadict = {}
for i in range(len(x)):
datadict[x[i]]=y[i]
return {'data':datadict, 'xunits:':xunits, 'yunits':yunits, 'comment':comment}
def remove_namespace(tag):
"""
Returns tag without namespace
"""
return tag[tag.find('}')+1:]
def construct_model(dictionary):
"""
This method constructs the MODEL-Dictionaries. A Dictionary which contains
the key/value - pairs (fieldname, path_to_value) will be translated into
executable code (evaluated with eval() ). The model-dictionary which is
evaluated and returned depends on the xml-parser/library which is used.
If the library is changed (e.g. to lxml). This function has to be replaced
or changed.
Syntax of the input-dictionary:
fieldname:path (tags without namespace connected with dot. Multiple occurances
are indicated by '[]' and functions which have to be applied are
appended at the end of the string with preceeding '\\'.
"""
model = {}
for field in dictionary:
code = ""
code_add = ""
iterator_code = None
if dictionary[field].find("\\")>-1:
path_array, function = dictionary[field].split("\\")
path_array = path_array.split(".")
else:
function = None
path_array = dictionary[field].split(".")
for tag in path_array:
# is an attribute
if len(tag) == 0:
pass
elif tag[0] == '@':
code_add = "get('%s')" % (tag[1:],)
# attribute can only at the last position
break
# xpath expression -> do not attach namespace
elif tag[-2:] == '[]' and tag[0] in ['*','.','/']:
iterator_code = "self.xml.findall('%s%s')" % (code, tag[:-2])
code = ""
elif tag[-2:] == '[]':
iterator_code = "self.xml.findall('%s{%s}%s')" % (code, NAMESPACE, tag[:-2])
code = ""
elif tag[0] in ['*','.','/']:
code += "%s/" % tag
# regular element -> attach namespace
else:
code += "{%s}%s/" % (NAMESPACE, tag)
# put path into find() if it is the last tag
# create code to generate a list if there was an iterable element
if iterator_code is not None:
if len(code) == 0:
if function is not None:
if function == 'self':
code = "[el for el in %s]" % (iterator_code)
else:
code = "[%s(el) for el in %s]" % (function, iterator_code)
elif len(code_add) == 0:
code = "[el.text for el in %s]" % (iterator_code)
else:
code = "[el.%s for el in %s]" % (code_add, iterator_code)
else:
if function is not None:
if function == 'self':
code = "[el.find('%s') for el in %s]" % (code[:-1], iterator_code)
else:
code = "[%s(el.find('%s')) for el in %s]" % (function, code[:-1], iterator_code)
elif len(code_add) == 0:
code = "[el.find('%s').text for el in %s]" % (code, iterator_code)
else:
code = "[el.find('%s').%s for el in %s]" % (code, code_add, iterator_code)
else:
if len(code) == 0:
if function is not None:
if function == 'self':
code = "self.xml"
else:
code = "%s(self.xml)" % (function,)
elif len(code_add) > 0:
code = "self.xml.%s" % (code_add,)
else:
print "ERROR --------"
else:
if function is not None:
if function == 'self':
code = "self.xml.find('%s')" % (code[:-1],)
else:
code = "%s(self.xml.find('%s'))" % (function, code[:-1],)
elif len(code_add) > 0:
code = "self.xml.find('%s').%s" % (code[:-1], code_add,)
else:
code = "self.xml.find('%s').text" % (code[:-1],)
model[field] = code
return model
class Model(object):
"""
Defines the general Model-Class from which all Model-classes are
inherited.
"""
def __init__(self, xml):
self.xml = xml
if self.xml is not None:
self.readXML(self.xml)
def additem(self, item, value):
"""
Adds a new element to the model. If the element name
contains a colon then a dictionary based on the value
preding the colon is created and the value is stored
in this dictionary
"""
if item.find(":") == -1:
try:
setattr(self, item, value)
except:
pass
else:
item_dict, item = item.split(":")
if not self.__dict__.has_key(item_dict):
setattr(self, item_dict, {})
self.__dict__[item_dict][item] = value
def readXML(self, xml):
for item in self.DICT:
try:
value = eval("%s" % self.DICT[item])
self.additem(item, value )
except AttributeError:
#print "Could not evaluate %s" % el
pass
# check for attributes
## try:
## for attribute in item.keys():
## self.additem(el+attribute.capitalize(), item.get(attribute))
## except:
## pass
def _construct_dictmodelclass(model_definitions, module):
"""
Creates and returns a Dictionary Class (e.g. for Molecules).
The elements of the dictionary are usually Model-Classes
(e.g. class Molecule), which are defined by _construct_class
"""
class _DictModel(dict):
DICT = construct_model(model_definitions['Dictionary'])
def __init__(self, xml):
dict.__init__(self)
self.xml = xml
for item in eval("%s" % self.DICT[model_definitions['Name']]):
element = module.__dict__[model_definitions['Type']](item)
self[element.Id] = element
return _DictModel
def _construct_class(model_definitions, module = None):
"""
Creates and returns a Model-Class (e.g. for a Molecule)
"""
class _Model(Model):
DICT = construct_model(model_definitions['Dictionary'])
def __repr__(self):
retval = ""
for field in model_definitions['representation_fields']:
try:
retval += "%r " % self.__dict__[field]
except KeyError:
retval += "None "
return retval
if model_definitions.has_key('methods'):
for method in model_definitions['methods']:
setattr(_Model, method['name'], method['method'])
return _Model
def register_models(DICT_MODELS, module):
"""
Creates classes and add them to this packages as well as
the package which calls this method
DICT_MODELS: Dictionary which defines Classes and its properties
"""
for model in DICT_MODELS['model_types']:
print "Register Class %s in %s" % (model['Name'], module.__name__)
model_class = _construct_class(model)
setattr(sys.modules[__name__], model['Name'], model_class )
setattr(module, model['Name'], model_class )
for model in DICT_MODELS['dict_types']:
print "Register DictClass %s in %s" % (model['Name'], module.__name__)
setattr(module, model['Name'], _construct_dictmodelclass(model, module))