diff --git a/Doc/howto/logging-cookbook.rst b/Doc/howto/logging-cookbook.rst index 79b4069f035076..7f4fe3a63a7026 100644 --- a/Doc/howto/logging-cookbook.rst +++ b/Doc/howto/logging-cookbook.rst @@ -714,6 +714,228 @@ which, when run, produces something like: 2010-09-06 22:38:15,301 d.e.f DEBUG IP: 123.231.231.123 User: fred A message at DEBUG level with 2 parameters 2010-09-06 22:38:15,301 d.e.f INFO IP: 123.231.231.123 User: fred A message at INFO level with 2 parameters +Use of ``contextvars`` +---------------------- + +Since Python 3.7, the :mod:`contextvars` module has provided context-local storage +which works for both :mod:`threading` and :mod:`asyncio` processing needs. This type +of storage may thus be generally preferable to thread-locals. The following example +shows how, in a multi-threaded environment, logs can populated with contextual +information such as, for example, request attributes handled by web applications. + +For the purposes of illustration, say that you have different web applications, each +independent of the other but running in the same Python process and using a library +common to them. How can each of these applications have their own log, where all +logging messages from the library (and other request processing code) are directed to +the appropriate application's log file, while including in the log additional +contextual information such as client IP, HTTP request method and client username? + +Let's assume that the library can be simulated by the following code: + +.. code-block:: python + + # webapplib.py + import logging + import time + + logger = logging.getLogger(__name__) + + def useful(): + # Just a representative event logged from the library + logger.debug('Hello from webapplib!') + # Just sleep for a bit so other threads get to run + time.sleep(0.01) + +We can simulate the multiple web applications by means of two simple classes, +``Request`` and ``WebApp``. These simulate how real threaded web applications work - +each request is handled by a thread: + +.. code-block:: python + + # main.py + import argparse + from contextvars import ContextVar + import logging + import os + from random import choice + import threading + import webapplib + + logger = logging.getLogger(__name__) + root = logging.getLogger() + root.setLevel(logging.DEBUG) + + class Request: + """ + A simple dummy request class which just holds dummy HTTP request method, + client IP address and client username + """ + def __init__(self, method, ip, user): + self.method = method + self.ip = ip + self.user = user + + # A dummy set of requests which will be used in the simulation - we'll just pick + # from this list randomly. Note that all GET requests are from 192.168.2.XXX + # addresses, whereas POST requests are from 192.16.3.XXX addresses. Three users + # are represented in the sample requests. + + REQUESTS = [ + Request('GET', '192.168.2.20', 'jim'), + Request('POST', '192.168.3.20', 'fred'), + Request('GET', '192.168.2.21', 'sheila'), + Request('POST', '192.168.3.21', 'jim'), + Request('GET', '192.168.2.22', 'fred'), + Request('POST', '192.168.3.22', 'sheila'), + ] + + # Note that the format string includes references to request context information + # such as HTTP method, client IP and username + + formatter = logging.Formatter('%(threadName)-11s %(appName)s %(name)-9s %(user)-6s %(ip)s %(method)-4s %(message)s') + + # Create our context variables. These will be filled at the start of request + # processing, and used in the logging that happens during that processing + + ctx_request = ContextVar('request') + ctx_appname = ContextVar('appname') + + class InjectingFilter(logging.Filter): + """ + A filter which injects context-specific information into logs and ensures + that only information for a specific webapp is included in its log + """ + def __init__(self, app): + self.app = app + + def filter(self, record): + request = ctx_request.get() + record.method = request.method + record.ip = request.ip + record.user = request.user + record.appName = appName = ctx_appname.get() + return appName == self.app.name + + class WebApp: + """ + A dummy web application class which has its own handler and filter for a + webapp-specific log. + """ + def __init__(self, name): + self.name = name + handler = logging.FileHandler(name + '.log', 'w') + f = InjectingFilter(self) + handler.setFormatter(formatter) + handler.addFilter(f) + root.addHandler(handler) + self.num_requests = 0 + + def process_request(self, request): + """ + This is the dummy method for processing a request. It's called on a + different thread for every request. We store the context information into + the context vars before doing anything else. + """ + ctx_request.set(request) + ctx_appname.set(self.name) + self.num_requests += 1 + logger.debug('Request processing started') + webapplib.useful() + logger.debug('Request processing finished') + + def main(): + fn = os.path.splitext(os.path.basename(__file__))[0] + adhf = argparse.ArgumentDefaultsHelpFormatter + ap = argparse.ArgumentParser(formatter_class=adhf, prog=fn, + description='Simulate a couple of web ' + 'applications handling some ' + 'requests, showing how request ' + 'context can be used to ' + 'populate logs') + aa = ap.add_argument + aa('--count', '-c', default=100, help='How many requests to simulate') + options = ap.parse_args() + + # Create the dummy webapps and put them in a list which we can use to select + # from randomly + app1 = WebApp('app1') + app2 = WebApp('app2') + apps = [app1, app2] + threads = [] + # Add a common handler which will capture all events + handler = logging.FileHandler('app.log', 'w') + handler.setFormatter(formatter) + root.addHandler(handler) + + # Generate calls to process requests + for i in range(options.count): + try: + # Pick an app at random and a request for it to process + app = choice(apps) + request = choice(REQUESTS) + # Process the request in its own thread + t = threading.Thread(target=app.process_request, args=(request,)) + threads.append(t) + t.start() + except KeyboardInterrupt: + break + + # Wait for the threads to terminate + for t in threads: + t.join() + + for app in apps: + print('%s processed %s requests' % (app.name, app.num_requests)) + + if __name__ == '__main__': + main() + +If you run the above, you should find that roughly half the requests go +into :file:`app1.log` and the rest into :file:`app2.log`, and the all the requests are +logged to :file:`app.log`. Each webapp-specific log will contain only log entries for +only that webapp, and the request information will be displayed consistently in the +log (i.e. the information in each dummy request will always appear together in a log +line). This is illustrated by the following shell output: + +.. code-block:: shell + + ~/logging-contextual-webapp$ python main.py + app1 processed 51 requests + app2 processed 49 requests + ~/logging-contextual-webapp$ wc -l *.log + 153 app1.log + 147 app2.log + 300 app.log + 600 total + ~/logging-contextual-webapp$ head -3 app1.log + Thread-3 (process_request) app1 __main__ jim 192.168.3.21 POST Request processing started + Thread-3 (process_request) app1 webapplib jim 192.168.3.21 POST Hello from webapplib! + Thread-5 (process_request) app1 __main__ jim 192.168.3.21 POST Request processing started + ~/logging-contextual-webapp$ head -3 app2.log + Thread-1 (process_request) app2 __main__ sheila 192.168.2.21 GET Request processing started + Thread-1 (process_request) app2 webapplib sheila 192.168.2.21 GET Hello from webapplib! + Thread-2 (process_request) app2 __main__ jim 192.168.2.20 GET Request processing started + ~/logging-contextual-webapp$ head app.log + Thread-1 (process_request) app2 __main__ sheila 192.168.2.21 GET Request processing started + Thread-1 (process_request) app2 webapplib sheila 192.168.2.21 GET Hello from webapplib! + Thread-2 (process_request) app2 __main__ jim 192.168.2.20 GET Request processing started + Thread-3 (process_request) app1 __main__ jim 192.168.3.21 POST Request processing started + Thread-2 (process_request) app2 webapplib jim 192.168.2.20 GET Hello from webapplib! + Thread-3 (process_request) app1 webapplib jim 192.168.3.21 POST Hello from webapplib! + Thread-4 (process_request) app2 __main__ fred 192.168.2.22 GET Request processing started + Thread-5 (process_request) app1 __main__ jim 192.168.3.21 POST Request processing started + Thread-4 (process_request) app2 webapplib fred 192.168.2.22 GET Hello from webapplib! + Thread-6 (process_request) app1 __main__ jim 192.168.3.21 POST Request processing started + ~/logging-contextual-webapp$ grep app1 app1.log | wc -l + 153 + ~/logging-contextual-webapp$ grep app2 app2.log | wc -l + 147 + ~/logging-contextual-webapp$ grep app1 app.log | wc -l + 153 + ~/logging-contextual-webapp$ grep app2 app.log | wc -l + 147 + + Imparting contextual information in handlers -------------------------------------------- diff --git a/Doc/library/ctypes.rst b/Doc/library/ctypes.rst index 52950b551b7560..475737144d40c6 100644 --- a/Doc/library/ctypes.rst +++ b/Doc/library/ctypes.rst @@ -148,15 +148,14 @@ Calling functions ^^^^^^^^^^^^^^^^^ You can call these functions like any other Python callable. This example uses -the ``time()`` function, which returns system time in seconds since the Unix -epoch, and the ``GetModuleHandleA()`` function, which returns a win32 module -handle. +the ``rand()`` function, which takes no arguments and returns a pseudo-random integer:: -This example calls both functions with a ``NULL`` pointer (``None`` should be used -as the ``NULL`` pointer):: + >>> print(libc.rand()) # doctest: +SKIP + 1804289383 + +On Windows, you can call the ``GetModuleHandleA()`` function, which returns a win32 module +handle (passing ``None`` as single argument to call it with a ``NULL`` pointer):: - >>> print(libc.time(None)) # doctest: +SKIP - 1150640792 >>> print(hex(windll.kernel32.GetModuleHandleA(None))) # doctest: +WINDOWS 0x1d000000 >>> @@ -247,6 +246,8 @@ Fundamental data types | :class:`c_ssize_t` | :c:type:`ssize_t` or | int | | | :c:type:`Py_ssize_t` | | +----------------------+------------------------------------------+----------------------------+ +| :class:`c_time_t` | :c:type:`time_t` | int | ++----------------------+------------------------------------------+----------------------------+ | :class:`c_float` | :c:type:`float` | float | +----------------------+------------------------------------------+----------------------------+ | :class:`c_double` | :c:type:`double` | float | @@ -447,6 +448,21 @@ By default functions are assumed to return the C :c:type:`int` type. Other return types can be specified by setting the :attr:`restype` attribute of the function object. +The C prototype of ``time()`` is ``time_t time(time_t *)``. Because ``time_t`` +might be of a different type than the default return type ``int``, you should +specify the ``restype``:: + + >>> libc.time.restype = c_time_t + +The argument types can be specified using ``argtypes``:: + + >>> libc.time.argtypes = (POINTER(c_time_t),) + +To call the function with a ``NULL`` pointer as first argument, use ``None``:: + + >>> print(libc.time(None)) # doctest: +SKIP + 1150640792 + Here is a more advanced example, it uses the ``strchr`` function, which expects a string pointer and a char, and returns a pointer to a string:: @@ -2275,6 +2291,13 @@ These are the fundamental ctypes data types: .. versionadded:: 3.2 +.. class:: c_time_t + + Represents the C :c:type:`time_t` datatype. + + .. versionadded:: 3.12 + + .. class:: c_ubyte Represents the C :c:type:`unsigned char` datatype, it interprets the value as diff --git a/Doc/library/idle.rst b/Doc/library/idle.rst index a4c9b1df8eb468..e91ec40c9add0d 100644 --- a/Doc/library/idle.rst +++ b/Doc/library/idle.rst @@ -594,7 +594,7 @@ One may edit pasted code first. If one pastes more than one statement into Shell, the result will be a :exc:`SyntaxError` when multiple statements are compiled as if they were one. -Lines containing ``'RESTART'`` mean that the user execution process has been +Lines containing ``RESTART`` mean that the user execution process has been re-started. This occurs when the user execution process has crashed, when one requests a restart on the Shell menu, or when one runs code in an editor window. @@ -775,7 +775,9 @@ IDLE's standard stream replacements are not inherited by subprocesses created in the execution process, whether directly by user code or by modules such as multiprocessing. If such subprocess use ``input`` from sys.stdin or ``print`` or ``write`` to sys.stdout or sys.stderr, -IDLE should be started in a command line window. The secondary subprocess +IDLE should be started in a command line window. (On Windows, +use ``python`` or ``py`` rather than ``pythonw`` or ``pyw``.) +The secondary subprocess will then be attached to that window for input and output. If ``sys`` is reset by user code, such as with ``importlib.reload(sys)``, diff --git a/Doc/library/logging.rst b/Doc/library/logging.rst index 51b5f86e69efe5..8716724af5625e 100644 --- a/Doc/library/logging.rst +++ b/Doc/library/logging.rst @@ -233,7 +233,7 @@ is the module's name in the Python package namespace. 2006-02-08 22:20:02,165 192.168.0.1 fbloggs Protocol problem: connection reset The keys in the dictionary passed in *extra* should not clash with the keys used - by the logging system. (See the :class:`Formatter` documentation for more + by the logging system. (See the section on :ref:`logrecord-attributes` for more information on which keys are used by the logging system.) If you choose to use these attributes in logged messages, you need to exercise diff --git a/Doc/library/shlex.rst b/Doc/library/shlex.rst index aab6a543792096..0bad51833aae13 100644 --- a/Doc/library/shlex.rst +++ b/Doc/library/shlex.rst @@ -36,9 +36,9 @@ The :mod:`shlex` module defines the following functions: instance, passing ``None`` for *s* will read the string to split from standard input. - .. deprecated:: 3.9 - Passing ``None`` for *s* will raise an exception in future Python - versions. + .. versionchanged:: 3.12 + Passing ``None`` for *s* argument now raises an exception, rather than + reading :data:`sys.stdin`. .. function:: join(split_command) diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst index a99485b6ba7bc4..33dfafd493099a 100644 --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -1069,6 +1069,8 @@ Now we plug :class:`Row` in:: 35.14 +.. _sqlite3-blob-objects: + Blob Objects ------------ @@ -1211,8 +1213,6 @@ The exception hierarchy is defined by the DB-API 2.0 (:pep:`249`). ``NotSupportedError`` is a subclass of :exc:`DatabaseError`. -.. _sqlite3-blob-objects: - .. _sqlite3-types: SQLite and Python types diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 620aa91f6da227..43239a75f701a2 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -293,6 +293,12 @@ Removed a C implementation of :func:`~hashlib.pbkdf2_hmac()` which is faster. (Contributed by Victor Stinner in :gh:`94199`.) +* :mod:`xml.etree`: Remove the ``ElementTree.Element.copy()`` method of the + pure Python implementation, deprecated in Python 3.10, use the + :func:`copy.copy` function instead. The C implementation of :mod:`xml.etree` + has no ``copy()`` method, only a ``__copy__()`` method. + (Contributed by Victor Stinner in :gh:`94383`.) + Porting to Python 3.12 ====================== @@ -324,6 +330,11 @@ Changes in the Python API to :term:`filesystem encoding and error handler`. Argument files should be encoded in UTF-8 instead of ANSI Codepage on Windows. +* :func:`shlex.split`: Passing ``None`` for *s* argument now raises an + exception, rather than reading :data:`sys.stdin`. The feature was deprecated + in Python 3.9. + (Contributed by Victor Stinner in :gh:`94352`.) + Build Changes ============= diff --git a/Lib/base64.py b/Lib/base64.py index 7e9c2a2ca477ff..30796a6fd6d05a 100755 --- a/Lib/base64.py +++ b/Lib/base64.py @@ -567,11 +567,10 @@ def decodebytes(s): def main(): """Small main program""" import sys, getopt - usage = """usage: %s [-h|-d|-e|-u|-t] [file|-] + usage = f"""usage: {sys.argv[0]} [-h|-d|-e|-u|-t] [file|-] -h: print this help message and exit -d, -u: decode - -e: encode (default) - -t: encode and decode string 'Aladdin:open sesame'"""%sys.argv[0] + -e: encode (default)""" try: opts, args = getopt.getopt(sys.argv[1:], 'hdeut') except getopt.error as msg: @@ -584,7 +583,6 @@ def main(): if o == '-e': func = encode if o == '-d': func = decode if o == '-u': func = decode - if o == '-t': test(); return if o == '-h': print(usage); return if args and args[0] != '-': with open(args[0], 'rb') as f: @@ -593,15 +591,5 @@ def main(): func(sys.stdin.buffer, sys.stdout.buffer) -def test(): - s0 = b"Aladdin:open sesame" - print(repr(s0)) - s1 = encodebytes(s0) - print(repr(s1)) - s2 = decodebytes(s1) - print(repr(s2)) - assert s0 == s2 - - if __name__ == '__main__': main() diff --git a/Lib/codecs.py b/Lib/codecs.py index e6ad6e3a052364..5a1e7ec804009c 100644 --- a/Lib/codecs.py +++ b/Lib/codecs.py @@ -1114,13 +1114,3 @@ def make_encoding_map(decoding_map): _false = 0 if _false: import encodings - -### Tests - -if __name__ == '__main__': - - # Make stdout translate Latin-1 output into UTF-8 output - sys.stdout = EncodedFile(sys.stdout, 'latin-1', 'utf-8') - - # Have stdin translate Latin-1 input into UTF-8 input - sys.stdin = EncodedFile(sys.stdin, 'utf-8', 'latin-1') diff --git a/Lib/ctypes/__init__.py b/Lib/ctypes/__init__.py index 26135ad96296ac..b94b337a3157b7 100644 --- a/Lib/ctypes/__init__.py +++ b/Lib/ctypes/__init__.py @@ -11,6 +11,7 @@ from _ctypes import __version__ as _ctypes_version from _ctypes import RTLD_LOCAL, RTLD_GLOBAL from _ctypes import ArgumentError +from _ctypes import SIZEOF_TIME_T from struct import calcsize as _calcsize @@ -563,4 +564,11 @@ def DllCanUnloadNow(): elif sizeof(kind) == 8: c_uint64 = kind del(kind) +if SIZEOF_TIME_T == 8: + c_time_t = c_int64 +elif SIZEOF_TIME_T == 4: + c_time_t = c_int32 +else: + raise SystemError(f"Unexpected sizeof(time_t): {SIZEOF_TIME_T=}") + _reset_cache() diff --git a/Lib/idlelib/help.html b/Lib/idlelib/help.html index 95b59b91d70a67..e8e7d2876097ad 100644 --- a/Lib/idlelib/help.html +++ b/Lib/idlelib/help.html @@ -664,7 +664,7 @@

