Skip to content

Commit

Permalink
gh-105751: test_ctypes avoids the operator module (GH-105797)
Browse files Browse the repository at this point in the history
* Replace operator.delitem(obj, index) with "del obj[index]".
* Replace operator.setitem(obj, index, value) with
  "obj[index] = value".
* Replace delattr(obj, "attr) with "del obj.attr".
* Replace grc() with sys.getrefcount() for readability.
  • Loading branch information
vstinner committed Jun 14, 2023
1 parent e7507bd commit 5ab13c5
Show file tree
Hide file tree
Showing 10 changed files with 85 additions and 80 deletions.
8 changes: 4 additions & 4 deletions Lib/test/test_ctypes/test_arrays.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,9 @@ def test_simple(self):
with self.assertRaises(IndexError): ia[-alen-1]

# change the items
from operator import setitem
new_values = list(range(42, 42+alen))
[setitem(ia, n, new_values[n]) for n in range(alen)]
for n in range(alen):
ia[n] = new_values[n]
values = [ia[i] for i in range(alen)]
self.assertEqual(values, new_values)

Expand Down Expand Up @@ -78,8 +78,8 @@ def test_simple(self):
self.assertEqual(len(ca), 3)

# cannot delete items
from operator import delitem
self.assertRaises(TypeError, delitem, ca, 0)
with self.assertRaises(TypeError):
del ca[0]

def test_step_overflow(self):
a = (c_int * 5)()
Expand Down
8 changes: 4 additions & 4 deletions Lib/test/test_ctypes/test_callbacks.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import functools
import sys
import unittest
from test import support

Expand Down Expand Up @@ -106,15 +107,14 @@ def test_char_p(self):

def test_pyobject(self):
o = ()
from sys import getrefcount as grc
for o in (), [], object():
initial = grc(o)
initial = sys.getrefcount(o)
# This call leaks a reference to 'o'...
self.check_type(py_object, o)
before = grc(o)
before = sys.getrefcount(o)
# ...but this call doesn't leak any more. Where is the refcount?
self.check_type(py_object, o)
after = grc(o)
after = sys.getrefcount(o)
self.assertEqual((after, o), (before, o))

def test_unsupported_restype_1(self):
Expand Down
14 changes: 8 additions & 6 deletions Lib/test/test_ctypes/test_delattr.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,18 @@ class X(Structure):

class TestCase(unittest.TestCase):
def test_simple(self):
self.assertRaises(TypeError,
delattr, c_int(42), "value")
with self.assertRaises(TypeError):
del c_int(42).value

def test_chararray(self):
self.assertRaises(TypeError,
delattr, (c_char * 5)(), "value")
chararray = (c_char * 5)()
with self.assertRaises(TypeError):
del chararray.value

def test_struct(self):
self.assertRaises(TypeError,
delattr, X(), "foo")
struct = X()
with self.assertRaises(TypeError):
del struct.foo


if __name__ == "__main__":
Expand Down
10 changes: 5 additions & 5 deletions Lib/test/test_ctypes/test_internals.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# This tests the internal _objects attribute
import sys
import unittest
from ctypes import Structure, POINTER, c_char_p, c_int
from sys import getrefcount as grc

# XXX This test must be reviewed for correctness!!!

Expand All @@ -20,16 +20,16 @@ def assertSame(self, a, b):

def test_ints(self):
i = 42000123
refcnt = grc(i)
refcnt = sys.getrefcount(i)
ci = c_int(i)
self.assertEqual(refcnt, grc(i))
self.assertEqual(refcnt, sys.getrefcount(i))
self.assertEqual(ci._objects, None)

def test_c_char_p(self):
s = b"Hello, World"
refcnt = grc(s)
refcnt = sys.getrefcount(s)
cs = c_char_p(s)
self.assertEqual(refcnt + 1, grc(s))
self.assertEqual(refcnt + 1, sys.getrefcount(s))
self.assertSame(cs._objects, s)

def test_simple_struct(self):
Expand Down
11 changes: 6 additions & 5 deletions Lib/test/test_ctypes/test_keeprefs.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from ctypes import Structure, POINTER, pointer, c_char_p, c_int
import sys
import unittest
from ctypes import Structure, POINTER, pointer, c_char_p, c_int


class SimpleTestCase(unittest.TestCase):
def test_cint(self):
Expand Down Expand Up @@ -100,16 +102,15 @@ class X(Structure):
_fields_ = [("p", POINTER(c_char_p))]
x = X()
i = c_char_p("abc def")
from sys import getrefcount as grc
print("2?", grc(i))
print("2?", sys.getrefcount(i))
x.p = pointer(i)
print("3?", grc(i))
print("3?", sys.getrefcount(i))
for i in range(320):
c_int(99)
x.p[0]
print(x.p[0])
## del x
## print "2?", grc(i)
## print "2?", sys.getrefcount(i)
## del i
import gc
gc.collect()
Expand Down
4 changes: 2 additions & 2 deletions Lib/test/test_ctypes/test_pointers.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,6 @@ def func(arg):
## print self.result

def test_basics(self):
from operator import delitem
for ct, pt in zip(ctype_types, python_types):
i = ct(42)
p = pointer(i)
Expand All @@ -108,7 +107,8 @@ def test_basics(self):
## self.assertEqual(p.contents, 42)
## self.assertEqual(p[0], 42)

self.assertRaises(TypeError, delitem, p, 0)
with self.assertRaises(TypeError):
del p[0]

def test_from_address(self):
from array import array
Expand Down
22 changes: 11 additions & 11 deletions Lib/test/test_ctypes/test_python_api.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import unittest
import sys
from test import support
from ctypes import (pythonapi, POINTER, c_buffer, sizeof,
py_object, c_char_p, c_char, c_long, c_size_t)
Expand All @@ -11,7 +12,6 @@

################################################################

from sys import getrefcount as grc

class PythonAPITestCase(unittest.TestCase):

Expand All @@ -29,41 +29,41 @@ def test_PyString_FromString(self):
pythonapi.PyBytes_FromString.argtypes = (c_char_p,)

s = b"abc"
refcnt = grc(s)
refcnt = sys.getrefcount(s)
pyob = pythonapi.PyBytes_FromString(s)
self.assertEqual(grc(s), refcnt)
self.assertEqual(sys.getrefcount(s), refcnt)
self.assertEqual(s, pyob)
del pyob
self.assertEqual(grc(s), refcnt)
self.assertEqual(sys.getrefcount(s), refcnt)

@support.refcount_test
def test_PyLong_Long(self):
ref42 = grc(42)
ref42 = sys.getrefcount(42)
pythonapi.PyLong_FromLong.restype = py_object
self.assertEqual(pythonapi.PyLong_FromLong(42), 42)

self.assertEqual(grc(42), ref42)
self.assertEqual(sys.getrefcount(42), ref42)

pythonapi.PyLong_AsLong.argtypes = (py_object,)
pythonapi.PyLong_AsLong.restype = c_long

res = pythonapi.PyLong_AsLong(42)
# Small int refcnts don't change
self.assertEqual(grc(res), ref42)
self.assertEqual(sys.getrefcount(res), ref42)
del res
self.assertEqual(grc(42), ref42)
self.assertEqual(sys.getrefcount(42), ref42)

@support.refcount_test
def test_PyObj_FromPtr(self):
s = "abc def ghi jkl"
ref = grc(s)
ref = sys.getrefcount(s)
# id(python-object) is the address
pyobj = PyObj_FromPtr(id(s))
self.assertIs(s, pyobj)

self.assertEqual(grc(s), ref + 1)
self.assertEqual(sys.getrefcount(s), ref + 1)
del pyobj
self.assertEqual(grc(s), ref)
self.assertEqual(sys.getrefcount(s), ref)

def test_PyOS_snprintf(self):
PyOS_snprintf = pythonapi.PyOS_snprintf
Expand Down
32 changes: 15 additions & 17 deletions Lib/test/test_ctypes/test_refcounts.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import unittest
from test import support
import ctypes
import gc
import sys
import unittest
from test import support

MyCallback = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_int)
OtherCallback = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_int, ctypes.c_ulonglong)
Expand All @@ -13,8 +14,6 @@ class RefcountTestCase(unittest.TestCase):

