##// END OF EJS Templates
use eval to uncan References...
MinRK -
Show More
@@ -1,493 +1,507 b''
1 1 # -*- coding: utf-8 -*-
2 2 """test View objects
3 3
4 4 Authors:
5 5
6 6 * Min RK
7 7 """
8 8 #-------------------------------------------------------------------------------
9 9 # Copyright (C) 2011 The IPython Development Team
10 10 #
11 11 # Distributed under the terms of the BSD License. The full license is in
12 12 # the file COPYING, distributed as part of this software.
13 13 #-------------------------------------------------------------------------------
14 14
15 15 #-------------------------------------------------------------------------------
16 16 # Imports
17 17 #-------------------------------------------------------------------------------
18 18
19 19 import sys
20 20 import time
21 21 from tempfile import mktemp
22 22 from StringIO import StringIO
23 23
24 24 import zmq
25 25 from nose import SkipTest
26 26
27 27 from IPython.testing import decorators as dec
28 28
29 29 from IPython import parallel as pmod
30 30 from IPython.parallel import error
31 31 from IPython.parallel import AsyncResult, AsyncHubResult, AsyncMapResult
32 32 from IPython.parallel import DirectView
33 33 from IPython.parallel.util import interactive
34 34
35 35 from IPython.parallel.tests import add_engines
36 36
37 37 from .clienttest import ClusterTestCase, crash, wait, skip_without
38 38
39 39 def setup():
40 40 add_engines(3)
41 41
42 42 class TestView(ClusterTestCase):
43 43
44 44 def test_z_crash_mux(self):
45 45 """test graceful handling of engine death (direct)"""
46 46 raise SkipTest("crash tests disabled, due to undesirable crash reports")
47 47 # self.add_engines(1)
48 48 eid = self.client.ids[-1]
49 49 ar = self.client[eid].apply_async(crash)
50 50 self.assertRaisesRemote(error.EngineError, ar.get, 10)
51 51 eid = ar.engine_id
52 52 tic = time.time()
53 53 while eid in self.client.ids and time.time()-tic < 5:
54 54 time.sleep(.01)
55 55 self.client.spin()
56 56 self.assertFalse(eid in self.client.ids, "Engine should have died")
57 57
58 58 def test_push_pull(self):
59 59 """test pushing and pulling"""
60 60 data = dict(a=10, b=1.05, c=range(10), d={'e':(1,2),'f':'hi'})
61 61 t = self.client.ids[-1]
62 62 v = self.client[t]
63 63 push = v.push
64 64 pull = v.pull
65 65 v.block=True
66 66 nengines = len(self.client)
67 67 push({'data':data})
68 68 d = pull('data')
69 69 self.assertEquals(d, data)
70 70 self.client[:].push({'data':data})
71 71 d = self.client[:].pull('data', block=True)
72 72 self.assertEquals(d, nengines*[data])
73 73 ar = push({'data':data}, block=False)
74 74 self.assertTrue(isinstance(ar, AsyncResult))
75 75 r = ar.get()
76 76 ar = self.client[:].pull('data', block=False)
77 77 self.assertTrue(isinstance(ar, AsyncResult))
78 78 r = ar.get()
79 79 self.assertEquals(r, nengines*[data])
80 80 self.client[:].push(dict(a=10,b=20))
81 81 r = self.client[:].pull(('a','b'), block=True)
82 82 self.assertEquals(r, nengines*[[10,20]])
83 83
84 84 def test_push_pull_function(self):
85 85 "test pushing and pulling functions"
86 86 def testf(x):
87 87 return 2.0*x
88 88
89 89 t = self.client.ids[-1]
90 90 v = self.client[t]
91 91 v.block=True
92 92 push = v.push
93 93 pull = v.pull
94 94 execute = v.execute
95 95 push({'testf':testf})
96 96 r = pull('testf')
97 97 self.assertEqual(r(1.0), testf(1.0))
98 98 execute('r = testf(10)')
99 99 r = pull('r')
100 100 self.assertEquals(r, testf(10))
101 101 ar = self.client[:].push({'testf':testf}, block=False)
102 102 ar.get()
103 103 ar = self.client[:].pull('testf', block=False)
104 104 rlist = ar.get()
105 105 for r in rlist:
106 106 self.assertEqual(r(1.0), testf(1.0))
107 107 execute("def g(x): return x*x")
108 108 r = pull(('testf','g'))
109 109 self.assertEquals((r[0](10),r[1](10)), (testf(10), 100))
110 110
111 111 def test_push_function_globals(self):
112 112 """test that pushed functions have access to globals"""
113 113 @interactive
114 114 def geta():
115 115 return a
116 116 # self.add_engines(1)
117 117 v = self.client[-1]
118 118 v.block=True
119 119 v['f'] = geta
120 120 self.assertRaisesRemote(NameError, v.execute, 'b=f()')
121 121 v.execute('a=5')
122 122 v.execute('b=f()')
123 123 self.assertEquals(v['b'], 5)
124 124
125 125 def test_push_function_defaults(self):
126 126 """test that pushed functions preserve default args"""
127 127 def echo(a=10):
128 128 return a
129 129 v = self.client[-1]
130 130 v.block=True
131 131 v['f'] = echo
132 132 v.execute('b=f()')
133 133 self.assertEquals(v['b'], 10)
134 134
135 135 def test_get_result(self):
136 136 """test getting results from the Hub."""
137 137 c = pmod.Client(profile='iptest')
138 138 # self.add_engines(1)
139 139 t = c.ids[-1]
140 140 v = c[t]
141 141 v2 = self.client[t]
142 142 ar = v.apply_async(wait, 1)
143 143 # give the monitor time to notice the message
144 144 time.sleep(.25)
145 145 ahr = v2.get_result(ar.msg_ids)
146 146 self.assertTrue(isinstance(ahr, AsyncHubResult))
147 147 self.assertEquals(ahr.get(), ar.get())
148 148 ar2 = v2.get_result(ar.msg_ids)
149 149 self.assertFalse(isinstance(ar2, AsyncHubResult))
150 150 c.spin()
151 151 c.close()
152 152
153 153 def test_run_newline(self):
154 154 """test that run appends newline to files"""
155 155 tmpfile = mktemp()
156 156 with open(tmpfile, 'w') as f:
157 157 f.write("""def g():
158 158 return 5
159 159 """)
160 160 v = self.client[-1]
161 161 v.run(tmpfile, block=True)
162 162 self.assertEquals(v.apply_sync(lambda f: f(), pmod.Reference('g')), 5)
163 163
164 164 def test_apply_tracked(self):
165 165 """test tracking for apply"""
166 166 # self.add_engines(1)
167 167 t = self.client.ids[-1]
168 168 v = self.client[t]
169 169 v.block=False
170 170 def echo(n=1024*1024, **kwargs):
171 171 with v.temp_flags(**kwargs):
172 172 return v.apply(lambda x: x, 'x'*n)
173 173 ar = echo(1, track=False)
174 174 self.assertTrue(isinstance(ar._tracker, zmq.MessageTracker))
175 175 self.assertTrue(ar.sent)
176 176 ar = echo(track=True)
177 177 self.assertTrue(isinstance(ar._tracker, zmq.MessageTracker))
178 178 self.assertEquals(ar.sent, ar._tracker.done)
179 179 ar._tracker.wait()
180 180 self.assertTrue(ar.sent)
181 181
182 182 def test_push_tracked(self):
183 183 t = self.client.ids[-1]
184 184 ns = dict(x='x'*1024*1024)
185 185 v = self.client[t]
186 186 ar = v.push(ns, block=False, track=False)
187 187 self.assertTrue(isinstance(ar._tracker, zmq.MessageTracker))
188 188 self.assertTrue(ar.sent)
189 189
190 190 ar = v.push(ns, block=False, track=True)
191 191 self.assertTrue(isinstance(ar._tracker, zmq.MessageTracker))
192 192 ar._tracker.wait()
193 193 self.assertEquals(ar.sent, ar._tracker.done)
194 194 self.assertTrue(ar.sent)
195 195 ar.get()
196 196
197 197 def test_scatter_tracked(self):
198 198 t = self.client.ids
199 199 x='x'*1024*1024
200 200 ar = self.client[t].scatter('x', x, block=False, track=False)
201 201 self.assertTrue(isinstance(ar._tracker, zmq.MessageTracker))
202 202 self.assertTrue(ar.sent)
203 203
204 204 ar = self.client[t].scatter('x', x, block=False, track=True)
205 205 self.assertTrue(isinstance(ar._tracker, zmq.MessageTracker))
206 206 self.assertEquals(ar.sent, ar._tracker.done)
207 207 ar._tracker.wait()
208 208 self.assertTrue(ar.sent)
209 209 ar.get()
210 210
211 211 def test_remote_reference(self):
212 212 v = self.client[-1]
213 213 v['a'] = 123
214 214 ra = pmod.Reference('a')
215 215 b = v.apply_sync(lambda x: x, ra)
216 216 self.assertEquals(b, 123)
217 217
218 218
219 219 def test_scatter_gather(self):
220 220 view = self.client[:]
221 221 seq1 = range(16)
222 222 view.scatter('a', seq1)
223 223 seq2 = view.gather('a', block=True)
224 224 self.assertEquals(seq2, seq1)
225 225 self.assertRaisesRemote(NameError, view.gather, 'asdf', block=True)
226 226
227 227 @skip_without('numpy')
228 228 def test_scatter_gather_numpy(self):
229 229 import numpy
230 230 from numpy.testing.utils import assert_array_equal, assert_array_almost_equal
231 231 view = self.client[:]
232 232 a = numpy.arange(64)
233 233 view.scatter('a', a)
234 234 b = view.gather('a', block=True)
235 235 assert_array_equal(b, a)
236 236
237 237 def test_map(self):
238 238 view = self.client[:]
239 239 def f(x):
240 240 return x**2
241 241 data = range(16)
242 242 r = view.map_sync(f, data)
243 243 self.assertEquals(r, map(f, data))
244 244
245 245 def test_map_iterable(self):
246 246 """test map on iterables (direct)"""
247 247 view = self.client[:]
248 248 # 101 is prime, so it won't be evenly distributed
249 249 arr = range(101)
250 250 # ensure it will be an iterator, even in Python 3
251 251 it = iter(arr)
252 252 r = view.map_sync(lambda x:x, arr)
253 253 self.assertEquals(r, list(arr))
254 254
255 255 def test_scatterGatherNonblocking(self):
256 256 data = range(16)
257 257 view = self.client[:]
258 258 view.scatter('a', data, block=False)
259 259 ar = view.gather('a', block=False)
260 260 self.assertEquals(ar.get(), data)
261 261
262 262 @skip_without('numpy')
263 263 def test_scatter_gather_numpy_nonblocking(self):
264 264 import numpy
265 265 from numpy.testing.utils import assert_array_equal, assert_array_almost_equal
266 266 a = numpy.arange(64)
267 267 view = self.client[:]
268 268 ar = view.scatter('a', a, block=False)
269 269 self.assertTrue(isinstance(ar, AsyncResult))
270 270 amr = view.gather('a', block=False)
271 271 self.assertTrue(isinstance(amr, AsyncMapResult))
272 272 assert_array_equal(amr.get(), a)
273 273
274 274 def test_execute(self):
275 275 view = self.client[:]
276 276 # self.client.debug=True
277 277 execute = view.execute
278 278 ar = execute('c=30', block=False)
279 279 self.assertTrue(isinstance(ar, AsyncResult))
280 280 ar = execute('d=[0,1,2]', block=False)
281 281 self.client.wait(ar, 1)
282 282 self.assertEquals(len(ar.get()), len(self.client))
283 283 for c in view['c']:
284 284 self.assertEquals(c, 30)
285 285
286 286 def test_abort(self):
287 287 view = self.client[-1]
288 288 ar = view.execute('import time; time.sleep(1)', block=False)
289 289 ar2 = view.apply_async(lambda : 2)
290 290 ar3 = view.apply_async(lambda : 3)
291 291 view.abort(ar2)
292 292 view.abort(ar3.msg_ids)
293 293 self.assertRaises(error.TaskAborted, ar2.get)
294 294 self.assertRaises(error.TaskAborted, ar3.get)
295 295
296 296 def test_abort_all(self):
297 297 """view.abort() aborts all outstanding tasks"""
298 298 view = self.client[-1]
299 299 ars = [ view.apply_async(time.sleep, 1) for i in range(10) ]
300 300 view.abort()
301 301 view.wait(timeout=5)
302 302 for ar in ars[5:]:
303 303 self.assertRaises(error.TaskAborted, ar.get)
304 304
305 305 def test_temp_flags(self):
306 306 view = self.client[-1]
307 307 view.block=True
308 308 with view.temp_flags(block=False):
309 309 self.assertFalse(view.block)
310 310 self.assertTrue(view.block)
311 311
312 312 @dec.known_failure_py3
313 313 def test_importer(self):
314 314 view = self.client[-1]
315 315 view.clear(block=True)
316 316 with view.importer:
317 317 import re
318 318
319 319 @interactive
320 320 def findall(pat, s):
321 321 # this globals() step isn't necessary in real code
322 322 # only to prevent a closure in the test
323 323 re = globals()['re']
324 324 return re.findall(pat, s)
325 325
326 326 self.assertEquals(view.apply_sync(findall, '\w+', 'hello world'), 'hello world'.split())
327 327
328 328 # parallel magic tests
329 329
330 330 def test_magic_px_blocking(self):
331 331 ip = get_ipython()
332 332 v = self.client[-1]
333 333 v.activate()
334 334 v.block=True
335 335
336 336 ip.magic_px('a=5')
337 337 self.assertEquals(v['a'], 5)
338 338 ip.magic_px('a=10')
339 339 self.assertEquals(v['a'], 10)
340 340 sio = StringIO()
341 341 savestdout = sys.stdout
342 342 sys.stdout = sio
343 343 # just 'print a' worst ~99% of the time, but this ensures that
344 344 # the stdout message has arrived when the result is finished:
345 345 ip.magic_px('import sys,time;print (a); sys.stdout.flush();time.sleep(0.2)')
346 346 sys.stdout = savestdout
347 347 buf = sio.getvalue()
348 348 self.assertTrue('[stdout:' in buf, buf)
349 349 self.assertTrue(buf.rstrip().endswith('10'))
350 350 self.assertRaisesRemote(ZeroDivisionError, ip.magic_px, '1/0')
351 351
352 352 def test_magic_px_nonblocking(self):
353 353 ip = get_ipython()
354 354 v = self.client[-1]
355 355 v.activate()
356 356 v.block=False
357 357
358 358 ip.magic_px('a=5')
359 359 self.assertEquals(v['a'], 5)
360 360 ip.magic_px('a=10')
361 361 self.assertEquals(v['a'], 10)
362 362 sio = StringIO()
363 363 savestdout = sys.stdout
364 364 sys.stdout = sio
365 365 ip.magic_px('print a')
366 366 sys.stdout = savestdout
367 367 buf = sio.getvalue()
368 368 self.assertFalse('[stdout:%i]'%v.targets in buf)
369 369 ip.magic_px('1/0')
370 370 ar = v.get_result(-1)
371 371 self.assertRaisesRemote(ZeroDivisionError, ar.get)
372 372
373 373 def test_magic_autopx_blocking(self):
374 374 ip = get_ipython()
375 375 v = self.client[-1]
376 376 v.activate()
377 377 v.block=True
378 378
379 379 sio = StringIO()
380 380 savestdout = sys.stdout
381 381 sys.stdout = sio
382 382 ip.magic_autopx()
383 383 ip.run_cell('\n'.join(('a=5','b=10','c=0')))
384 384 ip.run_cell('print b')
385 385 ip.run_cell("b/c")
386 386 ip.run_code(compile('b*=2', '', 'single'))
387 387 ip.magic_autopx()
388 388 sys.stdout = savestdout
389 389 output = sio.getvalue().strip()
390 390 self.assertTrue(output.startswith('%autopx enabled'))
391 391 self.assertTrue(output.endswith('%autopx disabled'))
392 392 self.assertTrue('RemoteError: ZeroDivisionError' in output)
393 393 ar = v.get_result(-2)
394 394 self.assertEquals(v['a'], 5)
395 395 self.assertEquals(v['b'], 20)
396 396 self.assertRaisesRemote(ZeroDivisionError, ar.get)
397 397
398 398 def test_magic_autopx_nonblocking(self):
399 399 ip = get_ipython()
400 400 v = self.client[-1]
401 401 v.activate()
402 402 v.block=False
403 403
404 404 sio = StringIO()
405 405 savestdout = sys.stdout
406 406 sys.stdout = sio
407 407 ip.magic_autopx()
408 408 ip.run_cell('\n'.join(('a=5','b=10','c=0')))
409 409 ip.run_cell('print b')
410 410 ip.run_cell("b/c")
411 411 ip.run_code(compile('b*=2', '', 'single'))
412 412 ip.magic_autopx()
413 413 sys.stdout = savestdout
414 414 output = sio.getvalue().strip()
415 415 self.assertTrue(output.startswith('%autopx enabled'))
416 416 self.assertTrue(output.endswith('%autopx disabled'))
417 417 self.assertFalse('ZeroDivisionError' in output)
418 418 ar = v.get_result(-2)
419 419 self.assertEquals(v['a'], 5)
420 420 self.assertEquals(v['b'], 20)
421 421 self.assertRaisesRemote(ZeroDivisionError, ar.get)
422 422
423 423 def test_magic_result(self):
424 424 ip = get_ipython()
425 425 v = self.client[-1]
426 426 v.activate()
427 427 v['a'] = 111
428 428 ra = v['a']
429 429
430 430 ar = ip.magic_result()
431 431 self.assertEquals(ar.msg_ids, [v.history[-1]])
432 432 self.assertEquals(ar.get(), 111)
433 433 ar = ip.magic_result('-2')
434 434 self.assertEquals(ar.msg_ids, [v.history[-2]])
435 435
436 436 def test_unicode_execute(self):
437 437 """test executing unicode strings"""
438 438 v = self.client[-1]
439 439 v.block=True
440 440 if sys.version_info[0] >= 3:
441 441 code="a='é'"
442 442 else:
443 443 code=u"a=u'é'"
444 444 v.execute(code)
445 445 self.assertEquals(v['a'], u'é')
446 446
447 447 def test_unicode_apply_result(self):
448 448 """test unicode apply results"""
449 449 v = self.client[-1]
450 450 r = v.apply_sync(lambda : u'é')
451 451 self.assertEquals(r, u'é')
452 452
453 453 def test_unicode_apply_arg(self):
454 454 """test passing unicode arguments to apply"""
455 455 v = self.client[-1]
456 456
457 457 @interactive
458 458 def check_unicode(a, check):
459 459 assert isinstance(a, unicode), "%r is not unicode"%a
460 460 assert isinstance(check, bytes), "%r is not bytes"%check
461 461 assert a.encode('utf8') == check, "%s != %s"%(a,check)
462 462
463 463 for s in [ u'é', u'ßø®∫',u'asdf' ]:
464 464 try:
465 465 v.apply_sync(check_unicode, s, s.encode('utf8'))
466 466 except error.RemoteError as e:
467 467 if e.ename == 'AssertionError':
468 468 self.fail(e.evalue)
469 469 else:
470 470 raise e
471 471
472 472 def test_map_reference(self):
473 473 """view.map(<Reference>, *seqs) should work"""
474 474 v = self.client[:]
475 475 v.scatter('n', self.client.ids, flatten=True)
476 476 v.execute("f = lambda x,y: x*y")
477 477 rf = pmod.Reference('f')
478 478 nlist = list(range(10))
479 479 mlist = nlist[::-1]
480 480 expected = [ m*n for m,n in zip(mlist, nlist) ]
481 481 result = v.map_sync(rf, mlist, nlist)
482 482 self.assertEquals(result, expected)
483 483
484 484 def test_apply_reference(self):
485 485 """view.apply(<Reference>, *args) should work"""
486 486 v = self.client[:]
487 487 v.scatter('n', self.client.ids, flatten=True)
488 488 v.execute("f = lambda x: n*x")
489 489 rf = pmod.Reference('f')
490 490 result = v.apply_sync(rf, 5)
491 491 expected = [ 5*id for id in self.client.ids ]
492 492 self.assertEquals(result, expected)
493 493
494 def test_eval_reference(self):
495 v = self.client[self.client.ids[0]]
496 v['g'] = range(5)
497 rg = pmod.Reference('g[0]')
498 echo = lambda x:x
499 self.assertEquals(v.apply_sync(echo, rg), 0)
500
501 def test_reference_nameerror(self):
502 v = self.client[self.client.ids[0]]
503 r = pmod.Reference('elvis_has_left')
504 echo = lambda x:x
505 self.assertRaisesRemote(NameError, v.apply_sync, echo, r)
506
507
@@ -1,153 +1,151 b''
1 1 # encoding: utf-8
2 2
3 3 """Pickle related utilities. Perhaps this should be called 'can'."""
4 4
5 5 __docformat__ = "restructuredtext en"
6 6
7 7 #-------------------------------------------------------------------------------
8 8 # Copyright (C) 2008-2011 The IPython Development Team
9 9 #
10 10 # Distributed under the terms of the BSD License. The full license is in
11 11 # the file COPYING, distributed as part of this software.
12 12 #-------------------------------------------------------------------------------
13 13
14 14 #-------------------------------------------------------------------------------
15 15 # Imports
16 16 #-------------------------------------------------------------------------------
17 17
18 18 import copy
19 19 import sys
20 20 from types import FunctionType
21 21
22 22 import codeutil
23 23
24 24 #-------------------------------------------------------------------------------
25 25 # Classes
26 26 #-------------------------------------------------------------------------------
27 27
28 28
29 29 class CannedObject(object):
30 30 def __init__(self, obj, keys=[]):
31 31 self.keys = keys
32 32 self.obj = copy.copy(obj)
33 33 for key in keys:
34 34 setattr(self.obj, key, can(getattr(obj, key)))
35 35
36 36
37 37 def getObject(self, g=None):
38 38 if g is None:
39 39 g = globals()
40 40 for key in self.keys:
41 41 setattr(self.obj, key, uncan(getattr(self.obj, key), g))
42 42 return self.obj
43 43
44 44 class Reference(CannedObject):
45 45 """object for wrapping a remote reference by name."""
46 46 def __init__(self, name):
47 47 if not isinstance(name, basestring):
48 48 raise TypeError("illegal name: %r"%name)
49 49 self.name = name
50 50
51 51 def __repr__(self):
52 52 return "<Reference: %r>"%self.name
53 53
54 54 def getObject(self, g=None):
55 55 if g is None:
56 56 g = globals()
57 try:
58 return g[self.name]
59 except KeyError:
60 raise NameError("name %r is not defined"%self.name)
57
58 return eval(self.name, g)
61 59
62 60
63 61 class CannedFunction(CannedObject):
64 62
65 63 def __init__(self, f):
66 64 self._checkType(f)
67 65 self.code = f.func_code
68 66 self.defaults = f.func_defaults
69 67 self.module = f.__module__ or '__main__'
70 68 self.__name__ = f.__name__
71 69
72 70 def _checkType(self, obj):
73 71 assert isinstance(obj, FunctionType), "Not a function type"
74 72
75 73 def getObject(self, g=None):
76 74 # try to load function back into its module:
77 75 if not self.module.startswith('__'):
78 76 try:
79 77 __import__(self.module)
80 78 except ImportError:
81 79 pass
82 80 else:
83 81 g = sys.modules[self.module].__dict__
84 82
85 83 if g is None:
86 84 g = globals()
87 85 newFunc = FunctionType(self.code, g, self.__name__, self.defaults)
88 86 return newFunc
89 87
90 88 #-------------------------------------------------------------------------------
91 89 # Functions
92 90 #-------------------------------------------------------------------------------
93 91
94 92 def can(obj):
95 93 # import here to prevent module-level circular imports
96 94 from IPython.parallel import dependent
97 95 if isinstance(obj, dependent):
98 96 keys = ('f','df')
99 97 return CannedObject(obj, keys=keys)
100 98 elif isinstance(obj, FunctionType):
101 99 return CannedFunction(obj)
102 100 elif isinstance(obj,dict):
103 101 return canDict(obj)
104 102 elif isinstance(obj, (list,tuple)):
105 103 return canSequence(obj)
106 104 else:
107 105 return obj
108 106
109 107 def canDict(obj):
110 108 if isinstance(obj, dict):
111 109 newobj = {}
112 110 for k, v in obj.iteritems():
113 111 newobj[k] = can(v)
114 112 return newobj
115 113 else:
116 114 return obj
117 115
118 116 def canSequence(obj):
119 117 if isinstance(obj, (list, tuple)):
120 118 t = type(obj)
121 119 return t([can(i) for i in obj])
122 120 else:
123 121 return obj
124 122
125 123 def uncan(obj, g=None):
126 124 if isinstance(obj, CannedObject):
127 125 return obj.getObject(g)
128 126 elif isinstance(obj,dict):
129 127 return uncanDict(obj, g)
130 128 elif isinstance(obj, (list,tuple)):
131 129 return uncanSequence(obj, g)
132 130 else:
133 131 return obj
134 132
135 133 def uncanDict(obj, g=None):
136 134 if isinstance(obj, dict):
137 135 newobj = {}
138 136 for k, v in obj.iteritems():
139 137 newobj[k] = uncan(v,g)
140 138 return newobj
141 139 else:
142 140 return obj
143 141
144 142 def uncanSequence(obj, g=None):
145 143 if isinstance(obj, (list, tuple)):
146 144 t = type(obj)
147 145 return t([uncan(i,g) for i in obj])
148 146 else:
149 147 return obj
150 148
151 149
152 150 def rebindFunctionGlobals(f, glbls):
153 151 return FunctionType(f.func_code, glbls)
General Comments 0
You need to be logged in to leave comments. Login now