Skip to content

Commit

Permalink
gh-107455: ctypes: Improve error messages when converting to an incom…
Browse files Browse the repository at this point in the history
…patible type (#107456)
  • Loading branch information
tomasr8 committed Aug 3, 2023
1 parent 1cd479c commit 62a3a15
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 11 deletions.
52 changes: 50 additions & 2 deletions Lib/test/test_ctypes/test_functions.py
Expand Up @@ -4,8 +4,8 @@
import unittest
from ctypes import (CDLL, Structure, Array, CFUNCTYPE,
byref, POINTER, pointer, ArgumentError,
c_char, c_wchar, c_byte, c_char_p,
c_short, c_int, c_long, c_longlong,
c_char, c_wchar, c_byte, c_char_p, c_wchar_p,
c_short, c_int, c_long, c_longlong, c_void_p,
c_float, c_double, c_longdouble)
from _ctypes import _Pointer, _SimpleCData

Expand Down Expand Up @@ -92,6 +92,54 @@ def test_wchar_parm(self):
"argument 2: TypeError: one character unicode string "
"expected")

def test_c_char_p_parm(self):
"""Test the error message when converting an incompatible type to c_char_p."""
proto = CFUNCTYPE(c_int, c_char_p)
def callback(*args):
return 0

callback = proto(callback)
self.assertEqual(callback(b"abc"), 0)

with self.assertRaises(ArgumentError) as cm:
callback(10)

self.assertEqual(str(cm.exception),
"argument 1: TypeError: 'int' object cannot be "
"interpreted as ctypes.c_char_p")

def test_c_wchar_p_parm(self):
"""Test the error message when converting an incompatible type to c_wchar_p."""
proto = CFUNCTYPE(c_int, c_wchar_p)
def callback(*args):
return 0

callback = proto(callback)
self.assertEqual(callback("abc"), 0)

with self.assertRaises(ArgumentError) as cm:
callback(10)

self.assertEqual(str(cm.exception),
"argument 1: TypeError: 'int' object cannot be "
"interpreted as ctypes.c_wchar_p")

def test_c_void_p_parm(self):
"""Test the error message when converting an incompatible type to c_void_p."""
proto = CFUNCTYPE(c_int, c_void_p)
def callback(*args):
return 0

callback = proto(callback)
self.assertEqual(callback(5), 0)

with self.assertRaises(ArgumentError) as cm:
callback(2.5)

self.assertEqual(str(cm.exception),
"argument 1: TypeError: 'float' object cannot be "
"interpreted as ctypes.c_void_p")

def test_wchar_result(self):
f = dll._testfunc_i_bhilfd
f.argtypes = [c_byte, c_short, c_int, c_long, c_float, c_double]
Expand Down
@@ -0,0 +1,3 @@
Improve error messages when converting an incompatible type to
:class:`ctypes.c_char_p`, :class:`ctypes.c_wchar_p` and
:class:`ctypes.c_void_p`.
18 changes: 9 additions & 9 deletions Modules/_ctypes/_ctypes.c
Expand Up @@ -1728,9 +1728,9 @@ c_wchar_p_from_param(PyObject *type, PyObject *value)
Py_DECREF(as_parameter);
return value;
}
/* XXX better message */
PyErr_SetString(PyExc_TypeError,
"wrong type");
PyErr_Format(PyExc_TypeError,
"'%.200s' object cannot be interpreted "
"as ctypes.c_wchar_p", Py_TYPE(value)->tp_name);
return NULL;
}

Expand Down Expand Up @@ -1792,9 +1792,9 @@ c_char_p_from_param(PyObject *type, PyObject *value)
Py_DECREF(as_parameter);
return value;
}
/* XXX better message */
PyErr_SetString(PyExc_TypeError,
"wrong type");
PyErr_Format(PyExc_TypeError,
"'%.200s' object cannot be interpreted "
"as ctypes.c_char_p", Py_TYPE(value)->tp_name);
return NULL;
}

Expand Down Expand Up @@ -1927,9 +1927,9 @@ c_void_p_from_param(PyObject *type, PyObject *value)
Py_DECREF(as_parameter);
return value;
}
/* XXX better message */
PyErr_SetString(PyExc_TypeError,
"wrong type");
PyErr_Format(PyExc_TypeError,
"'%.200s' object cannot be interpreted "
"as ctypes.c_void_p", Py_TYPE(value)->tp_name);
return NULL;
}

Expand Down

0 comments on commit 62a3a15

Please sign in to comment.