Skip to content

Commit 2785bd8

Browse files
authored
Merge pull request #6457 from youknowone/ctypes
Enable ctypes
2 parents ec75888 + 4a35234 commit 2785bd8

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

84 files changed

+3564
-1741
lines changed

Lib/ctypes/__init__.py

Lines changed: 51 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
"""create and manipulate C data types in Python"""
22

3-
import os as _os, sys as _sys
3+
import os as _os
4+
import sys as _sys
5+
import sysconfig as _sysconfig
46
import types as _types
57

68
__version__ = "1.1.0"
@@ -36,9 +38,6 @@
3638
FUNCFLAG_USE_ERRNO as _FUNCFLAG_USE_ERRNO, \
3739
FUNCFLAG_USE_LASTERROR as _FUNCFLAG_USE_LASTERROR
3840

39-
# TODO: RUSTPYTHON remove this
40-
from _ctypes import _non_existing_function
41-
4241
# WINOLEAPI -> HRESULT
4342
# WINOLEAPI_(type)
4443
#
@@ -110,7 +109,7 @@ class CFunctionType(_CFuncPtr):
110109
return CFunctionType
111110

112111
if _os.name == "nt":
113-
from _ctypes import LoadLibrary as _dlopen
112+
from _ctypes import LoadLibrary as _LoadLibrary
114113
from _ctypes import FUNCFLAG_STDCALL as _FUNCFLAG_STDCALL
115114

116115
_win_functype_cache = {}
@@ -305,8 +304,9 @@ def create_unicode_buffer(init, size=None):
305304
raise TypeError(init)
306305

307306

308-
# XXX Deprecated
309307
def SetPointerType(pointer, cls):
308+
import warnings
309+
warnings._deprecated("ctypes.SetPointerType", remove=(3, 15))
310310
if _pointer_type_cache.get(cls, None) is not None:
311311
raise RuntimeError("This type already exists in the cache")
312312
if id(pointer) not in _pointer_type_cache:
@@ -315,7 +315,6 @@ def SetPointerType(pointer, cls):
315315
_pointer_type_cache[cls] = pointer
316316
del _pointer_type_cache[id(pointer)]
317317

318-
# XXX Deprecated
319318
def ARRAY(typ, len):
320319
return typ * len
321320

@@ -347,52 +346,59 @@ def __init__(self, name, mode=DEFAULT_MODE, handle=None,
347346
use_errno=False,
348347
use_last_error=False,
349348
winmode=None):
349+
class _FuncPtr(_CFuncPtr):
350+
_flags_ = self._func_flags_
351+
_restype_ = self._func_restype_
352+
if use_errno:
353+
_flags_ |= _FUNCFLAG_USE_ERRNO
354+
if use_last_error:
355+
_flags_ |= _FUNCFLAG_USE_LASTERROR
356+
357+
self._FuncPtr = _FuncPtr
350358
if name:
351359
name = _os.fspath(name)
352360

361+
self._handle = self._load_library(name, mode, handle, winmode)
362+
363+
if _os.name == "nt":
364+
def _load_library(self, name, mode, handle, winmode):
365+
if winmode is None:
366+
import nt as _nt
367+
winmode = _nt._LOAD_LIBRARY_SEARCH_DEFAULT_DIRS
368+
# WINAPI LoadLibrary searches for a DLL if the given name
369+
# is not fully qualified with an explicit drive. For POSIX
370+
# compatibility, and because the DLL search path no longer
371+
# contains the working directory, begin by fully resolving
372+
# any name that contains a path separator.
373+
if name is not None and ('/' in name or '\\' in name):
374+
name = _nt._getfullpathname(name)
375+
winmode |= _nt._LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR
376+
self._name = name
377+
if handle is not None:
378+
return handle
379+
return _LoadLibrary(self._name, winmode)
380+
381+
else:
382+
def _load_library(self, name, mode, handle, winmode):
353383
# If the filename that has been provided is an iOS/tvOS/watchOS
354384
# .fwork file, dereference the location to the true origin of the
355385
# binary.
356-
if name.endswith(".fwork"):
386+
if name and name.endswith(".fwork"):
357387
with open(name) as f:
358388
name = _os.path.join(
359389
_os.path.dirname(_sys.executable),
360390
f.read().strip()
361391
)
362-
363-
self._name = name
364-
flags = self._func_flags_
365-
if use_errno:
366-
flags |= _FUNCFLAG_USE_ERRNO
367-
if use_last_error:
368-
flags |= _FUNCFLAG_USE_LASTERROR
369-
if _sys.platform.startswith("aix"):
370-
"""When the name contains ".a(" and ends with ")",
371-
e.g., "libFOO.a(libFOO.so)" - this is taken to be an
372-
archive(member) syntax for dlopen(), and the mode is adjusted.
373-
Otherwise, name is presented to dlopen() as a file argument.
374-
"""
375-
if name and name.endswith(")") and ".a(" in name:
376-
mode |= ( _os.RTLD_MEMBER | _os.RTLD_NOW )
377-
if _os.name == "nt":
378-
if winmode is not None:
379-
mode = winmode
380-
else:
381-
import nt
382-
mode = nt._LOAD_LIBRARY_SEARCH_DEFAULT_DIRS
383-
if '/' in name or '\\' in name:
384-
self._name = nt._getfullpathname(self._name)
385-
mode |= nt._LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR
386-
387-
class _FuncPtr(_CFuncPtr):
388-
_flags_ = flags
389-
_restype_ = self._func_restype_
390-
self._FuncPtr = _FuncPtr
391-
392-
if handle is None:
393-
self._handle = _dlopen(self._name, mode)
394-
else:
395-
self._handle = handle
392+
if _sys.platform.startswith("aix"):
393+
"""When the name contains ".a(" and ends with ")",
394+
e.g., "libFOO.a(libFOO.so)" - this is taken to be an
395+
archive(member) syntax for dlopen(), and the mode is adjusted.
396+
Otherwise, name is presented to dlopen() as a file argument.
397+
"""
398+
if name and name.endswith(")") and ".a(" in name:
399+
mode |= _os.RTLD_MEMBER | _os.RTLD_NOW
400+
self._name = name
401+
return _dlopen(name, mode)
396402

