Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit e6996ed

Browse files
author
Stefan Krah
committed
Issue #16145: Support legacy strings in the _csv module.
1 parent ed71918 commit e6996ed

3 files changed

Lines changed: 50 additions & 6 deletions

File tree

Lib/test/test_csv.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,17 @@ def write(self, buf):
197197
fileobj.seek(0)
198198
self.assertEqual(fileobj.read(), "a,b\r\nc,d\r\n")
199199

200+
@support.cpython_only
201+
def test_writerows_legacy_strings(self):
202+
import _testcapi
203+
204+
c = _testcapi.unicode_legacy_string('a')
205+
with TemporaryFile("w+", newline='') as fileobj:
206+
writer = csv.writer(fileobj)
207+
writer.writerows([[c]])
208+
fileobj.seek(0)
209+
self.assertEqual(fileobj.read(), "a\r\n")
210+
200211
def _read_test(self, input, expect, **kwargs):
201212
reader = csv.reader(input, **kwargs)
202213
result = list(reader)

Modules/_csv.c

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,6 @@ module instead.
1313
#include "Python.h"
1414
#include "structmember.h"
1515

16-
#define IS_BASESTRING(o) \
17-
PyUnicode_Check(o)
1816

1917
typedef struct {
2018
PyObject *error_obj; /* CSV exception */
@@ -248,6 +246,7 @@ _set_char(const char *name, Py_UCS4 *target, PyObject *src, Py_UCS4 dflt)
248246
name);
249247
return -1;
250248
}
249+
/* PyUnicode_READY() is called in PyUnicode_GetLength() */
251250
if (len > 0)
252251
*target = PyUnicode_READ_CHAR(src, 0);
253252
}
@@ -263,12 +262,14 @@ _set_str(const char *name, PyObject **target, PyObject *src, const char *dflt)
263262
else {
264263
if (src == Py_None)
265264
*target = NULL;
266-
else if (!IS_BASESTRING(src)) {
265+
else if (!PyUnicode_Check(src)) {
267266
PyErr_Format(PyExc_TypeError,
268267
"\"%s\" must be a string", name);
269268
return -1;
270269
}
271270
else {
271+
if (PyUnicode_READY(src) == -1)
272+
return -1;
272273
Py_XDECREF(*target);
273274
Py_INCREF(src);
274275
*target = src;
@@ -357,7 +358,7 @@ dialect_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
357358
return NULL;
358359

359360
if (dialect != NULL) {
360-
if (IS_BASESTRING(dialect)) {
361+
if (PyUnicode_Check(dialect)) {
361362
dialect = get_dialect_from_registry(dialect);
362363
if (dialect == NULL)
363364
return NULL;
@@ -808,6 +809,10 @@ Reader_iternext(ReaderObj *self)
808809
Py_DECREF(lineobj);
809810
return NULL;
810811
}
812+
if (PyUnicode_READY(lineobj) == -1) {
813+
Py_DECREF(lineobj);
814+
return NULL;
815+
}
811816
++self->line_num;
812817
kind = PyUnicode_KIND(lineobj);
813818
data = PyUnicode_DATA(lineobj);
@@ -1108,6 +1113,8 @@ join_append(WriterObj *self, PyObject *field, int *quoted, int quote_empty)
11081113
Py_ssize_t rec_len;
11091114

11101115
if (field != NULL) {
1116+
if (PyUnicode_READY(field) == -1)
1117+
return 0;
11111118
field_kind = PyUnicode_KIND(field);
11121119
field_data = PyUnicode_DATA(field);
11131120
field_len = PyUnicode_GET_LENGTH(field);
@@ -1403,11 +1410,13 @@ csv_register_dialect(PyObject *module, PyObject *args, PyObject *kwargs)
14031410

14041411
if (!PyArg_UnpackTuple(args, "", 1, 2, &name_obj, &dialect_obj))
14051412
return NULL;
1406-
if (!IS_BASESTRING(name_obj)) {
1413+
if (!PyUnicode_Check(name_obj)) {
14071414
PyErr_SetString(PyExc_TypeError,
1408-
"dialect name must be a string or unicode");
1415+
"dialect name must be a string");
14091416
return NULL;
14101417
}
1418+
if (PyUnicode_READY(name_obj) == -1)
1419+
return NULL;
14111420
dialect = _call_dialect(dialect_obj, kwargs);
14121421
if (dialect == NULL)
14131422
return NULL;

Modules/_testcapimodule.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1520,6 +1520,29 @@ unicode_transformdecimaltoascii(PyObject *self, PyObject *args)
15201520
return PyUnicode_TransformDecimalToASCII(unicode, length);
15211521
}
15221522

1523+
static PyObject *
1524+
unicode_legacy_string(PyObject *self, PyObject *args)
1525+
{
1526+
Py_UNICODE *data;
1527+
Py_ssize_t len;
1528+
PyObject *u;
1529+
1530+
if (!PyArg_ParseTuple(args, "u#", &data, &len))
1531+
return NULL;
1532+
1533+
u = PyUnicode_FromUnicode(NULL, len);
1534+
if (u == NULL)
1535+
return NULL;
1536+
1537+
memcpy(PyUnicode_AS_UNICODE(u), data, len * sizeof(Py_UNICODE));
1538+
1539+
if (len > 0) { /* The empty string is always ready. */
1540+
assert(!PyUnicode_IS_READY(u));
1541+
}
1542+
1543+
return u;
1544+
}
1545+
15231546
static PyObject *
15241547
getargs_w_star(PyObject *self, PyObject *args)
15251548
{
@@ -2506,6 +2529,7 @@ static PyMethodDef TestMethods[] = {
25062529
{"unicode_aswidecharstring",unicode_aswidecharstring, METH_VARARGS},
25072530
{"unicode_encodedecimal", unicode_encodedecimal, METH_VARARGS},
25082531
{"unicode_transformdecimaltoascii", unicode_transformdecimaltoascii, METH_VARARGS},
2532+
{"unicode_legacy_string", unicode_legacy_string, METH_VARARGS},
25092533
#ifdef WITH_THREAD
25102534
{"_test_thread_state", test_thread_state, METH_VARARGS},
25112535
{"_pending_threadfunc", pending_threadfunc, METH_VARARGS},

0 commit comments

Comments
 (0)