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