@@ -1184,12 +1184,13 @@ def _repr_dict(obj):
1184
1184
1185
1185
@register (dict )
1186
1186
def save_module_dict (pickler , obj ):
1187
- if is_dill (pickler , child = False ) and obj == pickler ._main .__dict__ and \
1187
+ _is_dill = is_dill (pickler , child = False )
1188
+ if _is_dill and obj == pickler ._main .__dict__ and \
1188
1189
not (pickler ._session and pickler ._first_pass ):
1189
1190
logger .trace (pickler , "D1: %s" , _repr_dict (obj )) # obj
1190
1191
pickler .write (bytes ('c__builtin__\n __main__\n ' , 'UTF-8' ))
1191
1192
logger .trace (pickler , "# D1" )
1192
- elif (not is_dill ( pickler , child = False ) ) and (obj == _main_module .__dict__ ):
1193
+ elif (not _is_dill ) and (obj == _main_module .__dict__ ):
1193
1194
logger .trace (pickler , "D3: %s" , _repr_dict (obj )) # obj
1194
1195
pickler .write (bytes ('c__main__\n __dict__\n ' , 'UTF-8' )) #XXX: works in general?
1195
1196
logger .trace (pickler , "# D3" )
@@ -1199,12 +1200,37 @@ def save_module_dict(pickler, obj):
1199
1200
logger .trace (pickler , "D4: %s" , _repr_dict (obj )) # obj
1200
1201
pickler .write (bytes ('c%s\n __dict__\n ' % obj ['__name__' ], 'UTF-8' ))
1201
1202
logger .trace (pickler , "# D4" )
1203
+ elif _is_dill and id (obj ) in pickler ._globals_cache :
1204
+ logger .trace (pickler , "D5: %s" , _repr_dict (obj )) # obj
1205
+ # This is a globals dictionary that was partially copied, but not fully saved.
1206
+ # Save the dictionary again to ensure that everything is there.
1207
+ globs_copy = pickler ._globals_cache [id (obj )]
1208
+ pickler .write (pickler .get (pickler .memo [id (globs_copy )][0 ]))
1209
+ pickler ._batch_setitems (iter (obj .items ()))
1210
+ del pickler ._globals_cache [id (obj )]
1211
+ pickler .memo [id (obj )] = (pickler .memo .pop (id (globs_copy ))[0 ], obj )
1212
+ logger .trace (pickler , "# D5" )
1202
1213
else :
1203
1214
logger .trace (pickler , "D2: %s" , _repr_dict (obj )) # obj
1204
- if is_dill ( pickler , child = False ) and pickler ._session :
1215
+ if _is_dill and pickler ._session :
1205
1216
# we only care about session the first pass thru
1206
1217
pickler ._first_pass = False
1207
- StockPickler .save_dict (pickler , obj )
1218
+
1219
+ from pickle import EMPTY_DICT , MARK , DICT , SETITEM
1220
+ if pickler .bin :
1221
+ pickler .write (EMPTY_DICT )
1222
+ else : # proto 0 -- can't use EMPTY_DICT
1223
+ pickler .write (MARK + DICT )
1224
+
1225
+ # StockPickler.save_dict(pickler, obj)
1226
+ pickler .memoize (obj )
1227
+ # add __name__ first
1228
+ if '__name__' in obj :
1229
+ pickler .save ('__name__' )
1230
+ pickler .save (obj ['__name__' ])
1231
+ pickler .write (SETITEM )
1232
+ pickler ._batch_setitems (obj .items ())
1233
+
1208
1234
logger .trace (pickler , "# D2" )
1209
1235
return
1210
1236
@@ -1797,7 +1823,11 @@ def save_function(pickler, obj):
1797
1823
postproc_list = []
1798
1824
1799
1825
globs = None
1800
- if _recurse :
1826
+ if id (obj .__globals__ ) in pickler .memo :
1827
+ # It is possible that the globals dictionary itself is also being
1828
+ # pickled directly.
1829
+ globs = globs_copy = obj .__globals__
1830
+ elif _recurse :
1801
1831
# recurse to get all globals referred to by obj
1802
1832
from .detect import globalvars
1803
1833
globs_copy = globalvars (obj , recurse = True , builtin = True )
0 commit comments