Skip to content

Commit 7046170

Browse files
committed
Merge remote-tracking branch 'uqfoundation/master' into enums
2 parents 977089f + 914d47f commit 7046170

File tree

10 files changed

+277
-81
lines changed

10 files changed

+277
-81
lines changed

.travis.yml

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,11 @@ matrix:
88
env:
99
- COVERAGE="true"
1010

11-
- python: '3.6'
11+
- python: '3.7'
1212
env:
1313
- COVERAGE="true"
1414
- NUMPY="true"
1515

16-
- python: '3.7'
17-
env:
18-
1916
- python: '3.8'
2017
env:
2118

@@ -32,10 +29,6 @@ matrix:
3229
dist: xenial
3330
env:
3431

35-
- python: 'pypy3.6-7.3.3' # most recent
36-
dist: bionic
37-
env:
38-
3932
- python: 'pypy3.7-7.3.5' # most recent
4033
dist: bionic
4134
env:

dill/_dill.py

Lines changed: 198 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ def _trace(boolean):
4040
OLDER = (PY3 and sys.hexversion < 0x3040000) or (sys.hexversion < 0x2070ab1)
4141
OLD33 = (sys.hexversion < 0x3030000)
4242
OLD37 = (sys.hexversion < 0x3070000)
43+
OLD39 = (sys.hexversion < 0x3090000)
44+
OLD310 = (sys.hexversion < 0x30a0000)
4345
PY34 = (0x3040000 <= sys.hexversion < 0x3050000)
4446
if PY3: #XXX: get types from .objtypes ?
4547
import builtins as __builtin__
@@ -221,6 +223,14 @@ class _member(object):
221223
ItemGetterType = type(itemgetter(0))
222224
AttrGetterType = type(attrgetter('__repr__'))
223225

226+
try:
227+
from functools import _lru_cache_wrapper as LRUCacheType
228+
except:
229+
LRUCacheType = None
230+
231+
if not isinstance(LRUCacheType, type):
232+
LRUCacheType = None
233+
224234
def get_file_type(*args, **kwargs):
225235
open = kwargs.pop("open", __builtin__.open)
226236
f = open(os.devnull, *args, **kwargs)
@@ -528,7 +538,8 @@ def __init__(self, *args, **kwds):
528538
self._strictio = False #_strictio
529539
self._fmode = settings['fmode'] if _fmode is None else _fmode
530540
self._recurse = settings['recurse'] if _recurse is None else _recurse
531-
self._postproc = {}
541+
from collections import OrderedDict
542+
self._postproc = OrderedDict()
532543

533544
def dump(self, obj): #NOTE: if settings change, need to update attributes
534545
# register if the object is a numpy ufunc
@@ -923,6 +934,23 @@ def __getattribute__(self, attr):
923934
attrs[index] = ".".join([attrs[index], attr])
924935
return type(self)(attrs, index)
925936

937+
class _dictproxy_helper(dict):
938+
def __ror__(self, a):
939+
return a
940+
941+
_dictproxy_helper_instance = _dictproxy_helper()
942+
943+
__d = {}
944+
try:
945+
# In CPython 3.9 and later, this trick can be used to exploit the
946+
# implementation of the __or__ function of MappingProxyType to get the true
947+
# mapping referenced by the proxy. It may work for other implementations,
948+
# but is not guaranteed.
949+
MAPPING_PROXY_TRICK = __d is (DictProxyType(__d) | _dictproxy_helper_instance)
950+
except:
951+
MAPPING_PROXY_TRICK = False
952+
del __d
953+
926954
# _CELL_REF and _CELL_EMPTY are used to stay compatible with versions of dill
927955
# whose _create_cell functions do not have a default value.
928956
# _CELL_REF can be safely removed entirely (replaced by empty tuples for calls
@@ -1203,6 +1231,62 @@ def save_module_dict(pickler, obj):
12031231
log.info("# D2")
12041232
return
12051233