Shell windowSyntaxError when multiple statements are compiled as if they were one.

-

Lines containing`’RESTART’` mean that the user execution process has been +

Lines containing RESTART mean that the user execution process has been re-started. This occurs when the user execution process has crashed, when one requests a restart on the Shell menu, or when one runs code in an editor window.

@@ -821,7 +821,9 @@

Running user codeinput from sys.stdin or print or write to sys.stdout or sys.stderr, -IDLE should be started in a command line window. The secondary subprocess +IDLE should be started in a command line window. (On Windows, +use python or py rather than pythonw or pyw.) +The secondary subprocess will then be attached to that window for input and output.

If sys is reset by user code, such as with importlib.reload(sys), IDLE’s changes are lost and input from the keyboard and output to the screen @@ -1139,7 +1141,7 @@

Navigation



- Last updated on Jun 26, 2022. + Last updated on Jul 03, 2022.
Found a bug?
diff --git a/Lib/importlib/abc.py b/Lib/importlib/abc.py index 3fa151f390ba7c..8fa9a0f3bc1e4b 100644 --- a/Lib/importlib/abc.py +++ b/Lib/importlib/abc.py @@ -15,20 +15,29 @@ import abc import warnings -# for compatibility with Python 3.10 -from .resources.abc import ResourceReader, Traversable, TraversableResources +from .resources import abc as _resources_abc __all__ = [ 'Loader', 'Finder', 'MetaPathFinder', 'PathEntryFinder', 'ResourceLoader', 'InspectLoader', 'ExecutionLoader', 'FileLoader', 'SourceLoader', - - # for compatibility with Python 3.10 - 'ResourceReader', 'Traversable', 'TraversableResources', ] +def __getattr__(name): + """ + For backwards compatibility, continue to make names + from _resources_abc available through this module. #93963 + """ + if name in _resources_abc.__all__: + obj = getattr(_resources_abc, name) + warnings._deprecated(f"{__name__}.{name}", remove=(3, 14)) + globals()[name] = obj + return obj + raise AttributeError(f'module {__name__!r} has no attribute {name!r}') + + def _register(abstract_cls, *classes): for cls in classes: abstract_cls.register(cls) diff --git a/Lib/shlex.py b/Lib/shlex.py index 4801a6c1d47bd9..a91c9b022627b1 100644 --- a/Lib/shlex.py +++ b/Lib/shlex.py @@ -305,9 +305,7 @@ def __next__(self): def split(s, comments=False, posix=True): """Split the string *s* using shell-like syntax.""" if s is None: - import warnings - warnings.warn("Passing None for 's' to shlex.split() is deprecated.", - DeprecationWarning, stacklevel=2) + raise ValueError("s argument must not be None") lex = shlex(s, posix=posix) lex.whitespace_split = True if not comments: diff --git a/Lib/test/test_base64.py b/Lib/test/test_base64.py index 217f2945468844..fa03fa1d61ceab 100644 --- a/Lib/test/test_base64.py +++ b/Lib/test/test_base64.py @@ -31,6 +31,8 @@ def test_encodebytes(self): b"YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNE" b"RUZHSElKS0xNTk9QUVJTVFVWV1hZWjAxMjM0\nNT" b"Y3ODkhQCMwXiYqKCk7Ojw+LC4gW117fQ==\n") + eq(base64.encodebytes(b"Aladdin:open sesame"), + b"QWxhZGRpbjpvcGVuIHNlc2FtZQ==\n") # Non-bytes eq(base64.encodebytes(bytearray(b'abc')), b'YWJj\n') eq(base64.encodebytes(memoryview(b'abc')), b'YWJj\n') @@ -50,6 +52,8 @@ def test_decodebytes(self): b"ABCDEFGHIJKLMNOPQRSTUVWXYZ" b"0123456789!@#0^&*();:<>,. []{}") eq(base64.decodebytes(b''), b'') + eq(base64.decodebytes(b"QWxhZGRpbjpvcGVuIHNlc2FtZQ==\n"), + b"Aladdin:open sesame") # Non-bytes eq(base64.decodebytes(bytearray(b'YWJj\n')), b'abc') eq(base64.decodebytes(memoryview(b'YWJj\n')), b'abc') @@ -762,14 +766,6 @@ def tearDown(self): def get_output(self, *args): return script_helper.assert_python_ok('-m', 'base64', *args).out - def test_encode_decode(self): - output = self.get_output('-t') - self.assertSequenceEqual(output.splitlines(), ( - b"b'Aladdin:open sesame'", - br"b'QWxhZGRpbjpvcGVuIHNlc2FtZQ==\n'", - b"b'Aladdin:open sesame'", - )) - def test_encode_file(self): with open(os_helper.TESTFN, 'wb') as fp: fp.write(b'a\xffb\n') diff --git a/Lib/test/test_code.py b/Lib/test/test_code.py index 308141aaf10e55..fd68f6dee7915a 100644 --- a/Lib/test/test_code.py +++ b/Lib/test/test_code.py @@ -376,7 +376,6 @@ def test_co_positions_artificial_instructions(self): for instruction in artificial_instructions ], [ - ('RESUME', 0), ("PUSH_EXC_INFO", None), ("LOAD_CONST", None), # artificial 'None' ("STORE_NAME", "e"), # XX: we know the location for this diff --git a/Lib/test/test_compile.py b/Lib/test/test_compile.py index 46b16e753ceee2..b778eff12f5ed2 100644 --- a/Lib/test/test_compile.py +++ b/Lib/test/test_compile.py @@ -161,7 +161,7 @@ def test_leading_newlines(self): co = compile(s256, 'fn', 'exec') self.assertEqual(co.co_firstlineno, 1) lines = list(co.co_lines()) - self.assertEqual(lines[0][2], None) + self.assertEqual(lines[0][2], 0) self.assertEqual(lines[1][2], 257) def test_literals_with_leading_zeroes(self): @@ -1090,6 +1090,8 @@ def generic_visit(self, node): # Check against the positions in the code object. for (line, end_line, col, end_col) in code.co_positions(): + if line == 0: + continue # This is an artificial module-start line # If the offset is not None (indicating missing data), ensure that # it was part of one of the AST nodes. if line is not None: diff --git a/Lib/test/test_ctypes/test_sizes.py b/Lib/test/test_ctypes/test_sizes.py index 4ceacbc2900802..bf8d6ea35aa399 100644 --- a/Lib/test/test_ctypes/test_sizes.py +++ b/Lib/test/test_ctypes/test_sizes.py @@ -28,6 +28,9 @@ def test_size_t(self): def test_ssize_t(self): self.assertEqual(sizeof(c_void_p), sizeof(c_ssize_t)) + def test_time_t(self): + self.assertEqual(sizeof(c_time_t), SIZEOF_TIME_T) + if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py index 07f1203ff06887..256004855d4a6e 100644 --- a/Lib/test/test_dis.py +++ b/Lib/test/test_dis.py @@ -267,7 +267,7 @@ def bug42562(): expr_str = "x + 1" dis_expr_str = """\ - RESUME 0 + 0 RESUME 0 1 LOAD_NAME 0 (x) LOAD_CONST 0 (1) @@ -278,7 +278,7 @@ def bug42562(): simple_stmt_str = "x = x + 1" dis_simple_stmt_str = """\ - RESUME 0 + 0 RESUME 0 1 LOAD_NAME 0 (x) LOAD_CONST 0 (1) @@ -297,7 +297,7 @@ def bug42562(): # leading newline is for a reason (tests lineno) dis_annot_stmt_str = """\ - RESUME 0 + 0 RESUME 0 2 SETUP_ANNOTATIONS LOAD_CONST 0 (1) @@ -335,7 +335,7 @@ def bug42562(): # Trailing newline has been deliberately omitted dis_compound_stmt_str = """\ - RESUME 0 + 0 RESUME 0 1 LOAD_CONST 0 (0) STORE_NAME 0 (x) @@ -1092,7 +1092,7 @@ def test_super_instructions(self): @cpython_only def test_binary_specialize(self): binary_op_quicken = """\ - 0 RESUME_QUICK 0 + 0 0 RESUME_QUICK 0 1 2 LOAD_NAME 0 (a) 4 LOAD_NAME 1 (b) @@ -1110,7 +1110,7 @@ def test_binary_specialize(self): self.do_disassembly_compare(got, binary_op_quicken % "BINARY_OP_ADD_UNICODE 0 (+)", True) binary_subscr_quicken = """\ - 0 RESUME_QUICK 0 + 0 0 RESUME_QUICK 0 1 2 LOAD_NAME 0 (a) 4 LOAD_CONST 0 (0) @@ -1130,7 +1130,7 @@ def test_binary_specialize(self): @cpython_only def test_load_attr_specialize(self): load_attr_quicken = """\ - 0 RESUME_QUICK 0 + 0 0 RESUME_QUICK 0 1 2 LOAD_CONST 0 ('a') 4 LOAD_ATTR_SLOT 0 (__class__) @@ -1144,7 +1144,7 @@ def test_load_attr_specialize(self): @cpython_only def test_call_specialize(self): call_quicken = """\ - RESUME_QUICK 0 + 0 RESUME_QUICK 0 1 PUSH_NULL LOAD_NAME 0 (str) @@ -1718,7 +1718,7 @@ def test_co_positions(self): for instr in dis.get_instructions(code) ] expected = [ - (None, None, None, None), + (0, 1, 0, 0), (1, 1, 0, 1), (1, 1, 0, 1), (2, 2, 2, 3), diff --git a/Lib/test/test_shlex.py b/Lib/test/test_shlex.py index 3081a785204edc..92598dbbd5f293 100644 --- a/Lib/test/test_shlex.py +++ b/Lib/test/test_shlex.py @@ -162,9 +162,8 @@ def oldSplit(self, s): tok = lex.get_token() return ret - @mock.patch('sys.stdin', io.StringIO()) - def testSplitNoneDeprecation(self): - with self.assertWarns(DeprecationWarning): + def testSplitNone(self): + with self.assertRaises(ValueError): shlex.split(None) def testSplitPosix(self): diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py index afa4641e6906b7..839955695b800f 100644 --- a/Lib/test/test_xml_etree.py +++ b/Lib/test/test_xml_etree.py @@ -2333,35 +2333,6 @@ def test___init__(self): self.assertIsNot(element_foo.attrib, attrib) self.assertNotEqual(element_foo.attrib, attrib) - def test_copy(self): - # Only run this test if Element.copy() is defined. - if "copy" not in dir(ET.Element): - raise unittest.SkipTest("Element.copy() not present") - - element_foo = ET.Element("foo", { "zix": "wyp" }) - element_foo.append(ET.Element("bar", { "baz": "qix" })) - - with self.assertWarns(DeprecationWarning): - element_foo2 = element_foo.copy() - - # elements are not the same - self.assertIsNot(element_foo2, element_foo) - - # string attributes are equal - self.assertEqual(element_foo2.tag, element_foo.tag) - self.assertEqual(element_foo2.text, element_foo.text) - self.assertEqual(element_foo2.tail, element_foo.tail) - - # number of children is the same - self.assertEqual(len(element_foo2), len(element_foo)) - - # children are the same - for (child1, child2) in itertools.zip_longest(element_foo, element_foo2): - self.assertIs(child1, child2) - - # attrib is a copy - self.assertEqual(element_foo2.attrib, element_foo.attrib) - def test___copy__(self): element_foo = ET.Element("foo", { "zix": "wyp" }) element_foo.append(ET.Element("bar", { "baz": "qix" })) diff --git a/Lib/xml/etree/ElementTree.py b/Lib/xml/etree/ElementTree.py index 1dc80351bf7ddd..ebbe2b703bfd8f 100644 --- a/Lib/xml/etree/ElementTree.py +++ b/Lib/xml/etree/ElementTree.py @@ -188,19 +188,6 @@ def makeelement(self, tag, attrib): """ return self.__class__(tag, attrib) - def copy(self): - """Return copy of current element. - - This creates a shallow copy. Subelements will be shared with the - original tree. - - """ - warnings.warn( - "elem.copy() is deprecated. Use copy.copy(elem) instead.", - DeprecationWarning - ) - return self.__copy__() - def __copy__(self): elem = self.makeelement(self.tag, self.attrib) elem.text = self.text diff --git a/Misc/NEWS.d/next/Build/2022-06-30-09-57-39.gh-issue-90005.9-pQyR.rst b/Misc/NEWS.d/next/Build/2022-06-30-09-57-39.gh-issue-90005.9-pQyR.rst new file mode 100644 index 00000000000000..9b14f767847dad --- /dev/null +++ b/Misc/NEWS.d/next/Build/2022-06-30-09-57-39.gh-issue-90005.9-pQyR.rst @@ -0,0 +1 @@ +``_dbm`` module dependencies are now detected by configure. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-07-01-20-00-19.gh-issue-94485.mo5st7.rst b/Misc/NEWS.d/next/Core and Builtins/2022-07-01-20-00-19.gh-issue-94485.mo5st7.rst new file mode 100644 index 00000000000000..14d90b7e764a77 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-07-01-20-00-19.gh-issue-94485.mo5st7.rst @@ -0,0 +1,2 @@ +Line number of a module's ``RESUME`` instruction is set to 0 as specified in +:pep:`626`. diff --git a/Misc/NEWS.d/next/Library/2022-05-17-06-27-39.gh-issue-92869.t8oBkw.rst b/Misc/NEWS.d/next/Library/2022-05-17-06-27-39.gh-issue-92869.t8oBkw.rst new file mode 100644 index 00000000000000..7787f3419de60e --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-05-17-06-27-39.gh-issue-92869.t8oBkw.rst @@ -0,0 +1,2 @@ +Added :class:`~ctypes.c_time_t` to :mod:`ctypes`, which has the same size as +the :c:type:`time_t` type in C. diff --git a/Misc/NEWS.d/next/Library/2022-06-17-16-00-55.gh-issue-93963.8YYZ-2.rst b/Misc/NEWS.d/next/Library/2022-06-17-16-00-55.gh-issue-93963.8YYZ-2.rst new file mode 100644 index 00000000000000..0973982dfeeffd --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-06-17-16-00-55.gh-issue-93963.8YYZ-2.rst @@ -0,0 +1,2 @@ +Officially deprecate from ``importlib.abc`` classes moved to +``importlib.resources.abc``. diff --git a/Misc/NEWS.d/next/Library/2022-06-24-19-16-09.gh-issue-93096.r1_oIc.rst b/Misc/NEWS.d/next/Library/2022-06-24-19-16-09.gh-issue-93096.r1_oIc.rst new file mode 100644 index 00000000000000..536a9d7cab1b81 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-06-24-19-16-09.gh-issue-93096.r1_oIc.rst @@ -0,0 +1,3 @@ +Removed undocumented ``-t`` argument of ``python -m base64``. Use +``python -m unittest test.test_base64.LegacyBase64TestCase.test_encodebytes`` +instead. diff --git a/Misc/NEWS.d/next/Library/2022-06-24-19-40-40.gh-issue-93096.3RlK2d.rst b/Misc/NEWS.d/next/Library/2022-06-24-19-40-40.gh-issue-93096.3RlK2d.rst new file mode 100644 index 00000000000000..f7d9e33eb414db --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-06-24-19-40-40.gh-issue-93096.3RlK2d.rst @@ -0,0 +1,2 @@ +Removed undocumented ``python -m codecs``. Use ``python -m unittest +test.test_codecs.EncodedFileTest`` instead. diff --git a/Misc/NEWS.d/next/Library/2022-06-28-00-24-48.gh-issue-94352.JY1Ayt.rst b/Misc/NEWS.d/next/Library/2022-06-28-00-24-48.gh-issue-94352.JY1Ayt.rst new file mode 100644 index 00000000000000..3a166abdcc3203 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-06-28-00-24-48.gh-issue-94352.JY1Ayt.rst @@ -0,0 +1,3 @@ +:func:`shlex.split`: Passing ``None`` for *s* argument now raises an exception, +rather than reading :data:`sys.stdin`. The feature was deprecated in Python +3.9. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Library/2022-06-28-14-41-22.gh-issue-94383.CXnquo.rst b/Misc/NEWS.d/next/Library/2022-06-28-14-41-22.gh-issue-94383.CXnquo.rst new file mode 100644 index 00000000000000..9ed476b717f334 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-06-28-14-41-22.gh-issue-94383.CXnquo.rst @@ -0,0 +1,5 @@ +:mod:`xml.etree`: Remove the ``ElementTree.Element.copy()`` method of the +pure Python implementation, deprecated in Python 3.10, use the +:func:`copy.copy` function instead. The C implementation of :mod:`xml.etree` +has no ``copy()`` method, only a ``__copy__()`` method. Patch by Victor +Stinner. diff --git a/Modules/Setup.stdlib.in b/Modules/Setup.stdlib.in index a199aefc510114..ad34f85e254514 100644 --- a/Modules/Setup.stdlib.in +++ b/Modules/Setup.stdlib.in @@ -68,7 +68,7 @@ # dbm/gdbm # dbm needs either libndbm, libgdbm_compat, or libdb 5.x -#@MODULE__DBM_TRUE@_dbm _dbmmodule.c +@MODULE__DBM_TRUE@_dbm _dbmmodule.c # gdbm module needs -lgdbm @MODULE__GDBM_TRUE@_gdbm _gdbmmodule.c diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c index 2c629d76beb3bd..a3c7c8c471e584 100644 --- a/Modules/_ctypes/_ctypes.c +++ b/Modules/_ctypes/_ctypes.c @@ -5784,6 +5784,7 @@ _ctypes_add_objects(PyObject *mod) MOD_ADD("RTLD_GLOBAL", PyLong_FromLong(RTLD_GLOBAL)); MOD_ADD("CTYPES_MAX_ARGCOUNT", PyLong_FromLong(CTYPES_MAX_ARGCOUNT)); MOD_ADD("ArgumentError", Py_NewRef(PyExc_ArgError)); + MOD_ADD("SIZEOF_TIME_T", PyLong_FromSsize_t(SIZEOF_TIME_T)); return 0; #undef MOD_ADD } diff --git a/Modules/_json.c b/Modules/_json.c index 9464b9f498ede5..89f55047abe421 100644 --- a/Modules/_json.c +++ b/Modules/_json.c @@ -14,19 +14,6 @@ #include "structmember.h" // PyMemberDef #include "pycore_accu.h" -typedef struct { - PyObject *PyScannerType; - PyObject *PyEncoderType; -} _jsonmodulestate; - -static inline _jsonmodulestate* -get_json_state(PyObject *module) -{ - void *state = PyModule_GetState(module); - assert(state != NULL); - return (_jsonmodulestate *)state; -} - typedef struct _PyScannerObject { PyObject_HEAD @@ -1815,70 +1802,40 @@ PyDoc_STRVAR(module_doc, static int _json_exec(PyObject *module) { - _jsonmodulestate *state = get_json_state(module); - - state->PyScannerType = PyType_FromSpec(&PyScannerType_spec); - if (state->PyScannerType == NULL) { + PyObject *PyScannerType = PyType_FromSpec(&PyScannerType_spec); + if (PyScannerType == NULL) { return -1; } - Py_INCREF(state->PyScannerType); - if (PyModule_AddObject(module, "make_scanner", state->PyScannerType) < 0) { - Py_DECREF(state->PyScannerType); + int rc = PyModule_AddObjectRef(module, "make_scanner", PyScannerType); + Py_DECREF(PyScannerType); + if (rc < 0) { return -1; } - state->PyEncoderType = PyType_FromSpec(&PyEncoderType_spec); - if (state->PyEncoderType == NULL) { + PyObject *PyEncoderType = PyType_FromSpec(&PyEncoderType_spec); + if (PyEncoderType == NULL) { return -1; } - Py_INCREF(state->PyEncoderType); - if (PyModule_AddObject(module, "make_encoder", state->PyEncoderType) < 0) { - Py_DECREF(state->PyEncoderType); + rc = PyModule_AddObjectRef(module, "make_encoder", PyEncoderType); + Py_DECREF(PyEncoderType); + if (rc < 0) { return -1; } return 0; } -static int -_jsonmodule_traverse(PyObject *module, visitproc visit, void *arg) -{ - _jsonmodulestate *state = get_json_state(module); - Py_VISIT(state->PyScannerType); - Py_VISIT(state->PyEncoderType); - return 0; -} - -static int -_jsonmodule_clear(PyObject *module) -{ - _jsonmodulestate *state = get_json_state(module); - Py_CLEAR(state->PyScannerType); - Py_CLEAR(state->PyEncoderType); - return 0; -} - -static void -_jsonmodule_free(void *module) -{ - _jsonmodule_clear((PyObject *)module); -} - static PyModuleDef_Slot _json_slots[] = { {Py_mod_exec, _json_exec}, {0, NULL} }; static struct PyModuleDef jsonmodule = { - PyModuleDef_HEAD_INIT, - "_json", - module_doc, - sizeof(_jsonmodulestate), - speedups_methods, - _json_slots, - _jsonmodule_traverse, - _jsonmodule_clear, - _jsonmodule_free, + .m_base = PyModuleDef_HEAD_INIT, + .m_name = "_json", + .m_doc = module_doc, + .m_methods = speedups_methods, + .m_slots = _json_slots, }; PyMODINIT_FUNC diff --git a/Modules/_multiprocessing/clinic/multiprocessing.c.h b/Modules/_multiprocessing/clinic/multiprocessing.c.h index e9953215aca7df..3a30833904792d 100644 --- a/Modules/_multiprocessing/clinic/multiprocessing.c.h +++ b/Modules/_multiprocessing/clinic/multiprocessing.c.h @@ -21,7 +21,8 @@ _multiprocessing_closesocket(PyObject *module, PyObject *arg) PyObject *return_value = NULL; HANDLE handle; - if (!PyArg_Parse(arg, ""F_HANDLE":closesocket", &handle)) { + handle = PyLong_AsVoidPtr(arg); + if (!handle && PyErr_Occurred()) { goto exit; } return_value = _multiprocessing_closesocket_impl(module, handle); @@ -52,8 +53,15 @@ _multiprocessing_recv(PyObject *module, PyObject *const *args, Py_ssize_t nargs) HANDLE handle; int size; - if (!_PyArg_ParseStack(args, nargs, ""F_HANDLE"i:recv", - &handle, &size)) { + if (!_PyArg_CheckPositional("recv", nargs, 2, 2)) { + goto exit; + } + handle = PyLong_AsVoidPtr(args[0]); + if (!handle && PyErr_Occurred()) { + goto exit; + } + size = _PyLong_AsInt(args[1]); + if (size == -1 && PyErr_Occurred()) { goto exit; } return_value = _multiprocessing_recv_impl(module, handle, size); @@ -84,8 +92,18 @@ _multiprocessing_send(PyObject *module, PyObject *const *args, Py_ssize_t nargs) HANDLE handle; Py_buffer buf = {NULL, NULL}; - if (!_PyArg_ParseStack(args, nargs, ""F_HANDLE"y*:send", - &handle, &buf)) { + if (!_PyArg_CheckPositional("send", nargs, 2, 2)) { + goto exit; + } + handle = PyLong_AsVoidPtr(args[0]); + if (!handle && PyErr_Occurred()) { + goto exit; + } + if (PyObject_GetBuffer(args[1], &buf, PyBUF_SIMPLE) != 0) { + goto exit; + } + if (!PyBuffer_IsContiguous(&buf, 'C')) { + _PyArg_BadArgument("send", "argument 2", "contiguous buffer", args[1]); goto exit; } return_value = _multiprocessing_send_impl(module, handle, &buf); @@ -148,4 +166,4 @@ _multiprocessing_sem_unlink(PyObject *module, PyObject *arg) #ifndef _MULTIPROCESSING_SEND_METHODDEF #define _MULTIPROCESSING_SEND_METHODDEF #endif /* !defined(_MULTIPROCESSING_SEND_METHODDEF) */ -/*[clinic end generated code: output=d3bbf69de578db7b input=a9049054013a1b77]*/ +/*[clinic end generated code: output=ab64ce752f933c55 input=a9049054013a1b77]*/ diff --git a/Modules/_multiprocessing/multiprocessing.c b/Modules/_multiprocessing/multiprocessing.c index 0809c2455dbebc..ed89a1e29a433f 100644 --- a/Modules/_multiprocessing/multiprocessing.c +++ b/Modules/_multiprocessing/multiprocessing.c @@ -14,8 +14,16 @@ class HANDLE_converter(CConverter): type = "HANDLE" format_unit = '"F_HANDLE"' + def parse_arg(self, argname, displayname): + return """ + {paramname} = PyLong_AsVoidPtr({argname}); + if (!{paramname} && PyErr_Occurred()) {{{{ + goto exit; + }}}} + """.format(argname=argname, paramname=self.parser_name) + [python start generated code]*/ -/*[python end generated code: output=da39a3ee5e6b4b0d input=9fad6080b79ace91]*/ +/*[python end generated code: output=da39a3ee5e6b4b0d input=3e537d244034affb]*/ /*[clinic input] module _multiprocessing diff --git a/PC/clinic/msvcrtmodule.c.h b/PC/clinic/msvcrtmodule.c.h index ea95897590fe47..e60fbd0b623cd4 100644 --- a/PC/clinic/msvcrtmodule.c.h +++ b/PC/clinic/msvcrtmodule.c.h @@ -141,8 +141,15 @@ msvcrt_open_osfhandle(PyObject *module, PyObject *const *args, Py_ssize_t nargs) int flags; long _return_value; - if (!_PyArg_ParseStack(args, nargs, ""_Py_PARSE_UINTPTR"i:open_osfhandle", - &handle, &flags)) { + if (!_PyArg_CheckPositional("open_osfhandle", nargs, 2, 2)) { + goto exit; + } + handle = PyLong_AsVoidPtr(args[0]); + if (!handle && PyErr_Occurred()) { + goto exit; + } + flags = _PyLong_AsInt(args[1]); + if (flags == -1 && PyErr_Occurred()) { goto exit; } _return_value = msvcrt_open_osfhandle_impl(module, handle, flags); @@ -488,8 +495,15 @@ msvcrt_CrtSetReportFile(PyObject *module, PyObject *const *args, Py_ssize_t narg void *file; void *_return_value; - if (!_PyArg_ParseStack(args, nargs, "i"_Py_PARSE_UINTPTR":CrtSetReportFile", - &type, &file)) { + if (!_PyArg_CheckPositional("CrtSetReportFile", nargs, 2, 2)) { + goto exit; + } + type = _PyLong_AsInt(args[0]); + if (type == -1 && PyErr_Occurred()) { + goto exit; + } + file = PyLong_AsVoidPtr(args[1]); + if (!file && PyErr_Occurred()) { goto exit; } _return_value = msvcrt_CrtSetReportFile_impl(module, type, file); @@ -647,4 +661,4 @@ msvcrt_SetErrorMode(PyObject *module, PyObject *arg) #ifndef MSVCRT_SET_ERROR_MODE_METHODDEF #define MSVCRT_SET_ERROR_MODE_METHODDEF #endif /* !defined(MSVCRT_SET_ERROR_MODE_METHODDEF) */ -/*[clinic end generated code: output=b543933cad520f2b input=a9049054013a1b77]*/ +/*[clinic end generated code: output=9d89e9414484d28c input=a9049054013a1b77]*/ diff --git a/PC/clinic/winreg.c.h b/PC/clinic/winreg.c.h index 6af24af539b0b9..1e64b1eedeb3ea 100644 --- a/PC/clinic/winreg.c.h +++ b/PC/clinic/winreg.c.h @@ -287,17 +287,52 @@ winreg_CreateKeyEx(PyObject *module, PyObject *const *args, Py_ssize_t nargs, Py { PyObject *return_value = NULL; static const char * const _keywords[] = {"key", "sub_key", "reserved", "access", NULL}; - static _PyArg_Parser _parser = {"O&O&|ii:CreateKeyEx", _keywords, 0}; + static _PyArg_Parser _parser = {NULL, _keywords, "CreateKeyEx", 0}; + PyObject *argsbuf[4]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 2; HKEY key; const Py_UNICODE *sub_key; int reserved = 0; REGSAM access = KEY_WRITE; HKEY _return_value; - if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser, - clinic_HKEY_converter, &key, _PyUnicode_WideCharString_Opt_Converter, &sub_key, &reserved, &access)) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 2, 4, 0, argsbuf); + if (!args) { + goto exit; + } + if (!clinic_HKEY_converter(args[0], &key)) { + goto exit; + } + if (args[1] == Py_None) { + sub_key = NULL; + } + else if (PyUnicode_Check(args[1])) { + sub_key = PyUnicode_AsWideCharString(args[1], NULL); + if (sub_key == NULL) { + goto exit; + } + } + else { + _PyArg_BadArgument("CreateKeyEx", "argument 'sub_key'", "str or None", args[1]); goto exit; } + if (!noptargs) { + goto skip_optional_pos; + } + if (args[2]) { + reserved = _PyLong_AsInt(args[2]); + if (reserved == -1 && PyErr_Occurred()) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_pos; + } + } + access = _PyLong_AsInt(args[3]); + if (access == -1 && PyErr_Occurred()) { + goto exit; + } +skip_optional_pos: _return_value = winreg_CreateKeyEx_impl(module, key, sub_key, reserved, access); if (_return_value == NULL) { goto exit; @@ -403,16 +438,46 @@ winreg_DeleteKeyEx(PyObject *module, PyObject *const *args, Py_ssize_t nargs, Py { PyObject *return_value = NULL; static const char * const _keywords[] = {"key", "sub_key", "access", "reserved", NULL}; - static _PyArg_Parser _parser = {"O&O&|ii:DeleteKeyEx", _keywords, 0}; + static _PyArg_Parser _parser = {NULL, _keywords, "DeleteKeyEx", 0}; + PyObject *argsbuf[4]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 2; HKEY key; const Py_UNICODE *sub_key; REGSAM access = KEY_WOW64_64KEY; int reserved = 0; - if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser, - clinic_HKEY_converter, &key, _PyUnicode_WideCharString_Converter, &sub_key, &access, &reserved)) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 2, 4, 0, argsbuf); + if (!args) { goto exit; } + if (!clinic_HKEY_converter(args[0], &key)) { + goto exit; + } + if (!PyUnicode_Check(args[1])) { + _PyArg_BadArgument("DeleteKeyEx", "argument 'sub_key'", "str", args[1]); + goto exit; + } + sub_key = PyUnicode_AsWideCharString(args[1], NULL); + if (sub_key == NULL) { + goto exit; + } + if (!noptargs) { + goto skip_optional_pos; + } + if (args[2]) { + access = _PyLong_AsInt(args[2]); + if (access == -1 && PyErr_Occurred()) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_pos; + } + } + reserved = _PyLong_AsInt(args[3]); + if (reserved == -1 && PyErr_Occurred()) { + goto exit; + } +skip_optional_pos: return_value = winreg_DeleteKeyEx_impl(module, key, sub_key, access, reserved); exit: @@ -754,17 +819,52 @@ winreg_OpenKey(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObje { PyObject *return_value = NULL; static const char * const _keywords[] = {"key", "sub_key", "reserved", "access", NULL}; - static _PyArg_Parser _parser = {"O&O&|ii:OpenKey", _keywords, 0}; + static _PyArg_Parser _parser = {NULL, _keywords, "OpenKey", 0}; + PyObject *argsbuf[4]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 2; HKEY key; const Py_UNICODE *sub_key; int reserved = 0; REGSAM access = KEY_READ; HKEY _return_value; - if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser, - clinic_HKEY_converter, &key, _PyUnicode_WideCharString_Opt_Converter, &sub_key, &reserved, &access)) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 2, 4, 0, argsbuf); + if (!args) { + goto exit; + } + if (!clinic_HKEY_converter(args[0], &key)) { + goto exit; + } + if (args[1] == Py_None) { + sub_key = NULL; + } + else if (PyUnicode_Check(args[1])) { + sub_key = PyUnicode_AsWideCharString(args[1], NULL); + if (sub_key == NULL) { + goto exit; + } + } + else { + _PyArg_BadArgument("OpenKey", "argument 'sub_key'", "str or None", args[1]); + goto exit; + } + if (!noptargs) { + goto skip_optional_pos; + } + if (args[2]) { + reserved = _PyLong_AsInt(args[2]); + if (reserved == -1 && PyErr_Occurred()) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_pos; + } + } + access = _PyLong_AsInt(args[3]); + if (access == -1 && PyErr_Occurred()) { goto exit; } +skip_optional_pos: _return_value = winreg_OpenKey_impl(module, key, sub_key, reserved, access); if (_return_value == NULL) { goto exit; @@ -809,17 +909,52 @@ winreg_OpenKeyEx(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyOb { PyObject *return_value = NULL; static const char * const _keywords[] = {"key", "sub_key", "reserved", "access", NULL}; - static _PyArg_Parser _parser = {"O&O&|ii:OpenKeyEx", _keywords, 0}; + static _PyArg_Parser _parser = {NULL, _keywords, "OpenKeyEx", 0}; + PyObject *argsbuf[4]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 2; HKEY key; const Py_UNICODE *sub_key; int reserved = 0; REGSAM access = KEY_READ; HKEY _return_value; - if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser, - clinic_HKEY_converter, &key, _PyUnicode_WideCharString_Opt_Converter, &sub_key, &reserved, &access)) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 2, 4, 0, argsbuf); + if (!args) { goto exit; } + if (!clinic_HKEY_converter(args[0], &key)) { + goto exit; + } + if (args[1] == Py_None) { + sub_key = NULL; + } + else if (PyUnicode_Check(args[1])) { + sub_key = PyUnicode_AsWideCharString(args[1], NULL); + if (sub_key == NULL) { + goto exit; + } + } + else { + _PyArg_BadArgument("OpenKeyEx", "argument 'sub_key'", "str or None", args[1]); + goto exit; + } + if (!noptargs) { + goto skip_optional_pos; + } + if (args[2]) { + reserved = _PyLong_AsInt(args[2]); + if (reserved == -1 && PyErr_Occurred()) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_pos; + } + } + access = _PyLong_AsInt(args[3]); + if (access == -1 && PyErr_Occurred()) { + goto exit; + } +skip_optional_pos: _return_value = winreg_OpenKeyEx_impl(module, key, sub_key, reserved, access); if (_return_value == NULL) { goto exit; @@ -1086,10 +1221,36 @@ winreg_SetValue(PyObject *module, PyObject *const *args, Py_ssize_t nargs) DWORD type; PyObject *value_obj; - if (!_PyArg_ParseStack(args, nargs, "O&O&kU:SetValue", - clinic_HKEY_converter, &key, _PyUnicode_WideCharString_Opt_Converter, &sub_key, &type, &value_obj)) { + if (!_PyArg_CheckPositional("SetValue", nargs, 4, 4)) { goto exit; } + if (!clinic_HKEY_converter(args[0], &key)) { + goto exit; + } + if (args[1] == Py_None) { + sub_key = NULL; + } + else if (PyUnicode_Check(args[1])) { + sub_key = PyUnicode_AsWideCharString(args[1], NULL); + if (sub_key == NULL) { + goto exit; + } + } + else { + _PyArg_BadArgument("SetValue", "argument 2", "str or None", args[1]); + goto exit; + } + if (!_PyLong_UnsignedLong_Converter(args[2], &type)) { + goto exit; + } + if (!PyUnicode_Check(args[3])) { + _PyArg_BadArgument("SetValue", "argument 4", "str", args[3]); + goto exit; + } + if (PyUnicode_READY(args[3]) == -1) { + goto exit; + } + value_obj = args[3]; return_value = winreg_SetValue_impl(module, key, sub_key, type, value_obj); exit: @@ -1160,10 +1321,30 @@ winreg_SetValueEx(PyObject *module, PyObject *const *args, Py_ssize_t nargs) DWORD type; PyObject *value; - if (!_PyArg_ParseStack(args, nargs, "O&O&OkO:SetValueEx", - clinic_HKEY_converter, &key, _PyUnicode_WideCharString_Opt_Converter, &value_name, &reserved, &type, &value)) { + if (!_PyArg_CheckPositional("SetValueEx", nargs, 5, 5)) { + goto exit; + } + if (!clinic_HKEY_converter(args[0], &key)) { + goto exit; + } + if (args[1] == Py_None) { + value_name = NULL; + } + else if (PyUnicode_Check(args[1])) { + value_name = PyUnicode_AsWideCharString(args[1], NULL); + if (value_name == NULL) { + goto exit; + } + } + else { + _PyArg_BadArgument("SetValueEx", "argument 2", "str or None", args[1]); + goto exit; + } + reserved = args[2]; + if (!_PyLong_UnsignedLong_Converter(args[3], &type)) { goto exit; } + value = args[4]; return_value = winreg_SetValueEx_impl(module, key, value_name, reserved, type, value); exit: @@ -1274,4 +1455,4 @@ winreg_QueryReflectionKey(PyObject *module, PyObject *arg) exit: return return_value; } -/*[clinic end generated code: output=9782b1630b59e201 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=504fc17ae25a7c75 input=a9049054013a1b77]*/ diff --git a/PC/msvcrtmodule.c b/PC/msvcrtmodule.c index 1f78d99c790ff9..988d9c95aaa22e 100644 --- a/PC/msvcrtmodule.c +++ b/PC/msvcrtmodule.c @@ -38,6 +38,14 @@ class HANDLE_converter(CConverter): type = 'void *' format_unit = '"_Py_PARSE_UINTPTR"' + def parse_arg(self, argname, displayname): + return """ + {paramname} = PyLong_AsVoidPtr({argname}); + if (!{paramname} && PyErr_Occurred()) {{{{ + goto exit; + }}}} + """.format(argname=argname, paramname=self.parser_name) + class HANDLE_return_converter(CReturnConverter): type = 'void *' @@ -66,7 +74,7 @@ class wchar_t_return_converter(CReturnConverter): data.return_conversion.append( 'return_value = PyUnicode_FromOrdinal(_return_value);\n') [python start generated code]*/ -/*[python end generated code: output=da39a3ee5e6b4b0d input=d102511df3cda2eb]*/ +/*[python end generated code: output=da39a3ee5e6b4b0d input=1e8e9fa3538ec08f]*/ /*[clinic input] module msvcrt diff --git a/PC/winreg.c b/PC/winreg.c index 92d05f5144a3ca..b326c3dfd2c782 100644 --- a/PC/winreg.c +++ b/PC/winreg.c @@ -217,13 +217,11 @@ class winreg.HKEYType "PyHKEYObject *" "&PyHKEY_Type" /*[clinic end generated code: output=da39a3ee5e6b4b0d input=4c964eba3bf914d6]*/ /*[python input] -class REGSAM_converter(CConverter): +class REGSAM_converter(int_converter): type = 'REGSAM' - format_unit = 'i' -class DWORD_converter(CConverter): +class DWORD_converter(unsigned_long_converter): type = 'DWORD' - format_unit = 'k' class HKEY_converter(CConverter): type = 'HKEY' @@ -249,7 +247,7 @@ class self_return_converter(CReturnConverter): data.return_conversion.append( 'return_value = (PyObject *)_return_value;\n') [python start generated code]*/ -/*[python end generated code: output=da39a3ee5e6b4b0d input=22f7aedc6d68e80e]*/ +/*[python end generated code: output=da39a3ee5e6b4b0d input=2ebb7a4922d408d6]*/ #include "clinic/winreg.c.h" diff --git a/Programs/test_frozenmain.h b/Programs/test_frozenmain.h index 55d461c8beb809..677ce180f95fdd 100644 --- a/Programs/test_frozenmain.h +++ b/Programs/test_frozenmain.h @@ -28,15 +28,15 @@ unsigned char M_test_frozenmain[] = { 3,0,0,0,218,3,107,101,121,169,0,243,0,0,0,0, 250,18,116,101,115,116,95,102,114,111,122,101,110,109,97,105, 110,46,112,121,250,8,60,109,111,100,117,108,101,62,114,18, - 0,0,0,1,0,0,0,115,145,0,0,0,248,240,6,0, - 1,11,128,10,128,10,128,10,216,0,24,208,0,24,208,0, - 24,208,0,24,224,0,5,128,5,208,6,26,212,0,27,208, - 0,27,216,0,5,128,5,128,106,144,35,151,40,145,40,212, - 0,27,208,0,27,216,9,38,208,9,26,215,9,38,209,9, - 38,212,9,40,168,24,212,9,50,128,6,240,2,6,12,2, - 240,0,7,1,42,241,0,7,1,42,128,67,240,14,0,5, - 10,128,69,208,10,40,144,67,208,10,40,208,10,40,152,54, - 160,35,156,59,208,10,40,208,10,40,212,4,41,208,4,41, - 208,4,41,240,15,7,1,42,240,0,7,1,42,114,16,0, - 0,0, + 0,0,0,1,0,0,0,115,149,0,0,0,240,3,1,1, + 1,240,8,0,1,11,128,10,128,10,128,10,216,0,24,208, + 0,24,208,0,24,208,0,24,224,0,5,128,5,208,6,26, + 212,0,27,208,0,27,216,0,5,128,5,128,106,144,35,151, + 40,145,40,212,0,27,208,0,27,216,9,38,208,9,26,215, + 9,38,209,9,38,212,9,40,168,24,212,9,50,128,6,240, + 2,6,12,2,240,0,7,1,42,241,0,7,1,42,128,67, + 240,14,0,5,10,128,69,208,10,40,144,67,208,10,40,208, + 10,40,152,54,160,35,156,59,208,10,40,208,10,40,212,4, + 41,208,4,41,208,4,41,240,15,7,1,42,240,0,7,1, + 42,114,16,0,0,0, }; diff --git a/Python/compile.c b/Python/compile.c index 5ae1e345201ce4..77176893f60c5c 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -1759,7 +1759,7 @@ compiler_enter_scope(struct compiler *c, identifier name, c->u->u_curblock = block; if (u->u_scope_type == COMPILER_SCOPE_MODULE) { - c->u->u_loc.lineno = -1; + c->u->u_loc.lineno = 0; } else { if (!compiler_set_qualname(c)) @@ -1767,6 +1767,9 @@ compiler_enter_scope(struct compiler *c, identifier name, } ADDOP_I(c, RESUME, 0); + if (u->u_scope_type == COMPILER_SCOPE_MODULE) { + c->u->u_loc.lineno = -1; + } return 1; } diff --git a/configure b/configure index 9144ee19036178..8d0ba9740b8eaf 100755 --- a/configure +++ b/configure @@ -664,6 +664,8 @@ MODULE_NIS_FALSE MODULE_NIS_TRUE MODULE__GDBM_FALSE MODULE__GDBM_TRUE +MODULE__DBM_FALSE +MODULE__DBM_TRUE MODULE__DECIMAL_FALSE MODULE__DECIMAL_TRUE MODULE__CTYPES_FALSE @@ -14040,7 +14042,6 @@ LIBS=$save_LIBS -# check for _dbmmodule.c dependencies for ac_header in ndbm.h do : ac_fn_c_check_header_mongrel "$LINENO" "ndbm.h" "ac_cv_header_ndbm_h" "$ac_includes_default" @@ -14049,14 +14050,18 @@ if test "x$ac_cv_header_ndbm_h" = xyes; then : #define HAVE_NDBM_H 1 _ACEOF - LIBS_SAVE="$LIBS" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dbm_open in -lndbm" >&5 -$as_echo_n "checking for dbm_open in -lndbm... " >&6; } -if ${ac_cv_lib_ndbm_dbm_open+:} false; then : + save_CFLAGS=$CFLAGS +save_CPPFLAGS=$CPPFLAGS +save_LDFLAGS=$LDFLAGS +save_LIBS=$LIBS + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing dbm_open" >&5 +$as_echo_n "checking for library containing dbm_open... " >&6; } +if ${ac_cv_search_dbm_open+:} false; then : $as_echo_n "(cached) " >&6 else - ac_check_lib_save_LIBS=$LIBS -LIBS="-lndbm $LIBS" + ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -14075,81 +14080,73 @@ return dbm_open (); return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_ndbm_dbm_open=yes -else - ac_cv_lib_ndbm_dbm_open=no +for ac_lib in '' ndbm gdbm_compat; do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + fi + if ac_fn_c_try_link "$LINENO"; then : + ac_cv_search_dbm_open=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ndbm_dbm_open" >&5 -$as_echo "$ac_cv_lib_ndbm_dbm_open" >&6; } -if test "x$ac_cv_lib_ndbm_dbm_open" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_LIBNDBM 1 -_ACEOF - - LIBS="-lndbm $LIBS" - + conftest$ac_exeext + if ${ac_cv_search_dbm_open+:} false; then : + break fi +done +if ${ac_cv_search_dbm_open+:} false; then : - LIBS="$LIBS_SAVE" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dbm_open in -lgdbm_compat" >&5 -$as_echo_n "checking for dbm_open in -lgdbm_compat... " >&6; } -if ${ac_cv_lib_gdbm_compat_dbm_open+:} false; then : - $as_echo_n "(cached) " >&6 else - ac_check_lib_save_LIBS=$LIBS -LIBS="-lgdbm_compat $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char dbm_open (); -int -main () -{ -return dbm_open (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_gdbm_compat_dbm_open=yes -else - ac_cv_lib_gdbm_compat_dbm_open=no + ac_cv_search_dbm_open=no fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_gdbm_compat_dbm_open" >&5 -$as_echo "$ac_cv_lib_gdbm_compat_dbm_open" >&6; } -if test "x$ac_cv_lib_gdbm_compat_dbm_open" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_LIBGDBM_COMPAT 1 -_ACEOF - - LIBS="-lgdbm_compat $LIBS" +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_dbm_open" >&5 +$as_echo "$ac_cv_search_dbm_open" >&6; } +ac_res=$ac_cv_search_dbm_open +if test "$ac_res" != no; then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi - LIBS="$LIBS_SAVE" + +CFLAGS=$save_CFLAGS +CPPFLAGS=$save_CPPFLAGS +LDFLAGS=$save_LDFLAGS +LIBS=$save_LIBS + + fi done -# "gdbm-ndbm.h" and "gdbm/ndbm.h" are both normalized to "gdbm_ndbm_h" -# unset ac_cv_header_gdbm_ndbm_h to prevent false positive cache hits. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ndbm presence and linker args" >&5 +$as_echo_n "checking for ndbm presence and linker args... " >&6; } +case $ac_cv_search_dbm_open in #( + *ndbm*|*gdbm_compat*) : + + dbm_ndbm="$ac_cv_search_dbm_open" + have_ndbm=yes + ;; #( + none*) : + + dbm_ndbm="" + have_ndbm=yes + ;; #( + no) : + have_ndbm=no + ;; #( + *) : + ;; +esac +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_ndbm ($dbm_ndbm)" >&5 +$as_echo "$have_ndbm ($dbm_ndbm)" >&6; } + { ac_cv_header_gdbm_ndbm_h=; unset ac_cv_header_gdbm_ndbm_h;} if ${ac_cv_header_gdbm_slash_ndbm_h+:} false; then : $as_echo_n "(cached) " >&6 @@ -14202,14 +14199,18 @@ fi { ac_cv_header_gdbm_ndbm_h=; unset ac_cv_header_gdbm_ndbm_h;} if test "$ac_cv_header_gdbm_slash_ndbm_h" = yes -o "$ac_cv_header_gdbm_dash_ndbm_h" = yes; then - LIBS_SAVE="$LIBS" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dbm_open in -lgdbm_compat" >&5 -$as_echo_n "checking for dbm_open in -lgdbm_compat... " >&6; } -if ${ac_cv_lib_gdbm_compat_dbm_open+:} false; then : + save_CFLAGS=$CFLAGS +save_CPPFLAGS=$CPPFLAGS +save_LDFLAGS=$LDFLAGS +save_LIBS=$LIBS + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing dbm_open" >&5 +$as_echo_n "checking for library containing dbm_open... " >&6; } +if ${ac_cv_search_dbm_open+:} false; then : $as_echo_n "(cached) " >&6 else - ac_check_lib_save_LIBS=$LIBS -LIBS="-lgdbm_compat $LIBS" + ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -14228,27 +14229,45 @@ return dbm_open (); return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_gdbm_compat_dbm_open=yes -else - ac_cv_lib_gdbm_compat_dbm_open=no +for ac_lib in '' gdbm_compat; do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + fi + if ac_fn_c_try_link "$LINENO"; then : + ac_cv_search_dbm_open=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS + conftest$ac_exeext + if ${ac_cv_search_dbm_open+:} false; then : + break fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_gdbm_compat_dbm_open" >&5 -$as_echo "$ac_cv_lib_gdbm_compat_dbm_open" >&6; } -if test "x$ac_cv_lib_gdbm_compat_dbm_open" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_LIBGDBM_COMPAT 1 -_ACEOF +done +if ${ac_cv_search_dbm_open+:} false; then : - LIBS="-lgdbm_compat $LIBS" +else + ac_cv_search_dbm_open=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_dbm_open" >&5 +$as_echo "$ac_cv_search_dbm_open" >&6; } +ac_res=$ac_cv_search_dbm_open +if test "$ac_res" != no; then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi - LIBS="$LIBS_SAVE" + +CFLAGS=$save_CFLAGS +CPPFLAGS=$save_CPPFLAGS +LDFLAGS=$save_LDFLAGS +LIBS=$save_LIBS + + fi # Check for libdb >= 5 with dbm_open() @@ -14267,16 +14286,21 @@ if ${ac_cv_have_libdb+:} false; then : $as_echo_n "(cached) " >&6 else - LIBS_SAVE="$LIBS" - LIBS="$LIBS -ldb" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext + save_CFLAGS=$CFLAGS +save_CPPFLAGS=$CPPFLAGS +save_LDFLAGS=$LDFLAGS +save_LIBS=$LIBS + + + LIBS="$LIBS -ldb" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ - #define DB_DBM_HSEARCH 1 - #include - #if DB_VERSION_MAJOR < 5 - #error "dh.h: DB_VERSION_MAJOR < 5 is not supported." - #endif + #define DB_DBM_HSEARCH 1 + #include + #if DB_VERSION_MAJOR < 5 + #error "dh.h: DB_VERSION_MAJOR < 5 is not supported." + #endif int main () @@ -14294,7 +14318,13 @@ else fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext - LIBS="$LIBS_SAVE" + +CFLAGS=$save_CFLAGS +CPPFLAGS=$save_CPPFLAGS +LDFLAGS=$save_LDFLAGS +LIBS=$save_LIBS + + fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_libdb" >&5 @@ -14349,6 +14379,43 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_dbmliborder" >&5 $as_echo "$with_dbmliborder" >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for _dbm module CFLAGS and LIBS" >&5 +$as_echo_n "checking for _dbm module CFLAGS and LIBS... " >&6; } +have_dbm=no +as_save_IFS=$IFS +IFS=: +for db in $with_dbmliborder; do + case "$db" in + ndbm) + if test "$have_ndbm" = yes; then + DBM_CFLAGS="-DUSE_NDBM" + DBM_LIBS="$dbm_ndbm" + have_dbm=yes + break + fi + ;; + gdbm) + if test "$have_gdbm_compat" = yes; then + DBM_CFLAGS="-DUSE_GDBM_COMPAT" + DBM_LIBS="-lgdbm_compat" + have_dbm=yes + break + fi + ;; + bdb) + if test "$ac_cv_have_libdb" = yes; then + DBM_CFLAGS="-DUSE_BERKDB" + DBM_LIBS="-ldb" + have_dbm=yes + break + fi + ;; + esac +done +IFS=$as_save_IFS +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $DBM_CFLAGS $DBM_LIBS" >&5 +$as_echo "$DBM_CFLAGS $DBM_LIBS" >&6; } + # Templates for things AC_DEFINEd more than once. # For a single AC_DEFINE, no template is needed. @@ -24604,6 +24671,40 @@ fi $as_echo "$py_cv_module__decimal" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module _dbm" >&5 +$as_echo_n "checking for stdlib extension module _dbm... " >&6; } + if test "$py_cv_module__dbm" != "n/a"; then : + + if test -n "$with_dbmliborder"; then : + if test "$have_dbm" != "no"; then : + py_cv_module__dbm=yes +else + py_cv_module__dbm=missing +fi +else + py_cv_module__dbm=disabled +fi + +fi + as_fn_append MODULE_BLOCK "MODULE__DBM_STATE=$py_cv_module__dbm$as_nl" + if test "x$py_cv_module__dbm" = xyes; then : + + as_fn_append MODULE_BLOCK "MODULE__DBM_CFLAGS=$DBM_CFLAGS$as_nl" + as_fn_append MODULE_BLOCK "MODULE__DBM_LDFLAGS=$DBM_LIBS$as_nl" + +fi + if test "$py_cv_module__dbm" = yes; then + MODULE__DBM_TRUE= + MODULE__DBM_FALSE='#' +else + MODULE__DBM_TRUE='#' + MODULE__DBM_FALSE= +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $py_cv_module__dbm" >&5 +$as_echo "$py_cv_module__dbm" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module _gdbm" >&5 $as_echo_n "checking for stdlib extension module _gdbm... " >&6; } if test "$py_cv_module__gdbm" != "n/a"; then : @@ -25622,6 +25723,10 @@ if test -z "${MODULE__DECIMAL_TRUE}" && test -z "${MODULE__DECIMAL_FALSE}"; then as_fn_error $? "conditional \"MODULE__DECIMAL\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi +if test -z "${MODULE__DBM_TRUE}" && test -z "${MODULE__DBM_FALSE}"; then + as_fn_error $? "conditional \"MODULE__DBM\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi if test -z "${MODULE__GDBM_TRUE}" && test -z "${MODULE__GDBM_FALSE}"; then as_fn_error $? "conditional \"MODULE__GDBM\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 diff --git a/configure.ac b/configure.ac index 12ae2ae8d87eb3..b03ead3bdefa04 100644 --- a/configure.ac +++ b/configure.ac @@ -3956,17 +3956,30 @@ WITH_SAVE_ENV([ ], [have_gdbm=no]) ]) -# check for _dbmmodule.c dependencies +dnl check for _dbmmodule.c dependencies +dnl ndbm, gdbm_compat, libdb AC_CHECK_HEADERS([ndbm.h], [ - LIBS_SAVE="$LIBS" - AC_CHECK_LIB([ndbm], [dbm_open]) - LIBS="$LIBS_SAVE" - AC_CHECK_LIB([gdbm_compat], [dbm_open]) - LIBS="$LIBS_SAVE" + WITH_SAVE_ENV([ + AC_SEARCH_LIBS([dbm_open], [ndbm gdbm_compat]) + ]) ]) -# "gdbm-ndbm.h" and "gdbm/ndbm.h" are both normalized to "gdbm_ndbm_h" -# unset ac_cv_header_gdbm_ndbm_h to prevent false positive cache hits. +AC_MSG_CHECKING([for ndbm presence and linker args]) +AS_CASE([$ac_cv_search_dbm_open], + [*ndbm*|*gdbm_compat*], [ + dbm_ndbm="$ac_cv_search_dbm_open" + have_ndbm=yes + ], + [none*], [ + dbm_ndbm="" + have_ndbm=yes + ], + [no], [have_ndbm=no] +) +AC_MSG_RESULT([$have_ndbm ($dbm_ndbm)]) + +dnl "gdbm-ndbm.h" and "gdbm/ndbm.h" are both normalized to "gdbm_ndbm_h" +dnl unset ac_cv_header_gdbm_ndbm_h to prevent false positive cache hits. AS_UNSET([ac_cv_header_gdbm_ndbm_h]) AC_CACHE_VAL([ac_cv_header_gdbm_slash_ndbm_h], [ AC_CHECK_HEADER( @@ -3991,26 +4004,26 @@ AS_VAR_IF([ac_cv_header_gdbm_dash_ndbm_h], [yes], [ AS_UNSET([ac_cv_header_gdbm_ndbm_h]) if test "$ac_cv_header_gdbm_slash_ndbm_h" = yes -o "$ac_cv_header_gdbm_dash_ndbm_h" = yes; then - LIBS_SAVE="$LIBS" - AC_CHECK_LIB([gdbm_compat], [dbm_open]) - LIBS="$LIBS_SAVE" + WITH_SAVE_ENV([ + AC_SEARCH_LIBS([dbm_open], [gdbm_compat]) + ]) fi # Check for libdb >= 5 with dbm_open() # db.h re-defines the name of the function AC_CHECK_HEADERS([db.h], [ AC_CACHE_CHECK([for libdb], [ac_cv_have_libdb], [ - LIBS_SAVE="$LIBS" - LIBS="$LIBS -ldb" - AC_LINK_IFELSE([AC_LANG_PROGRAM([ - #define DB_DBM_HSEARCH 1 - #include - #if DB_VERSION_MAJOR < 5 - #error "dh.h: DB_VERSION_MAJOR < 5 is not supported." - #endif - ], [DBM *dbm = dbm_open(NULL, 0, 0)]) - ], [ac_cv_have_libdb=yes], [ac_cv_have_libdb=no]) - LIBS="$LIBS_SAVE" + WITH_SAVE_ENV([ + LIBS="$LIBS -ldb" + AC_LINK_IFELSE([AC_LANG_PROGRAM([ + #define DB_DBM_HSEARCH 1 + #include + #if DB_VERSION_MAJOR < 5 + #error "dh.h: DB_VERSION_MAJOR < 5 is not supported." + #endif + ], [DBM *dbm = dbm_open(NULL, 0, 0)]) + ], [ac_cv_have_libdb=yes], [ac_cv_have_libdb=no]) + ]) ]) AS_VAR_IF([ac_cv_have_libdb], [yes], [ AC_DEFINE([HAVE_LIBDB], [1], [Define to 1 if you have the `db' library (-ldb).]) @@ -4018,7 +4031,7 @@ AC_CHECK_HEADERS([db.h], [ ]) # Check for --with-dbmliborder -AC_MSG_CHECKING(for --with-dbmliborder) +AC_MSG_CHECKING([for --with-dbmliborder]) AC_ARG_WITH(dbmliborder, AS_HELP_STRING([--with-dbmliborder=db1:db2:...], [override order to check db backends for dbm; a valid value is a colon separated string with the backend names `ndbm', `gdbm' and `bdb'.]), [], [with_dbmliborder=gdbm:ndbm:bdb]) @@ -4038,7 +4051,42 @@ IFS=$as_save_IFS AS_VAR_IF([with_dbmliborder], [error], [ AC_MSG_ERROR([proper usage is --with-dbmliborder=db1:db2:... (gdbm:ndbm:bdb)]) ]) -AC_MSG_RESULT($with_dbmliborder) +AC_MSG_RESULT([$with_dbmliborder]) + +AC_MSG_CHECKING([for _dbm module CFLAGS and LIBS]) +have_dbm=no +as_save_IFS=$IFS +IFS=: +for db in $with_dbmliborder; do + case "$db" in + ndbm) + if test "$have_ndbm" = yes; then + DBM_CFLAGS="-DUSE_NDBM" + DBM_LIBS="$dbm_ndbm" + have_dbm=yes + break + fi + ;; + gdbm) + if test "$have_gdbm_compat" = yes; then + DBM_CFLAGS="-DUSE_GDBM_COMPAT" + DBM_LIBS="-lgdbm_compat" + have_dbm=yes + break + fi + ;; + bdb) + if test "$ac_cv_have_libdb" = yes; then + DBM_CFLAGS="-DUSE_BERKDB" + DBM_LIBS="-ldb" + have_dbm=yes + break + fi + ;; + esac +done +IFS=$as_save_IFS +AC_MSG_RESULT([$DBM_CFLAGS $DBM_LIBS]) # Templates for things AC_DEFINEd more than once. # For a single AC_DEFINE, no template is needed. @@ -6940,7 +6988,9 @@ PY_STDLIB_MOD([_ctypes], dnl PY_STDLIB_MOD([_curses], [], [], [], []) dnl PY_STDLIB_MOD([_curses_panel], [], [], [], []) PY_STDLIB_MOD([_decimal], [], [], [$LIBMPDEC_CFLAGS], [$LIBMPDEC_LDFLAGS]) -dnl PY_STDLIB_MOD([_dbm], [], [], [], []) +PY_STDLIB_MOD([_dbm], + [test -n "$with_dbmliborder"], [test "$have_dbm" != "no"], + [$DBM_CFLAGS], [$DBM_LIBS]) PY_STDLIB_MOD([_gdbm], [test "$have_gdbm_dbmliborder" = yes], [test "$have_gdbm" = yes], [$GDBM_CFLAGS], [$GDBM_LIBS]) diff --git a/pyconfig.h.in b/pyconfig.h.in index 15933e75b1b079..b05ddd41c2bba3 100644 --- a/pyconfig.h.in +++ b/pyconfig.h.in @@ -640,18 +640,12 @@ /* Define to 1 if you have the `dld' library (-ldld). */ #undef HAVE_LIBDLD -/* Define to 1 if you have the `gdbm_compat' library (-lgdbm_compat). */ -#undef HAVE_LIBGDBM_COMPAT - /* Define to 1 if you have the `ieee' library (-lieee). */ #undef HAVE_LIBIEEE /* Define to 1 if you have the header file. */ #undef HAVE_LIBINTL_H -/* Define to 1 if you have the `ndbm' library (-lndbm). */ -#undef HAVE_LIBNDBM - /* Define to build the readline module. */ #undef HAVE_LIBREADLINE diff --git a/setup.py b/setup.py index 843ec35effe109..cc11dedee1b2e2 100644 --- a/setup.py +++ b/setup.py @@ -1163,77 +1163,7 @@ def detect_crypt(self): self.addext(Extension('_crypt', ['_cryptmodule.c'])) def detect_dbm_gdbm(self): - # Modules that provide persistent dictionary-like semantics. You will - # probably want to arrange for at least one of them to be available on - # your machine, though none are defined by default because of library - # dependencies. The Python module dbm/__init__.py provides an - # implementation independent wrapper for these; dbm/dumb.py provides - # similar functionality (but slower of course) implemented in Python. - - dbm_setup_debug = False # verbose debug prints from this script? - dbm_order = ['gdbm'] - - # libdb, gdbm and ndbm headers and libraries - have_ndbm_h = sysconfig.get_config_var("HAVE_NDBM_H") - have_gdbm_ndbm_h = sysconfig.get_config_var("HAVE_GDBM_NDBM_H") - have_gdbm_dash_ndbm_h = sysconfig.get_config_var("HAVE_GDBM_DASH_NDBM_H") - have_libndbm = sysconfig.get_config_var("HAVE_LIBNDBM") - have_libgdbm_compat = sysconfig.get_config_var("HAVE_LIBGDBM_COMPAT") - have_libdb = sysconfig.get_config_var("HAVE_LIBDB") - - # The standard Unix dbm module: - if not CYGWIN: - config_args = [arg.strip("'") - for arg in sysconfig.get_config_var("CONFIG_ARGS").split()] - dbm_args = [arg for arg in config_args - if arg.startswith('--with-dbmliborder=')] - if dbm_args: - dbm_order = [arg.split('=')[-1] for arg in dbm_args][-1].split(":") - else: - dbm_order = "gdbm:ndbm:bdb".split(":") - dbmext = None - for cand in dbm_order: - if cand == "ndbm": - if have_ndbm_h: - # Some systems have -lndbm, others have -lgdbm_compat, - # others don't have either - if have_libndbm: - ndbm_libs = ['ndbm'] - elif have_libgdbm_compat: - ndbm_libs = ['gdbm_compat'] - else: - ndbm_libs = [] - if dbm_setup_debug: print("building dbm using ndbm") - dbmext = Extension( - '_dbm', ['_dbmmodule.c'], - define_macros=[('USE_NDBM', None)], - libraries=ndbm_libs - ) - break - elif cand == "gdbm": - # dbm_open() is provided by libgdbm_compat, which wraps libgdbm - if have_libgdbm_compat and (have_gdbm_ndbm_h or have_gdbm_dash_ndbm_h): - if dbm_setup_debug: print("building dbm using gdbm") - dbmext = Extension( - '_dbm', ['_dbmmodule.c'], - define_macros=[('USE_GDBM_COMPAT', None)], - libraries=['gdbm_compat'] - ) - break - elif cand == "bdb": - if have_libdb: - if dbm_setup_debug: print("building dbm using bdb") - dbmext = Extension( - '_dbm', ['_dbmmodule.c'], - define_macros=[('USE_BERKDB', None)], - libraries=['db'] - ) - break - if dbmext is not None: - self.add(dbmext) - else: - self.missing.append('_dbm') - + self.addext(Extension('_dbm', ['_dbmmodule.c'])) # Anthony Baxter's gdbm module. GNU dbm(3) will require -lgdbm: self.addext(Extension('_gdbm', ['_gdbmmodule.c']))