@@ -40,6 +40,8 @@ def _trace(boolean):
4040OLDER = (PY3 and sys .hexversion < 0x3040000 ) or (sys .hexversion < 0x2070ab1 )
4141OLD33 = (sys .hexversion < 0x3030000 )
4242OLD37 = (sys .hexversion < 0x3070000 )
43+ OLD39 = (sys .hexversion < 0x3090000 )
44+ OLD310 = (sys .hexversion < 0x30a0000 )
4345PY34 = (0x3040000 <= sys .hexversion < 0x3050000 )
4446if PY3 : #XXX: get types from .objtypes ?
4547 import builtins as __builtin__
@@ -219,6 +221,14 @@ class _member(object):
219221ItemGetterType = type (itemgetter (0 ))
220222AttrGetterType = type (attrgetter ('__repr__' ))
221223
224+ try :
225+ from functools import _lru_cache_wrapper as LRUCacheType
226+ except :
227+ LRUCacheType = None
228+
229+ if not isinstance (LRUCacheType , type ):
230+ LRUCacheType = None
231+
222232def get_file_type (* args , ** kwargs ):
223233 open = kwargs .pop ("open" , __builtin__ .open )
224234 f = open (os .devnull , * args , ** kwargs )
@@ -262,6 +272,8 @@ def get_file_type(*args, **kwargs):
262272 except NameError : ExitType = None
263273 singletontypes = []
264274
275+ from collections import OrderedDict
276+
265277import inspect
266278
267279### Shims for different versions of Python and dill
@@ -914,6 +926,23 @@ def __getattribute__(self, attr):
914926 attrs [index ] = "." .join ([attrs [index ], attr ])
915927 return type (self )(attrs , index )
916928
929+ class _dictproxy_helper (dict ):
930+ def __ror__ (self , a ):
931+ return a
932+
933+ _dictproxy_helper_instance = _dictproxy_helper ()
934+
935+ __d = {}
936+ try :
937+ # In CPython 3.9 and later, this trick can be used to exploit the
938+ # implementation of the __or__ function of MappingProxyType to get the true
939+ # mapping referenced by the proxy. It may work for other implementations,
940+ # but is not guaranteed.
941+ MAPPING_PROXY_TRICK = __d is (DictProxyType (__d ) | _dictproxy_helper_instance )
942+ except :
943+ MAPPING_PROXY_TRICK = False
944+ del __d
945+
917946# _CELL_REF and _CELL_EMPTY are used to stay compatible with versions of dill
918947# whose _create_cell functions do not have a default value.
919948# _CELL_REF can be safely removed entirely (replaced by empty tuples for calls
@@ -1166,6 +1195,62 @@ def save_module_dict(pickler, obj):
11661195 log .info ("# D2" )
11671196 return
11681197
1198+
1199+ if not OLD310 and MAPPING_PROXY_TRICK :
1200+ def save_dict_view (dicttype ):
1201+ def save_dict_view_for_function (func ):
1202+ def _save_dict_view (pickler , obj ):
1203+ log .info ("Dkvi: <%s>" % (obj ,))
1204+ mapping = obj .mapping | _dictproxy_helper_instance
1205+ pickler .save_reduce (func , (mapping ,), obj = obj )
1206+ log .info ("# Dkvi" )
1207+ return _save_dict_view
1208+ return [
1209+ (funcname , save_dict_view_for_function (getattr (dicttype , funcname )))
1210+ for funcname in ('keys' , 'values' , 'items' )
1211+ ]
1212+ else :
1213+ # The following functions are based on 'cloudpickle'
1214+ # https://github.com/cloudpipe/cloudpickle/blob/5d89947288a18029672596a4d719093cc6d5a412/cloudpickle/cloudpickle.py#L922-L940
1215+ # Copyright (c) 2012, Regents of the University of California.
1216+ # Copyright (c) 2009 `PiCloud, Inc. <http://www.picloud.com>`_.
1217+ # License: https://github.com/cloudpipe/cloudpickle/blob/master/LICENSE
1218+ def save_dict_view (dicttype ):
1219+ def save_dict_keys (pickler , obj ):
1220+ log .info ("Dk: <%s>" % (obj ,))
1221+ dict_constructor = _shims .Reduce (dicttype .fromkeys , (list (obj ),))
1222+ pickler .save_reduce (dicttype .keys , (dict_constructor ,), obj = obj )
1223+ log .info ("# Dk" )
1224+
1225+ def save_dict_values (pickler , obj ):
1226+ log .info ("Dv: <%s>" % (obj ,))
1227+ dict_constructor = _shims .Reduce (dicttype , (enumerate (obj ),))
1228+ pickler .save_reduce (dicttype .values , (dict_constructor ,), obj = obj )
1229+ log .info ("# Dv" )
1230+
1231+ def save_dict_items (pickler , obj ):
1232+ log .info ("Di: <%s>" % (obj ,))
1233+ pickler .save_reduce (dicttype .items , (dicttype (obj ),), obj = obj )
1234+ log .info ("# Di" )
1235+
1236+ return (
1237+ ('keys' , save_dict_keys ),
1238+ ('values' , save_dict_values ),
1239+ ('items' , save_dict_items )
1240+ )
1241+
1242+ for __dicttype in (
1243+ dict ,
1244+ OrderedDict
1245+ ):
1246+ __obj = __dicttype ()
1247+ for __funcname , __savefunc in save_dict_view (__dicttype ):
1248+ __tview = type (getattr (__obj , __funcname )())
1249+ if __tview not in Pickler .dispatch :
1250+ Pickler .dispatch [__tview ] = __savefunc
1251+ del __dicttype , __obj , __funcname , __tview , __savefunc
1252+
1253+
11691254@register (ClassType )
11701255def save_classobj (pickler , obj ): #FIXME: enable pickler._byref
11711256 if obj .__module__ == '__main__' : #XXX: use _main_module.__name__ everywhere?
@@ -1206,24 +1291,25 @@ def save_socket(pickler, obj):
12061291 log .info ("# So" )
12071292 return
12081293
1209- @register (ItemGetterType )
1210- def save_itemgetter (pickler , obj ):
1211- log .info ("Ig: %s" % obj )
1212- helper = _itemgetter_helper ()
1213- obj (helper )
1214- pickler .save_reduce (type (obj ), tuple (helper .items ), obj = obj )
1215- log .info ("# Ig" )
1216- return
1294+ if sys .hexversion <= 0x3050000 :
1295+ @register (ItemGetterType )
1296+ def save_itemgetter (pickler , obj ):
1297+ log .info ("Ig: %s" % obj )
1298+ helper = _itemgetter_helper ()
1299+ obj (helper )
1300+ pickler .save_reduce (type (obj ), tuple (helper .items ), obj = obj )
1301+ log .info ("# Ig" )
1302+ return
12171303
1218- @register (AttrGetterType )
1219- def save_attrgetter (pickler , obj ):
1220- log .info ("Ag: %s" % obj )
1221- attrs = []
1222- helper = _attrgetter_helper (attrs )
1223- obj (helper )
1224- pickler .save_reduce (type (obj ), tuple (attrs ), obj = obj )
1225- log .info ("# Ag" )
1226- return
1304+ @register (AttrGetterType )
1305+ def save_attrgetter (pickler , obj ):
1306+ log .info ("Ag: %s" % obj )
1307+ attrs = []
1308+ helper = _attrgetter_helper (attrs )
1309+ obj (helper )
1310+ pickler .save_reduce (type (obj ), tuple (attrs ), obj = obj )
1311+ log .info ("# Ag" )
1312+ return
12271313
12281314def _save_file (pickler , obj , open_ ):
12291315 if obj .closed :
@@ -1303,13 +1389,33 @@ def save_stringo(pickler, obj):
13031389 log .info ("# Io" )
13041390 return
13051391
1306- @register (PartialType )
1307- def save_functor (pickler , obj ):
1308- log .info ("Fu: %s" % obj )
1309- pickler .save_reduce (_create_ftype , (type (obj ), obj .func , obj .args ,
1310- obj .keywords ), obj = obj )
1311- log .info ("# Fu" )
1312- return
1392+ if 0x2050000 <= sys .hexversion < 0x3010000 :
1393+ @register (PartialType )
1394+ def save_functor (pickler , obj ):
1395+ log .info ("Fu: %s" % obj )
1396+ pickler .save_reduce (_create_ftype , (type (obj ), obj .func , obj .args ,
1397+ obj .keywords ), obj = obj )
1398+ log .info ("# Fu" )
1399+ return
1400+
1401+ if LRUCacheType is not None :
1402+ from functools import lru_cache
1403+ @register (LRUCacheType )
1404+ def save_lru_cache (pickler , obj ):
1405+ log .info ("LRU: %s" % obj )
1406+ if OLD39 :
1407+ kwargs = obj .cache_info ()
1408+ args = (kwargs .maxsize ,)
1409+ else :
1410+ kwargs = obj .cache_parameters ()
1411+ args = (kwargs ['maxsize' ], kwargs ['typed' ])
1412+ if args != lru_cache .__defaults__ :
1413+ wrapper = Reduce (lru_cache , args , is_callable = True )
1414+ else :
1415+ wrapper = lru_cache
1416+ pickler .save_reduce (wrapper , (obj .__wrapped__ ,), obj = obj )
1417+ log .info ("# LRU" )
1418+ return
13131419
13141420@register (SuperType )
13151421def save_super (pickler , obj ):
@@ -1318,41 +1424,42 @@ def save_super(pickler, obj):
13181424 log .info ("# Su" )
13191425 return
13201426
1321- @register (BuiltinMethodType )
1322- def save_builtin_method (pickler , obj ):
1323- if obj .__self__ is not None :
1324- if obj .__self__ is __builtin__ :
1325- module = 'builtins' if PY3 else '__builtin__'
1326- _t = "B1"
1327- log .info ("%s: %s" % (_t , obj ))
1427+ if OLDER or not PY3 :
1428+ @register (BuiltinMethodType )
1429+ def save_builtin_method (pickler , obj ):
1430+ if obj .__self__ is not None :
1431+ if obj .__self__ is __builtin__ :
1432+ module = 'builtins' if PY3 else '__builtin__'
1433+ _t = "B1"
1434+ log .info ("%s: %s" % (_t , obj ))
1435+ else :
1436+ module = obj .__self__
1437+ _t = "B3"
1438+ log .info ("%s: %s" % (_t , obj ))
1439+ if is_dill (pickler , child = True ):
1440+ _recurse = pickler ._recurse
1441+ pickler ._recurse = False
1442+ pickler .save_reduce (_get_attr , (module , obj .__name__ ), obj = obj )
1443+ if is_dill (pickler , child = True ):
1444+ pickler ._recurse = _recurse
1445+ log .info ("# %s" % _t )
13281446 else :
1329- module = obj .__self__
1330- _t = "B3"
1331- log .info ("%s: %s" % (_t , obj ))
1332- if is_dill (pickler , child = True ):
1333- _recurse = pickler ._recurse
1334- pickler ._recurse = False
1335- pickler .save_reduce (_get_attr , (module , obj .__name__ ), obj = obj )
1336- if is_dill (pickler , child = True ):
1337- pickler ._recurse = _recurse
1338- log .info ("# %s" % _t )
1339- else :
1340- log .info ("B2: %s" % obj )
1341- name = getattr (obj , '__qualname__' , getattr (obj , '__name__' , None ))
1342- StockPickler .save_global (pickler , obj , name = name )
1343- log .info ("# B2" )
1344- return
1447+ log .info ("B2: %s" % obj )
1448+ name = getattr (obj , '__qualname__' , getattr (obj , '__name__' , None ))
1449+ StockPickler .save_global (pickler , obj , name = name )
1450+ log .info ("# B2" )
1451+ return
13451452
1346- @register (MethodType ) #FIXME: fails for 'hidden' or 'name-mangled' classes
1347- def save_instancemethod0 (pickler , obj ):# example: cStringIO.StringI
1348- log .info ("Me: %s" % obj ) #XXX: obj.__dict__ handled elsewhere?
1349- if PY3 :
1350- pickler .save_reduce (MethodType , (obj .__func__ , obj .__self__ ), obj = obj )
1351- else :
1352- pickler .save_reduce (MethodType , (obj .im_func , obj .im_self ,
1353- obj .im_class ), obj = obj )
1354- log .info ("# Me" )
1355- return
1453+ @register (MethodType ) #FIXME: fails for 'hidden' or 'name-mangled' classes
1454+ def save_instancemethod0 (pickler , obj ):# example: cStringIO.StringI
1455+ log .info ("Me: %s" % obj ) #XXX: obj.__dict__ handled elsewhere?
1456+ if PY3 :
1457+ pickler .save_reduce (MethodType , (obj .__func__ , obj .__self__ ), obj = obj )
1458+ else :
1459+ pickler .save_reduce (MethodType , (obj .im_func , obj .im_self ,
1460+ obj .im_class ), obj = obj )
1461+ log .info ("# Me" )
1462+ return
13561463
13571464if sys .hexversion >= 0x20500f0 :
13581465 if not IS_PYPY :
@@ -1440,7 +1547,15 @@ def save_cell(pickler, obj):
14401547 log .info ("# Ce1" )
14411548 return
14421549
1443- if not IS_PYPY :
1550+ if MAPPING_PROXY_TRICK :
1551+ @register (DictProxyType )
1552+ def save_dictproxy (pickler , obj ):
1553+ log .info ("Mp: %s" % obj )
1554+ mapping = obj | _dictproxy_helper_instance
1555+ pickler .save_reduce (DictProxyType , (mapping ,), obj = obj )
1556+ log .info ("# Mp" )
1557+ return
1558+ elif not IS_PYPY :
14441559 if not OLD33 :
14451560 @register (DictProxyType )
14461561 def save_dictproxy (pickler , obj ):
0 commit comments