Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Lib/ctypes/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,8 @@ def _load_library(self, name, mode, handle, winmode):
if name and name.endswith(")") and ".a(" in name:
mode |= _os.RTLD_MEMBER | _os.RTLD_NOW
self._name = name
if handle is not None:
return handle
return _dlopen(name, mode)

def __repr__(self):
Expand Down
26 changes: 16 additions & 10 deletions Lib/ctypes/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,24 +85,30 @@ def find_library(name):
wintypes.DWORD,
)

_psapi = ctypes.WinDLL('psapi', use_last_error=True)
_enum_process_modules = _psapi["EnumProcessModules"]
_enum_process_modules.restype = wintypes.BOOL
_enum_process_modules.argtypes = (
wintypes.HANDLE,
ctypes.POINTER(wintypes.HMODULE),
wintypes.DWORD,
wintypes.LPDWORD,
)
# gh-145307: We defer loading psapi.dll until _get_module_handles is called.
# Loading additional DLLs at startup for functionality that may never be
# used is wasteful.
_enum_process_modules = None

def _get_module_filename(module: wintypes.HMODULE):
name = (wintypes.WCHAR * 32767)() # UNICODE_STRING_MAX_CHARS
if _k32_get_module_file_name(module, name, len(name)):
return name.value
return None


def _get_module_handles():
global _enum_process_modules
if _enum_process_modules is None:
_psapi = ctypes.WinDLL('psapi', use_last_error=True)
_enum_process_modules = _psapi["EnumProcessModules"]
_enum_process_modules.restype = wintypes.BOOL
_enum_process_modules.argtypes = (
wintypes.HANDLE,
ctypes.POINTER(wintypes.HMODULE),
wintypes.DWORD,
wintypes.LPDWORD,
)

process = _get_current_process()
space_needed = wintypes.DWORD()
n = 1024
Expand Down
42 changes: 42 additions & 0 deletions Lib/test/test_ctypes/test_byteswap.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,48 @@ def test_endian_double(self):
self.assertEqual(s.value, math.pi)
self.assertEqual(bin(struct.pack(">d", math.pi)), bin(s))

@unittest.skipUnless(hasattr(ctypes, 'c_float_complex'), "No complex types")
def test_endian_float_complex(self):
c_float_complex = ctypes.c_float_complex
if sys.byteorder == "little":
self.assertIs(c_float_complex.__ctype_le__, c_float_complex)
self.assertIs(c_float_complex.__ctype_be__.__ctype_le__,
c_float_complex)
else:
self.assertIs(c_float_complex.__ctype_be__, c_float_complex)
self.assertIs(c_float_complex.__ctype_le__.__ctype_be__,
c_float_complex)
s = c_float_complex(math.pi+1j)
self.assertEqual(bin(struct.pack("F", math.pi+1j)), bin(s))
self.assertAlmostEqual(s.value, math.pi+1j, places=6)
s = c_float_complex.__ctype_le__(math.pi+1j)
self.assertAlmostEqual(s.value, math.pi+1j, places=6)
self.assertEqual(bin(struct.pack("<F", math.pi+1j)), bin(s))
s = c_float_complex.__ctype_be__(math.pi+1j)
self.assertAlmostEqual(s.value, math.pi+1j, places=6)
self.assertEqual(bin(struct.pack(">F", math.pi+1j)), bin(s))

@unittest.skipUnless(hasattr(ctypes, 'c_double_complex'), "No complex types")
def test_endian_double_complex(self):
c_double_complex = ctypes.c_double_complex
if sys.byteorder == "little":
self.assertIs(c_double_complex.__ctype_le__, c_double_complex)
self.assertIs(c_double_complex.__ctype_be__.__ctype_le__,
c_double_complex)
else:
self.assertIs(c_double_complex.__ctype_be__, c_double_complex)
self.assertIs(c_double_complex.__ctype_le__.__ctype_be__,
c_double_complex)
s = c_double_complex(math.pi+1j)
self.assertEqual(bin(struct.pack("D", math.pi+1j)), bin(s))
self.assertAlmostEqual(s.value, math.pi+1j, places=6)
s = c_double_complex.__ctype_le__(math.pi+1j)
self.assertAlmostEqual(s.value, math.pi+1j, places=6)
self.assertEqual(bin(struct.pack("<D", math.pi+1j)), bin(s))
s = c_double_complex.__ctype_be__(math.pi+1j)
self.assertAlmostEqual(s.value, math.pi+1j, places=6)
self.assertEqual(bin(struct.pack(">D", math.pi+1j)), bin(s))

