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
97 changes: 51 additions & 46 deletions Lib/ctypes/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
"""create and manipulate C data types in Python"""

import os as _os, sys as _sys
import os as _os
import sys as _sys
import sysconfig as _sysconfig
import types as _types

__version__ = "1.1.0"
Expand Down Expand Up @@ -36,9 +38,6 @@
FUNCFLAG_USE_ERRNO as _FUNCFLAG_USE_ERRNO, \
FUNCFLAG_USE_LASTERROR as _FUNCFLAG_USE_LASTERROR

# TODO: RUSTPYTHON remove this
from _ctypes import _non_existing_function

# WINOLEAPI -> HRESULT
# WINOLEAPI_(type)
#
Expand Down Expand Up @@ -110,7 +109,7 @@ class CFunctionType(_CFuncPtr):
return CFunctionType

if _os.name == "nt":
from _ctypes import LoadLibrary as _dlopen
from _ctypes import LoadLibrary as _LoadLibrary
from _ctypes import FUNCFLAG_STDCALL as _FUNCFLAG_STDCALL

_win_functype_cache = {}
Expand Down Expand Up @@ -305,8 +304,9 @@ def create_unicode_buffer(init, size=None):
raise TypeError(init)


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

# XXX Deprecated
def ARRAY(typ, len):
return typ * len

Expand Down Expand Up @@ -347,52 +346,59 @@ def __init__(self, name, mode=DEFAULT_MODE, handle=None,
use_errno=False,
use_last_error=False,
winmode=None):
class _FuncPtr(_CFuncPtr):
_flags_ = self._func_flags_
_restype_ = self._func_restype_
if use_errno:
_flags_ |= _FUNCFLAG_USE_ERRNO
if use_last_error:
_flags_ |= _FUNCFLAG_USE_LASTERROR

self._FuncPtr = _FuncPtr
if name:
name = _os.fspath(name)

self._handle = self._load_library(name, mode, handle, winmode)

if _os.name == "nt":
def _load_library(self, name, mode, handle, winmode):
if winmode is None:
import nt as _nt
winmode = _nt._LOAD_LIBRARY_SEARCH_DEFAULT_DIRS
# WINAPI LoadLibrary searches for a DLL if the given name
# is not fully qualified with an explicit drive. For POSIX
# compatibility, and because the DLL search path no longer
# contains the working directory, begin by fully resolving
# any name that contains a path separator.
if name is not None and ('/' in name or '\\' in name):
name = _nt._getfullpathname(name)
winmode |= _nt._LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR
self._name = name
if handle is not None:
return handle
return _LoadLibrary(self._name, winmode)

else:
def _load_library(self, name, mode, handle, winmode):
# If the filename that has been provided is an iOS/tvOS/watchOS
# .fwork file, dereference the location to the true origin of the
# binary.
if name.endswith(".fwork"):
if name and name.endswith(".fwork"):
with open(name) as f:
name = _os.path.join(
_os.path.dirname(_sys.executable),
f.read().strip()
)

self._name = name
flags = self._func_flags_
if use_errno:
flags |= _FUNCFLAG_USE_ERRNO
if use_last_error:
flags |= _FUNCFLAG_USE_LASTERROR
if _sys.platform.startswith("aix"):
"""When the name contains ".a(" and ends with ")",
e.g., "libFOO.a(libFOO.so)" - this is taken to be an
archive(member) syntax for dlopen(), and the mode is adjusted.
Otherwise, name is presented to dlopen() as a file argument.
"""
if name and name.endswith(")") and ".a(" in name:
mode |= ( _os.RTLD_MEMBER | _os.RTLD_NOW )
if _os.name == "nt":
if winmode is not None:
mode = winmode
else:
import nt
mode = nt._LOAD_LIBRARY_SEARCH_DEFAULT_DIRS
if '/' in name or '\\' in name:
self._name = nt._getfullpathname(self._name)
mode |= nt._LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR

class _FuncPtr(_CFuncPtr):
_flags_ = flags
_restype_ = self._func_restype_
self._FuncPtr = _FuncPtr

