Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit94306f7

Browse files
[3.14]gh-132813: Improve error messages for incorrect types and values of csv.Dialog attributes (GH-133241) (GH-135050)
Make them similar to PyArg_Parse error messages, mention None asa possible value, show a wrong type and the string length.(cherry picked from commitdf98a47)Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
1 parent9bbb0c5 commit94306f7

File tree

3 files changed

+69
-54
lines changed

3 files changed

+69
-54
lines changed

‎Lib/test/test_csv.py

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1122,19 +1122,22 @@ class mydialect(csv.Dialect):
11221122
withself.assertRaises(csv.Error)ascm:
11231123
mydialect()
11241124
self.assertEqual(str(cm.exception),
1125-
'"quotechar" must be a 1-character string')
1125+
'"quotechar" must be a unicode character or None, '
1126+
'not a string of length 0')
11261127

11271128
mydialect.quotechar="''"
11281129
withself.assertRaises(csv.Error)ascm:
11291130
mydialect()
11301131
self.assertEqual(str(cm.exception),
1131-
'"quotechar" must be a 1-character string')
1132+
'"quotechar" must be a unicode character or None, '
1133+
'not a string of length 2')
11321134

11331135
mydialect.quotechar=4
11341136
withself.assertRaises(csv.Error)ascm:
11351137
mydialect()
11361138
self.assertEqual(str(cm.exception),
1137-
'"quotechar" must be string or None, not int')
1139+
'"quotechar" must be a unicode character or None, '
1140+
'not int')
11381141

11391142
deftest_delimiter(self):
11401143
classmydialect(csv.Dialect):
@@ -1151,31 +1154,32 @@ class mydialect(csv.Dialect):
11511154
withself.assertRaises(csv.Error)ascm:
11521155
mydialect()
11531156
self.assertEqual(str(cm.exception),
1154-
'"delimiter" must be a 1-character string')
1157+
'"delimiter" must be a unicode character, '
1158+
'not a string of length 3')
11551159

11561160
mydialect.delimiter=""
11571161
withself.assertRaises(csv.Error)ascm:
11581162
mydialect()
11591163
self.assertEqual(str(cm.exception),
1160-
'"delimiter" must be a1-characterstring')
1164+
'"delimiter" must be aunicodecharacter, not astring of length 0')
11611165

11621166
mydialect.delimiter=b","
11631167
withself.assertRaises(csv.Error)ascm:
11641168
mydialect()
11651169
self.assertEqual(str(cm.exception),
1166-
'"delimiter" must bestring, not bytes')
1170+
'"delimiter" must bea unicode character, not bytes')
11671171

11681172
mydialect.delimiter=4
11691173
withself.assertRaises(csv.Error)ascm:
11701174
mydialect()
11711175
self.assertEqual(str(cm.exception),
1172-
'"delimiter" must bestring, not int')
1176+
'"delimiter" must bea unicode character, not int')
11731177

11741178
mydialect.delimiter=None
11751179
withself.assertRaises(csv.Error)ascm:
11761180
mydialect()
11771181
self.assertEqual(str(cm.exception),
1178-
'"delimiter" must bestring, not NoneType')
1182+
'"delimiter" must bea unicode character, not NoneType')
11791183

11801184
deftest_escapechar(self):
11811185
classmydialect(csv.Dialect):
@@ -1189,20 +1193,32 @@ class mydialect(csv.Dialect):
11891193
self.assertEqual(d.escapechar,"\\")
11901194

11911195
mydialect.escapechar=""
1192-
withself.assertRaisesRegex(csv.Error,'"escapechar" must be a 1-character string'):
1196+
withself.assertRaises(csv.Error)ascm:
11931197
mydialect()
1198+
self.assertEqual(str(cm.exception),
1199+
'"escapechar" must be a unicode character or None, '
1200+
'not a string of length 0')
11941201

11951202
mydialect.escapechar="**"
1196-
withself.assertRaisesRegex(csv.Error,'"escapechar" must be a 1-character string'):
1203+
withself.assertRaises(csv.Error)ascm:
11971204
mydialect()
1205+
self.assertEqual(str(cm.exception),
1206+
'"escapechar" must be a unicode character or None, '
1207+
'not a string of length 2')
11981208

11991209
mydialect.escapechar=b"*"
1200-
withself.assertRaisesRegex(csv.Error,'"escapechar" must be string or None, not bytes'):
1210+
withself.assertRaises(csv.Error)ascm:
12011211
mydialect()
1212+
self.assertEqual(str(cm.exception),
1213+
'"escapechar" must be a unicode character or None, '
1214+
'not bytes')
12021215

12031216
mydialect.escapechar=4
1204-
withself.assertRaisesRegex(csv.Error,'"escapechar" must be string or None, not int'):
1217+
withself.assertRaises(csv.Error)ascm:
12051218
mydialect()
1219+
self.assertEqual(str(cm.exception),
1220+
'"escapechar" must be a unicode character or None, '
1221+
'not int')
12061222

12071223
deftest_lineterminator(self):
12081224
classmydialect(csv.Dialect):
@@ -1223,7 +1239,13 @@ class mydialect(csv.Dialect):
12231239
withself.assertRaises(csv.Error)ascm:
12241240
mydialect()
12251241
self.assertEqual(str(cm.exception),
1226-
'"lineterminator" must be a string')
1242+
'"lineterminator" must be a string, not int')
1243+
1244+
mydialect.lineterminator=None
1245+
withself.assertRaises(csv.Error)ascm:
1246+
mydialect()
1247+
self.assertEqual(str(cm.exception),
1248+
'"lineterminator" must be a string, not NoneType')
12271249

