gh-105751: test_ctypes gets Windows attrs from ctypes (#105758)

test_ctypes now gets attributes specific to Windows from the ctypes
module, rather than relying on "from ctypes import *".

Attributes:

* ctypes.FormatError
* ctypes.WINFUNCTYPE
* ctypes.WinError
* ctypes.WinDLL
* ctypes.windll
* ctypes.oledll
* ctypes.get_last_error()
* ctypes.set_last_error()
This commit is contained in:
Victor Stinner 2023-06-14 04:46:47 +02:00 committed by GitHub
parent b87d288275
commit ac7b551bde
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 75 additions and 64 deletions

View File

@ -1,4 +1,5 @@
import unittest
import ctypes
from ctypes import *
from test.test_ctypes import need_symbol
import _ctypes_test
@ -6,8 +7,8 @@ import _ctypes_test
dll = CDLL(_ctypes_test.__file__)
try:
CALLBACK_FUNCTYPE = WINFUNCTYPE
except NameError:
CALLBACK_FUNCTYPE = ctypes.WINFUNCTYPE
except AttributeError:
# fake to enable this test on Linux
CALLBACK_FUNCTYPE = CFUNCTYPE

View File

@ -2,6 +2,7 @@ import functools
import unittest
from test import support
import ctypes
from ctypes import *
from test.test_ctypes import need_symbol
from _ctypes import CTYPES_MAX_ARGCOUNT
@ -152,7 +153,7 @@ class Callbacks(unittest.TestCase):
@need_symbol('WINFUNCTYPE')
def test_i38748_stackCorruption(self):
callback_funcType = WINFUNCTYPE(c_long, c_long, c_longlong)
callback_funcType = ctypes.WINFUNCTYPE(c_long, c_long, c_longlong)
@callback_funcType
def callback(a, b):
c = a + b
@ -163,12 +164,10 @@ class Callbacks(unittest.TestCase):
self.assertEqual(dll._test_i38748_runCallback(callback, 5, 10), 15)
@need_symbol('WINFUNCTYPE')
if hasattr(ctypes, 'WINFUNCTYPE'):
class StdcallCallbacks(Callbacks):
try:
functype = WINFUNCTYPE
except NameError:
pass
functype = ctypes.WINFUNCTYPE
################################################################
@ -216,13 +215,14 @@ class SampleCallbacksTestCase(unittest.TestCase):
global windowCount
windowCount = 0
@WINFUNCTYPE(BOOL, HWND, LPARAM)
@ctypes.WINFUNCTYPE(BOOL, HWND, LPARAM)
def EnumWindowsCallbackFunc(hwnd, lParam):
global windowCount
windowCount += 1
return True #Allow windows to keep enumerating
windll.user32.EnumWindows(EnumWindowsCallbackFunc, 0)
user32 = ctypes.windll.user32
user32.EnumWindows(EnumWindowsCallbackFunc, 0)
def test_callback_register_int(self):
# Issue #8275: buggy handling of callback args under Win64

View File

@ -2,6 +2,7 @@
# Byte order related?
import unittest
import ctypes
from ctypes import *
from test.test_ctypes import need_symbol
@ -197,12 +198,8 @@ class CFunctions(unittest.TestCase):
# The following repeats the above tests with stdcall functions (where
# they are available)
try:
WinDLL
except NameError:
def stdcall_dll(*_): pass
else:
class stdcall_dll(WinDLL):
if hasattr(ctypes, 'WinDLL'):
class stdcall_dll(ctypes.WinDLL):
def __getattr__(self, name):
if name[:2] == '__' and name[-2:] == '__':
raise AttributeError(name)
@ -210,7 +207,6 @@ else:
setattr(self, name, func)
return func
@need_symbol('WinDLL')
class stdcallCFunctions(CFunctions):
_dll = stdcall_dll(_ctypes_test.__file__)

View File

@ -1,5 +1,6 @@
import unittest
import ctypes
from ctypes import *
from test.test_ctypes import need_symbol
@ -28,9 +29,8 @@ class Test(unittest.TestCase):
@need_symbol('oledll')
def test_oledll(self):
self.assertRaises(OSError,
oledll.oleaut32.CreateTypeLib2,
0, None, None)
oleaut32 = ctypes.oledll.oleaut32
self.assertRaises(OSError, oleaut32.CreateTypeLib2, 0, None, None)
if __name__ == "__main__":
unittest.main()

View File

@ -1,6 +1,7 @@
import unittest, os, errno
import threading
import ctypes
from ctypes import *
from ctypes.util import find_library
@ -44,33 +45,33 @@ class Test(unittest.TestCase):
@unittest.skipUnless(os.name == "nt", 'Test specific to Windows')
def test_GetLastError(self):
dll = WinDLL("kernel32", use_last_error=True)
dll = ctypes.WinDLL("kernel32", use_last_error=True)
GetModuleHandle = dll.GetModuleHandleA
GetModuleHandle.argtypes = [c_wchar_p]
self.assertEqual(0, GetModuleHandle("foo"))
self.assertEqual(get_last_error(), 126)
self.assertEqual(ctypes.get_last_error(), 126)
self.assertEqual(set_last_error(32), 126)
self.assertEqual(get_last_error(), 32)
self.assertEqual(ctypes.set_last_error(32), 126)
self.assertEqual(ctypes.get_last_error(), 32)
def _worker():
set_last_error(0)
ctypes.set_last_error(0)
dll = WinDLL("kernel32", use_last_error=False)
dll = ctypes.WinDLL("kernel32", use_last_error=False)
GetModuleHandle = dll.GetModuleHandleW
GetModuleHandle.argtypes = [c_wchar_p]
GetModuleHandle("bar")
self.assertEqual(get_last_error(), 0)
self.assertEqual(ctypes.get_last_error(), 0)
t = threading.Thread(target=_worker)
t.start()
t.join()
self.assertEqual(get_last_error(), 32)
self.assertEqual(ctypes.get_last_error(), 32)
set_last_error(0)
ctypes.set_last_error(0)
if __name__ == "__main__":
unittest.main()

View File

@ -1,9 +1,10 @@
import unittest
import ctypes
from ctypes import *
try:
WINFUNCTYPE
except NameError:
WINFUNCTYPE = ctypes.WINFUNCTYPE
except AttributeError:
# fake to enable this test on Linux
WINFUNCTYPE = CFUNCTYPE
@ -39,7 +40,7 @@ class CFuncPtrTestCase(unittest.TestCase):
# possible, as in C, to call cdecl functions with more parameters.
#self.assertRaises(TypeError, c, 1, 2, 3)
self.assertEqual(c(1, 2, 3, 4, 5, 6), 3)
if not WINFUNCTYPE is CFUNCTYPE:
if WINFUNCTYPE is not CFUNCTYPE:
self.assertRaises(TypeError, s, 1, 2, 3)
def test_structures(self):
@ -91,7 +92,7 @@ class CFuncPtrTestCase(unittest.TestCase):
def NoNullHandle(value):
if not value:
raise WinError()
raise ctypes.WinError()
return value
strchr = lib.my_strchr

View File

@ -5,20 +5,21 @@ show how the type behave.
Later...
"""
import ctypes
from ctypes import *
from test.test_ctypes import need_symbol
import sys, unittest
try:
WINFUNCTYPE
except NameError:
WINFUNCTYPE = ctypes.WINFUNCTYPE
except AttributeError:
# fake to enable this test on Linux
WINFUNCTYPE = CFUNCTYPE
import _ctypes_test
dll = CDLL(_ctypes_test.__file__)
if sys.platform == "win32":
windll = WinDLL(_ctypes_test.__file__)
windll = ctypes.WinDLL(_ctypes_test.__file__)
class POINT(Structure):
_fields_ = [("x", c_int), ("y", c_int)]

View File

@ -1,4 +1,5 @@
from ctypes import *
import ctypes
import os
import shutil
import subprocess
@ -72,18 +73,18 @@ class LoaderTest(unittest.TestCase):
print(find_library("user32"))
if os.name == "nt":
windll.kernel32.GetModuleHandleW
windll["kernel32"].GetModuleHandleW
windll.LoadLibrary("kernel32").GetModuleHandleW
WinDLL("kernel32").GetModuleHandleW
ctypes.windll.kernel32.GetModuleHandleW
ctypes.windll["kernel32"].GetModuleHandleW
ctypes.windll.LoadLibrary("kernel32").GetModuleHandleW
ctypes.WinDLL("kernel32").GetModuleHandleW
# embedded null character
self.assertRaises(ValueError, windll.LoadLibrary, "kernel32\0")
self.assertRaises(ValueError, ctypes.windll.LoadLibrary, "kernel32\0")
@unittest.skipUnless(os.name == "nt",
'test specific to Windows')
def test_load_ordinal_functions(self):
import _ctypes_test
dll = WinDLL(_ctypes_test.__file__)
dll = ctypes.WinDLL(_ctypes_test.__file__)
# We load the same function both via ordinal and name
func_ord = dll[2]
func_name = dll.GetString
@ -114,14 +115,16 @@ class LoaderTest(unittest.TestCase):
# also has a high address. 'call_function' should accept
# addresses so large.
from _ctypes import call_function
advapi32 = windll.advapi32
advapi32 = ctypes.windll.advapi32
# Calling CloseEventLog with a NULL argument should fail,
# but the call should not segfault or so.
self.assertEqual(0, advapi32.CloseEventLog(None))
windll.kernel32.GetProcAddress.argtypes = c_void_p, c_char_p
windll.kernel32.GetProcAddress.restype = c_void_p
proc = windll.kernel32.GetProcAddress(advapi32._handle,
b"CloseEventLog")
kernel32 = ctypes.windll.kernel32
kernel32.GetProcAddress.argtypes = c_void_p, c_char_p
kernel32.GetProcAddress.restype = c_void_p
proc = kernel32.GetProcAddress(advapi32._handle, b"CloseEventLog")
self.assertTrue(proc)
# This is the real test: call the function via 'call_function'
self.assertEqual(0, call_function(proc, (None,)))
@ -130,7 +133,7 @@ class LoaderTest(unittest.TestCase):
'test specific to Windows')
def test_load_hasattr(self):
# bpo-34816: shouldn't raise OSError
self.assertFalse(hasattr(windll, 'test'))
self.assertFalse(hasattr(ctypes.windll, 'test'))
@unittest.skipUnless(os.name == "nt",
'test specific to Windows')

View File

@ -1,5 +1,6 @@
import unittest, sys
import ctypes
from ctypes import *
import _ctypes_test
@ -193,7 +194,7 @@ class PointersTestCase(unittest.TestCase):
# COM methods are boolean True:
if sys.platform == "win32":
mth = WINFUNCTYPE(None)(42, "name", (), None)
mth = ctypes.WINFUNCTYPE(None)(42, "name", (), None)
self.assertEqual(bool(mth), True)
def test_pointer_type_name(self):

View File

@ -1,4 +1,5 @@
from ctypes import *
import ctypes
import contextlib
from test import support
import unittest
@ -16,15 +17,17 @@ class call_function_TestCase(unittest.TestCase):
def test(self):
from _ctypes import call_function
windll.kernel32.LoadLibraryA.restype = c_void_p
windll.kernel32.GetProcAddress.argtypes = c_void_p, c_char_p
windll.kernel32.GetProcAddress.restype = c_void_p
hdll = windll.kernel32.LoadLibraryA(b"kernel32")
funcaddr = windll.kernel32.GetProcAddress(hdll, b"GetModuleHandleA")
kernel32 = ctypes.windll.kernel32
kernel32.LoadLibraryA.restype = c_void_p
kernel32.GetProcAddress.argtypes = c_void_p, c_char_p
kernel32.GetProcAddress.restype = c_void_p
hdll = kernel32.LoadLibraryA(b"kernel32")
funcaddr = kernel32.GetProcAddress(hdll, b"GetModuleHandleA")
self.assertEqual(call_function(funcaddr, (None,)),
windll.kernel32.GetModuleHandleA(None))
kernel32.GetModuleHandleA(None))
class CallbackTracbackTestCase(unittest.TestCase):
# When an exception is raised in a ctypes callback function, the C

View File

@ -1,5 +1,6 @@
# Windows specific tests
import ctypes
from ctypes import *
import unittest, sys
from test import support
@ -14,15 +15,17 @@ class FunctionCallTestCase(unittest.TestCase):
def test_SEH(self):
# Disable faulthandler to prevent logging the warning:
# "Windows fatal exception: access violation"
kernel32 = ctypes.windll.kernel32
with support.disable_faulthandler():
# Call functions with invalid arguments, and make sure
# that access violations are trapped and raise an
# exception.
self.assertRaises(OSError, windll.kernel32.GetModuleHandleA, 32)
self.assertRaises(OSError, kernel32.GetModuleHandleA, 32)
def test_noargs(self):
# This is a special case on win32 x64
windll.user32.GetDesktopWindow()
user32 = ctypes.windll.user32
user32.GetDesktopWindow()
@unittest.skipUnless(sys.platform == "win32", 'Windows-specific test')
@ -73,17 +76,18 @@ class TestWinError(unittest.TestCase):
# see Issue 16169
import errno
ERROR_INVALID_PARAMETER = 87
msg = FormatError(ERROR_INVALID_PARAMETER).strip()
msg = ctypes.FormatError(ERROR_INVALID_PARAMETER).strip()
args = (errno.EINVAL, msg, None, ERROR_INVALID_PARAMETER)
e = WinError(ERROR_INVALID_PARAMETER)
e = ctypes.WinError(ERROR_INVALID_PARAMETER)
self.assertEqual(e.args, args)
self.assertEqual(e.errno, errno.EINVAL)
self.assertEqual(e.winerror, ERROR_INVALID_PARAMETER)
windll.kernel32.SetLastError(ERROR_INVALID_PARAMETER)
kernel32 = ctypes.windll.kernel32
kernel32.SetLastError(ERROR_INVALID_PARAMETER)
try:
raise WinError()
raise ctypes.WinError()
except OSError as exc:
e = exc
self.assertEqual(e.args, args)