FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

gh-94808: add tests covering `PySequence_[InPlace_]Repeat` by sobolevn · Pull Request #99196 · python/cpython · GitHub

/ cpython Public
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension .c  (1) .py  (1) All 2 file types selected
Viewed files
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Unified
Split
Hide whitespace
Diff view
Unified
Split
Hide whitespace
166 changes: 166 additions & 0 deletions Lib/test/test_capi/test_misc.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -496,6 +496,172 @@ def __delitem__(self, index):
_testcapi.sequence_del_slice(mapping, 1, 3)
self.assertEqual(mapping, {1: 'a', 2: 'b', 3: 'c'})

def test_sequence_repeat(self):
# Basic test:
sequence = [1, 2, 3]
repeated_sequence = _testcapi.sequence_repeat(sequence, 2)
self.assertEqual(repeated_sequence, [1, 2, 3, 1, 2, 3])
self.assertEqual(repeated_sequence, sequence * 2)
self.assertEqual(sequence, [1, 2, 3]) # it must not change

# Corner values:
sequence = [1, 2, 3]
for value, res in [
(0, []),
(1, [1, 2, 3]),
(-1, []),
]:
repeated_sequence = _testcapi.sequence_repeat(sequence, value)
self.assertEqual(repeated_sequence, res)
self.assertEqual(repeated_sequence, sequence * value)
self.assertEqual(sequence, [1, 2, 3]) # it must not change

def test_sequence_repeat_subtypes(self):
# List subtype:
class CustomList(list): ...

sequence = CustomList(['a', 'b'])
repeated_sequence = _testcapi.sequence_repeat(sequence, 3)
self.assertEqual(repeated_sequence,
CustomList(['a', 'b', 'a', 'b', 'a', 'b']))
self.assertEqual(repeated_sequence, sequence * 3)
self.assertEqual(sequence, CustomList(['a', 'b']))

# Tuple subtype:
class CustomTuple(tuple): ...

sequence = CustomTuple(('a', 'b'))
repeated_sequence = _testcapi.sequence_repeat(sequence, 3)
self.assertEqual(repeated_sequence,
CustomTuple(('a', 'b', 'a', 'b', 'a', 'b')))
self.assertEqual(repeated_sequence, sequence * 3)
self.assertEqual(sequence, CustomTuple(('a', 'b')))

# String subtype:
class CustomStr(str): ...

sequence = CustomStr('abc')
repeated_sequence = _testcapi.sequence_repeat(sequence, 2)
self.assertEqual(repeated_sequence,
CustomStr('abcabc'))
self.assertEqual(repeated_sequence, sequence * 2)
self.assertEqual(sequence, CustomStr('abc'))

def test_sequence_repeat_errors(self):
# Corner case, custom subtype returns `NotImplemented`:
class CustomListWithNI(list):
def __mul__(self, other):
return NotImplemented

sequence = CustomListWithNI(['a', 'b'])
with self.assertRaises(TypeError):
_testcapi.sequence_repeat(sequence, 3)
self.assertEqual(sequence, CustomListWithNI(['a', 'b'])) # not changed

# Non-sequences do not work (even with `__mul__`):
class CustomTypeWithMul:
def __mul__(self, other):
return 5 # won't be called

not_sequence = CustomTypeWithMul()
with self.assertRaises(TypeError):
_testcapi.sequence_repeat(not_sequence, 1)

def test_sequence_inplace_repeat(self):
# Basic list test:
sequence = [1, 2, 3]
repeated_sequence = _testcapi.sequence_inplace_repeat(sequence, 2)
self.assertEqual(repeated_sequence, [1, 2, 3, 1, 2, 3])
self.assertEqual(repeated_sequence, sequence)
self.assertEqual(sequence, [1, 2, 3, 1, 2, 3]) # changed
sequence_copy = [1, 2, 3]
sequence_copy *= 2 # It is the same thing
self.assertEqual(repeated_sequence, sequence_copy)

# Basic tuple test:
sequence = (1, 2, 3)
repeated_sequence = _testcapi.sequence_inplace_repeat(sequence, 2)
self.assertEqual(repeated_sequence, (1, 2, 3, 1, 2, 3))
self.assertNotEqual(repeated_sequence, sequence)
self.assertEqual(sequence, (1, 2, 3)) # not changed
sequence *= 2
self.assertEqual(repeated_sequence, sequence)

# Basic string test:
sequence = 'abc'
repeated_sequence = _testcapi.sequence_inplace_repeat(sequence, 2)
self.assertEqual(repeated_sequence, 'abcabc')
self.assertNotEqual(repeated_sequence, sequence)
self.assertEqual(sequence, 'abc') # not changed
sequence *= 2
self.assertEqual(repeated_sequence, sequence)