1234+
1235+
if not OLD310 and MAPPING_PROXY_TRICK:
1236+
def save_dict_view(dicttype):
1237+
def save_dict_view_for_function(func):
1238+
def _save_dict_view(pickler, obj):
1239+
log.info("Dkvi: <%s>" % (obj,))
1240+
mapping = obj.mapping | _dictproxy_helper_instance
1241+
pickler.save_reduce(func, (mapping,), obj=obj)
1242+
log.info("# Dkvi")
1243+
return _save_dict_view
1244+
return [
1245+
(funcname, save_dict_view_for_function(getattr(dicttype, funcname)))
1246+
for funcname in ('keys', 'values', 'items')
1247+
]
1248+
else:
1249+
# The following functions are based on 'cloudpickle'
1250+
# https://github.com/cloudpipe/cloudpickle/blob/5d89947288a18029672596a4d719093cc6d5a412/cloudpickle/cloudpickle.py#L922-L940
1251+
# Copyright (c) 2012, Regents of the University of California.
1252+
# Copyright (c) 2009 `PiCloud, Inc. <http://www.picloud.com>`_.
1253+
# License: https://github.com/cloudpipe/cloudpickle/blob/master/LICENSE
1254+
def save_dict_view(dicttype):
1255+
def save_dict_keys(pickler, obj):
1256+
log.info("Dk: <%s>" % (obj,))
1257+
dict_constructor = _shims.Reduce(dicttype.fromkeys, (list(obj),))
1258+
pickler.save_reduce(dicttype.keys, (dict_constructor,), obj=obj)
1259+
log.info("# Dk")
1260+
1261+
def save_dict_values(pickler, obj):
1262+
log.info("Dv: <%s>" % (obj,))
1263+
dict_constructor = _shims.Reduce(dicttype, (enumerate(obj),))
1264+
pickler.save_reduce(dicttype.values, (dict_constructor,), obj=obj)
1265+
log.info("# Dv")
1266+
1267+
def save_dict_items(pickler, obj):
1268+
log.info("Di: <%s>" % (obj,))
1269+
pickler.save_reduce(dicttype.items, (dicttype(obj),), obj=obj)
1270+
log.info("# Di")
1271+
1272+
return (
1273+
('keys', save_dict_keys),
1274+
('values', save_dict_values),
1275+
('items', save_dict_items)
1276+
)
1277+
1278+
for __dicttype in (
1279+
dict,
1280+
OrderedDict
1281+
):
1282+
__obj = __dicttype()
1283+
for __funcname, __savefunc in save_dict_view(__dicttype):
1284+
__tview = type(getattr(__obj, __funcname)())
1285+
if __tview not in Pickler.dispatch:
1286+
Pickler.dispatch[__tview] = __savefunc
1287+
del __dicttype, __obj, __funcname, __tview, __savefunc
1288+
1289+
12061290
@register(ClassType)
12071291
def save_classobj(pickler, obj): #FIXME: enable pickler._byref
12081292
if obj.__module__ == '__main__': #XXX: use _main_module.__name__ everywhere?
@@ -1243,24 +1327,25 @@ def save_socket(pickler, obj):
12431327
log.info("# So")
12441328
return
12451329

1246-
@register(ItemGetterType)
1247-
def save_itemgetter(pickler, obj):
1248-
log.info("Ig: %s" % obj)
1249-
helper = _itemgetter_helper()
1250-
obj(helper)
1251-
pickler.save_reduce(type(obj), tuple(helper.items), obj=obj)
1252-
log.info("# Ig")
1253-
return
1330+
if sys.hexversion <= 0x3050000:
1331+
@register(ItemGetterType)
1332+
def save_itemgetter(pickler, obj):
1333+
log.info("Ig: %s" % obj)
1334+
helper = _itemgetter_helper()
1335+
obj(helper)
1336+
pickler.save_reduce(type(obj), tuple(helper.items), obj=obj)
1337+
log.info("# Ig")
1338+
return
12541339

1255-
@register(AttrGetterType)
1256-
def save_attrgetter(pickler, obj):
1257-
log.info("Ag: %s" % obj)
1258-
attrs = []
1259-
helper = _attrgetter_helper(attrs)
1260-
obj(helper)
1261-
pickler.save_reduce(type(obj), tuple(attrs), obj=obj)
1262-
log.info("# Ag")
1263-
return
1340+
@register(AttrGetterType)
1341+
def save_attrgetter(pickler, obj):
1342+
log.info("Ag: %s" % obj)
1343+
attrs = []
1344+
helper = _attrgetter_helper(attrs)
1345+
obj(helper)
1346+
pickler.save_reduce(type(obj), tuple(attrs), obj=obj)
1347+
log.info("# Ag")
1348+
return
12641349

12651350
def _save_file(pickler, obj, open_):
12661351
if obj.closed:
@@ -1340,13 +1425,33 @@ def save_stringo(pickler, obj):
13401425
log.info("# Io")
13411426
return
13421427

