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
|
from xml.etree.ElementTree import *
import re
import sys
import xml
import pdb
import util.Strings as Strings
import util.Search as Search
from logger import main_log, exception_log
classArgsMem = {}
CONFIG_PATH = 'config/'
DEFAULT_OVERRIDE_MODE = 'Merge'
def loadParamRequirementDict(className):
if not className in classArgsMem: #WOO CACHING
classArgsMem[className] = fileToDict(CONFIG_PATH + className)
return classArgsMem[className]
def loadConfigFile(fileName): #TODO: error handling etc.
"""Loads a config file. If its an xml file, inheritances are automatically resolved."""
try:
if '.params' in fileName:
return fileToDict(fileName)
if '.xml' in fileName:
config = ElementTree()
config.parse(fileName)
resolveDocumentInheritances(config.getroot())
return config
except Exception as inst:
main_log.error('Error loading config file ' + fileName)#, inst) TODO: log exception too
main_log.error(str(inst))
return None
def getElement(el):
"""Takes an Element or an ElementTree. If it is a tree, it returns its root. Otherwise, just returns
it"""
if xml.etree.ElementTree.iselement(el):
return el
elif el.__class__ == ElementTree:
return el.getroot()
def compositeXMLTrees(parentTree, overridingTree):
"""XML tree composition. Returns the resulting tree, but happens in-place in the overriding
tree."""
#TODO: break up into sub-methods, change it to use .find()
if parentTree == None:
return overridingTree
if overridingTree == None:
return parentTree #TODO: this will probably cause a bug since it isn't in-place on
#overridingTree
parentTree = getElement(parentTree)
overridingTree = getElement(overridingTree)
parentItems = parentTree.getchildren()
overrideItems = overridingTree.getchildren()
#first, lets figure out what tags we have in the override tree:
tagCollection = [el.tag for el in overrideItems] #we can speed this up with a dict if necessary
for item in parentItems:
if not item.tag in tagCollection: #no override
overridingTree.insert(-1, item) #insert the new item at the end
else:
#do we merge or replace?
intersectingElements = findElementsByTag(item.tag, overrideItems)
if len(intersectingElements) > 1:
main_log.warn('ABUSE! Override of multiple items isn\'t well defined. Don\'t do\
it!')
interEl = intersectingElements[0]
mode = DEFAULT_OVERRIDE_MODE
if Strings.OVERRIDE_BEHAVIOR in interEl.attrib:
mode = interEl.attrib[Strings.OVERRIDE_BEHAVIOR]
if mode != 'Replace' and mode != 'Merge':
main_log.warn('Bad Override Mode. Choosing to replace.')
mode = 'Replace'
if mode == 'Replace':
pass #we don't need to do anything
if mode == 'Merge':
interEl = compositeXMLTrees(item, interEl)
for item in overrideItems: #resolve appendages
if item.tag == 'APPEND':
children = item.getchildren()
for child in children:
overrideItems.insert(-1, child)
overrideItems.remove(item)
return overridingTree
def findElementsByTag(tag, eList):
return [el for el in eList if el.tag == tag]
def fileToDict(fileName):
fileText = ''
try:
with open(fileName) as f:
for line in f:
fileText += line.rstrip('\n').lstrip('\t') + ' '
except IOError:
exception_log.exception('Failure reading ' + fileName)
return {}
if fileText == '':
return {}
try:
resultDict = eval(fileText)
main_log.info(fileName + ' read and parsed')
return resultDict
except:
exception_log.info(fileName + ' is not a well formed python dict. Parsing failed')
return eval(fileText)
def pullArgsFromItem(parentNode):
"""Parses arguments into python objects if possible, otherwise leaves as strings"""
attribArgs = {}
for arg in parentNode.attrib: #automatically pull attributes into the argdict
attribArgs[arg] = attemptEval(parentNode.attrib[arg])
argNode = parentNode.find('Args')
args = generateArgDict(argNode)
for key in attribArgs:
args[key] = attribArgs[key]
return args
def attemptEval(val):
"""Runs an eval if possible, or converts into a lambda expression if indicated. Otherwise,
leaves as a string."""
try:
if '${' in val and '}$' in val: #TODO: this could be a little cleaner
dictVal = re.sub("'\$\{(.+?)\}\$'", "b['\\1']", val) #replace expressions '${blah}$' with b['blah']
dictVal = re.sub("\$\{(.+?)\}\$", "a['\\1']", dictVal) #replace all expressions like {blah} with a['blah']
if "'${" and "}$'" in val: #nested lambda madness
lambdaVal = eval('lambda a: lambda b: ' + dictVal)
else:
lambdaVal = eval('lambda a:'+dictVal) #TODO: nested lambdas
return lambdaVal #convert referential objects to lambda expressions which can be
#resolved dynamically.
else:
val = eval(val)
except (NameError, SyntaxError):
val = str(val)
return val
def generateArgDict(parentNode, recurse=False):
args = {}
for arg in parentNode.getchildren():
key = arg.tag
if arg.getchildren() != []:
value = generateArgDict(arg, True)
else:
#convert into python if possible, otherwise don't
value = attemptEval(arg.text)
if key in args: #build of lists of like-elements
if type(args[key]) != type([]):
args[key] = [args[key]]
args[key].append(value)
else:
args[key]=value
#if we should be a list but we aren't:
if len(args.keys()) == 1 and recurse:
return args[args.keys()[0]]
return args
def resolveDocumentInheritances(el):
"""In place resolution of document inheritances. Doesn't return anything."""
abstractMembers = Search.parental_tree_search(el, '.getchildren()', '.tag==\'InheritsFrom\'')
for subel in abstractMembers:
subel = resolveInheritance(subel)
def resolveInheritance(el):
"""In place resolution of inheritence. Doesn't return anything."""
parentClass = el.find('InheritsFrom')
if parentClass != None:
parentTree = loadConfigFile(parentClass.text)
if parentTree == None:
main_log.warn('Inheritance Failed. ' + parentClass.text + 'does not exist')
main_log.error('Inheritance Failed. ' + parentClass.text + 'does not exist')
return el
el = compositeXMLTrees(parentTree, el)
el.remove(parentClass) #get rid of the inheritance flag
|