Skip to content

Commit 8f43250

Browse files
[3.12] Add more C API tests (GH-112522) (GH-112525)
Add tests for PyObject_Str(), PyObject_Repr(), PyObject_ASCII() and PyObject_Bytes(). (cherry picked from commit e0449b9) Co-authored-by: Serhiy Storchaka <[email protected]>
1 parent c678126 commit 8f43250

File tree

2 files changed

+119
-0
lines changed

2 files changed

+119
-0
lines changed

Lib/test/test_capi/test_abstract.py

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,30 @@
88

99
NULL = None
1010

11+
class StrSubclass(str):
12+
pass
13+
14+
class BytesSubclass(bytes):
15+
pass
16+
17+
class WithStr:
18+
def __init__(self, value):
19+
self.value = value
20+
def __str__(self):
21+
return self.value
22+
23+
class WithRepr:
24+
def __init__(self, value):
25+
self.value = value
26+
def __repr__(self):
27+
return self.value
28+
29+
class WithBytes:
30+
def __init__(self, value):
31+
self.value = value
32+
def __bytes__(self):
33+
return self.value
34+
1135
class TestObject:
1236
@property
1337
def evil(self):
@@ -44,6 +68,68 @@ def gen():
4468

4569

4670
class CAPITest(unittest.TestCase):
71+
def assertTypedEqual(self, actual, expected):
72+
self.assertIs(type(actual), type(expected))
73+
self.assertEqual(actual, expected)
74+
75+
def test_object_str(self):
76+
# Test PyObject_Str()
77+
object_str = _testcapi.object_str
78+
self.assertTypedEqual(object_str(''), '')
79+
self.assertTypedEqual(object_str('abc'), 'abc')
80+
self.assertTypedEqual(object_str('\U0001f40d'), '\U0001f40d')
81+
self.assertTypedEqual(object_str(StrSubclass('abc')), 'abc')
82+
self.assertTypedEqual(object_str(WithStr('abc')), 'abc')
83+
self.assertTypedEqual(object_str(WithStr(StrSubclass('abc'))), StrSubclass('abc'))
84+
self.assertTypedEqual(object_str(WithRepr('<abc>')), '<abc>')
85+
self.assertTypedEqual(object_str(WithRepr(StrSubclass('<abc>'))), StrSubclass('<abc>'))
86+
self.assertTypedEqual(object_str(NULL), '<NULL>')
87+
88+
def test_object_repr(self):
89+
# Test PyObject_Repr()
90+
object_repr = _testcapi.object_repr
91+
self.assertTypedEqual(object_repr(''), "''")
92+
self.assertTypedEqual(object_repr('abc'), "'abc'")
93+
self.assertTypedEqual(object_repr('\U0001f40d'), "'\U0001f40d'")
94+
self.assertTypedEqual(object_repr(StrSubclass('abc')), "'abc'")
95+
self.assertTypedEqual(object_repr(WithRepr('<abc>')), '<abc>')
96+
self.assertTypedEqual(object_repr(WithRepr(StrSubclass('<abc>'))), StrSubclass('<abc>'))
97+
self.assertTypedEqual(object_repr(WithRepr('<\U0001f40d>')), '<\U0001f40d>')
98+
self.assertTypedEqual(object_repr(WithRepr(StrSubclass('<\U0001f40d>'))), StrSubclass('<\U0001f40d>'))
99+
self.assertTypedEqual(object_repr(NULL), '<NULL>')
100+
101+
def test_object_ascii(self):
102+
# Test PyObject_ASCII()
103+
object_ascii = _testcapi.object_ascii
104+
self.assertTypedEqual(object_ascii(''), "''")
105+
self.assertTypedEqual(object_ascii('abc'), "'abc'")
106+
self.assertTypedEqual(object_ascii('\U0001f40d'), r"'\U0001f40d'")
107+
self.assertTypedEqual(object_ascii(StrSubclass('abc')), "'abc'")
108+
self.assertTypedEqual(object_ascii(WithRepr('<abc>')), '<abc>')
109+
self.assertTypedEqual(object_ascii(WithRepr(StrSubclass('<abc>'))), StrSubclass('<abc>'))
110+
self.assertTypedEqual(object_ascii(WithRepr('<\U0001f40d>')), r'<\U0001f40d>')
111+
self.assertTypedEqual(object_ascii(WithRepr(StrSubclass('<\U0001f40d>'))), r'<\U0001f40d>')
112+
self.assertTypedEqual(object_ascii(NULL), '<NULL>')
113+
114+
def test_object_bytes(self):
115+
# Test PyObject_Bytes()
116+
object_bytes = _testcapi.object_bytes
117+
self.assertTypedEqual(object_bytes(b''), b'')
118+
self.assertTypedEqual(object_bytes(b'abc'), b'abc')
119+
self.assertTypedEqual(object_bytes(BytesSubclass(b'abc')), b'abc')
120+
self.assertTypedEqual(object_bytes(WithBytes(b'abc')), b'abc')
121+
self.assertTypedEqual(object_bytes(WithBytes(BytesSubclass(b'abc'))), BytesSubclass(b'abc'))
122+
self.assertTypedEqual(object_bytes(bytearray(b'abc')), b'abc')
123+
self.assertTypedEqual(object_bytes(memoryview(b'abc')), b'abc')
124+
self.assertTypedEqual(object_bytes([97, 98, 99]), b'abc')
125+
self.assertTypedEqual(object_bytes((97, 98, 99)), b'abc')
126+
self.assertTypedEqual(object_bytes(iter([97, 98, 99])), b'abc')
127+
self.assertRaises(TypeError, object_bytes, WithBytes(bytearray(b'abc')))
128+
self.assertRaises(TypeError, object_bytes, WithBytes([97, 98, 99]))
129+
self.assertRaises(TypeError, object_bytes, 3)
130+
self.assertRaises(TypeError, object_bytes, 'abc')
131+
self.assertRaises(TypeError, object_bytes, object())
132+
self.assertTypedEqual(object_bytes(NULL), b'<NULL>')
47133