@support.refcount_test
def test_1(self):
from sys import getrefcount as grc

f = dll._testfunc_callback_i_if
f.restype = ctypes.c_int
f.argtypes = [ctypes.c_int, MyCallback]
Expand All @@ -23,66 +22,65 @@ def callback(value):
#print "called back with", value
return value

self.assertEqual(grc(callback), 2)
self.assertEqual(sys.getrefcount(callback), 2)
cb = MyCallback(callback)

self.assertGreater(grc(callback), 2)
self.assertGreater(sys.getrefcount(callback), 2)
result = f(-10, cb)
self.assertEqual(result, -18)
cb = None

gc.collect()

self.assertEqual(grc(callback), 2)
self.assertEqual(sys.getrefcount(callback), 2)


@support.refcount_test
def test_refcount(self):
from sys import getrefcount as grc
def func(*args):
pass
# this is the standard refcount for func
self.assertEqual(grc(func), 2)
self.assertEqual(sys.getrefcount(func), 2)

# the CFuncPtr instance holds at least one refcount on func:
f = OtherCallback(func)
self.assertGreater(grc(func), 2)
self.assertGreater(sys.getrefcount(func), 2)

# and may release it again
del f
self.assertGreaterEqual(grc(func), 2)
self.assertGreaterEqual(sys.getrefcount(func), 2)

