[Zope-Checkins] CVS: Zope3/lib/python/Persistence - Function.py:1.8

Jeremy Hylton jeremy@zope.com
Wed, 10 Jul 2002 19:11:00 -0400


Update of /cvs-repository/Zope3/lib/python/Persistence
In directory cvs.zope.org:/tmp/cvs-serv28387

Modified Files:
	Function.py 
Log Message:
Extend CodeWrapper to make functions with nested functions picklable.

This allows code with nested functions to be written, although the
nested functions will not be persistent.





=== Zope3/lib/python/Persistence/Function.py 1.7 => 1.8 ===
 import dis
 import new
 import sys
-# in 2.3, this will be spelled new.function
-from types import FunctionType as function
+# in 2.3, this will be spelled new.function and new.code
+from types import FunctionType as function, CodeType as code
 
 from Persistence import Persistent
 
@@ -16,13 +16,26 @@
 class CodeWrapper:
     """Package a code object so that it can be pickled."""
 
+    nested = 0
+
     def __init__(self, co):
-        self.args = (co.co_argcount,
+        consts = co.co_consts
+        nested = [(i, c) for i, c in zip(range(len(consts)), consts)
+                  if isinstance(c, code)]
+        if nested:
+            self.nested = 1
+            L = list(consts)
+            for i, c in nested:
+                L[i] = CodeWrapper(c)
+            consts = tuple(L)
+
+        # args stores the arguments to new.code in order
+        self.args = [co.co_argcount,
                      co.co_nlocals,
                      co.co_stacksize,
                      co.co_flags,
                      co.co_code,
-                     co.co_consts,
+                     consts,
                      co.co_names,
                      co.co_varnames,
                      co.co_filename,
@@ -30,9 +43,15 @@
                      co.co_firstlineno,
                      co.co_lnotab,
                      co.co_freevars,
-                     co.co_cellvars)
+                     co.co_cellvars]
 
     def ascode(self):
+        if self.nested:
+            L = list(self.args[5])
+            for i, elt in zip(range(len(L)), L):
+                if isinstance(elt, CodeWrapper):
+                    L[i] = elt.ascode()
+            self.args[5] = tuple(L)
         return new.code(*self.args)
 
 def get_code_args(co):