if handle is None:
self._handle = _dlopen(self._name, mode)
else:
self._handle = handle
if _sys.platform.startswith("aix"):
"""When the name contains ".a(" and ends with ")",
e.g., "libFOO.a(libFOO.so)" - this is taken to be an
archive(member) syntax for dlopen(), and the mode is adjusted.
Otherwise, name is presented to dlopen() as a file argument.
"""
if name and name.endswith(")") and ".a(" in name:
mode |= _os.RTLD_MEMBER | _os.RTLD_NOW
self._name = name
return _dlopen(name, mode)

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

if _os.name == "nt":
pythonapi = PyDLL("python dll", None, _sys.dllhandle)
elif _sys.platform == "android":
pythonapi = PyDLL("libpython%d.%d.so" % _sys.version_info[:2])
elif _sys.platform == "cygwin":
pythonapi = PyDLL("libpython%d.%d.dll" % _sys.version_info[:2])
elif _sys.platform in ["android", "cygwin"]:
# These are Unix-like platforms which use a dynamically-linked libpython.
pythonapi = PyDLL(_sysconfig.get_config_var("LDLIBRARY"))
else:
pythonapi = PyDLL(None)

Expand Down
8 changes: 4 additions & 4 deletions Lib/ctypes/_endian.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import sys
from ctypes import *
from ctypes import Array, Structure, Union

_array_type = type(Array)

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

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

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

if sys.byteorder == "little":
Expand Down
16 changes: 0 additions & 16 deletions Lib/ctypes/test/__init__.py

This file was deleted.

4 changes: 0 additions & 4 deletions Lib/ctypes/test/__main__.py

This file was deleted.

21 changes: 0 additions & 21 deletions Lib/ctypes/test/test_delattr.py

This file was deleted.

55 changes: 0 additions & 55 deletions Lib/ctypes/test/test_simplesubclasses.py

This file was deleted.

18 changes: 15 additions & 3 deletions Lib/ctypes/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ def find_library(name):
return fname
return None

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

from ctypes._aix import find_library

elif sys.platform == "android":
def find_library(name):
directory = "/system/lib"
if "64" in os.uname().machine:
directory += "64"

fname = f"{directory}/lib{name}.so"
return fname if os.path.isfile(fname) else None

elif os.name == "posix":
# Andreas Degert's find functions, using gcc, /sbin/ldconfig, objdump
import re, tempfile

def _is_elf(filename):
"Return True if the given file is an ELF file"
elf_header = b'\x7fELF'
with open(filename, 'br') as thefile:
return thefile.read(4) == elf_header
try:
with open(filename, 'br') as thefile:
return thefile.read(4) == elf_header
except FileNotFoundError:
return False

def _findLib_gcc(name):
# Run GCC's linker with the -t (aka --trace) option and examine the
Expand Down
2 changes: 1 addition & 1 deletion Lib/platform.py
Original file line number Diff line number Diff line change
Expand Up @@ -1080,7 +1080,7 @@ def _sys_version(sys_version=None):
match.groups()

# XXX: RUSTPYTHON support
if "rustc" in sys_version:
if "RustPython" in sys_version:
name = "RustPython"
else:
name = 'CPython'
Expand Down
10 changes: 0 additions & 10 deletions Lib/test/test_ctypes.py

This file was deleted.

10 changes: 10 additions & 0 deletions Lib/test/test_ctypes/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import os
from test import support
from test.support import import_helper


# skip tests if the _ctypes extension was not built
import_helper.import_module('ctypes')

def load_tests(*args):
return support.load_package_tests(os.path.dirname(__file__), *args)
4 changes: 4 additions & 0 deletions Lib/test/test_ctypes/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from test.test_ctypes import load_tests
import unittest

unittest.main()
24 changes: 24 additions & 0 deletions Lib/test/test_ctypes/_support.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Some classes and types are not export to _ctypes module directly.

import ctypes
from _ctypes import Structure, Union, _Pointer, Array, _SimpleCData, CFuncPtr


_CData = Structure.__base__
assert _CData.__name__ == "_CData"

class _X(Structure):
_fields_ = [("x", ctypes.c_int)]
CField = type(_X.x)

# metaclasses
PyCStructType = type(Structure)
UnionType = type(Union)
PyCPointerType = type(_Pointer)
PyCArrayType = type(Array)
PyCSimpleType = type(_SimpleCData)
PyCFuncPtrType = type(CFuncPtr)

# type flags
Py_TPFLAGS_DISALLOW_INSTANTIATION = 1 << 7
Py_TPFLAGS_IMMUTABLETYPE = 1 << 8
Loading
Loading