diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst index 8dbebf7048b5835..f45ab397e936938 100644 --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -2179,6 +2179,11 @@ are always available. They are listed here in alphabetical order. in the same way that keywords in a class definition (besides *metaclass*) would. + Unlike a :keyword:`class` statement, the three argument form does not + call the metaclass ``__prepare__`` method (see :ref:`prepare`). Use + :func:`types.new_class` to dynamically create a class using the + appropriate metaclass. + See also :ref:`class-customization`. .. versionchanged:: 3.6 diff --git a/Doc/library/lzma.rst b/Doc/library/lzma.rst index cd72174d54f6e62..580829cfbb46e07 100644 --- a/Doc/library/lzma.rst +++ b/Doc/library/lzma.rst @@ -152,35 +152,14 @@ Compressing and decompressing data in memory :func:`compress`. The *format* argument specifies what container format should be used. - Possible values are: - - * :const:`FORMAT_XZ`: The ``.xz`` container format. - This is the default format. - - * :const:`FORMAT_ALONE`: The legacy ``.lzma`` container format. - This format is more limited than ``.xz`` -- it does not support integrity - checks or multiple filters. - - * :const:`FORMAT_RAW`: A raw data stream, not using any container format. - This format specifier does not support integrity checks, and requires that - you always specify a custom filter chain (for both compression and - decompression). Additionally, data compressed in this manner cannot be - decompressed using :const:`FORMAT_AUTO` (see :class:`LZMADecompressor`). + Possible values are :const:`FORMAT_XZ` (the default), + :const:`FORMAT_ALONE` and :const:`FORMAT_RAW`. The *check* argument specifies the type of integrity check to include in the compressed data. This check is used when decompressing, to ensure that the - data has not been corrupted. Possible values are: - - * :const:`CHECK_NONE`: No integrity check. - This is the default (and the only acceptable value) for - :const:`FORMAT_ALONE` and :const:`FORMAT_RAW`. - - * :const:`CHECK_CRC32`: 32-bit Cyclic Redundancy Check. - - * :const:`CHECK_CRC64`: 64-bit Cyclic Redundancy Check. - This is the default for :const:`FORMAT_XZ`. - - * :const:`CHECK_SHA256`: 256-bit Secure Hash Algorithm. + data has not been corrupted. Possible values are :const:`CHECK_NONE`, + :const:`CHECK_CRC32`, :const:`CHECK_CRC64` (the default for + :const:`FORMAT_XZ`) and :const:`CHECK_SHA256`. If the specified check is not supported, an :class:`LZMAError` is raised. @@ -412,6 +391,106 @@ These filters support one option, ``start_offset``. This specifies the address that should be mapped to the beginning of the input data. The default is 0. +Constants +--------- + +The following module-level constants are provided for use as the *format*, +*check*, *preset* and *filters* arguments of the classes and functions above. + +Container formats: + +.. data:: FORMAT_XZ + + The ``.xz`` container format. + +.. data:: FORMAT_ALONE + + The legacy ``.lzma`` container format. This format is more limited than + ``.xz`` -- it does not support integrity checks or multiple filters. + +.. data:: FORMAT_RAW + + A raw data stream, not using any container format. This format specifier + does not support integrity checks, and requires that you always specify a + custom filter chain (for both compression and decompression). Additionally, + data compressed in this manner cannot be decompressed using + :const:`FORMAT_AUTO`. + +.. data:: FORMAT_AUTO + + Used for decompression only. The container format is detected + automatically, so that both ``.xz`` and ``.lzma`` files can be decompressed. + +Integrity checks: + +.. data:: CHECK_NONE + + No integrity check. This is the default (and the only acceptable value) for + :const:`FORMAT_ALONE` and :const:`FORMAT_RAW`. + +.. data:: CHECK_CRC32 + + A 32-bit Cyclic Redundancy Check. + +.. data:: CHECK_CRC64 + + A 64-bit Cyclic Redundancy Check. This is the default for + :const:`FORMAT_XZ`. + +.. data:: CHECK_SHA256 + + A 256-bit Secure Hash Algorithm. + +.. data:: CHECK_UNKNOWN + + The integrity check used by a stream could not yet be determined. This may + be the value of the :attr:`LZMADecompressor.check` attribute until enough of + the input has been decoded. + +.. data:: CHECK_ID_MAX + + The largest supported integrity-check ID. + +Compression presets: + +.. data:: PRESET_DEFAULT + + The default compression preset, equivalent to preset level ``6``. + +.. data:: PRESET_EXTREME + + A flag that may be bitwise OR-ed with a preset level (``0`` to ``9``) to + select a slower but more thorough variant of that preset. + +Filter IDs and options: + +.. data:: FILTER_LZMA1 + FILTER_LZMA2 + + The LZMA1 and LZMA2 compression filters. :const:`FILTER_LZMA1` is for use + with :const:`FORMAT_ALONE`, while :const:`FILTER_LZMA2` is for use with + :const:`FORMAT_XZ` and :const:`FORMAT_RAW`. + +.. data:: FILTER_DELTA + + The delta filter. + +.. data:: MODE_FAST + MODE_NORMAL + + Compression modes that may be used as the ``mode`` option of a filter + specifier (see :ref:`filter-chain-specs`). + +.. data:: MF_HC3 + MF_HC4 + MF_BT2 + MF_BT3 + MF_BT4 + + Match finders that may be used as the ``mf`` option of a filter specifier + (see :ref:`filter-chain-specs`). + + Examples -------- diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore index c5d474895966119..ab592cfa5a1bbbd 100644 --- a/Doc/tools/.nitignore +++ b/Doc/tools/.nitignore @@ -12,7 +12,6 @@ Doc/library/email.parser.rst Doc/library/importlib.rst Doc/library/logging.config.rst Doc/library/logging.handlers.rst -Doc/library/lzma.rst Doc/library/mmap.rst Doc/library/multiprocessing.rst Doc/library/optparse.rst diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst index 2fa7267292d9940..64c6888d9947702 100644 --- a/Doc/whatsnew/3.14.rst +++ b/Doc/whatsnew/3.14.rst @@ -3312,6 +3312,16 @@ Changes in the Python API This temporary change affects other threads. (Contributed by Serhiy Storchaka in :gh:`69998`.) +* :func:`pickle.dump` and :func:`pickle.dumps` now raise + :exc:`~pickle.PicklingError` for some failures that previously raised + :exc:`AttributeError`, :exc:`ImportError`, :exc:`ValueError`, + :exc:`UnicodeEncodeError` or :exc:`!PicklingError`, + depending on the implementation + (for example, pickling a local object, or an object whose module cannot be imported). + The original exception is chained to the :exc:`!PicklingError`. + Code that caught these exceptions should also catch :exc:`!PicklingError`. + (Contributed by Serhiy Storchaka in :gh:`122311`.) + * :class:`types.UnionType` is now an alias for :class:`typing.Union`, causing changes in some behaviors. See :ref:`above ` for more details. diff --git a/Include/py_curses.h b/Include/py_curses.h index a5f5f3d76075827..85a540086c83844 100644 --- a/Include/py_curses.h +++ b/Include/py_curses.h @@ -43,6 +43,15 @@ # define PDC_NCMOUSE #endif +/* On Solaris/illumos, the SVr4 does "typedef char bool;", which + clashes with C's bool from . Define _BOOL to suppress it, and + include for the bool the header then needs. ncurses ignores + _BOOL. */ +#if defined(__sun) && !defined(_BOOL) +# include +# define _BOOL +#endif + #if defined(HAVE_NCURSESW_NCURSES_H) # include #elif defined(HAVE_NCURSESW_CURSES_H) diff --git a/Lib/asyncio/base_subprocess.py b/Lib/asyncio/base_subprocess.py index 224b1883808a412..3fa1ed1afd2a651 100644 --- a/Lib/asyncio/base_subprocess.py +++ b/Lib/asyncio/base_subprocess.py @@ -26,7 +26,6 @@ def __init__(self, loop, protocol, args, shell, self._pending_calls = collections.deque() self._pipes = {} self._finished = False - self._pipes_connected = False if stdin == subprocess.PIPE: self._pipes[0] = None @@ -214,7 +213,6 @@ async def _connect_pipes(self, waiter): else: if waiter is not None and not waiter.cancelled(): waiter.set_result(None) - self._pipes_connected = True def _call(self, cb, *data): if self._pending_calls is not None: @@ -235,6 +233,7 @@ def _process_exited(self, returncode): if self._loop.get_debug(): logger.info('%r exited with return code %r', self, returncode) self._returncode = returncode + if self._proc.returncode is None: # asyncio uses a child watcher: copy the status into the Popen # object. On Python 3.6, it is required to avoid a ResourceWarning. @@ -243,6 +242,13 @@ def _process_exited(self, returncode): self._try_finish() + # gh-119710: Wake up futures waiting for wait() as soon as the process + # exits. + for waiter in self._exit_waiters: + if not waiter.done(): + waiter.set_result(returncode) + self._exit_waiters = None + async def _wait(self): """Wait until the process exit and return the process return code. @@ -258,15 +264,7 @@ def _try_finish(self): assert not self._finished if self._returncode is None: return - if not self._pipes_connected: - # self._pipes_connected can be False if not all pipes were connected - # because either the process failed to start or the self._connect_pipes task - # got cancelled. In this broken state we consider all pipes disconnected and - # to avoid hanging forever in self._wait as otherwise _exit_waiters - # would never be woken up, we wake them up here. - for waiter in self._exit_waiters: - if not waiter.done(): - waiter.set_result(self._returncode) + if all(p is not None and p.disconnected for p in self._pipes.values()): self._finished = True @@ -276,11 +274,6 @@ def _call_connection_lost(self, exc): try: self._protocol.connection_lost(exc) finally: - # wake up futures waiting for wait() - for waiter in self._exit_waiters: - if not waiter.done(): - waiter.set_result(self._returncode) - self._exit_waiters = None self._loop = None self._proc = None self._protocol = None diff --git a/Lib/platform.py b/Lib/platform.py index 36489d4fdd98ae2..3141998e02dfe21 100644 --- a/Lib/platform.py +++ b/Lib/platform.py @@ -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. diff --git a/Lib/pydoc.py b/Lib/pydoc.py index 3140723f49b7d0d..72974af26bee64c 100644 --- a/Lib/pydoc.py +++ b/Lib/pydoc.py @@ -881,9 +881,10 @@ def docmodule(self, object, name=None, mod=None, *ignored): if data: contents = [] for key, value in data: - contents.append(self.document(value, key)) + contents.append( + f'
{self.document(value, key)}
') result = result + self.bigsection( - 'Data', 'data', '
\n'.join(contents)) + 'Data', 'data', '\n'.join(contents)) if hasattr(object, '__author__'): contents = self.markup(str(object.__author__), self.preformat) result = result + self.bigsection('Author', 'author', contents) diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py index 115a187a8a85882..8f665b3a98a0371 100644 --- a/Lib/test/_test_multiprocessing.py +++ b/Lib/test/_test_multiprocessing.py @@ -161,9 +161,10 @@ def wait_for_handle(handle, timeout): # try: - from ctypes import Structure, c_int, c_double, c_longlong + from ctypes.util import struct as ctypes_struct + from ctypes import c_int, c_double, c_longlong except ImportError: - Structure = object + def ctypes_struct(cls): return cls c_int = c_double = c_longlong = None @@ -4390,12 +4391,11 @@ def test_free_from_gc(self): # # -class _Foo(Structure): - _fields_ = [ - ('x', c_int), - ('y', c_double), - ('z', c_longlong,) - ] +@ctypes_struct +class _Foo: + x: c_int + y: c_double + z: c_longlong class _TestSharedCTypes(BaseTestCase): diff --git a/Lib/test/libregrtest/tsan.py b/Lib/test/libregrtest/tsan.py index bacfe5e21ba0b7d..c7ec63763bc9d85 100644 --- a/Lib/test/libregrtest/tsan.py +++ b/Lib/test/libregrtest/tsan.py @@ -8,6 +8,7 @@ 'test_ctypes', 'test_concurrent_futures', 'test_enum', + 'test_enumerate', 'test_functools', 'test_httpservers', 'test_imaplib', diff --git a/Lib/test/pythoninfo.py b/Lib/test/pythoninfo.py index 3227b91bd82a863..13a3199b1f1267b 100644 --- a/Lib/test/pythoninfo.py +++ b/Lib/test/pythoninfo.py @@ -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: @@ -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 = '' 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 diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index d17d9a2ecf8d9b0..e5bc2fd9b3d0954 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -236,20 +236,41 @@ def _is_gui_available(): # if Python is running as a service (such as the buildbot service), # gui interaction may be disallowed import ctypes + import ctypes.util import ctypes.wintypes + UOI_FLAGS = 1 WSF_VISIBLE = 0x0001 - class USEROBJECTFLAGS(ctypes.Structure): - _fields_ = [("fInherit", ctypes.wintypes.BOOL), - ("fReserved", ctypes.wintypes.BOOL), - ("dwFlags", ctypes.wintypes.DWORD)] - dll = ctypes.windll.user32 - h = dll.GetProcessWindowStation() + + @ctypes.util.struct + class USEROBJECTFLAGS: + fInherit: ctypes.wintypes.BOOL + fReserved: ctypes.wintypes.BOOL + dwFlags: ctypes.wintypes.DWORD + + user32 = ctypes.windll.user32 + + @ctypes.util.wrap_dll_function(user32) + def GetProcessWindowStation() -> ctypes.wintypes.HANDLE: + ... + + h = GetProcessWindowStation() if not h: raise ctypes.WinError() + + @ctypes.util.wrap_dll_function(user32) + def GetUserObjectInformationW( + hObj: ctypes.wintypes.HANDLE, + nIndex: ctypes.c_int, + pvInfo: ctypes.c_void_p, + nLength: ctypes.wintypes.DWORD, + lpnLengthNeeded: ctypes.POINTER(ctypes.wintypes.DWORD), + ) -> ctypes.wintypes.BOOL: + ... + uof = USEROBJECTFLAGS() needed = ctypes.wintypes.DWORD() - res = dll.GetUserObjectInformationW(h, + res = GetUserObjectInformationW(h, UOI_FLAGS, ctypes.byref(uof), ctypes.sizeof(uof), diff --git a/Lib/test/test_android.py b/Lib/test/test_android.py index 31daafbc3d63009..201d701aff11eb2 100644 --- a/Lib/test/test_android.py +++ b/Lib/test/test_android.py @@ -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: diff --git a/Lib/test/test_asyncio/test_subprocess.py b/Lib/test/test_asyncio/test_subprocess.py index bb1a7d6ff22be8d..2e97fa5820f8245 100644 --- a/Lib/test/test_asyncio/test_subprocess.py +++ b/Lib/test/test_asyncio/test_subprocess.py @@ -112,37 +112,6 @@ def test_subprocess_repr(self): ) transport.close() - def test_proc_exited_no_invalid_state_error_on_exit_waiters(self): - # gh-145541: when _connect_pipes hasn't completed (so - # _pipes_connected is False) and the process exits, _try_finish() - # sets the result on exit waiters. Then _call_connection_lost() must - # not call set_result() again on the same waiters. - self.loop.set_exception_handler( - lambda loop, context: self.fail( - f"unexpected exception: {context}") - ) - waiter = self.loop.create_future() - transport, protocol = self.create_transport(waiter) - - # Simulate a waiter registered via _wait() before the process exits. - exit_waiter = self.loop.create_future() - transport._exit_waiters.append(exit_waiter) - - # _connect_pipes hasn't completed, so _pipes_connected is False. - self.assertFalse(transport._pipes_connected) - - # Simulate process exit. _try_finish() will set the result on - # exit_waiter because _pipes_connected is False, and then schedule - # _call_connection_lost() because _pipes is empty (vacuously all - # disconnected). _call_connection_lost() must skip exit_waiter - # because it's already done. - transport._process_exited(6) - self.loop.run_until_complete(waiter) - - self.assertEqual(exit_waiter.result(), 6) - - transport.close() - class SubprocessMixin: @@ -436,6 +405,46 @@ async def len_message(message): self.assertEqual(output.rstrip(), b'3') self.assertEqual(exitcode, 0) + def test_wait_even_if_pipe_is_open(self): + # gh-119710: Process.wait() must return once the process exits even + # if its stdout pipe is inherited by a grandchild that keeps it open, + # so the pipe never reaches EOF. Otherwise wait() hangs forever + # despite the returncode being known. + + async def run(): + # The grandchild inherits the child's stdin and stdout pipes and + # keeps both open after the child is killed. It writes "ready" + # so we know it has started, and exits once its stdin hits EOF. + code = textwrap.dedent("""\ + import subprocess, sys + subprocess.run([sys.executable, "-c", + "import sys; sys.stdout.write('ready');" + " sys.stdout.flush(); sys.stdin.read()"]) + """) + + proc = await asyncio.create_subprocess_exec( + sys.executable, "-c", code, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + ) + try: + wait_proc = asyncio.create_task(proc.wait()) + # Wait until the grandchild holds the inherited pipes; this + # also lets the wait() task register its waiter. + await proc.stdout.readexactly(5) + proc.kill() + returncode = await asyncio.wait_for( + wait_proc, timeout=support.SHORT_TIMEOUT) + if sys.platform == 'win32': + self.assertIsInstance(returncode, int) + else: + self.assertEqual(-signal.SIGKILL, returncode) + finally: + proc.stdin.close() # let the grandchild exit + await proc.stdout.read() + + self.loop.run_until_complete(run()) + def test_empty_input(self): async def empty_input(): diff --git a/Lib/test/test_buffer.py b/Lib/test/test_buffer.py index 3213a4751273431..453dafe2709eb2f 100644 --- a/Lib/test/test_buffer.py +++ b/Lib/test/test_buffer.py @@ -37,6 +37,7 @@ try: import ctypes + import ctypes.util except ImportError: ctypes = None @@ -2849,8 +2850,11 @@ def test_memoryview_cast_1D_ND(self): if ctypes: # format: "T{>l:x:>d:y:}" - class BEPoint(ctypes.BigEndianStructure): - _fields_ = [("x", ctypes.c_long), ("y", ctypes.c_double)] + @ctypes.util.struct(endian='big') + class BEPoint: + x: ctypes.c_long + y: ctypes.c_double + point = BEPoint(100, 200.1) m1 = memoryview(point) m2 = m1.cast('B') @@ -3250,8 +3254,11 @@ def test_memoryview_compare_special_cases(self): # Some ctypes format strings are unknown to the struct module. if ctypes: # format: "T{>l:x:>l:y:}" - class BEPoint(ctypes.BigEndianStructure): - _fields_ = [("x", ctypes.c_long), ("y", ctypes.c_long)] + @ctypes.util.struct(endian='big') + class BEPoint: + x: ctypes.c_long + y: ctypes.c_long + point = BEPoint(100, 200) a = memoryview(point) b = memoryview(point) @@ -3988,8 +3995,11 @@ def test_memoryview_tobytes(self): # Unknown formats are handled: tobytes() purely depends on itemsize. if ctypes: # format: "T{>l:x:>l:y:}" - class BEPoint(ctypes.BigEndianStructure): - _fields_ = [("x", ctypes.c_long), ("y", ctypes.c_long)] + @ctypes.util.struct(endian='big') + class BEPoint: + x: ctypes.c_long + y: ctypes.c_long + point = BEPoint(100, 200) a = memoryview(point) self.assertEqual(a.tobytes(), bytes(point)) diff --git a/Lib/test/test_capi/test_misc.py b/Lib/test/test_capi/test_misc.py index 6d84f0b8c305dfb..7d668843d07debc 100644 --- a/Lib/test/test_capi/test_misc.py +++ b/Lib/test/test_capi/test_misc.py @@ -3043,22 +3043,37 @@ def test_pack_version(self): def test_pack_full_version_ctypes(self): ctypes = import_helper.import_module('ctypes') - ctypes_func = ctypes.pythonapi.Py_PACK_FULL_VERSION - ctypes_func.restype = ctypes.c_uint32 - ctypes_func.argtypes = [ctypes.c_int] * 5 + import ctypes.util # noqa: F811 + + @ctypes.util.wrap_dll_function(ctypes.pythonapi) + def Py_PACK_FULL_VERSION( + x: ctypes.c_int, + y: ctypes.c_int, + z: ctypes.c_int, + level: ctypes.c_int, + serial: ctypes.c_int, + ) -> ctypes.c_uint32: + pass + for *args, expected in self.full_cases: with self.subTest(hexversion=hex(expected)): - result = ctypes_func(*args) + result = Py_PACK_FULL_VERSION(*args) self.assertEqual(result, expected) def test_pack_version_ctypes(self): ctypes = import_helper.import_module('ctypes') - ctypes_func = ctypes.pythonapi.Py_PACK_VERSION - ctypes_func.restype = ctypes.c_uint32 - ctypes_func.argtypes = [ctypes.c_int] * 2 + import ctypes.util # noqa: F811 + + @ctypes.util.wrap_dll_function(ctypes.pythonapi) + def Py_PACK_VERSION( + x: ctypes.c_int, + y: ctypes.c_int, + ) -> ctypes.c_uint32: + pass + for *args, expected in self.xy_cases: with self.subTest(hexversion=hex(expected)): - result = ctypes_func(*args) + result = Py_PACK_VERSION(*args) self.assertEqual(result, expected) diff --git a/Lib/test/test_code.py b/Lib/test/test_code.py index bd2fa1d7b70421a..631e5fd2499b13e 100644 --- a/Lib/test/test_code.py +++ b/Lib/test/test_code.py @@ -1540,21 +1540,26 @@ async def afunc(): [(1,1,3)]) if check_impl_detail(cpython=True) and ctypes is not None: - py = ctypes.pythonapi - freefunc = ctypes.CFUNCTYPE(None,ctypes.c_voidp) - - RequestCodeExtraIndex = py.PyUnstable_Eval_RequestCodeExtraIndex - RequestCodeExtraIndex.argtypes = (freefunc,) - RequestCodeExtraIndex.restype = ctypes.c_ssize_t - - SetExtra = py.PyUnstable_Code_SetExtra - SetExtra.argtypes = (ctypes.py_object, ctypes.c_ssize_t, ctypes.c_voidp) - SetExtra.restype = ctypes.c_int - - GetExtra = py.PyUnstable_Code_GetExtra - GetExtra.argtypes = (ctypes.py_object, ctypes.c_ssize_t, - ctypes.POINTER(ctypes.c_voidp)) - GetExtra.restype = ctypes.c_int + import ctypes.util + freefunc = ctypes.CFUNCTYPE(None, ctypes.c_voidp) + + @ctypes.util.wrap_dll_function(ctypes.pythonapi) + def PyUnstable_Eval_RequestCodeExtraIndex(free: freefunc) -> ctypes.c_ssize_t: + pass + + @ctypes.util.wrap_dll_function(ctypes.pythonapi) + def PyUnstable_Code_SetExtra(code: ctypes.py_object, + index: ctypes.c_ssize_t, + extra: ctypes.c_voidp) -> ctypes.c_int: + pass + SetExtra = PyUnstable_Code_SetExtra + + @ctypes.util.wrap_dll_function(ctypes.pythonapi) + def PyUnstable_Code_GetExtra(code: ctypes.py_object, + index: ctypes.c_ssize_t, + extra: ctypes.POINTER(ctypes.c_voidp)) -> ctypes.c_int: + pass + GetExtra = PyUnstable_Code_GetExtra LAST_FREED = None def myfree(ptr): @@ -1562,7 +1567,7 @@ def myfree(ptr): LAST_FREED = ptr FREE_FUNC = freefunc(myfree) - FREE_INDEX = RequestCodeExtraIndex(FREE_FUNC) + FREE_INDEX = PyUnstable_Eval_RequestCodeExtraIndex(FREE_FUNC) # Make sure myfree sticks around at least as long as the interpreter, # since we (currently) can't unregister the function and leaving a # dangling pointer will cause a crash on deallocation of code objects if diff --git a/Lib/test/test_codecs.py b/Lib/test/test_codecs.py index c18b203f42f59f3..31704955df3e14e 100644 --- a/Lib/test/test_codecs.py +++ b/Lib/test/test_codecs.py @@ -36,21 +36,25 @@ def check(input, expect): self.assertEqual(coder(input), (expect, len(input))) return check -# On small versions of Windows like Windows IoT or Windows Nano Server not all codepages are present +# On small versions of Windows like Windows IoT or Windows Nano Server, +# not all codepages are present def is_code_page_present(cp): - from ctypes import POINTER, WINFUNCTYPE, WinDLL, Structure + from ctypes import POINTER, WINFUNCTYPE, WinDLL + from ctypes.util import struct from ctypes.wintypes import BOOL, BYTE, WCHAR, UINT, DWORD MAX_LEADBYTES = 12 # 5 ranges, 2 bytes ea., 0 term. MAX_DEFAULTCHAR = 2 # single or double byte MAX_PATH = 260 - class CPINFOEXW(Structure): - _fields_ = [("MaxCharSize", UINT), - ("DefaultChar", BYTE*MAX_DEFAULTCHAR), - ("LeadByte", BYTE*MAX_LEADBYTES), - ("UnicodeDefaultChar", WCHAR), - ("CodePage", UINT), - ("CodePageName", WCHAR*MAX_PATH)] + + @struct + class CPINFOEXW: + MaxCharSize: UINT + DefaultChar: BYTE * MAX_DEFAULTCHAR + LeadByte: BYTE * MAX_LEADBYTES + UnicodeDefaultChar: WCHAR + CodePage: UINT + CodePageName: WCHAR * MAX_PATH prototype = WINFUNCTYPE(BOOL, UINT, DWORD, POINTER(CPINFOEXW)) GetCPInfoEx = prototype(("GetCPInfoExW", WinDLL("kernel32"))) diff --git a/Lib/test/test_ctypes/test_pointers.py b/Lib/test/test_ctypes/test_pointers.py index 771cc8fbe0ec934..78480af34474a54 100644 --- a/Lib/test/test_ctypes/test_pointers.py +++ b/Lib/test/test_ctypes/test_pointers.py @@ -11,6 +11,7 @@ c_long, c_ulong, c_longlong, c_ulonglong, c_float, c_double) from ctypes import _pointer_type_cache, _pointer_type_cache_fallback +from test import support from test.support import import_helper from weakref import WeakSet _ctypes_test = import_helper.import_module("_ctypes_test") @@ -409,10 +410,9 @@ class BadType(ctypes._Pointer): pass func = ctypes.pythonapi.Py_GetVersion - func.argtypes = (BadType,) - - with self.assertRaises(ctypes.ArgumentError): - func(object()) + with support.swap_attr(func, 'argtypes', (BadType,)): + with self.assertRaises(ctypes.ArgumentError): + func(object()) class PointerTypeCacheTestCase(unittest.TestCase): # dummy tests to check warnings and base behavior diff --git a/Lib/test/test_ctypes/test_refcounts.py b/Lib/test/test_ctypes/test_refcounts.py index 1815649ceb5fff9..5191862658c5671 100644 --- a/Lib/test/test_ctypes/test_refcounts.py +++ b/Lib/test/test_ctypes/test_refcounts.py @@ -54,8 +54,10 @@ def func(*args): gc.collect() self.assertEqual(sys.getrefcount(func), orig_refcount) - class X(ctypes.Structure): - _fields_ = [("a", OtherCallback)] + @ctypes.util.struct + class X: + a: OtherCallback + x = X() x.a = OtherCallback(func) @@ -127,9 +129,9 @@ class PyObjectRestypeTest(unittest.TestCase): def test_restype_py_object_with_null_return(self): # Test that a function which returns a NULL PyObject * # without setting an exception does not crash. - PyErr_Occurred = ctypes.pythonapi.PyErr_Occurred - PyErr_Occurred.argtypes = [] - PyErr_Occurred.restype = ctypes.py_object + @ctypes.util.wrap_dll_function(ctypes.pythonapi) + def PyErr_Occurred() -> ctypes.py_object: + pass # At this point, there's no exception set, so PyErr_Occurred # returns NULL. Given the restype is py_object, the diff --git a/Lib/test/test_ctypes/test_unicode.py b/Lib/test/test_ctypes/test_unicode.py index d9e17371d135724..8e91f8f2c566803 100644 --- a/Lib/test/test_ctypes/test_unicode.py +++ b/Lib/test/test_ctypes/test_unicode.py @@ -1,4 +1,4 @@ -import ctypes +import ctypes.util import unittest from test.support import import_helper _ctypes_test = import_helper.import_module("_ctypes_test") @@ -26,8 +26,10 @@ def test_buffers(self): self.assertEqual(buf[6:5:-1], "") def test_embedded_null(self): - class TestStruct(ctypes.Structure): - _fields_ = [("unicode", ctypes.c_wchar_p)] + @ctypes.util.struct + class TestStruct: + unicode: ctypes.c_wchar_p + t = TestStruct() # This would raise a ValueError: t.unicode = "foo\0bar\0\0" diff --git a/Lib/test/test_ctypes/test_win32_com_foreign_func.py b/Lib/test/test_ctypes/test_win32_com_foreign_func.py index 7e54f8f6c31d33f..c797ab98cf1e424 100644 --- a/Lib/test/test_ctypes/test_win32_com_foreign_func.py +++ b/Lib/test/test_ctypes/test_win32_com_foreign_func.py @@ -1,4 +1,4 @@ -import ctypes +import ctypes.util import gc import sys import unittest @@ -20,14 +20,13 @@ E_NOINTERFACE = -2147467262 -class GUID(ctypes.Structure): +@ctypes.util.struct +class GUID: # https://learn.microsoft.com/en-us/windows/win32/api/guiddef/ns-guiddef-guid - _fields_ = [ - ("Data1", DWORD), - ("Data2", WORD), - ("Data3", WORD), - ("Data4", BYTE * 8), - ] + Data1: DWORD + Data2: WORD + Data3: WORD + Data4: BYTE * 8 def create_proto_com_method(name, index, restype, *argtypes): diff --git a/Lib/test/test_curses.py b/Lib/test/test_curses.py index b0592d3f1d92b95..4ca5dd73f55afee 100644 --- a/Lib/test/test_curses.py +++ b/Lib/test/test_curses.py @@ -84,10 +84,15 @@ def wrapped(self, *args, **kwargs): term = os.environ.get('TERM') SHORT_MAX = 0x7fff -# ncurses before 6.5 can crash on repeated newterm(). Fall back to initscr() -# and skip the tests that need several screens. +# ncurses before 6.5, and the native curses of NetBSD and illumos/Solaris, +# crash on repeated newterm()/delscreen(); fall back to initscr() and skip the +# multi-screen tests. The native ones are keyed off the platform so a fixed +# version can be excluded later. _ncurses_version = getattr(curses, 'ncurses_version', None) -BROKEN_NEWTERM = _ncurses_version is not None and _ncurses_version < (6, 5) +if _ncurses_version is not None: + BROKEN_NEWTERM = _ncurses_version < (6, 5) +else: + BROKEN_NEWTERM = sys.platform.startswith(('netbsd', 'sunos')) USE_NEWTERM = hasattr(curses, 'newterm') and not BROKEN_NEWTERM # Older macOS reports a variation selector as a spacing character (wcwidth() @@ -1140,8 +1145,17 @@ def test_attributes(self): win.standout() win.standend() + # attron()/attroff()/attrset() reject a bad attribute. + self.assertRaises(OverflowError, win.attron, 1 << 64) + self.assertRaises(OverflowError, win.attroff, -1) + self.assertRaises(OverflowError, win.attrset, 1 << 64) + self.assertRaises(TypeError, win.attron, 'x') + + @requires_curses_window_meth('attr_set') + def test_attr(self): # The attr_*() family works on attr_t attributes paired with a color # pair, unlike the chtype-based attron()/attroff()/attrset(). + win = curses.newwin(5, 15, 5, 2) win.attr_set(curses.A_BOLD | curses.A_UNDERLINE) attrs, pair = win.attr_get() self.assertTrue(attrs & curses.A_BOLD) @@ -1167,13 +1181,9 @@ def test_attributes(self): self.assertRaises(OverflowError, win.attr_set, -1) self.assertRaises(OverflowError, win.attr_on, -1) self.assertRaises(OverflowError, win.attr_set, 1 << 64) - # attron()/attroff()/attrset() reject a bad attribute too. - self.assertRaises(OverflowError, win.attron, 1 << 64) - self.assertRaises(OverflowError, win.attroff, -1) - self.assertRaises(OverflowError, win.attrset, 1 << 64) - self.assertRaises(TypeError, win.attron, 'x') @requires_colors + @requires_curses_window_meth('attr_set') def test_attr_color_pair(self): win = curses.newwin(5, 15, 5, 2) curses.init_pair(1, curses.COLOR_RED, curses.COLOR_BLACK) @@ -1383,8 +1393,10 @@ def test_scr_dump(self): stdscr.refresh() self.assertIsNone(curses.scr_restore(dump)) # scr_init() and scr_set() also accept a dump file and return None. + # scr_set() is not available on every curses (e.g. old SVr4). self.assertIsNone(curses.scr_init(dump)) - self.assertIsNone(curses.scr_set(dump)) + if hasattr(curses, 'scr_set'): + self.assertIsNone(curses.scr_set(dump)) # A bytes (path-like) filename is accepted too. curses.scr_dump(os.fsencode(dump)) # Restoring from a missing file is an error. @@ -1846,9 +1858,11 @@ def test_escdelay(self): def test_tabsize(self): tabsize = curses.get_tabsize() self.assertIsInstance(tabsize, int) - curses.set_tabsize(4) - self.assertEqual(curses.get_tabsize(), 4) - curses.set_tabsize(tabsize) + # set_tabsize() is not available on every curses (e.g. old SVr4). + if hasattr(curses, 'set_tabsize'): + curses.set_tabsize(4) + self.assertEqual(curses.get_tabsize(), 4) + curses.set_tabsize(tabsize) @requires_curses_func('getsyx') def test_getsyx(self): diff --git a/Lib/test/test_embed.py b/Lib/test/test_embed.py index 40036609a190551..1ff600e30bf4cbd 100644 --- a/Lib/test/test_embed.py +++ b/Lib/test/test_embed.py @@ -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'] diff --git a/Lib/test/test_enumerate.py b/Lib/test/test_enumerate.py index 5cb54cff9b76fdd..c8b85fe86921781 100644 --- a/Lib/test/test_enumerate.py +++ b/Lib/test/test_enumerate.py @@ -3,8 +3,11 @@ import sys import pickle import gc +import threading + from test import support +from test.support import threading_helper class G: 'Sequence using __getitem__' @@ -292,5 +295,28 @@ def enum(self, iterable, start=sys.maxsize + 1): (sys.maxsize+3,'c')] +@threading_helper.requires_working_threading() +class TestThreadSafety(EnumerateStartTestCase): + def test_thread_safety_while_iterating(self): + # gh-153932: calling reduce while iterating should pass with TSAN + + en = enumerate(range(10_000)) + stop = threading.Event() + + def advance(): + for _ in en: + pass + stop.set() + + def read(): + while not stop.is_set(): + en.__reduce__() + + threads = [threading.Thread(target=advance), threading.Thread(target=read)] + + with threading_helper.start_threads(threads): + pass + + if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py index cc7faef93e1af7c..6e458017298dffe 100644 --- a/Lib/test/test_exceptions.py +++ b/Lib/test/test_exceptions.py @@ -440,10 +440,16 @@ def test_WindowsError(self): def test_windows_message(self): """Should fill in unknown error code in Windows error message""" ctypes = import_module('ctypes') + import ctypes.util # noqa: F811 + + @ctypes.util.wrap_dll_function(ctypes.pythonapi) + def PyErr_SetFromWindowsErr(ierr: ctypes.c_int) -> ctypes.py_object: + pass + # this error code has no message, Python formats it as hexadecimal code = 3765269347 - with self.assertRaisesRegex(OSError, 'Windows Error 0x%x' % code): - ctypes.pythonapi.PyErr_SetFromWindowsErr(code) + with self.assertRaisesRegex(OSError, f'Windows Error 0x{code:x}'): + PyErr_SetFromWindowsErr(code) def testAttributes(self): # test that exception attributes are happy diff --git a/Lib/test/test_frame.py b/Lib/test/test_frame.py index fc50e16575da2b9..a3a329cb578a8dc 100644 --- a/Lib/test/test_frame.py +++ b/Lib/test/test_frame.py @@ -821,28 +821,37 @@ class TestFrameCApi(unittest.TestCase): def test_basic(self): x = 1 ctypes = import_helper.import_module('ctypes') - PyEval_GetFrameLocals = ctypes.pythonapi.PyEval_GetFrameLocals - PyEval_GetFrameLocals.restype = ctypes.py_object + import ctypes.util # noqa: F811 + + @ctypes.util.wrap_dll_function(ctypes.pythonapi) + def PyEval_GetFrameLocals() -> ctypes.py_object: + pass + + @ctypes.util.wrap_dll_function(ctypes.pythonapi) + def PyEval_GetFrameGlobals() -> ctypes.py_object: + pass + + @ctypes.util.wrap_dll_function(ctypes.pythonapi) + def PyEval_GetFrameBuiltins() -> ctypes.py_object: + pass + + @ctypes.util.wrap_dll_function(ctypes.pythonapi) + def PyFrame_GetLocals(frame: ctypes.py_object) -> ctypes.py_object: + pass + frame_locals = PyEval_GetFrameLocals() self.assertTrue(type(frame_locals), dict) self.assertEqual(frame_locals['x'], 1) frame_locals['x'] = 2 self.assertEqual(x, 1) - PyEval_GetFrameGlobals = ctypes.pythonapi.PyEval_GetFrameGlobals - PyEval_GetFrameGlobals.restype = ctypes.py_object frame_globals = PyEval_GetFrameGlobals() self.assertTrue(type(frame_globals), dict) self.assertIs(frame_globals, globals()) - PyEval_GetFrameBuiltins = ctypes.pythonapi.PyEval_GetFrameBuiltins - PyEval_GetFrameBuiltins.restype = ctypes.py_object frame_builtins = PyEval_GetFrameBuiltins() self.assertEqual(frame_builtins, __builtins__) - PyFrame_GetLocals = ctypes.pythonapi.PyFrame_GetLocals - PyFrame_GetLocals.argtypes = [ctypes.py_object] - PyFrame_GetLocals.restype = ctypes.py_object frame = sys._getframe() f_locals = PyFrame_GetLocals(frame) self.assertTrue(f_locals['x'], 1) diff --git a/Lib/test/test_free_threading/test_capi.py b/Lib/test/test_free_threading/test_capi.py index 146d7cfc97adb7d..b0be94629af009d 100644 --- a/Lib/test/test_free_threading/test_capi.py +++ b/Lib/test/test_free_threading/test_capi.py @@ -1,4 +1,4 @@ -import ctypes +import ctypes.util import sys import unittest @@ -6,9 +6,9 @@ from test.support.threading_helper import run_concurrently -_PyImport_AddModuleRef = ctypes.pythonapi.PyImport_AddModuleRef -_PyImport_AddModuleRef.argtypes = (ctypes.c_char_p,) -_PyImport_AddModuleRef.restype = ctypes.py_object +@ctypes.util.wrap_dll_function(ctypes.pythonapi) +def PyImport_AddModuleRef(name: ctypes.c_char_p) -> ctypes.py_object: + pass @threading_helper.requires_working_threading() @@ -26,7 +26,7 @@ def test_pyimport_addmoduleref_thread_safe(self): results = [] def worker(): - module = _PyImport_AddModuleRef(module_name_bytes) + module = PyImport_AddModuleRef(module_name_bytes) results.append(module) for _ in range(NUM_ITERS): diff --git a/Lib/test/test_free_threading/test_code.py b/Lib/test/test_free_threading/test_code.py index 2fc5eea3773c399..121f00c1d7a92d9 100644 --- a/Lib/test/test_free_threading/test_code.py +++ b/Lib/test/test_free_threading/test_code.py @@ -12,25 +12,28 @@ from test.support.threading_helper import run_concurrently if ctypes is not None: - capi = ctypes.pythonapi + import ctypes.util freefunc = ctypes.CFUNCTYPE(None, ctypes.c_voidp) - RequestCodeExtraIndex = capi.PyUnstable_Eval_RequestCodeExtraIndex - RequestCodeExtraIndex.argtypes = (freefunc,) - RequestCodeExtraIndex.restype = ctypes.c_ssize_t - - SetExtra = capi.PyUnstable_Code_SetExtra - SetExtra.argtypes = (ctypes.py_object, ctypes.c_ssize_t, ctypes.c_voidp) - SetExtra.restype = ctypes.c_int - - GetExtra = capi.PyUnstable_Code_GetExtra - GetExtra.argtypes = ( - ctypes.py_object, - ctypes.c_ssize_t, - ctypes.POINTER(ctypes.c_voidp), - ) - GetExtra.restype = ctypes.c_int + @ctypes.util.wrap_dll_function(ctypes.pythonapi) + def PyUnstable_Eval_RequestCodeExtraIndex(free: freefunc) -> ctypes.c_ssize_t: + pass + RequestCodeExtraIndex = PyUnstable_Eval_RequestCodeExtraIndex + + @ctypes.util.wrap_dll_function(ctypes.pythonapi) + def PyUnstable_Code_SetExtra(code: ctypes.py_object, + index: ctypes.c_ssize_t, + extra: ctypes.c_voidp) -> ctypes.c_int: + pass + SetExtra = PyUnstable_Code_SetExtra + + @ctypes.util.wrap_dll_function(ctypes.pythonapi) + def PyUnstable_Code_GetExtra(code: ctypes.py_object, + index: ctypes.c_ssize_t, + extra: ctypes.POINTER(ctypes.c_voidp)) -> ctypes.c_int: + pass + GetExtra = PyUnstable_Code_GetExtra # Note: each call to RequestCodeExtraIndex permanently allocates a slot # (the counter is monotonically increasing), up to MAX_CO_EXTRA_USERS (255). diff --git a/Lib/test/test_gc.py b/Lib/test/test_gc.py index 3fc084ea6e9c6e9..4c721c01a34f070 100644 --- a/Lib/test/test_gc.py +++ b/Lib/test/test_gc.py @@ -1434,6 +1434,11 @@ def test_refcount_errors(self): import subprocess code = textwrap.dedent(''' from test.support import gc_collect, SuppressCrashReport + import ctypes.util + + @ctypes.util.wrap_dll_function(ctypes.pythonapi) + def Py_DecRef(o: ctypes.py_object) -> None: + pass a = [1, 2, 3] b = [a, a] @@ -1445,8 +1450,7 @@ def test_refcount_errors(self): # Simulate the refcount of "a" being too low (compared to the # references held on it by live data), but keeping it above zero # (to avoid deallocating it): - import ctypes - ctypes.pythonapi.Py_DecRef(ctypes.py_object(a)) + Py_DecRef(a) del a del b diff --git a/Lib/test/test_io/utils.py b/Lib/test/test_io/utils.py index 3b1faec2140fbc6..dde49337a24f0b9 100644 --- a/Lib/test/test_io/utils.py +++ b/Lib/test/test_io/utils.py @@ -8,12 +8,13 @@ try: - import ctypes + import ctypes.util except ImportError: def byteslike(*pos, **kw): return array.array("b", bytes(*pos, **kw)) else: - class EmptyStruct(ctypes.Structure): + @ctypes.util.struct + class EmptyStruct: pass def byteslike(*pos, **kw): diff --git a/Lib/test/test_json/test_decode.py b/Lib/test/test_json/test_decode.py index 1d51fb2de0e69e4..33aeefa92f282ae 100644 --- a/Lib/test/test_json/test_decode.py +++ b/Lib/test/test_json/test_decode.py @@ -1,4 +1,5 @@ import decimal +import unittest.mock from io import StringIO from collections import OrderedDict from test.test_json import PyTest, CTest @@ -148,6 +149,10 @@ def test_negative_index(self): d = self.json.JSONDecoder() self.assertRaises(ValueError, d.raw_decode, 'a'*42, -50000) + def test_unterminated_string(self): + d = self.json.JSONDecoder() + self.assertRaises(self.JSONDecodeError, d.raw_decode, '"\\') + def test_limit_int(self): maxdigits = 5000 with support.adjust_int_max_str_digits(maxdigits): @@ -155,6 +160,15 @@ def test_limit_int(self): with self.assertRaises(ValueError): self.loads('1' * (maxdigits + 1)) + def test_explicit_cls_skips_json_decoder_default(self): + class CustomDecoder: + pass + + with unittest.mock.patch.object( + CustomDecoder, 'decode', create=True) as mock_decode: + self.loads('{}', cls=CustomDecoder) + mock_decode.assert_called_once() + class TestPyDecode(TestDecode, PyTest): pass class TestCDecode(TestDecode, CTest): pass diff --git a/Lib/test/test_ntpath.py b/Lib/test/test_ntpath.py index a3728b58335e63b..936332bf94ffe77 100644 --- a/Lib/test/test_ntpath.py +++ b/Lib/test/test_ntpath.py @@ -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] diff --git a/Lib/test/test_os/test_windows.py b/Lib/test/test_os/test_windows.py index f1c6283f60d35ed..b21dd8a4dca6609 100644 --- a/Lib/test/test_os/test_windows.py +++ b/Lib/test/test_os/test_windows.py @@ -27,7 +27,7 @@ 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 @@ -35,14 +35,17 @@ def _kill(self, sig): # 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;" @@ -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 @@ -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 diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py index 3d01804513bde98..96b43936be92cda 100644 --- a/Lib/test/test_threading.py +++ b/Lib/test/test_threading.py @@ -326,9 +326,13 @@ def f(mutex): @cpython_only def test_PyThreadState_SetAsyncExc(self): ctypes = import_module("ctypes") + import ctypes.util # noqa: F811 - set_async_exc = ctypes.pythonapi.PyThreadState_SetAsyncExc - set_async_exc.argtypes = (ctypes.c_ulong, ctypes.py_object) + @ctypes.util.wrap_dll_function(ctypes.pythonapi) + def PyThreadState_SetAsyncExc(id: ctypes.c_ulong, + exc: ctypes.py_object) -> ctypes.c_int: + pass + set_async_exc = PyThreadState_SetAsyncExc class AsyncExc(Exception): pass @@ -485,7 +489,17 @@ def test_finalize_running_thread(self): import_module("ctypes") rc, out, err = assert_python_failure("-c", """if 1: - import ctypes, sys, time, _thread + import ctypes.util, sys, time, _thread + + PyGILState_STATE = ctypes.c_int # enum + + @ctypes.util.wrap_dll_function(ctypes.pythonapi) + def PyGILState_Ensure() -> PyGILState_STATE: + pass + + @ctypes.util.wrap_dll_function(ctypes.pythonapi) + def PyGILState_Release(oldstate: PyGILState_STATE) -> None: + pass # This lock is used as a simple event variable. ready = _thread.allocate_lock() @@ -494,8 +508,8 @@ def test_finalize_running_thread(self): # Module globals are cleared before __del__ is run # So we save the functions in class dict class C: - ensure = ctypes.pythonapi.PyGILState_Ensure - release = ctypes.pythonapi.PyGILState_Release + ensure = PyGILState_Ensure + release = PyGILState_Release def __del__(self): state = self.ensure() self.release(state) diff --git a/Lib/test/test_urllib.py b/Lib/test/test_urllib.py index 2dd739b77b8e4d1..1e5f79998e7cab2 100644 --- a/Lib/test/test_urllib.py +++ b/Lib/test/test_urllib.py @@ -467,6 +467,25 @@ def test_redirect_limit_independent(self): finally: self.unfakehttp() + def test_http_error_attribute_values(self): + hdrs = { + "Authorization": "Bearer foobar", + "Accept": "application/json" + } + err = urllib.error.HTTPError("http://something", 404, "foo", hdrs, None) + self.assertEqual(err.filename, "http://something") + self.assertEqual(err.code, 404) + self.assertEqual(err.msg, "foo") + self.assertEqual(err.reason, "foo") + self.assertEqual(err.hdrs, hdrs) + self.assertEqual(err.headers, hdrs) + err.close() + + def test_http_error_default_fp(self): + err = urllib.error.HTTPError("http://something", 404, "foo", {}, None) + self.assertIsInstance(err.fp, io.BytesIO) + err.close() + def test_empty_socket(self): # urlopen() raises OSError if the underlying socket does not send any # data. (#1680230) @@ -513,6 +532,11 @@ def test_ftp_nonexisting(self): self.assertFalse(e.exception.filename) self.assertTrue(e.exception.reason) + def test_url_error_stringified(self): + reason = 'sixseven' + err = urllib.error.URLError(reason) + self.assertEqual(str(err), f'') + class urlopen_DataTests(unittest.TestCase): """Test urlopen() opening a data URL.""" diff --git a/Lib/test/win_console_handler.py b/Lib/test/win_console_handler.py index e7779b9363503b4..a1c7c42c109330b 100644 --- a/Lib/test/win_console_handler.py +++ b/Lib/test/win_console_handler.py @@ -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""" @@ -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 diff --git a/Misc/NEWS.d/next/Build/2026-07-19-07-48-43.gh-issue-154055.FemUJU.rst b/Misc/NEWS.d/next/Build/2026-07-19-07-48-43.gh-issue-154055.FemUJU.rst new file mode 100644 index 000000000000000..94fc9672ef7855f --- /dev/null +++ b/Misc/NEWS.d/next/Build/2026-07-19-07-48-43.gh-issue-154055.FemUJU.rst @@ -0,0 +1,4 @@ +The :mod:`curses` and :mod:`curses.panel` modules can now be built against a +curses library that lacks the X/Open ``attr_t`` and soft-label attribute +functions, ``scr_set()`` or ``resizeterm()`` -- such as the native SVr4 curses +of illumos and Solaris. These functions are probed and used only when present. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-07-19-12-33-27.gh-issue-153932.lKw2bo.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-07-19-12-33-27.gh-issue-153932.lKw2bo.rst new file mode 100644 index 000000000000000..56b96307ed04cd9 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-07-19-12-33-27.gh-issue-153932.lKw2bo.rst @@ -0,0 +1,2 @@ +Fix thread safety issue in the ``__reduce__`` method of +:py:class:`enumerate`. diff --git a/Misc/NEWS.d/next/Library/2026-06-11-10-00-00.gh-issue-119710.Qz7Kp2.rst b/Misc/NEWS.d/next/Library/2026-06-11-10-00-00.gh-issue-119710.Qz7Kp2.rst new file mode 100644 index 000000000000000..45f99d72ea29a2f --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-11-10-00-00.gh-issue-119710.Qz7Kp2.rst @@ -0,0 +1,4 @@ +Fix :mod:`asyncio` subprocess :meth:`~asyncio.subprocess.Process.wait` +hanging when the process has exited but one of its pipes is kept open by an +inherited child process (so the pipe never reaches EOF). ``wait()`` now +returns as soon as the process exits, regardless of the pipes' state. diff --git a/Misc/NEWS.d/next/Tests/2026-07-19-18-20-00.gh-issue-154144.tcbool.rst b/Misc/NEWS.d/next/Tests/2026-07-19-18-20-00.gh-issue-154144.tcbool.rst new file mode 100644 index 000000000000000..dc1ac8b4035153c --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2026-07-19-18-20-00.gh-issue-154144.tcbool.rst @@ -0,0 +1 @@ +Fix building the :mod:`!_testcapi` module on NetBSD. diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index 2253d9ff3d704f3..6df593001b8a1cb 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -2433,6 +2433,7 @@ _curses_window_attrset_impl(PyCursesWindowObject *self, attr_t attr) return curses_window_check_err(self, rtn, "wattrset", "attrset"); } +#ifdef HAVE_CURSES_WATTR_GET /*[clinic input] _curses.window.attr_get @@ -2458,7 +2459,9 @@ _curses_window_attr_get_impl(PyCursesWindowObject *self) } return Py_BuildValue("(ki)", (unsigned long)attrs, (int)pair); } +#endif /* HAVE_CURSES_WATTR_GET */ +#ifdef HAVE_CURSES_WATTR_SET /*[clinic input] _curses.window.attr_set @@ -2482,7 +2485,9 @@ _curses_window_attr_set_impl(PyCursesWindowObject *self, attr_t attr, #endif return curses_window_check_err(self, rtn, "wattr_set", "attr_set"); } +#endif /* HAVE_CURSES_WATTR_SET */ +#ifdef HAVE_CURSES_WATTR_ON /*[clinic input] _curses.window.attr_on @@ -2499,7 +2504,9 @@ _curses_window_attr_on_impl(PyCursesWindowObject *self, attr_t attr) int rtn = wattr_on(self->win, attr, NULL); return curses_window_check_err(self, rtn, "wattr_on", "attr_on"); } +#endif /* HAVE_CURSES_WATTR_ON */ +#ifdef HAVE_CURSES_WATTR_OFF /*[clinic input] _curses.window.attr_off @@ -2516,7 +2523,9 @@ _curses_window_attr_off_impl(PyCursesWindowObject *self, attr_t attr) int rtn = wattr_off(self->win, attr, NULL); return curses_window_check_err(self, rtn, "wattr_off", "attr_off"); } +#endif /* HAVE_CURSES_WATTR_OFF */ +#ifdef HAVE_CURSES_WCOLOR_SET /*[clinic input] _curses.window.color_set @@ -2538,6 +2547,7 @@ _curses_window_color_set_impl(PyCursesWindowObject *self, int pair) #endif return curses_window_check_err(self, rtn, "wcolor_set", "color_set"); } +#endif /* HAVE_CURSES_WCOLOR_SET */ /*[clinic input] _curses.window.getattrs @@ -6083,6 +6093,7 @@ _curses_scr_init(PyObject *module, PyObject *filename) /*[clinic end generated code: output=2e861d381d710419 input=81c45e4702124ef6]*/ ScreenDumpFunctionBody(scr_init) +#ifdef HAVE_CURSES_SCR_SET /*[clinic input] _curses.scr_set @@ -6099,6 +6110,7 @@ static PyObject * _curses_scr_set(PyObject *module, PyObject *filename) /*[clinic end generated code: output=6056fdec12c5935f input=d248c20543cc289b]*/ ScreenDumpFunctionBody(scr_set) +#endif /* HAVE_CURSES_SCR_SET */ #endif /* HAVE_CURSES_SCR_DUMP */ /*[clinic input] @@ -7462,9 +7474,10 @@ _curses_qiflush_impl(PyObject *module, int flag) Py_RETURN_NONE; } -#if defined(HAVE_CURSES_RESIZETERM) || defined(HAVE_CURSES_RESIZE_TERM) /* Internal helper used for updating curses.LINES, curses.COLS, _curses.LINES - * and _curses.COLS. Returns 1 on success and 0 on failure. */ + * and _curses.COLS. Returns 1 on success and 0 on failure. Used + * unconditionally (e.g. by set_term()), so it must not be gated on resizeterm(). + */ static int update_lines_cols(PyObject *private_module) { @@ -7533,8 +7546,6 @@ _curses_update_lines_cols_impl(PyObject *module) Py_RETURN_NONE; } -#endif - /*[clinic input] _curses.raw @@ -8371,6 +8382,7 @@ _curses_slk_attr_impl(PyObject *module) } #endif +#ifdef HAVE_CURSES_SLK_ATTR_ON /*[clinic input] _curses.slk_attr_on @@ -8388,7 +8400,9 @@ _curses_slk_attr_on_impl(PyObject *module, attr_t attr) return curses_check_err(module, slk_attr_on(attr, NULL), "slk_attr_on", NULL); } +#endif /* HAVE_CURSES_SLK_ATTR_ON */ +#ifdef HAVE_CURSES_SLK_ATTR_OFF /*[clinic input] _curses.slk_attr_off @@ -8406,7 +8420,9 @@ _curses_slk_attr_off_impl(PyObject *module, attr_t attr) return curses_check_err(module, slk_attr_off(attr, NULL), "slk_attr_off", NULL); } +#endif /* HAVE_CURSES_SLK_ATTR_OFF */ +#ifdef HAVE_CURSES_SLK_ATTR_SET /*[clinic input] _curses.slk_attr_set @@ -8430,7 +8446,9 @@ _curses_slk_attr_set_impl(PyObject *module, attr_t attr, int pair) #endif return curses_check_err(module, rtn, "slk_attr_set", NULL); } +#endif /* HAVE_CURSES_SLK_ATTR_SET */ +#ifdef HAVE_CURSES_SLK_COLOR /*[clinic input] _curses.slk_color @@ -8447,6 +8465,7 @@ _curses_slk_color_impl(PyObject *module, int pair) PyCursesStatefulInitialised(module); return curses_check_err(module, slk_color((short)pair), "slk_color", NULL); } +#endif /* HAVE_CURSES_SLK_COLOR */ #ifdef HAVE_CURSES_USE_ENV /*[clinic input] diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 799390c27053287..fb18a866e628128 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -15,6 +15,10 @@ #include "frameobject.h" // PyFrame_New() #include "marshal.h" // PyMarshal_WriteLongToFile() +#ifdef bool +# error "The public headers should not include , see gh-90904" +#endif + #include // FLT_MAX #include #include // offsetof() @@ -26,10 +30,6 @@ # include // sysctlbyname() #endif -#ifdef bool -# error "The public headers should not include , see gh-48924" -#endif - #include "_testcapi/util.h" diff --git a/Modules/_uuidmodule.c b/Modules/_uuidmodule.c index c31a7e8fea56084..3edc29a75b32ce9 100644 --- a/Modules/_uuidmodule.c +++ b/Modules/_uuidmodule.c @@ -20,6 +20,9 @@ #ifdef MS_WINDOWS #include +#ifndef RPC_S_OK +#define RPC_S_OK 0L +#endif #endif #ifndef MS_WINDOWS diff --git a/Modules/clinic/_cursesmodule.c.h b/Modules/clinic/_cursesmodule.c.h index da1b97c0ea5ad8b..70d99b4bf351a21 100644 --- a/Modules/clinic/_cursesmodule.c.h +++ b/Modules/clinic/_cursesmodule.c.h @@ -534,6 +534,8 @@ _curses_window_attrset(PyObject *self, PyObject *arg) return return_value; } +#if defined(HAVE_CURSES_WATTR_GET) + PyDoc_STRVAR(_curses_window_attr_get__doc__, "attr_get($self, /)\n" "--\n" @@ -552,6 +554,10 @@ _curses_window_attr_get(PyObject *self, PyObject *Py_UNUSED(ignored)) return _curses_window_attr_get_impl((PyCursesWindowObject *)self); } +#endif /* defined(HAVE_CURSES_WATTR_GET) */ + +#if defined(HAVE_CURSES_WATTR_SET) + PyDoc_STRVAR(_curses_window_attr_set__doc__, "attr_set($self, attr, pair=0, /)\n" "--\n" @@ -591,6 +597,10 @@ _curses_window_attr_set(PyObject *self, PyObject *const *args, Py_ssize_t nargs) return return_value; } +#endif /* defined(HAVE_CURSES_WATTR_SET) */ + +#if defined(HAVE_CURSES_WATTR_ON) + PyDoc_STRVAR(_curses_window_attr_on__doc__, "attr_on($self, attr, /)\n" "--\n" @@ -618,6 +628,10 @@ _curses_window_attr_on(PyObject *self, PyObject *arg) return return_value; } +#endif /* defined(HAVE_CURSES_WATTR_ON) */ + +#if defined(HAVE_CURSES_WATTR_OFF) + PyDoc_STRVAR(_curses_window_attr_off__doc__, "attr_off($self, attr, /)\n" "--\n" @@ -645,6 +659,10 @@ _curses_window_attr_off(PyObject *self, PyObject *arg) return return_value; } +#endif /* defined(HAVE_CURSES_WATTR_OFF) */ + +#if defined(HAVE_CURSES_WCOLOR_SET) + PyDoc_STRVAR(_curses_window_color_set__doc__, "color_set($self, pair, /)\n" "--\n" @@ -672,6 +690,8 @@ _curses_window_color_set(PyObject *self, PyObject *arg) return return_value; } +#endif /* defined(HAVE_CURSES_WCOLOR_SET) */ + PyDoc_STRVAR(_curses_window_getattrs__doc__, "getattrs($self, /)\n" "--\n" @@ -3104,7 +3124,7 @@ PyDoc_STRVAR(_curses_scr_init__doc__, #endif /* defined(HAVE_CURSES_SCR_DUMP) */ -#if defined(HAVE_CURSES_SCR_DUMP) +#if defined(HAVE_CURSES_SCR_DUMP) && defined(HAVE_CURSES_SCR_SET) PyDoc_STRVAR(_curses_scr_set__doc__, "scr_set($module, filename, /)\n" @@ -3120,7 +3140,7 @@ PyDoc_STRVAR(_curses_scr_set__doc__, #define _CURSES_SCR_SET_METHODDEF \ {"scr_set", (PyCFunction)_curses_scr_set, METH_O, _curses_scr_set__doc__}, -#endif /* defined(HAVE_CURSES_SCR_DUMP) */ +#endif /* defined(HAVE_CURSES_SCR_DUMP) && defined(HAVE_CURSES_SCR_SET) */ PyDoc_STRVAR(_curses_halfdelay__doc__, "halfdelay($module, tenths, /)\n" @@ -4752,8 +4772,6 @@ _curses_qiflush(PyObject *module, PyObject *const *args, Py_ssize_t nargs) return return_value; } -#if (defined(HAVE_CURSES_RESIZETERM) || defined(HAVE_CURSES_RESIZE_TERM)) - PyDoc_STRVAR(_curses_update_lines_cols__doc__, "update_lines_cols($module, /)\n" "--\n" @@ -4774,8 +4792,6 @@ _curses_update_lines_cols(PyObject *module, PyObject *Py_UNUSED(ignored)) return _curses_update_lines_cols_impl(module); } -#endif /* (defined(HAVE_CURSES_RESIZETERM) || defined(HAVE_CURSES_RESIZE_TERM)) */ - PyDoc_STRVAR(_curses_raw__doc__, "raw($module, flag=True, /)\n" "--\n" @@ -5755,6 +5771,8 @@ _curses_slk_attr(PyObject *module, PyObject *Py_UNUSED(ignored)) #endif /* (defined(NCURSES_EXT_FUNCS) || defined(PDCURSES)) */ +#if defined(HAVE_CURSES_SLK_ATTR_ON) + PyDoc_STRVAR(_curses_slk_attr_on__doc__, "slk_attr_on($module, attr, /)\n" "--\n" @@ -5782,6 +5800,10 @@ _curses_slk_attr_on(PyObject *module, PyObject *arg) return return_value; } +#endif /* defined(HAVE_CURSES_SLK_ATTR_ON) */ + +#if defined(HAVE_CURSES_SLK_ATTR_OFF) + PyDoc_STRVAR(_curses_slk_attr_off__doc__, "slk_attr_off($module, attr, /)\n" "--\n" @@ -5809,6 +5831,10 @@ _curses_slk_attr_off(PyObject *module, PyObject *arg) return return_value; } +#endif /* defined(HAVE_CURSES_SLK_ATTR_OFF) */ + +#if defined(HAVE_CURSES_SLK_ATTR_SET) + PyDoc_STRVAR(_curses_slk_attr_set__doc__, "slk_attr_set($module, attr, pair=0, /)\n" "--\n" @@ -5847,6 +5873,10 @@ _curses_slk_attr_set(PyObject *module, PyObject *const *args, Py_ssize_t nargs) return return_value; } +#endif /* defined(HAVE_CURSES_SLK_ATTR_SET) */ + +#if defined(HAVE_CURSES_SLK_COLOR) + PyDoc_STRVAR(_curses_slk_color__doc__, "slk_color($module, pair, /)\n" "--\n" @@ -5874,6 +5904,8 @@ _curses_slk_color(PyObject *module, PyObject *arg) return return_value; } +#endif /* defined(HAVE_CURSES_SLK_COLOR) */ + #if defined(HAVE_CURSES_USE_ENV) PyDoc_STRVAR(_curses_use_env__doc__, @@ -6003,6 +6035,26 @@ _curses_has_extended_color_support(PyObject *module, PyObject *Py_UNUSED(ignored return _curses_has_extended_color_support_impl(module); } +#ifndef _CURSES_WINDOW_ATTR_GET_METHODDEF + #define _CURSES_WINDOW_ATTR_GET_METHODDEF +#endif /* !defined(_CURSES_WINDOW_ATTR_GET_METHODDEF) */ + +#ifndef _CURSES_WINDOW_ATTR_SET_METHODDEF + #define _CURSES_WINDOW_ATTR_SET_METHODDEF +#endif /* !defined(_CURSES_WINDOW_ATTR_SET_METHODDEF) */ + +#ifndef _CURSES_WINDOW_ATTR_ON_METHODDEF + #define _CURSES_WINDOW_ATTR_ON_METHODDEF +#endif /* !defined(_CURSES_WINDOW_ATTR_ON_METHODDEF) */ + +#ifndef _CURSES_WINDOW_ATTR_OFF_METHODDEF + #define _CURSES_WINDOW_ATTR_OFF_METHODDEF +#endif /* !defined(_CURSES_WINDOW_ATTR_OFF_METHODDEF) */ + +#ifndef _CURSES_WINDOW_COLOR_SET_METHODDEF + #define _CURSES_WINDOW_COLOR_SET_METHODDEF +#endif /* !defined(_CURSES_WINDOW_COLOR_SET_METHODDEF) */ + #ifndef _CURSES_WINDOW_ENCLOSE_METHODDEF #define _CURSES_WINDOW_ENCLOSE_METHODDEF #endif /* !defined(_CURSES_WINDOW_ENCLOSE_METHODDEF) */ @@ -6135,10 +6187,6 @@ _curses_has_extended_color_support(PyObject *module, PyObject *Py_UNUSED(ignored #define _CURSES_MOUSEMASK_METHODDEF #endif /* !defined(_CURSES_MOUSEMASK_METHODDEF) */ -#ifndef _CURSES_UPDATE_LINES_COLS_METHODDEF - #define _CURSES_UPDATE_LINES_COLS_METHODDEF -#endif /* !defined(_CURSES_UPDATE_LINES_COLS_METHODDEF) */ - #ifndef _CURSES_RESIZETERM_METHODDEF #define _CURSES_RESIZETERM_METHODDEF #endif /* !defined(_CURSES_RESIZETERM_METHODDEF) */ @@ -6163,6 +6211,22 @@ _curses_has_extended_color_support(PyObject *module, PyObject *Py_UNUSED(ignored #define _CURSES_SLK_ATTR_METHODDEF #endif /* !defined(_CURSES_SLK_ATTR_METHODDEF) */ +#ifndef _CURSES_SLK_ATTR_ON_METHODDEF + #define _CURSES_SLK_ATTR_ON_METHODDEF +#endif /* !defined(_CURSES_SLK_ATTR_ON_METHODDEF) */ + +#ifndef _CURSES_SLK_ATTR_OFF_METHODDEF + #define _CURSES_SLK_ATTR_OFF_METHODDEF +#endif /* !defined(_CURSES_SLK_ATTR_OFF_METHODDEF) */ + +#ifndef _CURSES_SLK_ATTR_SET_METHODDEF + #define _CURSES_SLK_ATTR_SET_METHODDEF +#endif /* !defined(_CURSES_SLK_ATTR_SET_METHODDEF) */ + +#ifndef _CURSES_SLK_COLOR_METHODDEF + #define _CURSES_SLK_COLOR_METHODDEF +#endif /* !defined(_CURSES_SLK_COLOR_METHODDEF) */ + #ifndef _CURSES_USE_ENV_METHODDEF #define _CURSES_USE_ENV_METHODDEF #endif /* !defined(_CURSES_USE_ENV_METHODDEF) */ @@ -6174,4 +6238,4 @@ _curses_has_extended_color_support(PyObject *module, PyObject *Py_UNUSED(ignored #ifndef _CURSES_ASSUME_DEFAULT_COLORS_METHODDEF #define _CURSES_ASSUME_DEFAULT_COLORS_METHODDEF #endif /* !defined(_CURSES_ASSUME_DEFAULT_COLORS_METHODDEF) */ -/*[clinic end generated code: output=36fcacafc5044720 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=ae1359964feefd64 input=a9049054013a1b77]*/ diff --git a/Objects/enumobject.c b/Objects/enumobject.c index fc53f1bfee8dde4..68aa594c5540cee 100644 --- a/Objects/enumobject.c +++ b/Objects/enumobject.c @@ -277,10 +277,13 @@ enum_reduce(PyObject *op, PyObject *Py_UNUSED(ignored)) enumobject *en = _enumobject_CAST(op); PyObject *result; Py_BEGIN_CRITICAL_SECTION(en); - if (en->en_longindex != NULL) + if (en->en_longindex != NULL) { result = Py_BuildValue("O(OO)", Py_TYPE(en), en->en_sit, en->en_longindex); - else - result = Py_BuildValue("O(On)", Py_TYPE(en), en->en_sit, en->en_index); + } + else { + Py_ssize_t en_index = FT_ATOMIC_LOAD_SSIZE_RELAXED(en->en_index); + result = Py_BuildValue("O(On)", Py_TYPE(en), en->en_sit, en_index); + } Py_END_CRITICAL_SECTION(); return result; } diff --git a/configure b/configure index 9061cf905119c44..0fc2b0e819a1209 100755 --- a/configure +++ b/configure @@ -32395,6 +32395,546 @@ fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for curses function wattr_get" >&5 +printf %s "checking for curses function wattr_get... " >&6; } +if test ${ac_cv_lib_curses_wattr_get+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#define NCURSES_OPAQUE 0 +#if defined(HAVE_NCURSESW_NCURSES_H) +# include +#elif defined(HAVE_NCURSESW_CURSES_H) +# include +#elif defined(HAVE_NCURSES_NCURSES_H) +# include +#elif defined(HAVE_NCURSES_CURSES_H) +# include +#elif defined(HAVE_NCURSES_H) +# include +#elif defined(HAVE_CURSES_H) +# include +#endif + +int +main (void) +{ + + #ifndef wattr_get + void *x=wattr_get + #endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_lib_curses_wattr_get=yes +else case e in #( + e) ac_cv_lib_curses_wattr_get=no ;; +esac +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_curses_wattr_get" >&5 +printf "%s\n" "$ac_cv_lib_curses_wattr_get" >&6; } + if test "x$ac_cv_lib_curses_wattr_get" = xyes +then : + +printf "%s\n" "#define HAVE_CURSES_WATTR_GET 1" >>confdefs.h + +fi + + + + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for curses function wattr_set" >&5 +printf %s "checking for curses function wattr_set... " >&6; } +if test ${ac_cv_lib_curses_wattr_set+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#define NCURSES_OPAQUE 0 +#if defined(HAVE_NCURSESW_NCURSES_H) +# include +#elif defined(HAVE_NCURSESW_CURSES_H) +# include +#elif defined(HAVE_NCURSES_NCURSES_H) +# include +#elif defined(HAVE_NCURSES_CURSES_H) +# include +#elif defined(HAVE_NCURSES_H) +# include +#elif defined(HAVE_CURSES_H) +# include +#endif + +int +main (void) +{ + + #ifndef wattr_set + void *x=wattr_set + #endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_lib_curses_wattr_set=yes +else case e in #( + e) ac_cv_lib_curses_wattr_set=no ;; +esac +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_curses_wattr_set" >&5 +printf "%s\n" "$ac_cv_lib_curses_wattr_set" >&6; } + if test "x$ac_cv_lib_curses_wattr_set" = xyes +then : + +printf "%s\n" "#define HAVE_CURSES_WATTR_SET 1" >>confdefs.h + +fi + + + + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for curses function wattr_on" >&5 +printf %s "checking for curses function wattr_on... " >&6; } +if test ${ac_cv_lib_curses_wattr_on+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#define NCURSES_OPAQUE 0 +#if defined(HAVE_NCURSESW_NCURSES_H) +# include +#elif defined(HAVE_NCURSESW_CURSES_H) +# include +#elif defined(HAVE_NCURSES_NCURSES_H) +# include +#elif defined(HAVE_NCURSES_CURSES_H) +# include +#elif defined(HAVE_NCURSES_H) +# include +#elif defined(HAVE_CURSES_H) +# include +#endif + +int +main (void) +{ + + #ifndef wattr_on + void *x=wattr_on + #endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_lib_curses_wattr_on=yes +else case e in #( + e) ac_cv_lib_curses_wattr_on=no ;; +esac +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_curses_wattr_on" >&5 +printf "%s\n" "$ac_cv_lib_curses_wattr_on" >&6; } + if test "x$ac_cv_lib_curses_wattr_on" = xyes +then : + +printf "%s\n" "#define HAVE_CURSES_WATTR_ON 1" >>confdefs.h + +fi + + + + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for curses function wattr_off" >&5 +printf %s "checking for curses function wattr_off... " >&6; } +if test ${ac_cv_lib_curses_wattr_off+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#define NCURSES_OPAQUE 0 +#if defined(HAVE_NCURSESW_NCURSES_H) +# include +#elif defined(HAVE_NCURSESW_CURSES_H) +# include +#elif defined(HAVE_NCURSES_NCURSES_H) +# include +#elif defined(HAVE_NCURSES_CURSES_H) +# include +#elif defined(HAVE_NCURSES_H) +# include +#elif defined(HAVE_CURSES_H) +# include +#endif + +int +main (void) +{ + + #ifndef wattr_off + void *x=wattr_off + #endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_lib_curses_wattr_off=yes +else case e in #( + e) ac_cv_lib_curses_wattr_off=no ;; +esac +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_curses_wattr_off" >&5 +printf "%s\n" "$ac_cv_lib_curses_wattr_off" >&6; } + if test "x$ac_cv_lib_curses_wattr_off" = xyes +then : + +printf "%s\n" "#define HAVE_CURSES_WATTR_OFF 1" >>confdefs.h + +fi + + + + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for curses function wcolor_set" >&5 +printf %s "checking for curses function wcolor_set... " >&6; } +if test ${ac_cv_lib_curses_wcolor_set+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#define NCURSES_OPAQUE 0 +#if defined(HAVE_NCURSESW_NCURSES_H) +# include +#elif defined(HAVE_NCURSESW_CURSES_H) +# include +#elif defined(HAVE_NCURSES_NCURSES_H) +# include +#elif defined(HAVE_NCURSES_CURSES_H) +# include +#elif defined(HAVE_NCURSES_H) +# include +#elif defined(HAVE_CURSES_H) +# include +#endif + +int +main (void) +{ + + #ifndef wcolor_set + void *x=wcolor_set + #endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_lib_curses_wcolor_set=yes +else case e in #( + e) ac_cv_lib_curses_wcolor_set=no ;; +esac +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_curses_wcolor_set" >&5 +printf "%s\n" "$ac_cv_lib_curses_wcolor_set" >&6; } + if test "x$ac_cv_lib_curses_wcolor_set" = xyes +then : + +printf "%s\n" "#define HAVE_CURSES_WCOLOR_SET 1" >>confdefs.h + +fi + + + + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for curses function slk_attr_on" >&5 +printf %s "checking for curses function slk_attr_on... " >&6; } +if test ${ac_cv_lib_curses_slk_attr_on+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#define NCURSES_OPAQUE 0 +#if defined(HAVE_NCURSESW_NCURSES_H) +# include +#elif defined(HAVE_NCURSESW_CURSES_H) +# include +#elif defined(HAVE_NCURSES_NCURSES_H) +# include +#elif defined(HAVE_NCURSES_CURSES_H) +# include +#elif defined(HAVE_NCURSES_H) +# include +#elif defined(HAVE_CURSES_H) +# include +#endif + +int +main (void) +{ + + #ifndef slk_attr_on + void *x=slk_attr_on + #endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_lib_curses_slk_attr_on=yes +else case e in #( + e) ac_cv_lib_curses_slk_attr_on=no ;; +esac +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_curses_slk_attr_on" >&5 +printf "%s\n" "$ac_cv_lib_curses_slk_attr_on" >&6; } + if test "x$ac_cv_lib_curses_slk_attr_on" = xyes +then : + +printf "%s\n" "#define HAVE_CURSES_SLK_ATTR_ON 1" >>confdefs.h + +fi + + + + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for curses function slk_attr_off" >&5 +printf %s "checking for curses function slk_attr_off... " >&6; } +if test ${ac_cv_lib_curses_slk_attr_off+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#define NCURSES_OPAQUE 0 +#if defined(HAVE_NCURSESW_NCURSES_H) +# include +#elif defined(HAVE_NCURSESW_CURSES_H) +# include +#elif defined(HAVE_NCURSES_NCURSES_H) +# include +#elif defined(HAVE_NCURSES_CURSES_H) +# include +#elif defined(HAVE_NCURSES_H) +# include +#elif defined(HAVE_CURSES_H) +# include +#endif + +int +main (void) +{ + + #ifndef slk_attr_off + void *x=slk_attr_off + #endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_lib_curses_slk_attr_off=yes +else case e in #( + e) ac_cv_lib_curses_slk_attr_off=no ;; +esac +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_curses_slk_attr_off" >&5 +printf "%s\n" "$ac_cv_lib_curses_slk_attr_off" >&6; } + if test "x$ac_cv_lib_curses_slk_attr_off" = xyes +then : + +printf "%s\n" "#define HAVE_CURSES_SLK_ATTR_OFF 1" >>confdefs.h + +fi + + + + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for curses function slk_attr_set" >&5 +printf %s "checking for curses function slk_attr_set... " >&6; } +if test ${ac_cv_lib_curses_slk_attr_set+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#define NCURSES_OPAQUE 0 +#if defined(HAVE_NCURSESW_NCURSES_H) +# include +#elif defined(HAVE_NCURSESW_CURSES_H) +# include +#elif defined(HAVE_NCURSES_NCURSES_H) +# include +#elif defined(HAVE_NCURSES_CURSES_H) +# include +#elif defined(HAVE_NCURSES_H) +# include +#elif defined(HAVE_CURSES_H) +# include +#endif + +int +main (void) +{ + + #ifndef slk_attr_set + void *x=slk_attr_set + #endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_lib_curses_slk_attr_set=yes +else case e in #( + e) ac_cv_lib_curses_slk_attr_set=no ;; +esac +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_curses_slk_attr_set" >&5 +printf "%s\n" "$ac_cv_lib_curses_slk_attr_set" >&6; } + if test "x$ac_cv_lib_curses_slk_attr_set" = xyes +then : + +printf "%s\n" "#define HAVE_CURSES_SLK_ATTR_SET 1" >>confdefs.h + +fi + + + + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for curses function slk_color" >&5 +printf %s "checking for curses function slk_color... " >&6; } +if test ${ac_cv_lib_curses_slk_color+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#define NCURSES_OPAQUE 0 +#if defined(HAVE_NCURSESW_NCURSES_H) +# include +#elif defined(HAVE_NCURSESW_CURSES_H) +# include +#elif defined(HAVE_NCURSES_NCURSES_H) +# include +#elif defined(HAVE_NCURSES_CURSES_H) +# include +#elif defined(HAVE_NCURSES_H) +# include +#elif defined(HAVE_CURSES_H) +# include +#endif + +int +main (void) +{ + + #ifndef slk_color + void *x=slk_color + #endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_lib_curses_slk_color=yes +else case e in #( + e) ac_cv_lib_curses_slk_color=no ;; +esac +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_curses_slk_color" >&5 +printf "%s\n" "$ac_cv_lib_curses_slk_color" >&6; } + if test "x$ac_cv_lib_curses_slk_color" = xyes +then : + +printf "%s\n" "#define HAVE_CURSES_SLK_COLOR 1" >>confdefs.h + +fi + + + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for curses variable ESCDELAY" >&5 printf %s "checking for curses variable ESCDELAY... " >&6; } if test ${ac_cv_lib_curses_ESCDELAY+y} @@ -32621,6 +33161,66 @@ fi + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for curses function scr_set" >&5 +printf %s "checking for curses function scr_set... " >&6; } +if test ${ac_cv_lib_curses_scr_set+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#define NCURSES_OPAQUE 0 +#if defined(HAVE_NCURSESW_NCURSES_H) +# include +#elif defined(HAVE_NCURSESW_CURSES_H) +# include +#elif defined(HAVE_NCURSES_NCURSES_H) +# include +#elif defined(HAVE_NCURSES_CURSES_H) +# include +#elif defined(HAVE_NCURSES_H) +# include +#elif defined(HAVE_CURSES_H) +# include +#endif + +int +main (void) +{ + + #ifndef scr_set + void *x=scr_set + #endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_lib_curses_scr_set=yes +else case e in #( + e) ac_cv_lib_curses_scr_set=no ;; +esac +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_curses_scr_set" >&5 +printf "%s\n" "$ac_cv_lib_curses_scr_set" >&6; } + if test "x$ac_cv_lib_curses_scr_set" = xyes +then : + +printf "%s\n" "#define HAVE_CURSES_SCR_SET 1" >>confdefs.h + +fi + + + CPPFLAGS=$ac_save_cppflags fi diff --git a/configure.ac b/configure.ac index 97d2091dbf89a70..980ed2af50b13f7 100644 --- a/configure.ac +++ b/configure.ac @@ -7345,6 +7345,17 @@ PY_CHECK_CURSES_FUNC([define_key]) PY_CHECK_CURSES_FUNC([keyok]) PY_CHECK_CURSES_FUNC([set_escdelay]) PY_CHECK_CURSES_FUNC([set_tabsize]) +dnl The X/Open attr_t and soft-label attribute functions are absent on old +dnl SVr4 curses (e.g. illumos). +PY_CHECK_CURSES_FUNC([wattr_get]) +PY_CHECK_CURSES_FUNC([wattr_set]) +PY_CHECK_CURSES_FUNC([wattr_on]) +PY_CHECK_CURSES_FUNC([wattr_off]) +PY_CHECK_CURSES_FUNC([wcolor_set]) +PY_CHECK_CURSES_FUNC([slk_attr_on]) +PY_CHECK_CURSES_FUNC([slk_attr_off]) +PY_CHECK_CURSES_FUNC([slk_attr_set]) +PY_CHECK_CURSES_FUNC([slk_color]) PY_CHECK_CURSES_VAR([ESCDELAY]) PY_CHECK_CURSES_VAR([TABSIZE]) @@ -7360,9 +7371,10 @@ AS_VAR_IF([ac_cv_lib_curses_getmouse], [yes], [AC_DEFINE([HAVE_CURSES_GETMOUSE], [1], [Define if you have the 'getmouse' function with the X/Open signature.])]) -dnl scr_dump and its companions scr_restore/scr_init/scr_set are an inseparable -dnl group; probing scr_dump alone gates the whole family. +dnl scr_dump gates scr_dump/scr_restore/scr_init; scr_set is separate, since +dnl old SVr4 curses (e.g. illumos) has the former but not scr_set. PY_CHECK_CURSES_FUNC([scr_dump]) +PY_CHECK_CURSES_FUNC([scr_set]) CPPFLAGS=$ac_save_cppflags ])dnl have_curses != no ])dnl save env diff --git a/pyconfig.h.in b/pyconfig.h.in index 2f9b2140d9f191a..e259eda7439761e 100644 --- a/pyconfig.h.in +++ b/pyconfig.h.in @@ -257,12 +257,27 @@ /* Define if you have the 'scr_dump' function. */ #undef HAVE_CURSES_SCR_DUMP +/* Define if you have the 'scr_set' function. */ +#undef HAVE_CURSES_SCR_SET + /* Define if you have the 'set_escdelay' function. */ #undef HAVE_CURSES_SET_ESCDELAY /* Define if you have the 'set_tabsize' function. */ #undef HAVE_CURSES_SET_TABSIZE +/* Define if you have the 'slk_attr_off' function. */ +#undef HAVE_CURSES_SLK_ATTR_OFF + +/* Define if you have the 'slk_attr_on' function. */ +#undef HAVE_CURSES_SLK_ATTR_ON + +/* Define if you have the 'slk_attr_set' function. */ +#undef HAVE_CURSES_SLK_ATTR_SET + +/* Define if you have the 'slk_color' function. */ +#undef HAVE_CURSES_SLK_COLOR + /* Define if you have the 'syncok' function. */ #undef HAVE_CURSES_SYNCOK @@ -284,9 +299,24 @@ /* Define if you have the 'use_window' function. */ #undef HAVE_CURSES_USE_WINDOW +/* Define if you have the 'wattr_get' function. */ +#undef HAVE_CURSES_WATTR_GET + +/* Define if you have the 'wattr_off' function. */ +#undef HAVE_CURSES_WATTR_OFF + +/* Define if you have the 'wattr_on' function. */ +#undef HAVE_CURSES_WATTR_ON + +/* Define if you have the 'wattr_set' function. */ +#undef HAVE_CURSES_WATTR_SET + /* Define if you have the 'wchgat' function. */ #undef HAVE_CURSES_WCHGAT +/* Define if you have the 'wcolor_set' function. */ +#undef HAVE_CURSES_WCOLOR_SET + /* Define to 1 if you have the header file. */ #undef HAVE_DB_H