diff --git a/Python/clinic/marshal.c.h b/Python/clinic/marshal.c.h new file mode 100644 index 00000000000..ae2c8990a6c --- /dev/null +++ b/Python/clinic/marshal.c.h @@ -0,0 +1,145 @@ +/*[clinic input] +preserve +[clinic start generated code]*/ + +PyDoc_STRVAR(marshal_dump__doc__, +"dump($module, value, file, version=version, /)\n" +"--\n" +"\n" +"Write the value on the open file.\n" +"\n" +" value\n" +" Must be a supported type.\n" +" file\n" +" Must be a writeable binary file.\n" +" version\n" +" Indicates the data format that dump should use.\n" +"\n" +"If the value has (or contains an object that has) an unsupported type, a\n" +"ValueError exception is raised - but garbage data will also be written\n" +"to the file. The object will not be properly read back by load()."); + +#define MARSHAL_DUMP_METHODDEF \ + {"dump", (PyCFunction)marshal_dump, METH_FASTCALL, marshal_dump__doc__}, + +static PyObject * +marshal_dump_impl(PyObject *module, PyObject *value, PyObject *file, + int version); + +static PyObject * +marshal_dump(PyObject *module, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + PyObject *value; + PyObject *file; + int version = Py_MARSHAL_VERSION; + + if (!_PyArg_ParseStack(args, nargs, "OO|i:dump", + &value, &file, &version)) { + goto exit; + } + + if (!_PyArg_NoStackKeywords("dump", kwnames)) { + goto exit; + } + return_value = marshal_dump_impl(module, value, file, version); + +exit: + return return_value; +} + +PyDoc_STRVAR(marshal_load__doc__, +"load($module, file, /)\n" +"--\n" +"\n" +"Read one value from the open file and return it.\n" +"\n" +" file\n" +" Must be readable binary file.\n" +"\n" +"If no valid value is read (e.g. because the data has a different Python\n" +"version\'s incompatible marshal format), raise EOFError, ValueError or\n" +"TypeError.\n" +"\n" +"Note: If an object containing an unsupported type was marshalled with\n" +"dump(), load() will substitute None for the unmarshallable type."); + +#define MARSHAL_LOAD_METHODDEF \ + {"load", (PyCFunction)marshal_load, METH_O, marshal_load__doc__}, + +PyDoc_STRVAR(marshal_dumps__doc__, +"dumps($module, value, version=version, /)\n" +"--\n" +"\n" +"Return the bytes object that would be written to a file by dump(value, file).\n" +"\n" +" value\n" +" Must be a supported type.\n" +" version\n" +" Indicates the data format that dumps should use.\n" +"\n" +"Raise a ValueError exception if value has (or contains an object that has) an\n" +"unsupported type."); + +#define MARSHAL_DUMPS_METHODDEF \ + {"dumps", (PyCFunction)marshal_dumps, METH_FASTCALL, marshal_dumps__doc__}, + +static PyObject * +marshal_dumps_impl(PyObject *module, PyObject *value, int version); + +static PyObject * +marshal_dumps(PyObject *module, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + PyObject *value; + int version = Py_MARSHAL_VERSION; + + if (!_PyArg_ParseStack(args, nargs, "O|i:dumps", + &value, &version)) { + goto exit; + } + + if (!_PyArg_NoStackKeywords("dumps", kwnames)) { + goto exit; + } + return_value = marshal_dumps_impl(module, value, version); + +exit: + return return_value; +} + +PyDoc_STRVAR(marshal_loads__doc__, +"loads($module, bytes, /)\n" +"--\n" +"\n" +"Convert the bytes-like object to a value.\n" +"\n" +"If no valid value is found, raise EOFError, ValueError or TypeError. Extra\n" +"bytes in the input are ignored."); + +#define MARSHAL_LOADS_METHODDEF \ + {"loads", (PyCFunction)marshal_loads, METH_O, marshal_loads__doc__}, + +static PyObject * +marshal_loads_impl(PyObject *module, Py_buffer *bytes); + +static PyObject * +marshal_loads(PyObject *module, PyObject *arg) +{ + PyObject *return_value = NULL; + Py_buffer bytes = {NULL, NULL}; + + if (!PyArg_Parse(arg, "y*:loads", &bytes)) { + goto exit; + } + return_value = marshal_loads_impl(module, &bytes); + +exit: + /* Cleanup for bytes */ + if (bytes.obj) { + PyBuffer_Release(&bytes); + } + + return return_value; +} +/*[clinic end generated code: output=9dec2158b8c5d975 input=a9049054013a1b77]*/ diff --git a/Python/marshal.c b/Python/marshal.c index a0fb0f3d8ae..b2c00a0b6c5 100644 --- a/Python/marshal.c +++ b/Python/marshal.c @@ -14,6 +14,13 @@ #include "marshal.h" #include "../Modules/hashtable.h" +/*[clinic input] +module marshal +[clinic start generated code]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=c982b7930dee17db]*/ + +#include "clinic/marshal.c.h" + /* High water mark to determine when the marshalled object is dangerously deep * and risks coring the interpreter. When the object stack gets this deep, * raise an exception instead of continuing. @@ -1632,42 +1639,62 @@ PyMarshal_WriteObjectToString(PyObject *x, int version) } /* And an interface for Python programs... */ +/*[clinic input] +marshal.dump + + value: object + Must be a supported type. + file: object + Must be a writeable binary file. + version: int(c_default="Py_MARSHAL_VERSION") = version + Indicates the data format that dump should use. + / + +Write the value on the open file. + +If the value has (or contains an object that has) an unsupported type, a +ValueError exception is raised - but garbage data will also be written +to the file. The object will not be properly read back by load(). +[clinic start generated code]*/ static PyObject * -marshal_dump(PyObject *self, PyObject *args) +marshal_dump_impl(PyObject *module, PyObject *value, PyObject *file, + int version) +/*[clinic end generated code: output=aaee62c7028a7cb2 input=6c7a3c23c6fef556]*/ { /* XXX Quick hack -- need to do this differently */ - PyObject *x; - PyObject *f; - int version = Py_MARSHAL_VERSION; PyObject *s; PyObject *res; _Py_IDENTIFIER(write); - if (!PyArg_ParseTuple(args, "OO|i:dump", &x, &f, &version)) - return NULL; - s = PyMarshal_WriteObjectToString(x, version); + s = PyMarshal_WriteObjectToString(value, version); if (s == NULL) return NULL; - res = _PyObject_CallMethodIdObjArgs(f, &PyId_write, s, NULL); + res = _PyObject_CallMethodIdObjArgs(file, &PyId_write, s, NULL); Py_DECREF(s); return res; } -PyDoc_STRVAR(dump_doc, -"dump(value, file[, version])\n\ -\n\ -Write the value on the open file. The value must be a supported type.\n\ -The file must be a writeable binary file.\n\ -\n\ -If the value has (or contains an object that has) an unsupported type, a\n\ -ValueError exception is raised - but garbage data will also be written\n\ -to the file. The object will not be properly read back by load()\n\ -\n\ -The version argument indicates the data format that dump should use."); +/*[clinic input] +marshal.load + + file: object + Must be readable binary file. + / + +Read one value from the open file and return it. + +If no valid value is read (e.g. because the data has a different Python +version's incompatible marshal format), raise EOFError, ValueError or +TypeError. + +Note: If an object containing an unsupported type was marshalled with +dump(), load() will substitute None for the unmarshallable type. +[clinic start generated code]*/ static PyObject * -marshal_load(PyObject *self, PyObject *f) +marshal_load(PyObject *module, PyObject *file) +/*[clinic end generated code: output=f8e5c33233566344 input=c85c2b594cd8124a]*/ { PyObject *data, *result; _Py_IDENTIFIER(read); @@ -1680,19 +1707,19 @@ marshal_load(PyObject *self, PyObject *f) * This can be removed if we guarantee good error handling * for r_string() */ - data = _PyObject_CallMethodId(f, &PyId_read, "i", 0); + data = _PyObject_CallMethodId(file, &PyId_read, "i", 0); if (data == NULL) return NULL; if (!PyBytes_Check(data)) { PyErr_Format(PyExc_TypeError, - "f.read() returned not bytes but %.100s", + "file.read() returned not bytes but %.100s", data->ob_type->tp_name); result = NULL; } else { rf.depth = 0; rf.fp = NULL; - rf.readable = f; + rf.readable = file; rf.current_filename = NULL; rf.ptr = rf.end = NULL; rf.buf = NULL; @@ -1708,50 +1735,48 @@ marshal_load(PyObject *self, PyObject *f) return result; } -PyDoc_STRVAR(load_doc, -"load(file)\n\ -\n\ -Read one value from the open file and return it. If no valid value is\n\ -read (e.g. because the data has a different Python version's\n\ -incompatible marshal format), raise EOFError, ValueError or TypeError.\n\ -The file must be a readable binary file.\n\ -\n\ -Note: If an object containing an unsupported type was marshalled with\n\ -dump(), load() will substitute None for the unmarshallable type."); +/*[clinic input] +marshal.dumps + value: object + Must be a supported type. + version: int(c_default="Py_MARSHAL_VERSION") = version + Indicates the data format that dumps should use. + / + +Return the bytes object that would be written to a file by dump(value, file). + +Raise a ValueError exception if value has (or contains an object that has) an +unsupported type. +[clinic start generated code]*/ static PyObject * -marshal_dumps(PyObject *self, PyObject *args) +marshal_dumps_impl(PyObject *module, PyObject *value, int version) +/*[clinic end generated code: output=9c200f98d7256cad input=a2139ea8608e9b27]*/ { - PyObject *x; - int version = Py_MARSHAL_VERSION; - if (!PyArg_ParseTuple(args, "O|i:dumps", &x, &version)) - return NULL; - return PyMarshal_WriteObjectToString(x, version); + return PyMarshal_WriteObjectToString(value, version); } -PyDoc_STRVAR(dumps_doc, -"dumps(value[, version])\n\ -\n\ -Return the bytes object that would be written to a file by dump(value, file).\n\ -The value must be a supported type. Raise a ValueError exception if\n\ -value has (or contains an object that has) an unsupported type.\n\ -\n\ -The version argument indicates the data format that dumps should use."); +/*[clinic input] +marshal.loads + bytes: Py_buffer + / + +Convert the bytes-like object to a value. + +If no valid value is found, raise EOFError, ValueError or TypeError. Extra +bytes in the input are ignored. +[clinic start generated code]*/ static PyObject * -marshal_loads(PyObject *self, PyObject *args) +marshal_loads_impl(PyObject *module, Py_buffer *bytes) +/*[clinic end generated code: output=9fc65985c93d1bb1 input=6f426518459c8495]*/ { RFILE rf; - Py_buffer p; - char *s; - Py_ssize_t n; + char *s = bytes->buf; + Py_ssize_t n = bytes->len; PyObject* result; - if (!PyArg_ParseTuple(args, "y*:loads", &p)) - return NULL; - s = p.buf; - n = p.len; rf.fp = NULL; rf.readable = NULL; rf.current_filename = NULL; @@ -1761,23 +1786,15 @@ marshal_loads(PyObject *self, PyObject *args) if ((rf.refs = PyList_New(0)) == NULL) return NULL; result = read_object(&rf); - PyBuffer_Release(&p); Py_DECREF(rf.refs); return result; } -PyDoc_STRVAR(loads_doc, -"loads(bytes)\n\ -\n\ -Convert the bytes-like object to a value. If no valid value is found,\n\ -raise EOFError, ValueError or TypeError. Extra bytes in the input are\n\ -ignored."); - static PyMethodDef marshal_methods[] = { - {"dump", marshal_dump, METH_VARARGS, dump_doc}, - {"load", marshal_load, METH_O, load_doc}, - {"dumps", marshal_dumps, METH_VARARGS, dumps_doc}, - {"loads", marshal_loads, METH_VARARGS, loads_doc}, + MARSHAL_DUMP_METHODDEF + MARSHAL_LOAD_METHODDEF + MARSHAL_DUMPS_METHODDEF + MARSHAL_LOADS_METHODDEF {NULL, NULL} /* sentinel */ };