Skip to content

Commit 0767ad4

Browse files
bpo-20185: Convert the marshal module to Argument Clinic. (#541)
Based on patch by Vajrasky Kok.
1 parent c611a5b commit 0767ad4

File tree

2 files changed

+229
-67
lines changed

2 files changed

+229
-67
lines changed

Python/clinic/marshal.c.h

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
/*[clinic input]
2+
preserve
3+
[clinic start generated code]*/
4+
5+
PyDoc_STRVAR(marshal_dump__doc__,
6+
"dump($module, value, file, version=version, /)\n"
7+
"--\n"
8+
"\n"
9+
"Write the value on the open file.\n"
10+
"\n"
11+
" value\n"
12+
" Must be a supported type.\n"
13+
" file\n"
14+
" Must be a writeable binary file.\n"
15+
" version\n"
16+
" Indicates the data format that dump should use.\n"
17+
"\n"
18+
"If the value has (or contains an object that has) an unsupported type, a\n"
19+
"ValueError exception is raised - but garbage data will also be written\n"
20+
"to the file. The object will not be properly read back by load().");
21+
22+
#define MARSHAL_DUMP_METHODDEF \
23+
{"dump", (PyCFunction)marshal_dump, METH_FASTCALL, marshal_dump__doc__},
24+
25+
static PyObject *
26+
marshal_dump_impl(PyObject *module, PyObject *value, PyObject *file,
27+
int version);
28+
29+
static PyObject *
30+
marshal_dump(PyObject *module, PyObject **args, Py_ssize_t nargs, PyObject *kwnames)
31+
{
32+
PyObject *return_value = NULL;
33+
PyObject *value;
34+
PyObject *file;
35+
int version = Py_MARSHAL_VERSION;
36+
37+
if (!_PyArg_ParseStack(args, nargs, "OO|i:dump",
38+
&value, &file, &version)) {
39+
goto exit;
40+
}
41+
42+
if (!_PyArg_NoStackKeywords("dump", kwnames)) {
43+
goto exit;
44+
}
45+
return_value = marshal_dump_impl(module, value, file, version);
46+
47+
exit:
48+
return return_value;
49+
}
50+
51+
PyDoc_STRVAR(marshal_load__doc__,
52+
"load($module, file, /)\n"
53+
"--\n"
54+
"\n"
55+
"Read one value from the open file and return it.\n"
56+
"\n"
57+
" file\n"
58+
" Must be readable binary file.\n"
59+
"\n"
60+
"If no valid value is read (e.g. because the data has a different Python\n"
61+
"version\'s incompatible marshal format), raise EOFError, ValueError or\n"
62+
"TypeError.\n"
63+
"\n"
64+
"Note: If an object containing an unsupported type was marshalled with\n"
65+
"dump(), load() will substitute None for the unmarshallable type.");
66+
67+
#define MARSHAL_LOAD_METHODDEF \
68+
{"load", (PyCFunction)marshal_load, METH_O, marshal_load__doc__},
69+
70+
PyDoc_STRVAR(marshal_dumps__doc__,
71+
"dumps($module, value, version=version, /)\n"
72+
"--\n"
73+
"\n"
74+
"Return the bytes object that would be written to a file by dump(value, file).\n"
75+
"\n"
76+
" value\n"
77+
" Must be a supported type.\n"
78+
" version\n"
79+
" Indicates the data format that dumps should use.\n"
80+
"\n"
81+
"Raise a ValueError exception if value has (or contains an object that has) an\n"
82+
"unsupported type.");
83+
84+
#define MARSHAL_DUMPS_METHODDEF \
85+
{"dumps", (PyCFunction)marshal_dumps, METH_FASTCALL, marshal_dumps__doc__},
86+
87+
static PyObject *
88+
marshal_dumps_impl(PyObject *module, PyObject *value, int version);
89+
90+
static PyObject *
91+
marshal_dumps(PyObject *module, PyObject **args, Py_ssize_t nargs, PyObject *kwnames)
92+
{
93+
PyObject *return_value = NULL;
94+
PyObject *value;
95+
int version = Py_MARSHAL_VERSION;
96+
97+
if (!_PyArg_ParseStack(args, nargs, "O|i:dumps",
98+
&value, &version)) {
99+
goto exit;
100+
}
101+
102+
if (!_PyArg_NoStackKeywords("dumps", kwnames)) {
103+
goto exit;
104+
}
105+
return_value = marshal_dumps_impl(module, value, version);
106+
107+
exit:
108+
return return_value;
109+
}
110+
111+
PyDoc_STRVAR(marshal_loads__doc__,
112+
"loads($module, bytes, /)\n"
113+
"--\n"
114+
"\n"
115+
"Convert the bytes-like object to a value.\n"
116+
"\n"
117+
"If no valid value is found, raise EOFError, ValueError or TypeError. Extra\n"
118+
"bytes in the input are ignored.");
119+
120+
#define MARSHAL_LOADS_METHODDEF \
121+
{"loads", (PyCFunction)marshal_loads, METH_O, marshal_loads__doc__},
122+
123+
static PyObject *
124+
marshal_loads_impl(PyObject *module, Py_buffer *bytes);
125+
126+
static PyObject *
127+
marshal_loads(PyObject *module, PyObject *arg)
128+
{
129+
PyObject *return_value = NULL;
130+
Py_buffer bytes = {NULL, NULL};
131+
132+
if (!PyArg_Parse(arg, "y*:loads", &bytes)) {
133+
goto exit;
134+
}
135+
return_value = marshal_loads_impl(module, &bytes);
136+
137+
exit:
138+
/* Cleanup for bytes */
139+
if (bytes.obj) {
140+
PyBuffer_Release(&bytes);
141+
}
142+
143+
return return_value;
144+
}
145+
/*[clinic end generated code: output=9dec2158b8c5d975 input=a9049054013a1b77]*/

Python/marshal.c

Lines changed: 84 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,13 @@
1414
#include "marshal.h"
1515
#include "../Modules/hashtable.h"
1616

17+
/*[clinic input]
18+
module marshal
19+
[clinic start generated code]*/
20+
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=c982b7930dee17db]*/
21+
22+
#include "clinic/marshal.c.h"
23+
1724
/* High water mark to determine when the marshalled object is dangerously deep
1825
* and risks coring the interpreter. When the object stack gets this deep,
1926
* raise an exception instead of continuing.
@@ -1632,42 +1639,62 @@ PyMarshal_WriteObjectToString(PyObject *x, int version)
16321639
}
16331640

16341641
/* And an interface for Python programs... */
1642+
/*[clinic input]
1643+
marshal.dump
1644+
1645+
value: object
1646+
Must be a supported type.
1647+
file: object
1648+
Must be a writeable binary file.
1649+
version: int(c_default="Py_MARSHAL_VERSION") = version
1650+
Indicates the data format that dump should use.
1651+
/
1652+
1653+
Write the value on the open file.
1654+
1655+
If the value has (or contains an object that has) an unsupported type, a
1656+
ValueError exception is raised - but garbage data will also be written
1657+
to the file. The object will not be properly read back by load().
1658+
[clinic start generated code]*/
16351659

