Skip to content

Commit d8c11b7

Browse files
gh-94808: add tests covering PySequence_{Set,Del}Slice (GH-99123)
(cherry picked from commit c5c4077) Co-authored-by: Nikita Sobolev <[email protected]>
1 parent 07734a4 commit d8c11b7

File tree

2 files changed

+113
-0
lines changed

2 files changed

+113
-0
lines changed

Lib/test/test_capi.py

+80
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,86 @@ class SubDict(dict):
415415
self.assertTrue(_testcapi.mapping_has_key(dct2, 'a'))
416416
self.assertFalse(_testcapi.mapping_has_key(dct2, 'b'))
417417

418+
def test_sequence_set_slice(self):
419+
# Correct case:
420+
data = [1, 2, 3, 4, 5]
421+
data_copy = data.copy()
422+
423+
_testcapi.sequence_set_slice(data, 1, 3, [8, 9])
424+
data_copy[1:3] = [8, 9]
425+
self.assertEqual(data, data_copy)
426+
self.assertEqual(data, [1, 8, 9, 4, 5])
427+
428+
# Custom class:
429+
class Custom:
430+
def __setitem__(self, index, value):
431+
self.index = index
432+
self.value = value
433+
434+
c = Custom()
435+
_testcapi.sequence_set_slice(c, 0, 5, 'abc')
436+
self.assertEqual(c.index, slice(0, 5))
437+
self.assertEqual(c.value, 'abc')
438+
439+
# Immutable sequences must raise:
440+
bad_seq1 = (1, 2, 3, 4)
441+
with self.assertRaises(TypeError):
442+
_testcapi.sequence_set_slice(bad_seq1, 1, 3, (8, 9))
443+
self.assertEqual(bad_seq1, (1, 2, 3, 4))
444+
445+
bad_seq2 = 'abcd'
446+
with self.assertRaises(TypeError):
447+
_testcapi.sequence_set_slice(bad_seq2, 1, 3, 'xy')
448+
self.assertEqual(bad_seq2, 'abcd')
449+
450+
# Not a sequence:
451+
with self.assertRaises(TypeError):
452+
_testcapi.sequence_set_slice(None, 1, 3, 'xy')
453+
454+
mapping = {1: 'a', 2: 'b', 3: 'c'}
455+
with self.assertRaises(TypeError):
456+
_testcapi.sequence_set_slice(mapping, 1, 3, 'xy')
457+
self.assertEqual(mapping, {1: 'a', 2: 'b', 3: 'c'})
458+
459+
def test_sequence_del_slice(self):
460+
# Correct case:
461+
data = [1, 2, 3, 4, 5]
462+
data_copy = data.copy()
463+
464+
_testcapi.sequence_del_slice(data, 1, 3)
465+
del data_copy[1:3]
466+
self.assertEqual(data, data_copy)
467+
self.assertEqual(data, [1, 4, 5])
468+
469+
# Custom class:
470+
class Custom:
471+
def __delitem__(self, index):
472+
self.index = index
473+
474+
c = Custom()
475+
_testcapi.sequence_del_slice(c, 0, 5)
476+
self.assertEqual(c.index, slice(0, 5))
477+
478+
# Immutable sequences must raise:
479+
bad_seq1 = (1, 2, 3, 4)
480+
with self.assertRaises(TypeError):
481+
_testcapi.sequence_del_slice(bad_seq1, 1, 3)
482+
self.assertEqual(bad_seq1, (1, 2, 3, 4))
483+
484+
bad_seq2 = 'abcd'
485+
with self.assertRaises(TypeError):
486+
_testcapi.sequence_del_slice(bad_seq2, 1, 3)
487+
self.assertEqual(bad_seq2, 'abcd')
488+
489+
# Not a sequence:
490+
with self.assertRaises(TypeError):
491+
_testcapi.sequence_del_slice(None, 1, 3)
492+
493+
mapping = {1: 'a', 2: 'b', 3: 'c'}
494+
with self.assertRaises(TypeError):
495+
_testcapi.sequence_del_slice(mapping, 1, 3)
496+
self.assertEqual(mapping, {1: 'a', 2: 'b', 3: 'c'})
497+
418498
@unittest.skipUnless(hasattr(_testcapi, 'negative_refcount'),
419499
'need _testcapi.negative_refcount')
420500
def test_negative_refcount(self):

Modules/_testcapimodule.c

+33
Original file line numberDiff line numberDiff line change
@@ -5382,6 +5382,37 @@ mapping_has_key(PyObject* self, PyObject *args)
53825382
return PyLong_FromLong(PyMapping_HasKey(context, key));
53835383
}
53845384

5385+
static PyObject *
5386+
sequence_set_slice(PyObject* self, PyObject *args)
5387+
{
5388+
PyObject *sequence, *obj;
5389+
Py_ssize_t i1, i2;
5390+
if (!PyArg_ParseTuple(args, "OnnO", &sequence, &i1, &i2, &obj)) {
5391+
return NULL;
5392+
}
5393+
5394+
int res = PySequence_SetSlice(sequence, i1, i2, obj);
5395+
if (res == -1) {
5396+
return NULL;
5397+
}
5398+
Py_RETURN_NONE;
5399+
}
5400+
5401+
static PyObject *
5402+
sequence_del_slice(PyObject* self, PyObject *args)
5403+
{
5404+
PyObject *sequence;
5405+
Py_ssize_t i1, i2;
5406+
if (!PyArg_ParseTuple(args, "Onn", &sequence, &i1, &i2)) {
5407+
return NULL;
5408+
}
5409+
5410+
int res = PySequence_DelSlice(sequence, i1, i2);
5411+
if (res == -1) {
5412+
return NULL;
5413+
}
5414+
Py_RETURN_NONE;
5415+
}
53855416

53865417
static PyObject *
53875418
test_pythread_tss_key_state(PyObject *self, PyObject *args)
@@ -6424,6 +6455,8 @@ static PyMethodDef TestMethods[] = {
64246455
{"get_mapping_items", get_mapping_items, METH_O},
64256456
{"test_mapping_has_key_string", test_mapping_has_key_string, METH_NOARGS},
64266457
{"mapping_has_key", mapping_has_key, METH_VARARGS},
6458+
{"sequence_set_slice", sequence_set_slice, METH_VARARGS},
6459+
{"sequence_del_slice", sequence_del_slice, METH_VARARGS},
64276460
{"test_pythread_tss_key_state", test_pythread_tss_key_state, METH_VARARGS},
64286461
{"hamt", new_hamt, METH_NOARGS},
64296462
{"bad_get", _PyCFunction_CAST(bad_get), METH_FASTCALL},

0 commit comments

Comments
 (0)