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
12 changes: 8 additions & 4 deletions Lib/platform.py
Original file line number Diff line number Diff line change
Expand Up @@ -543,21 +543,25 @@ def android_ver(release="", api_level=0, manufacturer="", model="", device="",
is_emulator=False):
if sys.platform == "android":
try:
from ctypes import CDLL, c_char_p, create_string_buffer
from ctypes import CDLL, c_int, c_char_p, create_string_buffer
from ctypes.util import wrap_dll_function
except ImportError:
pass
else:
# An NDK developer confirmed that this is an officially-supported
# API (https://stackoverflow.com/a/28416743). Use `getattr` to avoid
# private name mangling.
system_property_get = getattr(CDLL("libc.so"), "__system_property_get")
system_property_get.argtypes = (c_char_p, c_char_p)
libc = CDLL("libc.so")

@wrap_dll_function(libc)
def __system_property_get(name: c_char_p, value: c_char_p) -> c_int:
pass

def getprop(name, default):
# https://android.googlesource.com/platform/bionic/+/refs/tags/android-5.0.0_r1/libc/include/sys/system_properties.h#39
PROP_VALUE_MAX = 92
buffer = create_string_buffer(PROP_VALUE_MAX)
length = system_property_get(name.encode("UTF-8"), buffer)
length = __system_property_get(name.encode("UTF-8"), buffer)
if length == 0:
# This API doesn’t distinguish between an empty property and
# a missing one.
Expand Down
17 changes: 8 additions & 9 deletions Lib/test/pythoninfo.py
Original file line number Diff line number Diff line change
Expand Up @@ -995,7 +995,7 @@ def collect_windows(info_add):
# windows.RtlAreLongPathsEnabled: RtlAreLongPathsEnabled()
# windows.is_admin: IsUserAnAdmin()
try:
import ctypes
import ctypes.util
if not hasattr(ctypes, 'WinDLL'):
raise ImportError
except ImportError:
Expand All @@ -1004,20 +1004,19 @@ def collect_windows(info_add):
ntdll = ctypes.WinDLL('ntdll')
BOOLEAN = ctypes.c_ubyte
try:
RtlAreLongPathsEnabled = ntdll.RtlAreLongPathsEnabled
@ctypes.util.wrap_dll_function(ntdll)
def RtlAreLongPathsEnabled() -> BOOLEAN:
pass
except AttributeError:
res = '<function not available>'
else:
RtlAreLongPathsEnabled.restype = BOOLEAN
RtlAreLongPathsEnabled.argtypes = ()
res = bool(RtlAreLongPathsEnabled())
info_add('windows.RtlAreLongPathsEnabled', res)

shell32 = ctypes.windll.shell32
IsUserAnAdmin = shell32.IsUserAnAdmin
IsUserAnAdmin.restype = BOOLEAN
IsUserAnAdmin.argtypes = ()
info_add('windows.is_admin', IsUserAnAdmin())
@ctypes.util.wrap_dll_function(ctypes.windll.shell32)
def IsUserAnAdmin() -> BOOLEAN:
pass
info_add('windows.is_admin', bool(IsUserAnAdmin()))

try:
import _winapi
Expand Down
13 changes: 9 additions & 4 deletions Lib/test/test_android.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,18 @@ def logcat_thread():

try:
from ctypes import CDLL, c_char_p, c_int
android_log_write = getattr(CDLL("liblog.so"), "__android_log_write")
android_log_write.argtypes = (c_int, c_char_p, c_char_p)
ANDROID_LOG_INFO = 4
from ctypes.util import wrap_dll_function
liblog = CDLL("liblog.so")

@wrap_dll_function(liblog)
def __android_log_write(prio: c_int, tag: c_char_p,
text: c_char_p) -> c_int:
pass

