Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
190 changes: 109 additions & 81 deletions Modules/_csv.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,9 @@ module instead.

/*[clinic input]
module _csv
class _csv.Dialect "DialectObj *" "clinic_state()->dialect_type"
[clinic start generated code]*/
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=385118b71aa43706]*/

#include "clinic/_csv.c.h"
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=042fcc14c7d541cc]*/
#define NOT_SET ((Py_UCS4)-1)
#define EOL ((Py_UCS4)-2)

Expand Down Expand Up @@ -125,6 +124,8 @@ typedef struct {
bool nonascii_special;
} DialectObj;

#include "clinic/_csv.c.h"

typedef struct {
PyObject_HEAD

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

PyDoc_STRVAR(dialect_reduce_doc, "raises an exception to avoid pickling");
/*[clinic input]
_csv.Dialect.__reduce__

Raise an exception to avoid pickling.
[clinic start generated code]*/

static PyObject *
Dialect_reduce(PyObject *self, PyObject *args) {
_csv_Dialect___reduce___impl(DialectObj *self)
/*[clinic end generated code: output=f728b34af509ed69 input=e46419b46279e480]*/
{
PyErr_Format(PyExc_TypeError,
"cannot pickle '%.100s' instances", _PyType_Name(Py_TYPE(self)));
return NULL;
}

PyDoc_STRVAR(dialect_replace_doc,
"__replace__($self, /, **changes)\n"
"--\n"
"\n"
"Return a copy of the dialect with the specified options replaced.");
/*[clinic input]
_csv.Dialect.__reduce_ex__

protocol: object
/

Raise an exception to avoid pickling.
[clinic start generated code]*/

static PyObject *
Dialect_replace(PyObject *self, PyObject *args, PyObject *kwargs)
_csv_Dialect___reduce_ex___impl(DialectObj *self, PyObject *protocol)
/*[clinic end generated code: output=d45dec397da6575a input=c6ebd579e8959040]*/
{
return _csv_Dialect___reduce___impl(self);
}

/*[clinic input]
_csv.Dialect.__replace__

**changes: dict

Return a copy of the dialect with the specified options replaced.
[clinic start generated code]*/

static PyObject *
_csv_Dialect___replace___impl(DialectObj *self, PyObject *changes)
/*[clinic end generated code: output=8f692c2c63a61b50 input=154beb565fbabd4c]*/
{
if (PyTuple_GET_SIZE(args) != 0) {
PyErr_SetString(PyExc_TypeError,
"__replace__() takes no positional arguments");
return NULL;
}
PyObject *newargs = PyTuple_Pack(1, self);
if (newargs == NULL) {
return NULL;
}
PyObject *result = dialect_new(Py_TYPE(self), newargs, kwargs);
PyObject *result = dialect_new(Py_TYPE(self), newargs, changes);
Py_DECREF(newargs);
return result;
}

static struct PyMethodDef dialect_methods[] = {
{"__reduce__", Dialect_reduce, METH_VARARGS, dialect_reduce_doc},
{"__reduce_ex__", Dialect_reduce, METH_VARARGS, dialect_reduce_doc},
{"__replace__", _PyCFunction_CAST(Dialect_replace),
METH_VARARGS | METH_KEYWORDS, dialect_replace_doc},
_CSV_DIALECT___REDUCE___METHODDEF
_CSV_DIALECT___REDUCE_EX___METHODDEF
_CSV_DIALECT___REPLACE___METHODDEF
{NULL, NULL}
};

Expand Down Expand Up @@ -1162,10 +1182,31 @@ PyType_Spec Reader_Type_spec = {
};


/*[clinic input]
_csv.reader

iterable: object
dialect: object(c_default='NULL') = 'excel'
/
**fmtparams: dict

Return a reader object that will process lines from the given iterable.

The "iterable" argument can be any object that returns a line
of input for each iteration, such as a file object or a list. The
optional "dialect" argument defines a CSV dialect. The function
also accepts optional keyword arguments which override settings
provided by the dialect.

The returned object is an iterator. Each iteration returns a row
of the CSV file (which can span multiple input lines).
[clinic start generated code]*/

static PyObject *
csv_reader(PyObject *module, PyObject *args, PyObject *keyword_args)
_csv_reader_impl(PyObject *module, PyObject *iterable, PyObject *dialect,
PyObject *fmtparams)
/*[clinic end generated code: output=c7033323f4e82fae input=330c6d58878e33b7]*/
{
PyObject * iterator, * dialect = NULL;
_csvstate *module_state = get_csv_state(module);
ReaderObj * self = PyObject_GC_New(
ReaderObj,
Expand All @@ -1186,17 +1227,13 @@ csv_reader(PyObject *module, PyObject *args, PyObject *keyword_args)
return NULL;
}

if (!PyArg_UnpackTuple(args, "reader", 1, 2, &iterator, &dialect)) {
Py_DECREF(self);
return NULL;
}
self->input_iter = PyObject_GetIter(iterator);
self->input_iter = PyObject_GetIter(iterable);
if (self->input_iter == NULL) {
Py_DECREF(self);
return NULL;
}
self->dialect = (DialectObj *)_call_dialect(module_state, dialect,
keyword_args);
fmtparams);
if (self->dialect == NULL) {
Py_DECREF(self);
return NULL;
Expand Down Expand Up @@ -1624,10 +1661,27 @@ PyType_Spec Writer_Type_spec = {
};


/*[clinic input]
_csv.writer

fileobj as output_file: object
dialect: object(c_default='NULL') = 'excel'
/
**fmtparams: dict

Return a writer object writing user data to the given file object.

The "fileobj" argument can be any object that supports the file API.
The optional "dialect" argument defines a CSV dialect. The function
also accepts optional keyword arguments which override settings
provided by the dialect.
[clinic start generated code]*/

static PyObject *
csv_writer(PyObject *module, PyObject *args, PyObject *keyword_args)
_csv_writer_impl(PyObject *module, PyObject *output_file, PyObject *dialect,
PyObject *fmtparams)
/*[clinic end generated code: output=3f57919e03cca475 input=18d396d2aa8138f0]*/
{
PyObject * output_file, * dialect = NULL;
_csvstate *module_state = get_csv_state(module);
WriterObj * self = PyObject_GC_New(WriterObj, module_state->writer_type);

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

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

if (!PyArg_UnpackTuple(args, "writer", 1, 2, &output_file, &dialect)) {
Py_DECREF(self);
return NULL;
}
if (PyObject_GetOptionalAttr(output_file,
module_state->str_write,
&self->write) < 0) {
Expand All @@ -1661,7 +1711,7 @@ csv_writer(PyObject *module, PyObject *args, PyObject *keyword_args)
return NULL;
}
self->dialect = (DialectObj *)_call_dialect(module_state, dialect,
keyword_args);
fmtparams);
if (self->dialect == NULL) {
Py_DECREF(self);
return NULL;
Expand All @@ -1687,21 +1737,36 @@ _csv_list_dialects_impl(PyObject *module)
return PyDict_Keys(get_csv_state(module)->dialects);
}

/*[clinic input]
_csv.register_dialect

name as name_obj: object
dialect as dialect_obj: object(c_default='NULL') = 'excel'
/
**fmtparams: dict

Create a mapping from a string name to a CVS dialect.

The optional "dialect" argument specifies the base dialect instance
or the name of the registered dialect. The function also accepts
optional keyword arguments which override settings provided by the
dialect.
[clinic start generated code]*/

static PyObject *
csv_register_dialect(PyObject *module, PyObject *args, PyObject *kwargs)
_csv_register_dialect_impl(PyObject *module, PyObject *name_obj,
PyObject *dialect_obj, PyObject *fmtparams)
/*[clinic end generated code: output=b00b54de5b950472 input=64e9180e18d88a97]*/
{
PyObject *name_obj, *dialect_obj = NULL;
_csvstate *module_state = get_csv_state(module);
PyObject *dialect;

if (!PyArg_UnpackTuple(args, "register_dialect", 1, 2, &name_obj, &dialect_obj))
return NULL;
if (!PyUnicode_Check(name_obj)) {
PyErr_SetString(PyExc_TypeError,
"dialect name must be a string");
return NULL;
}
dialect = _call_dialect(module_state, dialect_obj, kwargs);
dialect = _call_dialect(module_state, dialect_obj, fmtparams);
if (dialect == NULL)
return NULL;
if (PyDict_SetItem(module_state->dialects, name_obj, dialect) < 0) {
Expand Down Expand Up @@ -1800,47 +1865,10 @@ PyType_Spec error_spec = {

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

PyDoc_STRVAR(csv_reader_doc,
"reader($module, iterable, /, dialect='excel', **fmtparams)\n"
"--\n\n"
"Return a reader object that will process lines from the given iterable.\n"
"\n"
"The \"iterable\" argument can be any object that returns a line\n"
"of input for each iteration, such as a file object or a list. The\n"
"optional \"dialect\" argument defines a CSV dialect. The function\n"
"also accepts optional keyword arguments which override settings\n"
"provided by the dialect.\n"
"\n"
"The returned object is an iterator. Each iteration returns a row\n"
"of the CSV file (which can span multiple input lines).\n");

PyDoc_STRVAR(csv_writer_doc,
"writer($module, fileobj, /, dialect='excel', **fmtparams)\n"
"--\n\n"
"Return a writer object that will write user data on the given file object.\n"
"\n"
"The \"fileobj\" argument can be any object that supports the file API.\n"
"The optional \"dialect\" argument defines a CSV dialect. The function\n"
"also accepts optional keyword arguments which override settings\n"
"provided by the dialect.\n");

PyDoc_STRVAR(csv_register_dialect_doc,
"register_dialect($module, name, /, dialect='excel', **fmtparams)\n"
"--\n\n"
"Create a mapping from a string name to a CVS dialect.\n"
"\n"
"The optional \"dialect\" argument specifies the base dialect instance\n"
"or the name of the registered dialect. The function also accepts\n"
"optional keyword arguments which override settings provided by the\n"
"dialect.\n");

static struct PyMethodDef csv_methods[] = {
{ "reader", _PyCFunction_CAST(csv_reader),
METH_VARARGS | METH_KEYWORDS, csv_reader_doc},
{ "writer", _PyCFunction_CAST(csv_writer),
METH_VARARGS | METH_KEYWORDS, csv_writer_doc},
{ "register_dialect", _PyCFunction_CAST(csv_register_dialect),
METH_VARARGS | METH_KEYWORDS, csv_register_dialect_doc},
_CSV_READER_METHODDEF
_CSV_WRITER_METHODDEF
_CSV_REGISTER_DIALECT_METHODDEF
_CSV_LIST_DIALECTS_METHODDEF
_CSV_UNREGISTER_DIALECT_METHODDEF
_CSV_GET_DIALECT_METHODDEF
Expand Down
Loading
Loading