summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Lib/pickle.py59
-rw-r--r--Lib/test/test_pickle.py13
-rw-r--r--Misc/NEWS.d/next/Library/2019-06-12-16-10-50.bpo-37210.r4yMg6.rst1
3 files changed, 41 insertions, 32 deletions
diff --git a/Lib/pickle.py b/Lib/pickle.py
index a67ac7d..71aa57d 100644
--- a/Lib/pickle.py
+++ b/Lib/pickle.py
@@ -36,10 +36,16 @@ import io
import codecs
import _compat_pickle
-from _pickle import PickleBuffer
-
__all__ = ["PickleError", "PicklingError", "UnpicklingError", "Pickler",
- "Unpickler", "dump", "dumps", "load", "loads", "PickleBuffer"]
+ "Unpickler", "dump", "dumps", "load", "loads"]
+
+try:
+ from _pickle import PickleBuffer
+ __all__.append("PickleBuffer")
+ _HAVE_PICKLE_BUFFER = True
+except ImportError:
+ _HAVE_PICKLE_BUFFER = False
+
# Shortcut for use in isinstance testing
bytes_types = (bytes, bytearray)
@@ -812,31 +818,32 @@ class _Pickler:
self.write(BYTEARRAY8 + pack("<Q", n) + obj)
dispatch[bytearray] = save_bytearray
- def save_picklebuffer(self, obj):
- if self.proto < 5:
- raise PicklingError("PickleBuffer can only pickled with "
- "protocol >= 5")
- with obj.raw() as m:
- if not m.contiguous:
- raise PicklingError("PickleBuffer can not be pickled when "
- "pointing to a non-contiguous buffer")
- in_band = True
- if self._buffer_callback is not None:
- in_band = bool(self._buffer_callback(obj))
- if in_band:
- # Write data in-band
- # XXX The C implementation avoids a copy here
- if m.readonly:
- self.save_bytes(m.tobytes())
+ if _HAVE_PICKLE_BUFFER:
+ def save_picklebuffer(self, obj):
+ if self.proto < 5:
+ raise PicklingError("PickleBuffer can only pickled with "
+ "protocol >= 5")
+ with obj.raw() as m:
+ if not m.contiguous:
+ raise PicklingError("PickleBuffer can not be pickled when "
+ "pointing to a non-contiguous buffer")
+ in_band = True
+ if self._buffer_callback is not None:
+ in_band = bool(self._buffer_callback(obj))
+ if in_band:
+ # Write data in-band
+ # XXX The C implementation avoids a copy here
+ if m.readonly:
+ self.save_bytes(m.tobytes())
+ else:
+ self.save_bytearray(m.tobytes())
else:
- self.save_bytearray(m.tobytes())
- else:
- # Write data out-of-band
- self.write(NEXT_BUFFER)
- if m.readonly:
- self.write(READONLY_BUFFER)
+ # Write data out-of-band
+ self.write(NEXT_BUFFER)
+ if m.readonly:
+ self.write(READONLY_BUFFER)
- dispatch[PickleBuffer] = save_picklebuffer
+ dispatch[PickleBuffer] = save_picklebuffer
def save_str(self, obj):
if self.bin:
diff --git a/Lib/test/test_pickle.py b/Lib/test/test_pickle.py
index 5f7a879..2307b13 100644
--- a/Lib/test/test_pickle.py
+++ b/Lib/test/test_pickle.py
@@ -203,6 +203,13 @@ class PyChainDispatchTableTests(AbstractDispatchTableTests):
return collections.ChainMap({}, pickle.dispatch_table)
+class PyPicklerHookTests(AbstractHookTests):
+ class CustomPyPicklerClass(pickle._Pickler,
+ AbstractCustomPicklerClass):
+ pass
+ pickler_class = CustomPyPicklerClass
+
+
if has_c_implementation:
class CPickleTests(AbstractPickleModuleTests):
from _pickle import dump, dumps, load, loads, Pickler, Unpickler
@@ -255,12 +262,6 @@ if has_c_implementation:
def get_dispatch_table(self):
return collections.ChainMap({}, pickle.dispatch_table)
- class PyPicklerHookTests(AbstractHookTests):
- class CustomPyPicklerClass(pickle._Pickler,
- AbstractCustomPicklerClass):
- pass
- pickler_class = CustomPyPicklerClass
-
class CPicklerHookTests(AbstractHookTests):
class CustomCPicklerClass(_pickle.Pickler, AbstractCustomPicklerClass):
pass
diff --git a/Misc/NEWS.d/next/Library/2019-06-12-16-10-50.bpo-37210.r4yMg6.rst b/Misc/NEWS.d/next/Library/2019-06-12-16-10-50.bpo-37210.r4yMg6.rst
new file mode 100644
index 0000000..58fc66b
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2019-06-12-16-10-50.bpo-37210.r4yMg6.rst
@@ -0,0 +1 @@
+Allow pure Python implementation of :mod:`pickle` to work even when the C :mod:`_pickle` module is unavailable.