Skip to content

Commit

Permalink
fix: #528, test_registered syncs objects w typemap
Browse files Browse the repository at this point in the history
  • Loading branch information
mmckerns committed Jul 21, 2022
1 parent 74e0fd4 commit 990b5a1
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 34 deletions.
9 changes: 7 additions & 2 deletions dill/_dill.py
Original file line number Diff line number Diff line change
Expand Up @@ -1053,12 +1053,15 @@ def _create_typemap():
return
_reverse_typemap = dict(_create_typemap())
_reverse_typemap.update({
'CellType': CellType,
'PartialType': PartialType,
'SuperType': SuperType,
'ItemGetterType': ItemGetterType,
'AttrGetterType': AttrGetterType,
})
if sys.hexversion < 0x30800a2:
_reverse_typemap.update({
'CellType': CellType,
})

# "Incidental" implementation specific types. Unpickling these types in another
# implementation of Python (PyPy -> CPython) is not guaranteed to work
Expand Down Expand Up @@ -1100,15 +1103,17 @@ def _create_typemap():
_incedental_reverse_typemap["SymtableEntryType"] = type(symtable.symtable("", "string", "exec")._table)
except: #FIXME: fails to pickle
pass
'''
if sys.hexversion >= 0x30a00a0:
_incedental_reverse_typemap['LineIteratorType'] = type(compile('3', '', 'eval').co_lines())
'''

if sys.hexversion >= 0x30b00b0:
from types import GenericAlias
_incedental_reverse_typemap["GenericAliasIteratorType"] = type(iter(GenericAlias(list, (int,))))
'''
_incedental_reverse_typemap['PositionsIteratorType'] = type(compile('3', '', 'eval').co_positions())
'''

try:
import winreg
Expand Down
80 changes: 48 additions & 32 deletions dill/_objects.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,23 +172,25 @@ class _Struct(ctypes.Structure):
a['OptionGroupType'] = optparse.OptionGroup(_oparser,"foo") # pickle ok
a['OptionType'] = optparse.Option('--foo') # pickle ok
if HAS_CTYPES:
a['CCharType'] = _cchar = ctypes.c_char()
a['CWCharType'] = ctypes.c_wchar() # fail == 2.6
a['CByteType'] = ctypes.c_byte()
a['CUByteType'] = ctypes.c_ubyte()
a['CShortType'] = ctypes.c_short()
a['CUShortType'] = ctypes.c_ushort()
a['CIntType'] = ctypes.c_int()
a['CUIntType'] = ctypes.c_uint()
a['CLongType'] = ctypes.c_long()
a['CULongType'] = ctypes.c_ulong()
a['CLongLongType'] = ctypes.c_longlong()
a['CULongLongType'] = ctypes.c_ulonglong()
a['CFloatType'] = ctypes.c_float()
a['CDoubleType'] = ctypes.c_double()
a['CSizeTType'] = ctypes.c_size_t()
z = x if IS_PYPY else a
z['CCharType'] = _cchar = ctypes.c_char()
z['CWCharType'] = ctypes.c_wchar() # fail == 2.6
z['CByteType'] = ctypes.c_byte()
z['CUByteType'] = ctypes.c_ubyte()
z['CShortType'] = ctypes.c_short()
z['CUShortType'] = ctypes.c_ushort()
z['CIntType'] = ctypes.c_int()
z['CUIntType'] = ctypes.c_uint()
z['CLongType'] = ctypes.c_long()
z['CULongType'] = ctypes.c_ulong()
z['CLongLongType'] = ctypes.c_longlong()
z['CULongLongType'] = ctypes.c_ulonglong()
z['CFloatType'] = ctypes.c_float()
z['CDoubleType'] = ctypes.c_double()
z['CSizeTType'] = ctypes.c_size_t()
x['CLibraryLoaderType'] = ctypes.cdll
a['StructureType'] = _Struct
del z
# if not IS_PYPY:
# a['BigEndianStructureType'] = ctypes.BigEndianStructure()
#NOTE: also LittleEndianStructureType and UnionType... abstract classes
Expand All @@ -212,14 +214,18 @@ class _Struct(ctypes.Structure):
a['UnicodeIOType'] = TextIO() # the new StringIO
a['LoggerAdapterType'] = logging.LoggerAdapter(_logger,_dict) # pickle ok
if HAS_CTYPES:
a['CBoolType'] = ctypes.c_bool(1)
a['CLongDoubleType'] = ctypes.c_longdouble()
z = x if IS_PYPY else a
z['CBoolType'] = ctypes.c_bool(1)
z['CLongDoubleType'] = ctypes.c_longdouble()
del z
import argparse
# data types (CH 8)
a['OrderedDictType'] = collections.OrderedDict(_dict)
a['CounterType'] = collections.Counter(_dict)
if HAS_CTYPES:
a['CSSizeTType'] = ctypes.c_ssize_t()
z = x if IS_PYPY else a
z['CSSizeTType'] = ctypes.c_ssize_t()
del z
# generic operating system services (CH 15)
a['NullHandlerType'] = logging.NullHandler() # pickle ok # new 2.7
a['ArgParseFileType'] = argparse.FileType() # pickle ok
Expand Down Expand Up @@ -254,7 +260,9 @@ class _Struct(ctypes.Structure):
except ImportError:
pass
# other (concrete) object types
d['CellType'] = (_lambda)(0).__closure__[0]
z = d if sys.hexversion < 0x30800a2 else a
z['CellType'] = (_lambda)(0).__closure__[0]
del z
a['XRangeType'] = _xrange = range(1)
a['MethodDescriptorType'] = type.__dict__['mro']
a['WrapperDescriptorType'] = type.__repr__
Expand Down Expand Up @@ -360,7 +368,9 @@ class _Struct(ctypes.Structure):
a['XRangeIteratorType'] = iter(_xrange) # empty vs non-empty
a["BytesIteratorType"] = iter(b'')
a["BytearrayIteratorType"] = iter(bytearray(b''))
a["CallableIteratorType"] = iter(iter, None)
z = x if IS_PYPY else a
z["CallableIteratorType"] = iter(iter, None)
del z
x["MemoryIteratorType"] = iter(memoryview(b''))
a["ListReverseiteratorType"] = reversed([])
X = a['OrderedDictType']
Expand All @@ -386,12 +396,12 @@ class _Struct(ctypes.Structure):
pass