# Corner values:
sequence = (1, 2, 3)
for value, res in [
(0, ()),
(1, (1, 2, 3)),
(-1, ()),
]:
repeated_sequence = _testcapi.sequence_inplace_repeat(sequence,
value)
self.assertEqual(repeated_sequence, res)
self.assertEqual(repeated_sequence, sequence * value)
self.assertEqual(sequence, (1, 2, 3)) # tuple must not change

def test_sequence_inplace_repeat_subtypes(self):
# List subtype:
class CustomList(list): ...

sequence = CustomList(['a', 'b'])
repeated_sequence = _testcapi.sequence_inplace_repeat(sequence, 3)
self.assertEqual(repeated_sequence,
CustomList(['a', 'b', 'a', 'b', 'a', 'b']))
self.assertEqual(repeated_sequence, sequence)

# Tuple subtype:
class CustomTuple(tuple): ...

sequence = CustomTuple(('a', 'b'))
repeated_sequence = _testcapi.sequence_inplace_repeat(sequence, 3)
self.assertEqual(repeated_sequence,
CustomTuple(('a', 'b', 'a', 'b', 'a', 'b')))
self.assertEqual(repeated_sequence, sequence * 3)
self.assertEqual(sequence, CustomTuple(('a', 'b')))

# String subtype:
class CustomStr(str): ...

sequence = CustomStr('abc')
repeated_sequence = _testcapi.sequence_inplace_repeat(sequence, 2)
self.assertEqual(repeated_sequence, CustomStr('abcabc'))
self.assertEqual(repeated_sequence, sequence * 2)
self.assertEqual(sequence, CustomStr('abc'))

def test_sequence_inplace_repeat_errors(self):
# Corner case, custom subtype returns `NotImplemented`:
class CustomListWithNI(list):
def __mul__(self, other):
return NotImplemented
def __imul__(self, other):
return NotImplemented

sequence = CustomListWithNI(['a', 'b'])
with self.assertRaises(TypeError):
_testcapi.sequence_inplace_repeat(sequence, 3)
self.assertEqual(sequence, CustomListWithNI(['a', 'b'])) # not changed

# Non-sequences do not work (even with `__mul__` and `__imul__`):
class CustomTypeWithMul:
def __mul__(self, other):
return 0
def __imul__(self, other):
return 1 # won't be called

not_sequence = CustomTypeWithMul()
with self.assertRaises(TypeError):
_testcapi.sequence_inplace_repeat(not_sequence, 1)

@unittest.skipUnless(hasattr(_testcapi, 'negative_refcount'),
'need _testcapi.negative_refcount')
def test_negative_refcount(self):
Expand Down
26 changes: 26 additions & 0 deletions Modules/_testcapimodule.c
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -4829,6 +4829,30 @@ sequence_del_slice(PyObject* self, PyObject *args)
Py_RETURN_NONE;
}

static PyObject *
sequence_repeat(PyObject* self, PyObject *args)
{
PyObject *sequence;
Py_ssize_t count;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

And here.

if (!PyArg_ParseTuple(args, "On", &sequence, &count)) {
return NULL;
}

return PySequence_Repeat(sequence, count);
}

static PyObject *
sequence_inplace_repeat(PyObject* self, PyObject *args)
{
PyObject *sequence;
Py_ssize_t count;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

PEP 7: blank line after local variable declarations;)

if (!PyArg_ParseTuple(args, "On", &sequence, &count)) {
return NULL;
}

return PySequence_InPlaceRepeat(sequence, count);
}

static PyObject *
test_pythread_tss_key_state(PyObject *self, PyObject *args)
{
Expand Down Expand Up @@ -6376,6 +6400,8 @@ static PyMethodDef TestMethods[] = {
{"mapping_has_key", mapping_has_key, METH_VARARGS},
{"sequence_set_slice", sequence_set_slice, METH_VARARGS},
{"sequence_del_slice", sequence_del_slice, METH_VARARGS},
{"sequence_repeat", sequence_repeat, METH_VARARGS},
{"sequence_inplace_repeat", sequence_inplace_repeat, METH_VARARGS},
{"test_pythread_tss_key_state", test_pythread_tss_key_state, METH_VARARGS},
{"hamt", new_hamt, METH_NOARGS},
{"bad_get", _PyCFunction_CAST(bad_get), METH_FASTCALL},
Expand Down

Back | FazBrowse Home | New Git URL