1343-
@register(PartialType)
1344-
def save_functor(pickler, obj):
1345-
log.info("Fu: %s" % obj)
1346-
pickler.save_reduce(_create_ftype, (type(obj), obj.func, obj.args,
1347-
obj.keywords), obj=obj)
1348-
log.info("# Fu")
1349-
return
1428+
if 0x2050000 <= sys.hexversion < 0x3010000:
1429+
@register(PartialType)
1430+
def save_functor(pickler, obj):
1431+
log.info("Fu: %s" % obj)
1432+
pickler.save_reduce(_create_ftype, (type(obj), obj.func, obj.args,
1433+
obj.keywords), obj=obj)
1434+
log.info("# Fu")
1435+
return
1436+
1437+
if LRUCacheType is not None:
1438+
from functools import lru_cache
1439+
@register(LRUCacheType)
1440+
def save_lru_cache(pickler, obj):
1441+
log.info("LRU: %s" % obj)
1442+
if OLD39:
1443+
kwargs = obj.cache_info()
1444+
args = (kwargs.maxsize,)
1445+
else:
1446+
kwargs = obj.cache_parameters()
1447+
args = (kwargs['maxsize'], kwargs['typed'])
1448+
if args != lru_cache.__defaults__:
1449+
wrapper = Reduce(lru_cache, args, is_callable=True)
1450+
else:
1451+
wrapper = lru_cache
1452+
pickler.save_reduce(wrapper, (obj.__wrapped__,), obj=obj)
1453+
log.info("# LRU")
1454+
return
13501455

13511456
@register(SuperType)
13521457
def save_super(pickler, obj):
@@ -1355,41 +1460,42 @@ def save_super(pickler, obj):
13551460
log.info("# Su")
13561461
return
13571462

1358-
@register(BuiltinMethodType)
1359-
def save_builtin_method(pickler, obj):
1360-
if obj.__self__ is not None:
1361-
if obj.__self__ is __builtin__:
1362-
module = 'builtins' if PY3 else '__builtin__'
1363-
_t = "B1"
1364-
log.info("%s: %s" % (_t, obj))
1463+
if OLDER or not PY3:
1464+
@register(BuiltinMethodType)
1465+
def save_builtin_method(pickler, obj):
1466+
if obj.__self__ is not None:
1467+
if obj.__self__ is __builtin__:
1468+
module = 'builtins' if PY3 else '__builtin__'
1469+
_t = "B1"
1470+
log.info("%s: %s" % (_t, obj))
1471+
else:
1472+
module = obj.__self__
1473+
_t = "B3"
1474+
log.info("%s: %s" % (_t, obj))
1475+
if is_dill(pickler, child=True):
1476+
_recurse = pickler._recurse
1477+
pickler._recurse = False
1478+
pickler.save_reduce(_get_attr, (module, obj.__name__), obj=obj)
1479+
if is_dill(pickler, child=True):
1480+
pickler._recurse = _recurse
1481+
log.info("# %s" % _t)
13651482
else:
1366-
module = obj.__self__
1367-
_t = "B3"
1368-
log.info("%s: %s" % (_t, obj))
1369-
if is_dill(pickler, child=True):
1370-
_recurse = pickler._recurse
1371-
pickler._recurse = False
1372-
pickler.save_reduce(_get_attr, (module, obj.__name__), obj=obj)
1373-
if is_dill(pickler, child=True):
1374-
pickler._recurse = _recurse
1375-
log.info("# %s" % _t)
1376-
else:
1377-
log.info("B2: %s" % obj)
1378-
name = getattr(obj, '__qualname__', getattr(obj, '__name__', None))
1379-
StockPickler.save_global(pickler, obj, name=name)
1380-
log.info("# B2")
1381-
return
1483+
log.info("B2: %s" % obj)
1484+
name = getattr(obj, '__qualname__', getattr(obj, '__name__', None))
1485+
StockPickler.save_global(pickler, obj, name=name)
1486+
log.info("# B2")
1487+
return
13821488

1383-
@register(MethodType) #FIXME: fails for 'hidden' or 'name-mangled' classes
1384-
def save_instancemethod0(pickler, obj):# example: cStringIO.StringI
1385-
log.info("Me: %s" % obj) #XXX: obj.__dict__ handled elsewhere?
1386-
if PY3:
1387-
pickler.save_reduce(MethodType, (obj.__func__, obj.__self__), obj=obj)
1388-
else:
1389-
pickler.save_reduce(MethodType, (obj.im_func, obj.im_self,
1390-
obj.im_class), obj=obj)
1391-
log.info("# Me")
1392-
return
1489+
@register(MethodType) #FIXME: fails for 'hidden' or 'name-mangled' classes
1490+
def save_instancemethod0(pickler, obj):# example: cStringIO.StringI
1491+
log.info("Me: %s" % obj) #XXX: obj.__dict__ handled elsewhere?
1492+
if PY3:
1493+
pickler.save_reduce(MethodType, (obj.__func__, obj.__self__), obj=obj)
1494+
else:
1495+
pickler.save_reduce(MethodType, (obj.im_func, obj.im_self,
1496+
obj.im_class), obj=obj)
1497+
log.info("# Me")
1498+
return
13931499

13941500
if sys.hexversion >= 0x20500f0:
13951501
if not IS_PYPY:
@@ -1462,22 +1568,30 @@ def save_cell(pickler, obj):
14621568
log.info("# Ce3")
14631569
return
14641570
if is_dill(pickler, child=True):
1465-
postproc = pickler._postproc.get(id(f))
1571+
postproc = next(iter(pickler._postproc.values()), None)
14661572
if postproc is not None:
14671573
log.info("Ce2: %s" % obj)
14681574
# _CELL_REF is defined in _shims.py to support older versions of
14691575
# dill. When breaking changes are made to dill, (_CELL_REF,) can
14701576
# be replaced by ()
1471-
postproc.append((_shims._setattr, (obj, 'cell_contents', f)))
14721577
pickler.save_reduce(_create_cell, (_CELL_REF,), obj=obj)
1578+
postproc.append((_shims._setattr, (obj, 'cell_contents', f)))
14731579
log.info("# Ce2")
14741580
return
14751581
log.info("Ce1: %s" % obj)
14761582
pickler.save_reduce(_create_cell, (f,), obj=obj)
14771583
log.info("# Ce1")
14781584
return
14791585

1480-
if not IS_PYPY:
1586+
if MAPPING_PROXY_TRICK:
1587+
@register(DictProxyType)
1588+
def save_dictproxy(pickler, obj):
1589+
log.info("Mp: %s" % obj)
1590+
mapping = obj | _dictproxy_helper_instance
1591+
pickler.save_reduce(DictProxyType, (mapping,), obj=obj)
1592+
log.info("# Mp")
1593+
return
1594+
elif not IS_PYPY:
14811595
if not OLD33:
14821596
@register(DictProxyType)
14831597
def save_dictproxy(pickler, obj):
@@ -1884,16 +1998,37 @@ def save_function(pickler, obj):
18841998
postproc_list.append((_setitems, (globs, globs_copy)))
18851999

18862000
if PY3:
2001+
closure = obj.__closure__
18872002
fkwdefaults = getattr(obj, '__kwdefaults__', None)
18882003
_save_with_postproc(pickler, (_create_function, (
18892004
obj.__code__, globs, obj.__name__, obj.__defaults__,
1890-
obj.__closure__, obj.__dict__, fkwdefaults
2005+
closure, obj.__dict__, fkwdefaults
18912006
)), obj=obj, postproc_list=postproc_list)
18922007
else:
2008+
closure = obj.func_closure
18932009
_save_with_postproc(pickler, (_create_function, (
18942010
obj.func_code, globs, obj.func_name, obj.func_defaults,
1895-
obj.func_closure, obj.__dict__
2011+
closure, obj.__dict__
18962012
)), obj=obj, postproc_list=postproc_list)
2013+
2014+
# Lift closure cell update to earliest function (#458)
2015+
topmost_postproc = next(iter(pickler._postproc.values()), None)
2016+
if closure and topmost_postproc:
2017+
for cell in closure:
2018+
possible_postproc = (setattr, (cell, 'cell_contents', obj))
2019+
try:
2020+
topmost_postproc.remove(possible_postproc)
2021+
except ValueError:
2022+
continue
2023+
2024+
# Change the value of the cell
2025+
pickler.save_reduce(*possible_postproc)
2026+
# pop None created by calling preprocessing step off stack
2027+
if PY3:
2028+
pickler.write(bytes('0', 'UTF-8'))
2029+
else:
2030+
pickler.write('0')
2031+
18972032
log.info("# F1")
18982033
else:
18992034
log.info("F2: %s" % obj)

dill/_shims.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
#
33
# Author: Mike McKerns (mmckerns @caltech and @uqfoundation)
44
# Author: Anirudh Vegesana ([email protected])
5-
# Copyright (c) 2021 The Uncertainty Quantification Foundation.
5+
# Copyright (c) 2021-2022 The Uncertainty Quantification Foundation.
66
# License: 3-clause BSD. The full license text is available at:
77
# - https://github.com/uqfoundation/dill/blob/master/LICENSE
88
"""

dill/source.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -644,7 +644,7 @@ def _namespace(obj):
644644
# mostly for functions and modules and such
645645
#FIXME: 'wrong' for decorators and curried functions
646646
try: #XXX: needs some work and testing on different types
647-
module = qual = str(getmodule(obj)).split()[1].strip('"').strip("'")
647+
module = qual = str(getmodule(obj)).split()[1].strip('>').strip('"').strip("'")
648648
qual = qual.split('.')
649649
if ismodule(obj):
650650
return qual

0 commit comments

Comments
 (0)