12281250
deftest_invalid_chars(self):
12291251
defcreate_invalid(field_name,value,**kwargs):
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Improve error messages for incorrect types and values of:class:`csv.Dialect`
2+
attributes.

‎Modules/_csv.c

Lines changed: 32 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ _set_int(const char *name, int *target, PyObject *src, int dflt)
237237
intvalue;
238238
if (!PyLong_CheckExact(src)) {
239239
PyErr_Format(PyExc_TypeError,
240-
"\"%s\" must be an integer",name);
240+
"\"%s\" must be an integer, not %T",name,src);
241241
return-1;
242242
}
243243
value=PyLong_AsInt(src);
@@ -255,27 +255,29 @@ _set_char_or_none(const char *name, Py_UCS4 *target, PyObject *src, Py_UCS4 dflt
255255
if (src==NULL) {
256256
*target=dflt;
257257
}
258-
else {
258+
elseif (src==Py_None){
259259
*target=NOT_SET;
260-
if (src!=Py_None) {
261-
if (!PyUnicode_Check(src)) {
262-
PyErr_Format(PyExc_TypeError,
263-
"\"%s\" must be string or None, not %.200s",name,
264-
Py_TYPE(src)->tp_name);
265-
return-1;
266-
}
267-
Py_ssize_tlen=PyUnicode_GetLength(src);
268-
if (len<0) {
269-
return-1;
270-
}
271-
if (len!=1) {
272-
PyErr_Format(PyExc_TypeError,
273-
"\"%s\" must be a 1-character string",
274-
name);
275-
return-1;
276-
}
277-
*target=PyUnicode_READ_CHAR(src,0);
260+
}
261+
else {
262+
// similar to PyArg_Parse("C?")
263+
if (!PyUnicode_Check(src)) {
264+
PyErr_Format(PyExc_TypeError,
265+
"\"%s\" must be a unicode character or None, not %T",
266+
name,src);
267+
return-1;
268+
}
269+
Py_ssize_tlen=PyUnicode_GetLength(src);
270+
if (len<0) {
271+
return-1;
278272
}
273+
if (len!=1) {
274+
PyErr_Format(PyExc_TypeError,
275+
"\"%s\" must be a unicode character or None, "
276+
"not a string of length %zd",
277+
name,len);
278+
return-1;
279+
}
280+
*target=PyUnicode_READ_CHAR(src,0);
279281
}
280282
return0;
281283
}
@@ -287,20 +289,22 @@ _set_char(const char *name, Py_UCS4 *target, PyObject *src, Py_UCS4 dflt)
287289
*target=dflt;
288290
}
289291
else {
292+
// similar to PyArg_Parse("C")
290293
if (!PyUnicode_Check(src)) {
291294
PyErr_Format(PyExc_TypeError,
292-
"\"%s\" must bestring, not %.200s",name,
293-
Py_TYPE(src)->tp_name);
294-
return-1;
295+
"\"%s\" must bea unicode character, not %T",
296+
name,src);
297+
return-1;
295298
}
296299
Py_ssize_tlen=PyUnicode_GetLength(src);
297300
if (len<0) {
298301
return-1;
299302
}
300303
if (len!=1) {
301304
PyErr_Format(PyExc_TypeError,
302-
"\"%s\" must be a 1-character string",
303-
name);
305+
"\"%s\" must be a unicode character, "
306+
"not a string of length %zd",
307+
name,len);
304308
return-1;
305309
}
306310
*target=PyUnicode_READ_CHAR(src,0);
@@ -314,16 +318,12 @@ _set_str(const char *name, PyObject **target, PyObject *src, const char *dflt)
314318
if (src==NULL)
315319
*target=PyUnicode_DecodeASCII(dflt,strlen(dflt),NULL);
316320
else {
317-
if (src==Py_None)
318-
*target=NULL;
319-
elseif (!PyUnicode_Check(src)) {
321+
if (!PyUnicode_Check(src)) {
320322
PyErr_Format(PyExc_TypeError,
321-
"\"%s\" must be a string",name);
323+
"\"%s\" must be a string, not %T",name,src);
322324
return-1;
323325
}
324-
else {
325-
Py_XSETREF(*target,Py_NewRef(src));
326-
}
326+
Py_XSETREF(*target,Py_NewRef(src));
327327
}
328328
return0;
329329
}
@@ -533,22 +533,13 @@ dialect_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
533533
/* validate options */
534534
if (dialect_check_quoting(self->quoting))
535535
gotoerr;
536-
if (self->delimiter==NOT_SET) {
537-
PyErr_SetString(PyExc_TypeError,
538-
"\"delimiter\" must be a 1-character string");
539-
gotoerr;
540-
}
541536
if (quotechar==Py_None&&quoting==NULL)
542537
self->quoting=QUOTE_NONE;
543538
if (self->quoting!=QUOTE_NONE&&self->quotechar==NOT_SET) {
544539
PyErr_SetString(PyExc_TypeError,
545540
"quotechar must be set if quoting enabled");
546541
gotoerr;
547542
}
548-
if (self->lineterminator==NULL) {
549-
PyErr_SetString(PyExc_TypeError,"lineterminator must be set");
550-
gotoerr;
551-
}
552543
if (dialect_check_char("delimiter",self->delimiter,self, true)||
553544
dialect_check_char("escapechar",self->escapechar,self,
554545
!self->skipinitialspace)||

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp