summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Lib/pickle.py20
-rw-r--r--Modules/cPickle.c131
2 files changed, 95 insertions, 56 deletions
diff --git a/Lib/pickle.py b/Lib/pickle.py
index 45bc38c..92b4802 100644
--- a/Lib/pickle.py
+++ b/Lib/pickle.py
@@ -174,13 +174,17 @@ class Pickler:
protocol; supported protocols are 0, 1, 2. The default
protocol is 0, to be backwards compatible. (Protocol 0 is the
only protocol that can be written to a file opened in text
- mode and read back successfully.)
+ mode and read back successfully. When using a protocol higher
+ than 0, make sure the file is opened in binary mode, both when
+ pickling and unpickling.)
Protocol 1 is more efficient than protocol 0; protocol 2 is
more efficient than protocol 1.
Specifying a negative protocol version selects the highest
- protocol version supported.
+ protocol version supported. The higher the protocol used, the
+ more recent the version of Python needed to read the pickle
+ produced.
The file parameter must have a write() method that accepts a single
string argument. It can thus be an open file object, a StringIO
@@ -209,12 +213,7 @@ class Pickler:
self.memo.clear()
def dump(self, obj):
- """Write a pickled representation of obj to the open file.
-
- Either the binary or ASCII format will be used, depending on the
- value of the bin flag passed to the constructor.
-
- """
+ """Write a pickled representation of obj to the open file."""
if self.proto >= 2:
self.write(PROTO + chr(self.proto))
self.save(obj)
@@ -931,9 +930,8 @@ class Unpickler:
def __init__(self, file):
"""This takes a file-like object for reading a pickle data stream.
- This class automatically determines whether the data stream was
- written in binary mode or not, so it does not need a flag as in
- the Pickler class factory.
+ The protocol version of the pickle is detected automatically, so no
+ proto argument is needed.
The file-like object must have two methods, a read() method that
takes an integer argument, and a readline() method that requires no
diff --git a/Modules/cPickle.c b/Modules/cPickle.c
index e726667..4364f4d 100644
--- a/Modules/cPickle.c
+++ b/Modules/cPickle.c
@@ -14,6 +14,9 @@ PyDoc_STRVAR(cPickle_module_documentation,
#define WRITE_BUF_SIZE 256
+/* Bump this when new opcodes are added to the pickle protocol. */
+#define CURRENT_PROTOCOL_NUMBER 2
+
/*
* Pickle opcodes. These must be kept in synch with pickle.py. Extensive
* docs are in pickletools.py.
@@ -2316,13 +2319,24 @@ static struct PyMethodDef Pickler_methods[] =
static Picklerobject *
-newPicklerobject(PyObject *file, int bin)
+newPicklerobject(PyObject *file, int proto)
{
Picklerobject *self;
- if (!( self = PyObject_New(Picklerobject, &Picklertype)))
+ if (proto < 0)
+ proto = CURRENT_PROTOCOL_NUMBER;
+ if (proto > CURRENT_PROTOCOL_NUMBER) {
+ PyErr_Format(PyExc_ValueError, "pickle protocol %d asked for; "
+ "the highest available protocol is %d",
+ proto, CURRENT_PROTOCOL_NUMBER);
return NULL;
+ }
+ self = PyObject_New(Picklerobject, &Picklertype);
+ if (self == NULL)
+ return NULL;
+ self->proto = proto;
+ self->bin = proto > 0;
self->fp = NULL;
self->write = NULL;
self->memo = NULL;
@@ -2330,7 +2344,6 @@ newPicklerobject(PyObject *file, int bin)
self->pers_func = NULL;
self->inst_pers_func = NULL;
self->write_buf = NULL;
- self->bin = bin;
self->fast = 0;
self->nesting = 0;
self->fast_container = 0;
@@ -2338,13 +2351,15 @@ newPicklerobject(PyObject *file, int bin)
self->buf_size = 0;
self->dispatch_table = NULL;
+ self->file = NULL;
if (file)
Py_INCREF(file);
- else
- file=Pdata_New();
-
- if (!( self->file = file ))
- goto err;
+ else {
+ file = Pdata_New();
+ if (file == NULL)
+ goto err;
+ }
+ self->file = file;
if (!( self->memo = PyDict_New()))
goto err;
@@ -2352,7 +2367,8 @@ newPicklerobject(PyObject *file, int bin)
if (PyFile_Check(file)) {
self->fp = PyFile_AsFile(file);
if (self->fp == NULL) {
- PyErr_SetString(PyExc_ValueError, "I/O operation on closed file");
+ PyErr_SetString(PyExc_ValueError,
+ "I/O operation on closed file");
goto err;
}
self->write_func = write_file;
@@ -2377,8 +2393,8 @@ newPicklerobject(PyObject *file, int bin)
}
}
- if (!( self->write_buf =
- (char *)malloc(WRITE_BUF_SIZE * sizeof(char)))) {
+ self->write_buf = (char *)PyMem_Malloc(WRITE_BUF_SIZE);
+ if (self->write_buf == NULL) {
PyErr_NoMemory();
goto err;
}
@@ -2401,7 +2417,7 @@ newPicklerobject(PyObject *file, int bin)
return self;
err:
- Py_DECREF((PyObject *)self);
+ Py_DECREF(self);
return NULL;
}
@@ -2410,15 +2426,20 @@ static PyObject *
get_Pickler(PyObject *self, PyObject *args)
{
PyObject *file = NULL;
- int bin = 1;
+ int proto = 0;
- if (!PyArg_ParseTuple(args, "|i:Pickler", &bin)) {
+ /* XXX What is this doing? The documented signature is
+ * XXX Pickler(file, proto=0), but this accepts Pickler() and
+ * XXX Pickler(integer) too. The meaning then is clear as mud.
+ * XXX Bug? Feature?
+ */
+ if (!PyArg_ParseTuple(args, "|i:Pickler", &proto)) {
PyErr_Clear();
- bin = 0;
- if (!PyArg_ParseTuple(args, "O|i:Pickler", &file, &bin))
+ proto = 0;
+ if (!PyArg_ParseTuple(args, "O|i:Pickler", &file, &proto))
return NULL;
}
- return (PyObject *)newPicklerobject(file, bin);
+ return (PyObject *)newPicklerobject(file, proto);
}
@@ -2433,11 +2454,7 @@ Pickler_dealloc(Picklerobject *self)
Py_XDECREF(self->pers_func);
Py_XDECREF(self->inst_pers_func);
Py_XDECREF(self->dispatch_table);
-
- if (self->write_buf) {
- free(self->write_buf);
- }
-
+ PyMem_Free(self->write_buf);
PyObject_Del(self);
}
@@ -4487,18 +4504,22 @@ Unpickler_setattr(Unpicklerobject *self, char *name, PyObject *value)
return -1;
}
+/* ---------------------------------------------------------------------------
+ * Module-level functions.
+ */
+/* dump(obj, file, proto=0). */
static PyObject *
cpm_dump(PyObject *self, PyObject *args)
{
PyObject *ob, *file, *res = NULL;
Picklerobject *pickler = 0;
- int bin = 0;
+ int proto = 0;
- if (!( PyArg_ParseTuple(args, "OO|i", &ob, &file, &bin)))
+ if (!( PyArg_ParseTuple(args, "OO|i", &ob, &file, &proto)))
goto finally;
- if (!( pickler = newPicklerobject(file, bin)))
+ if (!( pickler = newPicklerobject(file, proto)))
goto finally;
if (dump(pickler, ob) < 0)
@@ -4514,20 +4535,21 @@ cpm_dump(PyObject *self, PyObject *args)
}
+/* dumps(obj, proto=0). */
static PyObject *
cpm_dumps(PyObject *self, PyObject *args)
{
PyObject *ob, *file = 0, *res = NULL;
Picklerobject *pickler = 0;
- int bin = 0;
+ int proto = 0;
- if (!( PyArg_ParseTuple(args, "O|i:dumps", &ob, &bin)))
+ if (!( PyArg_ParseTuple(args, "O|i:dumps", &ob, &proto)))
goto finally;
if (!( file = PycStringIO->NewOutput(128)))
goto finally;
- if (!( pickler = newPicklerobject(file, bin)))
+ if (!( pickler = newPicklerobject(file, proto)))
goto finally;
if (dump(pickler, ob) < 0)
@@ -4543,6 +4565,7 @@ cpm_dumps(PyObject *self, PyObject *args)
}
+/* load(fileobj). */
static PyObject *
cpm_load(PyObject *self, PyObject *args)
{
@@ -4564,6 +4587,7 @@ cpm_load(PyObject *self, PyObject *args)
}
+/* loads(string) */
static PyObject *
cpm_loads(PyObject *self, PyObject *args)
{
@@ -4619,34 +4643,53 @@ static PyTypeObject Unpicklertype = {
static struct PyMethodDef cPickle_methods[] = {
{"dump", (PyCFunction)cpm_dump, METH_VARARGS,
- PyDoc_STR("dump(object, file, [binary]) --"
- "Write an object in pickle format to the given file\n"
+ PyDoc_STR("dump(object, file, proto=0) -- "
+ "Write an object in pickle format to the given file.\n"
"\n"
- "If the optional argument, binary, is provided and is true, then the\n"
- "pickle will be written in binary format, which is more space and\n"
- "computationally efficient. \n")
+ "See the Pickler docstring for the meaning of optional argument proto.")
},
+
{"dumps", (PyCFunction)cpm_dumps, METH_VARARGS,
- PyDoc_STR("dumps(object, [binary]) --"
- "Return a string containing an object in pickle format\n"
+ PyDoc_STR("dumps(object, proto=0) -- "
+ "Return a string containing an object in pickle format.\n"
"\n"
- "If the optional argument, binary, is provided and is true, then the\n"
- "pickle will be written in binary format, which is more space and\n"
- "computationally efficient. \n")
+ "See the Pickler docstring for the meaning of optional argument proto.")
},
+
{"load", (PyCFunction)cpm_load, METH_VARARGS,
PyDoc_STR("load(file) -- Load a pickle from the given file")},
+
{"loads", (PyCFunction)cpm_loads, METH_VARARGS,
PyDoc_STR("loads(string) -- Load a pickle from the given string")},
+
{"Pickler", (PyCFunction)get_Pickler, METH_VARARGS,
- PyDoc_STR("Pickler(file, [binary]) -- Create a pickler\n"
+ PyDoc_STR("Pickler(file, proto=0) -- Create a pickler.\n"
+ "\n"
+ "This takes a file-like object for writing a pickle data stream.\n"
+ "The optional proto argument tells the pickler to use the given\n"
+ "protocol; supported protocols are 0, 1, 2. The default\n"
+ "protocol is 0, to be backwards compatible. (Protocol 0 is the\n"
+ "only protocol that can be written to a file opened in text\n"
+ "mode and read back successfully. When using a protocol higher\n"
+ "than 0, make sure the file is opened in binary mode, both when\n"
+ "pickling and unpickling.)\n"
+ "\n"
+ "Protocol 1 is more efficient than protocol 0; protocol 2 is\n"
+ "more efficient than protocol 1.\n"
+ "\n"
+ "Specifying a negative protocol version selects the highest\n"
+ "protocol version supported. The higher the protocol used, the\n"
+ "more recent the version of Python needed to read the pickle\n"
+ "produced.\n"
"\n"
- "If the optional argument, binary, is provided and is true, then\n"
- "pickles will be written in binary format, which is more space and\n"
- "computationally efficient. \n")
+ "The file parameter must have a write() method that accepts a single\n"
+ "string argument. It can thus be an open file object, a StringIO\n"
+ "object, or any other custom object that meets this interface.\n")
},
+
{"Unpickler", (PyCFunction)get_Unpickler, METH_VARARGS,
- PyDoc_STR("Unpickler(file) -- Create an unpickler")},
+ PyDoc_STR("Unpickler(file) -- Create an unpickler.")},
+
{ NULL, NULL }
};
@@ -4684,8 +4727,6 @@ init_stuff(PyObject *module_dict)
Py_DECREF(copy_reg);
- /* Down to here ********************************** */
-
if (!( empty_tuple = PyTuple_New(0)))
return -1;