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 window 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 codeFound 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']))