397403
def __repr__(self):
398404
return "<%s '%s', handle %x at %#x>" % \
@@ -480,10 +486,9 @@ def LoadLibrary(self, name):
480486

481487
if _os.name == "nt":
482488
pythonapi = PyDLL("python dll", None, _sys.dllhandle)
483-
elif _sys.platform == "android":
484-
pythonapi = PyDLL("libpython%d.%d.so" % _sys.version_info[:2])
485-
elif _sys.platform == "cygwin":
486-
pythonapi = PyDLL("libpython%d.%d.dll" % _sys.version_info[:2])
489+
elif _sys.platform in ["android", "cygwin"]:
490+
# These are Unix-like platforms which use a dynamically-linked libpython.
491+
pythonapi = PyDLL(_sysconfig.get_config_var("LDLIBRARY"))
487492
else:
488493
pythonapi = PyDLL(None)
489494

Lib/ctypes/_endian.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import sys
2-
from ctypes import *
2+
from ctypes import Array, Structure, Union
33

44
_array_type = type(Array)
55

@@ -15,8 +15,8 @@ def _other_endian(typ):
1515
# if typ is array
1616
if isinstance(typ, _array_type):
1717
return _other_endian(typ._type_) * typ._length_
18-
# if typ is structure
19-
if issubclass(typ, Structure):
18+
# if typ is structure or union
19+
if issubclass(typ, (Structure, Union)):
2020
return typ
2121
raise TypeError("This type does not support other endian: %s" % typ)
2222

@@ -37,7 +37,7 @@ class _swapped_union_meta(_swapped_meta, type(Union)): pass
3737
################################################################
3838

3939
# Note: The Structure metaclass checks for the *presence* (not the
40-
# value!) of a _swapped_bytes_ attribute to determine the bit order in
40+
# value!) of a _swappedbytes_ attribute to determine the bit order in
4141
# structures containing bit fields.
4242

4343
if sys.byteorder == "little":

Lib/ctypes/test/__init__.py

Lines changed: 0 additions & 16 deletions
This file was deleted.

Lib/ctypes/test/__main__.py

Lines changed: 0 additions & 4 deletions
This file was deleted.

Lib/ctypes/test/test_delattr.py

Lines changed: 0 additions & 21 deletions
This file was deleted.

Lib/ctypes/test/test_simplesubclasses.py

Lines changed: 0 additions & 55 deletions
This file was deleted.

Lib/ctypes/util.py

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ def find_library(name):
6767
return fname
6868
return None
6969

70-
elif os.name == "posix" and sys.platform == "darwin":
70+
elif os.name == "posix" and sys.platform in {"darwin", "ios", "tvos", "watchos"}:
7171
from ctypes.macholib.dyld import dyld_find as _dyld_find
7272
def find_library(name):
7373
possible = ['lib%s.dylib' % name,
@@ -89,15 +89,27 @@ def find_library(name):
8989

9090
from ctypes._aix import find_library
9191

92+
elif sys.platform == "android":
93+
def find_library(name):
94+
directory = "/system/lib"
95+
if "64" in os.uname().machine:
96+
directory += "64"
97+
98+
fname = f"{directory}/lib{name}.so"
99+
return fname if os.path.isfile(fname) else None
100+
92101
elif os.name == "posix":
93102
# Andreas Degert's find functions, using gcc, /sbin/ldconfig, objdump
94103
import re, tempfile
95104

96105
def _is_elf(filename):
97106
"Return True if the given file is an ELF file"
98107
elf_header = b'\x7fELF'
99-
with open(filename, 'br') as thefile:
100-
return thefile.read(4) == elf_header
108+
try:
109+
with open(filename, 'br') as thefile:
110+
return thefile.read(4) == elf_header
111+
except FileNotFoundError:
112+
return False
101113

102114
def _findLib_gcc(name):
103115
# Run GCC's linker with the -t (aka --trace) option and examine the

Lib/platform.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1080,7 +1080,7 @@ def _sys_version(sys_version=None):
10801080
match.groups()
10811081

10821082
# XXX: RUSTPYTHON support
1083-
if "rustc" in sys_version:
1083+
if "RustPython" in sys_version:
10841084
name = "RustPython"
10851085
else:
10861086
name = 'CPython'

Lib/test/test_ctypes.py

Lines changed: 0 additions & 10 deletions
This file was deleted.

Lib/test/test_ctypes/__init__.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import os
2+
from test import support
3+
from test.support import import_helper
4+
5+
6+
# skip tests if the _ctypes extension was not built
7+
import_helper.import_module('ctypes')
8+
9+
def load_tests(*args):
10+
return support.load_package_tests(os.path.dirname(__file__), *args)

0 commit comments

Comments
 (0)