##// END OF EJS Templates
Merge pull request #5762 from minrk/better_closure_check...
Thomas Kluyver -
r16518:161841f4 merge
parent child Browse files
Show More
@@ -0,0 +1,62 b''
1
2 import pickle
3
4 import nose.tools as nt
5 from IPython.utils import codeutil
6 from IPython.utils.pickleutil import can, uncan
7
8 def interactive(f):
9 f.__module__ = '__main__'
10 return f
11
12 def dumps(obj):
13 return pickle.dumps(can(obj))
14
15 def loads(obj):
16 return uncan(pickle.loads(obj))
17
18 def test_no_closure():
19 @interactive
20 def foo():
21 a = 5
22 return a
23
24 pfoo = dumps(foo)
25 bar = loads(pfoo)
26 nt.assert_equal(foo(), bar())
27
28 def test_generator_closure():
29 # this only creates a closure on Python 3
30 @interactive
31 def foo():
32 i = 'i'
33 r = [ i for j in (1,2) ]
34 return r
35
36 pfoo = dumps(foo)
37 bar = loads(pfoo)
38 nt.assert_equal(foo(), bar())
39
40 def test_nested_closure():
41 @interactive
42 def foo():
43 i = 'i'
44 def g():
45 return i
46 return g()
47
48 pfoo = dumps(foo)
49 bar = loads(pfoo)
50 nt.assert_equal(foo(), bar())
51
52 def test_closure():
53 i = 'i'
54 @interactive
55 def foo():
56 return i
57
58 # true closures are not supported
59 with nt.assert_raises(ValueError):
60 pfoo = dumps(foo)
61
62 No newline at end of file
@@ -10,19 +10,6 b' we need to automate all of this so that functions themselves can be pickled.'
10 Reference: A. Tremols, P Cogolo, "Python Cookbook," p 302-305
10 Reference: A. Tremols, P Cogolo, "Python Cookbook," p 302-305
11 """
11 """
12
12
13 __docformat__ = "restructuredtext en"
14
15 #-------------------------------------------------------------------------------
16 # Copyright (C) 2008-2011 The IPython Development Team
17 #
18 # Distributed under the terms of the BSD License. The full license is in
19 # the file COPYING, distributed as part of this software.
20 #-------------------------------------------------------------------------------
21
22 #-------------------------------------------------------------------------------
23 # Imports
24 #-------------------------------------------------------------------------------
25
26 import sys
13 import sys
27 import types
14 import types
28 try:
15 try:
@@ -34,12 +21,10 b' def code_ctor(*args):'
34 return types.CodeType(*args)
21 return types.CodeType(*args)
35
22
36 def reduce_code(co):
23 def reduce_code(co):
37 if co.co_freevars or co.co_cellvars:
38 raise ValueError("Sorry, cannot pickle code objects with closures")
39 args = [co.co_argcount, co.co_nlocals, co.co_stacksize,
24 args = [co.co_argcount, co.co_nlocals, co.co_stacksize,
40 co.co_flags, co.co_code, co.co_consts, co.co_names,
25 co.co_flags, co.co_code, co.co_consts, co.co_names,
41 co.co_varnames, co.co_filename, co.co_name, co.co_firstlineno,
26 co.co_varnames, co.co_filename, co.co_name, co.co_firstlineno,
42 co.co_lnotab]
27 co.co_lnotab, co.co_freevars, co.co_cellvars]
43 if sys.version_info[0] >= 3:
28 if sys.version_info[0] >= 3:
44 args.insert(1, co.co_kwonlyargcount)
29 args.insert(1, co.co_kwonlyargcount)
45 return code_ctor, tuple(args)
30 return code_ctor, tuple(args)
@@ -2,18 +2,8 b''
2
2
3 """Pickle related utilities. Perhaps this should be called 'can'."""
3 """Pickle related utilities. Perhaps this should be called 'can'."""
4
4
5 __docformat__ = "restructuredtext en"
5 # Copyright (c) IPython Development Team.
6
6 # Distributed under the terms of the Modified BSD License.
7 #-------------------------------------------------------------------------------
8 # Copyright (C) 2008-2011 The IPython Development Team
9 #
10 # Distributed under the terms of the BSD License. The full license is in
11 # the file COPYING, distributed as part of this software.
12 #-------------------------------------------------------------------------------
13
14 #-------------------------------------------------------------------------------
15 # Imports
16 #-------------------------------------------------------------------------------
17
7
18 import copy
8 import copy
19 import logging
9 import logging
@@ -35,9 +25,11 b' from IPython.config import Application'
35 if py3compat.PY3:
25 if py3compat.PY3:
36 buffer = memoryview
26 buffer = memoryview
37 class_type = type
27 class_type = type
28 closure_attr = '__closure__'
38 else:
29 else:
39 from types import ClassType
30 from types import ClassType
40 class_type = (type, ClassType)
31 class_type = (type, ClassType)
32 closure_attr = 'func_closure'
41
33
42 #-------------------------------------------------------------------------------
34 #-------------------------------------------------------------------------------
43 # Functions
35 # Functions
@@ -140,6 +132,9 b' class CannedFunction(CannedObject):'
140 self.defaults = [ can(fd) for fd in f.__defaults__ ]
132 self.defaults = [ can(fd) for fd in f.__defaults__ ]
141 else:
133 else:
142 self.defaults = None
134 self.defaults = None
135
136 if getattr(f, closure_attr, None):
137 raise ValueError("Sorry, cannot pickle functions with closures.")
143 self.module = f.__module__ or '__main__'
138 self.module = f.__module__ or '__main__'
144 self.__name__ = f.__name__
139 self.__name__ = f.__name__
145 self.buffers = []
140 self.buffers = []
General Comments 0
You need to be logged in to leave comments. Login now