-
Notifications
You must be signed in to change notification settings - Fork 5
/
Tools.py
executable file
·312 lines (253 loc) · 9.52 KB
/
Tools.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
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
import random
import os
import commonVar as common
import inspect
"""
A memo from
http://www.devshed.com/c/a/Python/Python-Parameters-Functions-and-Arguments/
At the end of the parameters, you may optionally use either or both
of the special forms *identifier1 and **identifier2 .
If both forms are present, the form with two asterisks must
be last. *identifier1 specifies that any call to the function may
supply any number of extra positional arguments, while **identifier2
specifies that any call to the function may supply any number of
extra named arguments (positional and named arguments are covered
in "Calling Functions" on page 73). Every call to the function
binds identifier1 to a tuple whose items are the extra positional
arguments (or the empty tuple, if there are none). Similarly,
identifier2 gets bound to a dictionary whose items are the names
and values of the extra named arguments (or the empty dictionary,
if there are none).
"""
# two functions to apply different ways of writing the methods to run
# them as applied to an instance or to a set of instances
# extract the method from m (in Python3 m is a function); formerly it
# was an unbound method (see the from2to3.md file in the main folder)
# m is in the form Class.method
def extractMethodFromMethodFunction(m):
# m is Class.method; the method can also be defined in a super class
# NB if m is not a valid Class.method combination, Python raises an error
# so, we have to include the call to this funcion in a
# try/except structure
# class (or super class) name and class address are not necessary, but just in case ...
# cName=m.__qualname__.split(".")[0] # name of the class that defined the
# method reported in m (that contains 'class.method')
#print (cName)
# c=m.__globals__[cName] # class address
#print (c)
mName = m.__qualname__.split(".")[1] # name of the method (naked)
#print (mName)
return mName
# run a method over an instance
def applyMethod(instance, method, **k):
# NB, the call of this function can be included in a try/except
# strucutre to catch the case of an invalid dotted pair
# class.method
# handmade changes from Py 2 to Py 3
# we use extractMethodFromMethodFunction because we have to align to
# the need of writing methods as strings of characters, when we extract
# the content of the script of the schedule (.txt or .xls)
try:
if inspect.isfunction(method):
# unbound method/function case, extract method/function in str
# format
method = extractMethodFromMethodFunction(method)
except BaseException:
pass
# we wrote the method as a str (preferred way from v.1.36)
if not isinstance(method, str):
print(method, "is neither an unbound method nor a string")
return False
else:
# method is a str
# find the class of the instance
c = instance.__class__
# check if that class has the method 'method'
space = {}
space['c'] = c
space['inspect'] = inspect
test = False
try:
exec("test=inspect.isfunction(c." + method + ")", space)
test = space['test']
except BaseException: pass
if test:
space['instance'] = instance
space['k'] = k
exec("result=c." + method + "(instance,**k)", space)
result = space['result']
return result
else:
print("Warning, class", c.__name__, "(or above) of agent",
instance.agType, "does not have the method", method)
return False
# dictionary of the action groups (not necessary, kept only for
# retro compatibility)
actionDictionary = {}
# applying a method to a collection of instances
def askEachAgentInCollection(collection, method, **k):
""" collection, method, dict. of the parameters (may be empty)"""
for a in collection:
if common.debug:
applyMethod(a, method, **k)
else:
try:
applyMethod(a, method, **k)
except SystemExit:
print('method', method,'raising an exit condition while '+\
'acting on agent number', a.number, 'of type ', a.agType)
os.sys.exit(1)
except BaseException:
print('cannot apply (case 0) method', method,
'to agent number', a.number, 'of type ', a.agType)
# very special case
if a.agType == "recipes":
print("first step", a.content[0])
pass
# if we use k (a dictionary), the same notation has to
# be placed into the agent methods
# applying a method to a collection of instances
def askEachAgentInCollectionAndExecLocalCode(collection, method, **k):
""" collection, method, dict. of the parameters (may be empty)"""
setLocalCode("")
for a in collection:
if common.debug:
applyMethod(a, method, **k)
else:
try:
applyMethod(a, method, **k)
except SystemExit:
print('method', method,'raising an exit condition while '+\
'acting on agent number', a.number, 'of type ', a.agType)
os.sys.exit(1)
except BaseException:
print('cannot apply (case 1) method', method,
'to agent number', a.number, 'of type ', a.agType)
pass
# if we use k (a dictionary), the same notation has to
# be placed into the agent methods
execLocalCode()
# applying a method to an instance of a class
def askAgent(agent, method, **k):
""" agent, method, dict. of the parameters (may be empty)"""
if common.debug:
applyMethod(agent, method, **k)
else:
try:
applyMethod(agent, method, **k)
except SystemExit:
print('method', method,'raising an exit condition while '+\
'acting on agent number', a.number, 'of type ', a.agType)
os.sys.exit(1)
except BaseException:
print('cannot apply (case 2) method', method, 'to agent number',
a.number)
pass
# applying a method to an instance of a class
def askAgentAndExecLocalCode(agent, method, **k):
""" agent, method, dict. of the parameters (may be empty)"""
setLocalCode("")
if common.debug:
applyMethod(agent, method, **k)
else:
try:
applyMethod(agent, method, **k)
except SystemExit:
print('method', method,'raising an exit condition while '+\
'acting on agent number', a.number, 'of type ', a.agType)
os.sys.exit(1)
except BaseException:
print('cannot apply (case 3) method', method, 'to agent number',
a.number)
pass
execLocalCode()
# extracting a step and rotating a list (obsolete)
"""
def extractAStepAndRotate(aList):
if len(aList)==0:
print "Error: action list is empty"
os.sys.exit(1)
aSubList=aList.pop(0)
if type(aSubList)!=list:
print "Error: the elements of the action list need to be a list"
os.sys.exit(1)
aList.append(aSubList)
return aSubList[:] # with [:] we return the elements
# of aSubList, not the address
"""
# extracting a subStep
def extractASubStep(aSubList):
if len(aSubList) > 0:
return aSubList.pop(0)
else:
return []
# insert an element in next position
def insertElementNextPosition(aList, what):
aList.insert(0, what)
# exec("instruction 1; instruction 2; ...")
# pay attention to the semicolon
def execLocalCode():
global localCode
exec(localCode)
cleanLocalCode()
def cleanLocalCode():
global localCode
localCode = ""
def getLocalCode():
global localCode
return localCode
def setLocalCode(code):
global localCode
localCode = code
def checkRunningIn():
try:
__IPYTHON__
return True
except NameError:
return False
def checkVersion(version, name, k0, k1, k2):
# managing the presence of strings as rc in the version components
vv = version.split('.')
try:
v0 = int(vv[0])
except BaseException:
try:
v0 = int(vv[0][0:2])
except BaseException:
try:
v0 = int(vv[0][0:1])
except BaseException:
print("error in lib", name, "not regular version number")
os.sys.exit(1)
if v0 >k0:
return True
if len(vv) >= 2:
try:
v1 = int(vv[1])
except BaseException:
try:
v1 = int(vv[1][0:2])
except BaseException:
try:
v1 = int(vv[1][0:1])
except BaseException:
print("error in lib", name, "not regular version number")
os.sys.exit(1)
if v0 ==k0 and v1>k1:
return True
if len(vv) >= 3:
try:
v2 = int(vv[2])
except BaseException:
try:
v2 = int(vv[2][0:2])
except BaseException:
try:
v2 = int(vv[2][0:1])
except BaseException:
print("error in lib", name, "not regular version number")
os.sys.exit(1)
if v0 ==k0 and v1==k1 and v2>=k2:
return True
# the sequence never succeded
return False