if sys.hexversion >= 0x30a00a0:
a['LineIteratorType'] = compile('3', '', 'eval').co_lines()
x['LineIteratorType'] = compile('3', '', 'eval').co_lines()

if sys.hexversion >= 0x30b00b0:
from types import GenericAlias
a["GenericAliasIteratorType"] = iter(GenericAlias(list, (int,)))
a['PositionsIteratorType'] = compile('3', '', 'eval').co_positions()
d["GenericAliasIteratorType"] = iter(GenericAlias(list, (int,)))
x['PositionsIteratorType'] = compile('3', '', 'eval').co_positions()

# data types (CH 8)
a['PrettyPrinterType'] = pprint.PrettyPrinter()
Expand Down Expand Up @@ -428,7 +438,9 @@ class _Struct(ctypes.Structure):
# python object persistence (CH 11)
# x['DbShelveType'] = shelve.open('foo','n')#,protocol=2) #XXX: delete foo
if HAS_ALL:
x['DbmType'] = dbm.open(_tempfile,'n')
z = a if IS_PYPY else x
z['DbmType'] = dbm.open(_tempfile,'n')
del z
# x['DbCursorType'] = _dbcursor = anydbm.open('foo','n') #XXX: delete foo
# x['DbType'] = _dbcursor.db
# data compression and archiving (CH 12)
Expand Down Expand Up @@ -469,9 +481,11 @@ class _Struct(ctypes.Structure):
x['NullPtrType'] = _lpchar()
x['NullPyObjectType'] = ctypes.py_object()
x['PyObjectType'] = ctypes.py_object(lambda :None)
x['FieldType'] = _field = _Struct._field
x['CFUNCTYPEType'] = _cfunc = ctypes.CFUNCTYPE(ctypes.c_char)
z = a if IS_PYPY else x
z['FieldType'] = _field = _Struct._field
z['CFUNCTYPEType'] = _cfunc = ctypes.CFUNCTYPE(ctypes.c_char)
x['CFunctionType'] = _cfunc(str)
del z
# numeric and mathematical types (CH 9)
a['MethodCallerType'] = operator.methodcaller('mro') # 2.6
# built-in types (CH 5)
Expand All @@ -484,8 +498,10 @@ class _Struct(ctypes.Structure):
a['RawTextHelpFormatterType'] = argparse.RawTextHelpFormatter('PROG')
a['RawDescriptionHelpFormatterType'] = argparse.RawDescriptionHelpFormatter('PROG')
a['ArgDefaultsHelpFormatterType'] = argparse.ArgumentDefaultsHelpFormatter('PROG')
x['CmpKeyType'] = _cmpkey = functools.cmp_to_key(_methodwrap) # 2.7, >=3.2
x['CmpKeyObjType'] = _cmpkey('0') #2.7, >=3.2
z = a if IS_PYPY else x
z['CmpKeyType'] = _cmpkey = functools.cmp_to_key(_methodwrap) # 2.7, >=3.2
z['CmpKeyObjType'] = _cmpkey('0') #2.7, >=3.2
del z
# oddities: removed, etc
x['BufferType'] = x['MemoryType']

Expand All @@ -495,16 +511,16 @@ class _Struct(ctypes.Structure):
del _testcapsule

if hasattr(dataclasses, '_HAS_DEFAULT_FACTORY'):
x['DataclassesHasDefaultFactoryType'] = dataclasses._HAS_DEFAULT_FACTORY
a['DataclassesHasDefaultFactoryType'] = dataclasses._HAS_DEFAULT_FACTORY

if hasattr(dataclasses, 'MISSING'):
x['DataclassesMissingType'] = dataclasses.MISSING
a['DataclassesMissingType'] = dataclasses.MISSING

if hasattr(dataclasses, 'KW_ONLY'):
x['DataclassesKWOnlyType'] = dataclasses.KW_ONLY
a['DataclassesKWOnlyType'] = dataclasses.KW_ONLY

if hasattr(dataclasses, '_FIELD_BASE'):
x['DataclassesFieldBaseType'] = dataclasses._FIELD
a['DataclassesFieldBaseType'] = dataclasses._FIELD

# -- cleanup ----------------------------------------------------------------
a.update(d) # registered also succeed
Expand Down
26 changes: 26 additions & 0 deletions dill/tests/test_registered.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import dill
from dill._objects import failures, registered, succeeds
import warnings
warnings.filterwarnings('ignore')

def check(d, ok=True):
res = []
for k,v in d.items():
try:
z = dill.copy(v)
if ok: res.append(k)
except:
if not ok: res.append(k)
return res

assert not bool(check(failures))
assert not bool(check(registered, ok=False))
assert not bool(check(succeeds, ok=False))

import builtins
import types
q = dill._dill._reverse_typemap
p = {k:v for k,v in q.items() if k not in vars(builtins) and k not in vars(types)}
assert not bool(set(p.keys()).difference(registered.keys()))
assert not bool(set(registered.keys()).difference(p.keys()))

0 comments on commit 990b5a1

Please sign in to comment.