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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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