Skip to content

Commit 93142c9

Browse files
gh-155496: Use Argument Clinic for more functions of the _csv module (GH-158133)
1 parent 964535a commit 93142c9

2 files changed

Lines changed: 353 additions & 83 deletions

File tree

‎Modules/_csv.c‎

Lines changed: 109 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,9 @@ module instead.
2121

2222
/*[clinic input]
2323
module _csv
24+
class _csv.Dialect "DialectObj *" "clinic_state()->dialect_type"
2425
[clinic start generated code]*/
25-
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=385118b71aa43706]*/
26-
27-
#include "clinic/_csv.c.h"
26+
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=042fcc14c7d541cc]*/
2827
#define NOT_SET ((Py_UCS4)-1)
2928
#define EOL ((Py_UCS4)-2)
3029

@@ -125,6 +124,8 @@ typedef struct {
125124
bool nonascii_special;
126125
} DialectObj;
127126

127+
#include "clinic/_csv.c.h"
128+
128129
typedef struct {
129130
PyObject_HEAD
130131

@@ -631,43 +632,62 @@ dialect_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
631632
/* Since dialect is now a heap type, it inherits pickling method for
632633
* protocol 0 and 1 from object, therefore it needs to be overridden */
633634

634-
PyDoc_STRVAR(dialect_reduce_doc, "raises an exception to avoid pickling");
635+
/*[clinic input]
636+
_csv.Dialect.__reduce__
637+
638+
Raise an exception to avoid pickling.
639+
[clinic start generated code]*/
635640

636641
static PyObject *
637-
Dialect_reduce(PyObject *self, PyObject *args) {
642+
_csv_Dialect___reduce___impl(DialectObj *self)
643+
/*[clinic end generated code: output=f728b34af509ed69 input=e46419b46279e480]*/
644+
{
638645
PyErr_Format(PyExc_TypeError,
639646
"cannot pickle '%.100s' instances", _PyType_Name(Py_TYPE(self)));
640647
return NULL;
641648
}
642649

643-
PyDoc_STRVAR(dialect_replace_doc,
644-
"__replace__($self, /, **changes)\n"
645-
"--\n"
646-
"\n"
647-
"Return a copy of the dialect with the specified options replaced.");
650+
/*[clinic input]
651+
_csv.Dialect.__reduce_ex__
652+
653+
protocol: object
654+
/
655+
656+
Raise an exception to avoid pickling.
657+
[clinic start generated code]*/
648658

649659
static PyObject *
650-
Dialect_replace(PyObject *self, PyObject *args, PyObject *kwargs)
660+
_csv_Dialect___reduce_ex___impl(DialectObj *self, PyObject *protocol)
661+
/*[clinic end generated code: output=d45dec397da6575a input=c6ebd579e8959040]*/
662+
{
663+
return _csv_Dialect___reduce___impl(self);
664+
}
665+
666+
/*[clinic input]
667+
_csv.Dialect.__replace__
668+
669+
**changes: dict
670+
671+
Return a copy of the dialect with the specified options replaced.
672+
[clinic start generated code]*/
673+
674+
static PyObject *
675+
_csv_Dialect___replace___impl(DialectObj *self, PyObject *changes)
676+
/*[clinic end generated code: output=8f692c2c63a61b50 input=154beb565fbabd4c]*/
651677
{
652-
if (PyTuple_GET_SIZE(args) != 0) {
653-
PyErr_SetString(PyExc_TypeError,
654-
"__replace__() takes no positional arguments");
655-
return NULL;
656-
}
657678
PyObject *newargs = PyTuple_Pack(1, self);
658679
if (newargs == NULL) {
659680
return NULL;
660681
}
661-
PyObject *result = dialect_new(Py_TYPE(self), newargs, kwargs);
682+
PyObject *result = dialect_new(Py_TYPE(self), newargs, changes);
662683
Py_DECREF(newargs);
663684
return result;
664685
}
665686

666687
static struct PyMethodDef dialect_methods[] = {
667-
{"__reduce__", Dialect_reduce, METH_VARARGS, dialect_reduce_doc},
668-
{"__reduce_ex__", Dialect_reduce, METH_VARARGS, dialect_reduce_doc},
669-
{"__replace__", _PyCFunction_CAST(Dialect_replace),
670-
METH_VARARGS | METH_KEYWORDS, dialect_replace_doc},
688+
_CSV_DIALECT___REDUCE___METHODDEF
689+
_CSV_DIALECT___REDUCE_EX___METHODDEF
690+
_CSV_DIALECT___REPLACE___METHODDEF
671691
{NULL, NULL}
672692
};
673693

@@ -1162,10 +1182,31 @@ PyType_Spec Reader_Type_spec = {
11621182
};
11631183

11641184

1185+
/*[clinic input]
1186+
_csv.reader
1187+
1188+
iterable: object
1189+
dialect: object(c_default='NULL') = 'excel'
1190+
/
1191+
**fmtparams: dict
1192+
1193+
Return a reader object that will process lines from the given iterable.
1194+
1195+
The "iterable" argument can be any object that returns a line
1196+
of input for each iteration, such as a file object or a list. The
1197+
optional "dialect" argument defines a CSV dialect. The function
1198+
also accepts optional keyword arguments which override settings
1199+
provided by the dialect.
1200+
1201+
The returned object is an iterator. Each iteration returns a row
1202+
of the CSV file (which can span multiple input lines).
1203+
[clinic start generated code]*/
1204+
11651205
static PyObject *
1166-
csv_reader(PyObject *module, PyObject *args, PyObject *keyword_args)
1206+
_csv_reader_impl(PyObject *module, PyObject *iterable, PyObject *dialect,
1207+
PyObject *fmtparams)
1208+
/*[clinic end generated code: output=c7033323f4e82fae input=330c6d58878e33b7]*/
11671209
{
1168-
PyObject * iterator, * dialect = NULL;
11691210
_csvstate *module_state = get_csv_state(module);
11701211
ReaderObj * self = PyObject_GC_New(
11711212
ReaderObj,
@@ -1186,17 +1227,13 @@ csv_reader(PyObject *module, PyObject *args, PyObject *keyword_args)
11861227
return NULL;
11871228
}
11881229

1189-
if (!PyArg_UnpackTuple(args, "reader", 1, 2, &iterator, &dialect)) {
1190-
Py_DECREF(self);
1191-
return NULL;
1192-
}
1193-
self->input_iter = PyObject_GetIter(iterator);
1230+
self->input_iter = PyObject_GetIter(iterable);
11941231
if (self->input_iter == NULL) {
11951232
Py_DECREF(self);
11961233
return NULL;
11971234
}
11981235
self->dialect = (DialectObj *)_call_dialect(module_state, dialect,
1199-
keyword_args);
1236+
fmtparams);
12001237
if (self->dialect == NULL) {
12011238
Py_DECREF(self);
12021239
return NULL;
@@ -1624,10 +1661,27 @@ PyType_Spec Writer_Type_spec = {
16241661
};
16251662

16261663

1664+
/*[clinic input]
1665+
_csv.writer
1666+
1667+
fileobj as output_file: object
1668+
dialect: object(c_default='NULL') = 'excel'
1669+
/
1670+
**fmtparams: dict
1671+
1672+
Return a writer object writing user data to the given file object.
1673+
1674+
The "fileobj" argument can be any object that supports the file API.
1675+
The optional "dialect" argument defines a CSV dialect. The function
1676+
also accepts optional keyword arguments which override settings
1677+
provided by the dialect.
1678+
[clinic start generated code]*/
1679+
16271680
static PyObject *
1628-
csv_writer(PyObject *module, PyObject *args, PyObject *keyword_args)
1681+
_csv_writer_impl(PyObject *module, PyObject *output_file, PyObject *dialect,
1682+
PyObject *fmtparams)
1683+
/*[clinic end generated code: output=3f57919e03cca475 input=18d396d2aa8138f0]*/
16291684
{
1630-
PyObject * output_file, * dialect = NULL;
16311685
_csvstate *module_state = get_csv_state(module);
16321686
WriterObj * self = PyObject_GC_New(WriterObj, module_state->writer_type);
16331687

@@ -1644,10 +1698,6 @@ csv_writer(PyObject *module, PyObject *args, PyObject *keyword_args)
16441698

16451699
self->error_obj = Py_NewRef(module_state->error_obj);
16461700

1647-
if (!PyArg_UnpackTuple(args, "writer", 1, 2, &output_file, &dialect)) {
1648-
Py_DECREF(self);
1649-
return NULL;
1650-
}
16511701
if (PyObject_GetOptionalAttr(output_file,
16521702
module_state->str_write,
16531703
&self->write) < 0) {
@@ -1661,7 +1711,7 @@ csv_writer(PyObject *module, PyObject *args, PyObject *keyword_args)
16611711
return NULL;
16621712
}
16631713
self->dialect = (DialectObj *)_call_dialect(module_state, dialect,
1664-
keyword_args);
1714+
fmtparams);
16651715
if (self->dialect == NULL) {
16661716
Py_DECREF(self);
16671717
return NULL;
@@ -1687,21 +1737,36 @@ _csv_list_dialects_impl(PyObject *module)
16871737
return PyDict_Keys(get_csv_state(module)->dialects);
16881738
}
16891739

1740+
/*[clinic input]
1741+
_csv.register_dialect
1742+
1743+
name as name_obj: object
1744+
dialect as dialect_obj: object(c_default='NULL') = 'excel'
1745+
/
1746+
**fmtparams: dict
1747+
1748+
Create a mapping from a string name to a CVS dialect.
1749+
1750+
The optional "dialect" argument specifies the base dialect instance
1751+
or the name of the registered dialect. The function also accepts
1752+
optional keyword arguments which override settings provided by the
1753+
dialect.
1754+
[clinic start generated code]*/
1755+
16901756
static PyObject *
1691-
csv_register_dialect(PyObject *module, PyObject *args, PyObject *kwargs)
1757+
_csv_register_dialect_impl(PyObject *module, PyObject *name_obj,
1758+
PyObject *dialect_obj, PyObject *fmtparams)
1759+
/*[clinic end generated code: output=b00b54de5b950472 input=64e9180e18d88a97]*/
16921760
{
1693-
PyObject *name_obj, *dialect_obj = NULL;
16941761
_csvstate *module_state = get_csv_state(module);
16951762
PyObject *dialect;
16961763

1697-
if (!PyArg_UnpackTuple(args, "register_dialect", 1, 2, &name_obj, &dialect_obj))
1698-
return NULL;
16991764
if (!PyUnicode_Check(name_obj)) {
17001765
PyErr_SetString(PyExc_TypeError,
17011766
"dialect name must be a string");
17021767
return NULL;
17031768
}
1704-
dialect = _call_dialect(module_state, dialect_obj, kwargs);
1769+
dialect = _call_dialect(module_state, dialect_obj, fmtparams);
17051770
if (dialect == NULL)
17061771
return NULL;
17071772
if (PyDict_SetItem(module_state->dialects, name_obj, dialect) < 0) {
@@ -1800,47 +1865,10 @@ PyType_Spec error_spec = {
18001865

18011866
PyDoc_STRVAR(csv_module_doc, "CSV parsing and writing.\n");
18021867

1803-
PyDoc_STRVAR(csv_reader_doc,
1804-
"reader($module, iterable, /, dialect='excel', **fmtparams)\n"
1805-
"--\n\n"
1806-
"Return a reader object that will process lines from the given iterable.\n"
1807-
"\n"
1808-
"The \"iterable\" argument can be any object that returns a line\n"
1809-
"of input for each iteration, such as a file object or a list. The\n"
1810-
"optional \"dialect\" argument defines a CSV dialect. The function\n"
1811-
"also accepts optional keyword arguments which override settings\n"
1812-
"provided by the dialect.\n"
1813-
"\n"
1814-
"The returned object is an iterator. Each iteration returns a row\n"
1815-
"of the CSV file (which can span multiple input lines).\n");
1816-
1817-
PyDoc_STRVAR(csv_writer_doc,
1818-
"writer($module, fileobj, /, dialect='excel', **fmtparams)\n"
1819-
"--\n\n"
1820-
"Return a writer object that will write user data on the given file object.\n"
1821-
"\n"
1822-
"The \"fileobj\" argument can be any object that supports the file API.\n"
1823-
"The optional \"dialect\" argument defines a CSV dialect. The function\n"
1824-
"also accepts optional keyword arguments which override settings\n"
1825-
"provided by the dialect.\n");
1826-
1827-
PyDoc_STRVAR(csv_register_dialect_doc,
1828-
"register_dialect($module, name, /, dialect='excel', **fmtparams)\n"
1829-
"--\n\n"
1830-
"Create a mapping from a string name to a CVS dialect.\n"
1831-
"\n"
1832-
"The optional \"dialect\" argument specifies the base dialect instance\n"
1833-
"or the name of the registered dialect. The function also accepts\n"
1834-
"optional keyword arguments which override settings provided by the\n"
1835-
"dialect.\n");
1836-
18371868
static struct PyMethodDef csv_methods[] = {
1838-
{ "reader", _PyCFunction_CAST(csv_reader),
1839-
METH_VARARGS | METH_KEYWORDS, csv_reader_doc},
1840-
{ "writer", _PyCFunction_CAST(csv_writer),
1841-
METH_VARARGS | METH_KEYWORDS, csv_writer_doc},
1842-
{ "register_dialect", _PyCFunction_CAST(csv_register_dialect),
1843-
METH_VARARGS | METH_KEYWORDS, csv_register_dialect_doc},
1869+
_CSV_READER_METHODDEF
1870+
_CSV_WRITER_METHODDEF
1871+
_CSV_REGISTER_DIALECT_METHODDEF
18441872
_CSV_LIST_DIALECTS_METHODDEF
18451873
_CSV_UNREGISTER_DIALECT_METHODDEF
18461874
_CSV_GET_DIALECT_METHODDEF

0 commit comments

Comments
 (0)