16361660
static PyObject *
1637-
marshal_dump(PyObject *self, PyObject *args)
1661+
marshal_dump_impl(PyObject *module, PyObject *value, PyObject *file,
1662+
int version)
1663+
/*[clinic end generated code: output=aaee62c7028a7cb2 input=6c7a3c23c6fef556]*/
16381664
{
16391665
/* XXX Quick hack -- need to do this differently */
1640-
PyObject *x;
1641-
PyObject *f;
1642-
int version = Py_MARSHAL_VERSION;
16431666
PyObject *s;
16441667
PyObject *res;
16451668
_Py_IDENTIFIER(write);
16461669

1647-
if (!PyArg_ParseTuple(args, "OO|i:dump", &x, &f, &version))
1648-
return NULL;
1649-
s = PyMarshal_WriteObjectToString(x, version);
1670+
s = PyMarshal_WriteObjectToString(value, version);
16501671
if (s == NULL)
16511672
return NULL;
1652-
res = _PyObject_CallMethodIdObjArgs(f, &PyId_write, s, NULL);
1673+
res = _PyObject_CallMethodIdObjArgs(file, &PyId_write, s, NULL);
16531674
Py_DECREF(s);
16541675
return res;
16551676
}
16561677

1657-
PyDoc_STRVAR(dump_doc,
1658-
"dump(value, file[, version])\n\
1659-
\n\
1660-
Write the value on the open file. The value must be a supported type.\n\
1661-
The file must be a writeable binary file.\n\
1662-
\n\
1663-
If the value has (or contains an object that has) an unsupported type, a\n\
1664-
ValueError exception is raised - but garbage data will also be written\n\
1665-
to the file. The object will not be properly read back by load()\n\
1666-
\n\
1667-
The version argument indicates the data format that dump should use.");
1678+
/*[clinic input]
1679+
marshal.load
1680+
1681+
file: object
1682+
Must be readable binary file.
1683+
/
1684+
1685+
Read one value from the open file and return it.
1686+
1687+
If no valid value is read (e.g. because the data has a different Python
1688+
version's incompatible marshal format), raise EOFError, ValueError or
1689+
TypeError.
1690+
1691+
Note: If an object containing an unsupported type was marshalled with
1692+
dump(), load() will substitute None for the unmarshallable type.
1693+
[clinic start generated code]*/
16681694

16691695
static PyObject *
1670-
marshal_load(PyObject *self, PyObject *f)
1696+
marshal_load(PyObject *module, PyObject *file)
1697+
/*[clinic end generated code: output=f8e5c33233566344 input=c85c2b594cd8124a]*/
16711698
{
16721699
PyObject *data, *result;
16731700
_Py_IDENTIFIER(read);
@@ -1680,19 +1707,19 @@ marshal_load(PyObject *self, PyObject *f)
16801707
* This can be removed if we guarantee good error handling
16811708
* for r_string()
16821709
*/
1683-
data = _PyObject_CallMethodId(f, &PyId_read, "i", 0);
1710+
data = _PyObject_CallMethodId(file, &PyId_read, "i", 0);
16841711
if (data == NULL)
16851712
return NULL;
16861713
if (!PyBytes_Check(data)) {
16871714
PyErr_Format(PyExc_TypeError,
1688-
"f.read() returned not bytes but %.100s",
1715+
"file.read() returned not bytes but %.100s",
16891716
data->ob_type->tp_name);
16901717
result = NULL;
16911718
}
16921719
else {
16931720
rf.depth = 0;
16941721
rf.fp = NULL;
1695-
rf.readable = f;
1722+
rf.readable = file;
16961723
rf.current_filename = NULL;
16971724
rf.ptr = rf.end = NULL;
16981725
rf.buf = NULL;
@@ -1708,50 +1735,48 @@ marshal_load(PyObject *self, PyObject *f)
17081735
return result;
17091736
}
17101737

1711-
PyDoc_STRVAR(load_doc,
1712-
"load(file)\n\
1713-
\n\
1714-
Read one value from the open file and return it. If no valid value is\n\
1715-
read (e.g. because the data has a different Python version's\n\
1716-
incompatible marshal format), raise EOFError, ValueError or TypeError.\n\
1717-
The file must be a readable binary file.\n\
1718-
\n\
1719-
Note: If an object containing an unsupported type was marshalled with\n\
1720-
dump(), load() will substitute None for the unmarshallable type.");
1738+
/*[clinic input]
1739+
marshal.dumps
1740+
1741+
value: object
1742+
Must be a supported type.
1743+
version: int(c_default="Py_MARSHAL_VERSION") = version
1744+
Indicates the data format that dumps should use.
1745+
/
17211746
1747+
Return the bytes object that would be written to a file by dump(value, file).
1748+
1749+
Raise a ValueError exception if value has (or contains an object that has) an
1750+
unsupported type.
1751+
[clinic start generated code]*/
17221752

17231753
static PyObject *
1724-
marshal_dumps(PyObject *self, PyObject *args)
1754+
marshal_dumps_impl(PyObject *module, PyObject *value, int version)
1755+
/*[clinic end generated code: output=9c200f98d7256cad input=a2139ea8608e9b27]*/
17251756
{
1726-
PyObject *x;
1727-
int version = Py_MARSHAL_VERSION;
1728-
if (!PyArg_ParseTuple(args, "O|i:dumps", &x, &version))
1729-
return NULL;
1730-
return PyMarshal_WriteObjectToString(x, version);
1757+
return PyMarshal_WriteObjectToString(value, version);
17311758
}
17321759

1733-
PyDoc_STRVAR(dumps_doc,
1734-
"dumps(value[, version])\n\
1735-
\n\
1736-
Return the bytes object that would be written to a file by dump(value, file).\n\
1737-
The value must be a supported type. Raise a ValueError exception if\n\
1738-
value has (or contains an object that has) an unsupported type.\n\
1739-
\n\
1740-
The version argument indicates the data format that dumps should use.");
1760+
/*[clinic input]
1761+
marshal.loads
1762+
1763+
bytes: Py_buffer
1764+
/
1765+
1766+
Convert the bytes-like object to a value.
17411767
1768+
If no valid value is found, raise EOFError, ValueError or TypeError. Extra
1769+
bytes in the input are ignored.
1770+
[clinic start generated code]*/
17421771

17431772
static PyObject *
1744-
marshal_loads(PyObject *self, PyObject *args)
1773+
marshal_loads_impl(PyObject *module, Py_buffer *bytes)
1774+
/*[clinic end generated code: output=9fc65985c93d1bb1 input=6f426518459c8495]*/
17451775
{
17461776
RFILE rf;
1747-
Py_buffer p;
1748-
char *s;
1749-
Py_ssize_t n;
1777+
char *s = bytes->buf;
1778+
Py_ssize_t n = bytes->len;
17501779
PyObject* result;
1751-
if (!PyArg_ParseTuple(args, "y*:loads", &p))
1752-
return NULL;
1753-
s = p.buf;
1754-
n = p.len;
17551780
rf.fp = NULL;
17561781
rf.readable = NULL;
17571782
rf.current_filename = NULL;
@@ -1761,23 +1786,15 @@ marshal_loads(PyObject *self, PyObject *args)
17611786
if ((rf.refs = PyList_New(0)) == NULL)
17621787
return NULL;
17631788
result = read_object(&rf);
1764-
PyBuffer_Release(&p);
17651789
Py_DECREF(rf.refs);
17661790
return result;
17671791
}
17681792

1769-
PyDoc_STRVAR(loads_doc,
1770-
"loads(bytes)\n\
1771-
\n\
1772-
Convert the bytes-like object to a value. If no valid value is found,\n\
1773-
raise EOFError, ValueError or TypeError. Extra bytes in the input are\n\
1774-
ignored.");
1775-
17761793
static PyMethodDef marshal_methods[] = {
1777-
{"dump", marshal_dump, METH_VARARGS, dump_doc},
1778-
{"load", marshal_load, METH_O, load_doc},
1779-
{"dumps", marshal_dumps, METH_VARARGS, dumps_doc},
1780-
{"loads", marshal_loads, METH_VARARGS, loads_doc},
1794+
MARSHAL_DUMP_METHODDEF
1795+
MARSHAL_LOAD_METHODDEF
1796+
MARSHAL_DUMPS_METHODDEF
1797+
MARSHAL_LOADS_METHODDEF
17811798
{NULL, NULL} /* sentinel */
17821799
};
17831800

0 commit comments

Comments
 (0)