# Separate tests using a marker line with a different tag.
ANDROID_LOG_INFO = 4
tag, message = "python.test", f"{self.id()} {time()}"
android_log_write(
__android_log_write(
ANDROID_LOG_INFO, tag.encode("UTF-8"), message.encode("UTF-8"))
self.assert_log("I", tag, message, skip=True)
except:
Expand Down
36 changes: 24 additions & 12 deletions Lib/test/test_embed.py
Original file line number Diff line number Diff line change
Expand Up @@ -1884,19 +1884,31 @@ def test_global_pathconfig(self):
# The global path configuration (_Py_path_config) must be a copy
# of the path configuration of PyInterpreter.config (PyConfig).
ctypes = import_helper.import_module('ctypes')
import ctypes.util # noqa: F811

def get_func(name):
func = getattr(ctypes.pythonapi, name)
func.argtypes = ()
func.restype = ctypes.c_wchar_p
return func

Py_GetPath = get_func('Py_GetPath')
Py_GetPrefix = get_func('Py_GetPrefix')
Py_GetExecPrefix = get_func('Py_GetExecPrefix')
Py_GetProgramName = get_func('Py_GetProgramName')
Py_GetProgramFullPath = get_func('Py_GetProgramFullPath')
Py_GetPythonHome = get_func('Py_GetPythonHome')
@ctypes.util.wrap_dll_function(ctypes.pythonapi)
def Py_GetPath() -> ctypes.c_wchar_p:
pass

@ctypes.util.wrap_dll_function(ctypes.pythonapi)
def Py_GetPrefix() -> ctypes.c_wchar_p:
pass

@ctypes.util.wrap_dll_function(ctypes.pythonapi)
def Py_GetExecPrefix() -> ctypes.c_wchar_p:
pass

@ctypes.util.wrap_dll_function(ctypes.pythonapi)
def Py_GetProgramName() -> ctypes.c_wchar_p:
pass

@ctypes.util.wrap_dll_function(ctypes.pythonapi)
def Py_GetProgramFullPath() -> ctypes.c_wchar_p:
pass

@ctypes.util.wrap_dll_function(ctypes.pythonapi)
def Py_GetPythonHome() -> ctypes.c_wchar_p:
pass

config = _testinternalcapi.get_configs()['config']

Expand Down
18 changes: 14 additions & 4 deletions Lib/test/test_ntpath.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,19 +31,29 @@
HAVE_GETFINALPATHNAME = True

try:
import ctypes
import ctypes.util
import ctypes.wintypes
except ImportError:
HAVE_GETSHORTPATHNAME = False
else:
HAVE_GETSHORTPATHNAME = True
def _getshortpathname(path):
GSPN = ctypes.WinDLL("kernel32", use_last_error=True).GetShortPathNameW
GSPN.argtypes = [ctypes.c_wchar_p, ctypes.c_wchar_p, ctypes.c_uint32]
GSPN.restype = ctypes.c_uint32
kernel32 = ctypes.WinDLL("kernel32", use_last_error=True)

@ctypes.util.wrap_dll_function(kernel32)
def GetShortPathNameW(
lpszLongPath: ctypes.c_wchar_p,
lpszShortPath: ctypes.c_wchar_p,
cchBuffer: ctypes.wintypes.DWORD,
) -> ctypes.wintypes.DWORD:
pass
GSPN = GetShortPathNameW

result_len = GSPN(path, None, 0)
if not result_len:
raise OSError("failed to get short path name 0x{:08X}"
.format(ctypes.get_last_error()))

result = ctypes.create_unicode_buffer(result_len)
result_len = GSPN(path, result, result_len)
return result[:result_len]
Expand Down
45 changes: 26 additions & 19 deletions Lib/test/test_os/test_windows.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,22 +27,25 @@ def _kill(self, sig):
# subprocess to the parent that the interpreter is ready. When it
# becomes ready, send *sig* via os.kill to the subprocess and check
# that the return code is equal to *sig*.
import ctypes
import ctypes.util
from ctypes import wintypes
import msvcrt

# Since we can't access the contents of the process' stdout until the
# process has exited, use PeekNamedPipe to see what's inside stdout
# without waiting. This is done so we can tell that the interpreter
# is started and running at a point where it could handle a signal.
PeekNamedPipe = ctypes.windll.kernel32.PeekNamedPipe
PeekNamedPipe.restype = wintypes.BOOL
PeekNamedPipe.argtypes = (wintypes.HANDLE, # Pipe handle
ctypes.POINTER(ctypes.c_char), # stdout buf
wintypes.DWORD, # Buffer size
ctypes.POINTER(wintypes.DWORD), # bytes read
ctypes.POINTER(wintypes.DWORD), # bytes avail
ctypes.POINTER(wintypes.DWORD)) # bytes left
@ctypes.util.wrap_dll_function(ctypes.windll.kernel32)
def PeekNamedPipe(
hNamedPipe: wintypes.HANDLE,
lpBuffer: ctypes.POINTER(ctypes.c_char),
nBufferSize: wintypes.DWORD,
lpBytesRead: ctypes.POINTER(wintypes.DWORD),
lpTotalBytesAvail: ctypes.POINTER(wintypes.DWORD),
lpBytesLeftThisMessage: ctypes.POINTER(wintypes.DWORD),
) -> wintypes.BOOL:
pass

msg = "running"
proc = subprocess.Popen([sys.executable, "-c",
"import sys;"
Expand Down Expand Up @@ -126,10 +129,11 @@ def test_CTRL_C_EVENT(self):

# Make a NULL value by creating a pointer with no argument.
NULL = ctypes.POINTER(ctypes.c_int)()
SetConsoleCtrlHandler = ctypes.windll.kernel32.SetConsoleCtrlHandler
SetConsoleCtrlHandler.argtypes = (ctypes.POINTER(ctypes.c_int),
wintypes.BOOL)
SetConsoleCtrlHandler.restype = wintypes.BOOL

@ctypes.util.wrap_dll_function(ctypes.windll.kernel32)
def SetConsoleCtrlHandler(HandlerRoutine: ctypes.POINTER(ctypes.c_int),
Add: wintypes.BOOL) -> wintypes.BOOL:
pass

# Calling this with NULL and FALSE causes the calling process to
# handle Ctrl+C, rather than ignore it. This property is inherited
Expand Down Expand Up @@ -458,17 +462,20 @@ def test_getfinalpathname_handles(self):
import ctypes.wintypes # noqa: F811

kernel = ctypes.WinDLL('Kernel32.dll', use_last_error=True)
kernel.GetCurrentProcess.restype = ctypes.wintypes.HANDLE
@ctypes.util.wrap_dll_function(kernel)
def GetCurrentProcess() -> ctypes.wintypes.HANDLE:
pass

kernel.GetProcessHandleCount.restype = ctypes.wintypes.BOOL
kernel.GetProcessHandleCount.argtypes = (ctypes.wintypes.HANDLE,
ctypes.wintypes.LPDWORD)
@ctypes.util.wrap_dll_function(kernel)
def GetProcessHandleCount(khProcess: ctypes.wintypes.HANDLE,
pdwHandleCount: ctypes.wintypes.LPDWORD) -> ctypes.wintypes.BOOL:
pass

# This is a pseudo-handle that doesn't need to be closed
hproc = kernel.GetCurrentProcess()
hproc = GetCurrentProcess()

handle_count = ctypes.wintypes.DWORD()
ok = kernel.GetProcessHandleCount(hproc, ctypes.byref(handle_count))
ok = GetProcessHandleCount(hproc, ctypes.byref(handle_count))
self.assertEqual(1, ok)

before_count = handle_count.value
Expand Down
11 changes: 6 additions & 5 deletions Lib/test/win_console_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
import sys

# Function prototype for the handler function. Returns BOOL, takes a DWORD.
HandlerRoutine = WINFUNCTYPE(wintypes.BOOL, wintypes.DWORD)
HANDLER_ROUTINE = WINFUNCTYPE(wintypes.BOOL, wintypes.DWORD)

def _ctrl_handler(sig):
"""Handle a sig event and return 0 to terminate the process"""
Expand All @@ -27,12 +27,13 @@ def _ctrl_handler(sig):
print("UNKNOWN EVENT")
return 0

ctrl_handler = HandlerRoutine(_ctrl_handler)
ctrl_handler = HANDLER_ROUTINE(_ctrl_handler)


SetConsoleCtrlHandler = ctypes.windll.kernel32.SetConsoleCtrlHandler
SetConsoleCtrlHandler.argtypes = (HandlerRoutine, wintypes.BOOL)
SetConsoleCtrlHandler.restype = wintypes.BOOL
@ctypes.util.wrap_dll_function(ctypes.windll.kernel32)
def SetConsoleCtrlHandler(HandlerRoutine: HANDLER_ROUTINE,
Add: wintypes.BOOL) -> wintypes.BOOL:
pass

if __name__ == "__main__":
# Add our console control handling function with value 1
Expand Down
Loading