48134
def test_object_getattr(self):
49135
xgetattr = _testcapi.object_getattr

Modules/_testcapi/abstract.c

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,34 @@
33
#include "util.h"
44

55

6+
static PyObject *
7+
object_repr(PyObject *self, PyObject *arg)
8+
{
9+
NULLABLE(arg);
10+
return PyObject_Repr(arg);
11+
}
12+
13+
static PyObject *
14+
object_ascii(PyObject *self, PyObject *arg)
15+
{
16+
NULLABLE(arg);
17+
return PyObject_ASCII(arg);
18+
}
19+
20+
static PyObject *
21+
object_str(PyObject *self, PyObject *arg)
22+
{
23+
NULLABLE(arg);
24+
return PyObject_Str(arg);
25+
}
26+
27+
static PyObject *
28+
object_bytes(PyObject *self, PyObject *arg)
29+
{
30+
NULLABLE(arg);
31+
return PyObject_Bytes(arg);
32+
}
33+
634
static PyObject *
735
object_getattr(PyObject *self, PyObject *args)
836
{
@@ -459,6 +487,11 @@ sequence_tuple(PyObject *self, PyObject *obj)
459487

460488

461489
static PyMethodDef test_methods[] = {
490+
{"object_repr", object_repr, METH_O},
491+
{"object_ascii", object_ascii, METH_O},
492+
{"object_str", object_str, METH_O},
493+
{"object_bytes", object_bytes, METH_O},
494+
462495
{"object_getattr", object_getattr, METH_VARARGS},
463496
{"object_getattrstring", object_getattrstring, METH_VARARGS},
464497
{"object_hasattr", object_hasattr, METH_VARARGS},

0 commit comments

Comments
 (0)