def test_endian_other(self):
self.assertIs(c_byte.__ctype_le__, c_byte)
self.assertIs(c_byte.__ctype_be__, c_byte)
Expand Down
4 changes: 1 addition & 3 deletions Lib/test/test_ctypes/test_dllist.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
)
class ListSharedLibraries(unittest.TestCase):

# TODO: RUSTPYTHON
@unittest.skipIf(not APPLE, "TODO: RUSTPYTHON")
def test_lists_system(self):
dlls = ctypes.util.dllist()
Expand All @@ -36,8 +35,7 @@ def test_lists_system(self):
any(lib in dll for dll in dlls for lib in KNOWN_LIBRARIES), f"loaded={dlls}"
)

# TODO: RUSTPYTHON
@unittest.expectedFailure
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_lists_updates(self):
dlls = ctypes.util.dllist()

Expand Down
8 changes: 8 additions & 0 deletions Lib/test/test_ctypes/test_loading.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,14 @@ def test_load_without_name_and_with_handle(self):
lib = ctypes.WinDLL(name=None, handle=handle)
self.assertIs(handle, lib._handle)

@unittest.skipIf(os.name == "nt", 'POSIX-specific test')
@unittest.skipIf(libc_name is None, 'could not find libc')
def test_load_without_name_and_with_handle_posix(self):
lib1 = CDLL(libc_name)
handle = lib1._handle
lib2 = CDLL(name=None, handle=handle)
self.assertIs(lib2._handle, handle)

@unittest.skipUnless(os.name == "nt", 'Windows-specific test')
def test_1703286_A(self):
# On winXP 64-bit, advapi32 loads at an address that does
Expand Down
6 changes: 2 additions & 4 deletions Lib/test/test_ctypes/test_python_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@


class PythonAPITestCase(unittest.TestCase):
# TODO: RUSTPYTHON - requires pythonapi (Python C API)
@unittest.expectedFailure
@unittest.expectedFailure # TODO: RUSTPYTHON; - requires pythonapi (Python C API)
def test_PyBytes_FromStringAndSize(self):
PyBytes_FromStringAndSize = pythonapi.PyBytes_FromStringAndSize

Expand Down Expand Up @@ -59,8 +58,7 @@ def test_PyObj_FromPtr(self):
del pyobj
self.assertEqual(sys.getrefcount(s), ref)

# TODO: RUSTPYTHON - requires pythonapi (Python C API)
@unittest.expectedFailure
@unittest.expectedFailure # TODO: RUSTPYTHON; - requires pythonapi (Python C API)
def test_PyOS_snprintf(self):
PyOS_snprintf = pythonapi.PyOS_snprintf
PyOS_snprintf.argtypes = POINTER(c_char), c_size_t, c_char_p
Expand Down
6 changes: 2 additions & 4 deletions Lib/test/test_ctypes/test_values.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,17 +39,15 @@ def test_undefined(self):
class PythonValuesTestCase(unittest.TestCase):
"""This test only works when python itself is a dll/shared library"""

# TODO: RUSTPYTHON - requires pythonapi (Python C API)
@unittest.expectedFailure
@unittest.expectedFailure # TODO: RUSTPYTHON; - requires pythonapi (Python C API)
def test_optimizeflag(self):
# This test accesses the Py_OptimizeFlag integer, which is
# exported by the Python dll and should match the sys.flags value

opt = c_int.in_dll(pythonapi, "Py_OptimizeFlag").value
self.assertEqual(opt, sys.flags.optimize)

# TODO: RUSTPYTHON - requires pythonapi (Python C API)
@unittest.expectedFailure
@unittest.expectedFailure # TODO: RUSTPYTHON; - requires pythonapi (Python C API)
@thread_unsafe('overrides frozen modules')
def test_frozentable(self):
# Python exports a PyImport_FrozenModules symbol. This is a
Expand Down
3 changes: 1 addition & 2 deletions Lib/test/test_ctypes/test_win32.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@

@unittest.skipUnless(sys.platform == "win32", 'Windows-specific test')
class FunctionCallTestCase(unittest.TestCase):
# TODO: RUSTPYTHON: SEH not implemented, crashes with STATUS_ACCESS_VIOLATION
@unittest.skip("TODO: RUSTPYTHON")
@unittest.skip("TODO: RUSTPYTHON; SEH not implemented, crashes with STATUS_ACCESS_VIOLATION")
@unittest.skipUnless('MSC' in sys.version, "SEH only supported by MSC")
@unittest.skipIf(sys.executable.lower().endswith('_d.exe'),
"SEH not enabled in debug builds")
Expand Down
Loading