# but now it must be gone
gc.collect()
self.assertEqual(grc(func), 2)
self.assertEqual(sys.getrefcount(func), 2)

class X(ctypes.Structure):
_fields_ = [("a", OtherCallback)]
x = X()
x.a = OtherCallback(func)

# the CFuncPtr instance holds at least one refcount on func:
self.assertGreater(grc(func), 2)
self.assertGreater(sys.getrefcount(func), 2)

# and may release it again
del x
self.assertGreaterEqual(grc(func), 2)
self.assertGreaterEqual(sys.getrefcount(func), 2)

# and now it must be gone again
gc.collect()
self.assertEqual(grc(func), 2)
self.assertEqual(sys.getrefcount(func), 2)

f = OtherCallback(func)

# the CFuncPtr instance holds at least one refcount on func:
self.assertGreater(grc(func), 2)
self.assertGreater(sys.getrefcount(func), 2)

# create a cycle
f.cycle = f

del f
gc.collect()
self.assertEqual(grc(func), 2)
self.assertEqual(sys.getrefcount(func), 2)

class AnotherLeak(unittest.TestCase):
def test_callback(self):
Expand Down
50 changes: 27 additions & 23 deletions Lib/test/test_ctypes/test_slicing.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,18 +46,21 @@ def test_setslice_cint(self):
b[33::-3] = range(12)
self.assertEqual(a[:], b)

from operator import setitem

# TypeError: int expected instead of str instance
self.assertRaises(TypeError, setitem, a, slice(0, 5), "abcde")
with self.assertRaises(TypeError):
a[:5] = "abcde"

# TypeError: int expected instead of str instance
self.assertRaises(TypeError, setitem, a, slice(0, 5),
["a", "b", "c", "d", "e"])
with self.assertRaises(TypeError):
a[:5] = ["a", "b", "c", "d", "e"]

# TypeError: int expected instead of float instance
self.assertRaises(TypeError, setitem, a, slice(0, 5),
[1, 2, 3, 4, 3.14])
with self.assertRaises(TypeError):
a[:5] = [1, 2, 3, 4, 3.14]

# ValueError: Can only assign sequence of same size
self.assertRaises(ValueError, setitem, a, slice(0, 5), range(32))
with self.assertRaises(ValueError):
a[:5] = range(32)

def test_char_ptr(self):
s = b"abcdefghijklmnopqrstuvwxyz"
Expand All @@ -73,18 +76,20 @@ def test_char_ptr(self):
self.assertEqual(res[len(s)-1:5:-7], s[:5:-7])
self.assertEqual(res[0:-1:-1], s[0::-1])

import operator
self.assertRaises(ValueError, operator.getitem,
res, slice(None, None, None))
self.assertRaises(ValueError, operator.getitem,
res, slice(0, None, None))
self.assertRaises(ValueError, operator.getitem,
res, slice(None, 5, -1))
self.assertRaises(ValueError, operator.getitem,
res, slice(-5, None, None))

self.assertRaises(TypeError, operator.setitem,
res, slice(0, 5), "abcde")
# get items
with self.assertRaises(ValueError):
res[:]
with self.assertRaises(ValueError):
res[0:]
with self.assertRaises(ValueError):
res[:5:-1]
with self.assertRaises(ValueError):
res[-5:]

# set items
with self.assertRaises(TypeError):
res[:5] = "abcde"

dll.my_free(res)

dll.my_strdup.restype = POINTER(c_byte)
Expand Down Expand Up @@ -139,9 +144,8 @@ def test_wchar_ptr(self):
self.assertEqual(res[len(s)-1:-1:-1], s[::-1])
self.assertEqual(res[len(s)-1:5:-7], s[:5:-7])

import operator
self.assertRaises(TypeError, operator.setitem,
res, slice(0, 5), "abcde")
with self.assertRaises(TypeError):
res[:5] = "abcde"
dll.my_free(res)

if sizeof(c_wchar) == sizeof(c_short):
Expand Down

0 comments on commit 5ab13c5

Please sign in to comment.