[Python-checkins] [3.13] gh-132354: document return value for `asyncio.Task.cancel` (GH-132374) (#132465)
https://github.com/python/cpython/commit/ff66901d8a8753c11d4411e62376b26f17aa90cf commit: ff66901d8a8753c11d4411e62376b26f17aa90cf branch: 3.13 author: Miss Islington (bot) <[email protected]> committer: kumaraditya303 date: 2025-04-13T07:41:26Z summary: [3.13] gh-132354: document return value for `asyncio.Task.cancel` (GH-132374) (#132465) gh-132354: document return value for `asyncio.Task.cancel` (GH-132374) (cherry picked from commit 64b066ad298506f715647c9a2524c9fbbc764cc2) Co-authored-by: Felix Scherz files: M Doc/library/asyncio-task.rst M Misc/ACKS diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst index ddba9f20a3c03b..6c83ab94af3955 100644 --- a/Doc/library/asyncio-task.rst +++ b/Doc/library/asyncio-task.rst @@ -1336,7 +1336,10 @@ Task Object Request the Task to be cancelled. - This arranges for a :exc:`CancelledError` exception to be thrown + If the Task is already *done* or *cancelled*, return ``False``, + otherwise, return ``True``. + + The method arranges for a :exc:`CancelledError` exception to be thrown into the wrapped coroutine on the next cycle of the event loop. The coroutine then has a chance to clean up or even deny the diff --git a/Misc/ACKS b/Misc/ACKS index f236c6400c2b30..3adb168f33c40a 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1644,6 +1644,7 @@ Andreas Schawo Neil Schemenauer David Scherer Wolfgang Scherer +Felix Scherz Hynek Schlawack Bob Schmertz Gregor Schmid ___ Python-checkins mailing list -- [email protected] To unsubscribe send an email to [email protected] https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: [email protected]
[Python-checkins] gh-123471: Make concurrent iteration over itertools.repeat safe under free-threading (#131247)
https://github.com/python/cpython/commit/9d127e83b9e6fbbb50ee047a0444c189a8770ada
commit: 9d127e83b9e6fbbb50ee047a0444c189a8770ada
branch: main
author: Pieter Eendebak
committer: kumaraditya303
date: 2025-04-13T13:26:58+05:30
summary:
gh-123471: Make concurrent iteration over itertools.repeat safe under
free-threading (#131247)
files:
A Misc/NEWS.d/next/Library/2025-03-14-14-18-49.gh-issue-123471.sduBKk.rst
M Modules/itertoolsmodule.c
diff --git
a/Misc/NEWS.d/next/Library/2025-03-14-14-18-49.gh-issue-123471.sduBKk.rst
b/Misc/NEWS.d/next/Library/2025-03-14-14-18-49.gh-issue-123471.sduBKk.rst
new file mode 100644
index 00..b3829c72e5cad7
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2025-03-14-14-18-49.gh-issue-123471.sduBKk.rst
@@ -0,0 +1 @@
+Make concurrent iterations over :class:`itertools.repeat` safe under
free-threading.
diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c
index c0448efed19a44..943c1e8607b38f 100644
--- a/Modules/itertoolsmodule.c
+++ b/Modules/itertoolsmodule.c
@@ -3628,10 +3628,14 @@ static PyObject *
repeat_next(PyObject *op)
{
repeatobject *ro = repeatobject_CAST(op);
-if (ro->cnt == 0)
+Py_ssize_t cnt = FT_ATOMIC_LOAD_SSIZE_RELAXED(ro->cnt);
+if (cnt == 0) {
return NULL;
-if (ro->cnt > 0)
-ro->cnt--;
+}
+if (cnt > 0) {
+cnt--;
+FT_ATOMIC_STORE_SSIZE_RELAXED(ro->cnt, cnt);
+}
return Py_NewRef(ro->element);
}
___
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: [email protected]
[Python-checkins] gh-129169: update `asyncio.ensure_future` docs to suggest taskgroups
https://github.com/python/cpython/commit/00cf5eacc52d4790c23a24c835fb6b048cb27d8c commit: 00cf5eacc52d4790c23a24c835fb6b048cb27d8c branch: main author: Case Zumbrum <[email protected]> committer: kumaraditya303 date: 2025-04-13T07:59:22Z summary: gh-129169: update `asyncio.ensure_future` docs to suggest taskgroups Co-authored-by: Kumar Aditya files: M Doc/library/asyncio-future.rst diff --git a/Doc/library/asyncio-future.rst b/Doc/library/asyncio-future.rst index 9dce0731411940..32771ba72e0002 100644 --- a/Doc/library/asyncio-future.rst +++ b/Doc/library/asyncio-future.rst @@ -51,12 +51,13 @@ Future Functions .. important:: - See also the :func:`create_task` function which is the - preferred way for creating new Tasks. - Save a reference to the result of this function, to avoid a task disappearing mid-execution. + See also the :func:`create_task` function which is the + preferred way for creating new tasks or use :class:`asyncio.TaskGroup` + which keeps reference to the task internally. + .. versionchanged:: 3.5.1 The function accepts any :term:`awaitable` object. ___ Python-checkins mailing list -- [email protected] To unsubscribe send an email to [email protected] https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: [email protected]
[Python-checkins] gh-132099: Fix documentation for the BTPROTO_HCI protocol (GH-132118)
https://github.com/python/cpython/commit/1d97488c957f4595f8c3ea42e24c1995b23e39d4 commit: 1d97488c957f4595f8c3ea42e24c1995b23e39d4 branch: main author: Serhiy Storchaka committer: serhiy-storchaka date: 2025-04-13T18:39:22+03:00 summary: gh-132099: Fix documentation for the BTPROTO_HCI protocol (GH-132118) files: M Doc/library/socket.rst diff --git a/Doc/library/socket.rst b/Doc/library/socket.rst index 970698c5f644a2..2e38101c01d89d 100644 --- a/Doc/library/socket.rst +++ b/Doc/library/socket.rst @@ -149,19 +149,25 @@ created. Socket addresses are represented as follows: :const:`BDADDR_LE_RANDOM`. .. versionchanged:: 3.14 - Added ``cid`` and ``bdaddr_type`` fields. + Added ``cid`` and ``bdaddr_type`` fields. - :const:`BTPROTO_RFCOMM` accepts ``(bdaddr, channel)`` where ``bdaddr`` is the Bluetooth address as a string and ``channel`` is an integer. - - :const:`BTPROTO_HCI` accepts ``(device_id,)`` where ``device_id`` is -either an integer or a string with the Bluetooth address of the -interface. (This depends on your OS; NetBSD and DragonFlyBSD expect -a Bluetooth address while everything else expects an integer.) + - :const:`BTPROTO_HCI` accepts a format that depends on your OS. + +- On Linux it accepts a tuple ``(device_id,)`` where ``device_id`` + is an integer specifying the number of the Bluetooth device. +- On FreeBSD, NetBSD and DragonFly BSD it accepts ``bdaddr`` where ``bdaddr`` + is a :class:`bytes` object containing the Bluetooth address in a + string format. (ex. ``b'12:23:34:45:56:67'``) .. versionchanged:: 3.2 NetBSD and DragonFlyBSD support added. +.. versionchanged:: 3.13.3 + FreeBSD support added. + - :const:`BTPROTO_SCO` accepts ``bdaddr`` where ``bdaddr`` is a :class:`bytes` object containing the Bluetooth address in a string format. (ex. ``b'12:23:34:45:56:67'``) @@ -662,16 +668,15 @@ Constants These constants describe the Bluetooth address type when binding or connecting a :const:`BTPROTO_L2CAP` socket. -.. versionadded:: 3.14 + .. versionadded:: 3.14 .. data:: HCI_FILTER HCI_TIME_STAMP HCI_DATA_DIR - For use with :const:`BTPROTO_HCI`. :const:`HCI_FILTER` is not - available for NetBSD or DragonFlyBSD. :const:`HCI_TIME_STAMP` and - :const:`HCI_DATA_DIR` are not available for FreeBSD, NetBSD, or - DragonFlyBSD. + For use with :const:`BTPROTO_HCI`. :const:`!HCI_FILTER` is only + available on Linux and FreeBSD. :const:`!HCI_TIME_STAMP` and + :const:`!HCI_DATA_DIR` are only available on Linux. .. data:: AF_QIPCRTR ___ Python-checkins mailing list -- [email protected] To unsubscribe send an email to [email protected] https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: [email protected]
[Python-checkins] [3.13] gh-132106: Ensure that running `logging.handlers.QueueListener… (GH-132471)
https://github.com/python/cpython/commit/1dcdac6e084471c14b4690ae9154b928e93a7222
commit: 1dcdac6e084471c14b4690ae9154b928e93a7222
branch: 3.13
author: Vinay Sajip
committer: vsajip
date: 2025-04-13T13:00:50+01:00
summary:
[3.13] gh-132106: Ensure that running `logging.handlers.QueueListener…
(GH-132471)
Cherry-picked using 5863cd70b8782313b52bb8c71a4127d7ea4c50e9
files:
A Misc/NEWS.d/next/Library/2025-04-12-09-30-24.gh-issue-132106.OxUds3.rst
M Doc/library/logging.handlers.rst
M Lib/logging/handlers.py
M Lib/test/test_logging.py
diff --git a/Doc/library/logging.handlers.rst b/Doc/library/logging.handlers.rst
index 5a081f9e7add99..e63c253e123552 100644
--- a/Doc/library/logging.handlers.rst
+++ b/Doc/library/logging.handlers.rst
@@ -1172,6 +1172,10 @@ possible, while any potentially slow operations (such as
sending an email via
This starts up a background thread to monitor the queue for
LogRecords to process.
+ .. versionchanged:: next
+ Raises :exc:`RuntimeError` if called and the listener is already
+ running.
+
.. method:: stop()
Stops the listener.
diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py
index da9c59c119f3db..d3ea06c731ef89 100644
--- a/Lib/logging/handlers.py
+++ b/Lib/logging/handlers.py
@@ -1545,6 +1545,9 @@ def start(self):
This starts up a background thread to monitor the queue for
LogRecords to process.
"""
+if self._thread is not None:
+raise RuntimeError("Listener already started")
+
self._thread = t = threading.Thread(target=self._monitor)
t.daemon = True
t.start()
diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py
index 678c23dad67faa..58e0381c4aa934 100644
--- a/Lib/test/test_logging.py
+++ b/Lib/test/test_logging.py
@@ -4300,8 +4300,6 @@ def test_formatting(self):
self.assertEqual(formatted_msg, log_record.msg)
self.assertEqual(formatted_msg, log_record.message)
[email protected](hasattr(logging.handlers, 'QueueListener'),
- 'logging.handlers.QueueListener required for this
test')
def test_queue_listener(self):
handler = TestHandler(support.Matcher())
listener = logging.handlers.QueueListener(self.queue, handler)
@@ -4336,8 +4334,18 @@ def test_queue_listener(self):
self.assertTrue(handler.matches(levelno=logging.CRITICAL, message='6'))
handler.close()
[email protected](hasattr(logging.handlers, 'QueueListener'),
- 'logging.handlers.QueueListener required for this
test')
+# doesn't hurt to call stop() more than once.
+listener.stop()
+self.assertIsNone(listener._thread)
+
+def test_queue_listener_multi_start(self):
+handler = TestHandler(support.Matcher())
+listener = logging.handlers.QueueListener(self.queue, handler)
+listener.start()
+self.assertRaises(RuntimeError, listener.start)
+listener.stop()
+self.assertIsNone(listener._thread)
+
def test_queue_listener_with_StreamHandler(self):
# Test that traceback and stack-info only appends once (bpo-34334,
bpo-46755).
listener = logging.handlers.QueueListener(self.queue, self.root_hdlr)
@@ -4352,8 +4360,6 @@ def test_queue_listener_with_StreamHandler(self):
self.assertEqual(self.stream.getvalue().strip().count('Traceback'), 1)
self.assertEqual(self.stream.getvalue().strip().count('Stack'), 1)
[email protected](hasattr(logging.handlers, 'QueueListener'),
- 'logging.handlers.QueueListener required for this
test')
def test_queue_listener_with_multiple_handlers(self):
# Test that queue handler format doesn't affect other handler formats
(bpo-35726).
self.que_hdlr.setFormatter(self.root_formatter)
diff --git
a/Misc/NEWS.d/next/Library/2025-04-12-09-30-24.gh-issue-132106.OxUds3.rst
b/Misc/NEWS.d/next/Library/2025-04-12-09-30-24.gh-issue-132106.OxUds3.rst
new file mode 100644
index 00..b6d58a29f9b42f
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2025-04-12-09-30-24.gh-issue-132106.OxUds3.rst
@@ -0,0 +1,2 @@
+:meth:`QueueListener.start ` now
+raises a :exc:`RuntimeError` if the listener is already started.
___
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: [email protected]
[Python-checkins] GH-125866: Support complete "file:" URLs in urllib (#132378)
https://github.com/python/cpython/commit/ccad61e35d240972d14f993507566706fbf419f1 commit: ccad61e35d240972d14f993507566706fbf419f1 branch: main author: Barney Gale committer: barneygale date: 2025-04-14T01:49:02+01:00 summary: GH-125866: Support complete "file:" URLs in urllib (#132378) Add optional *add_scheme* argument to `urllib.request.pathname2url()`; when set to true, a complete URL is returned. Likewise add optional *require_scheme* argument to `url2pathname()`; when set to true, a complete URL is accepted. Co-authored-by: Bénédikt Tran <[email protected]> files: A Misc/NEWS.d/next/Library/2025-04-10-21-43-04.gh-issue-125866.EZ9X8D.rst M Doc/library/urllib.request.rst M Doc/whatsnew/3.14.rst M Lib/pathlib/__init__.py M Lib/test/test_pathlib/test_pathlib.py M Lib/test/test_urllib.py M Lib/test/test_urllib2.py M Lib/test/test_urllib2net.py M Lib/urllib/request.py diff --git a/Doc/library/urllib.request.rst b/Doc/library/urllib.request.rst index edfc249eb43c78..a5f1b9b292a85a 100644 --- a/Doc/library/urllib.request.rst +++ b/Doc/library/urllib.request.rst @@ -146,16 +146,19 @@ The :mod:`urllib.request` module defines the following functions: attribute to modify its position in the handlers list. -.. function:: pathname2url(path) +.. function:: pathname2url(path, *, add_scheme=False) Convert the given local path to a ``file:`` URL. This function uses - :func:`~urllib.parse.quote` function to encode the path. For historical - reasons, the return value omits the ``file:`` scheme prefix. This example - shows the function being used on Windows:: + :func:`~urllib.parse.quote` function to encode the path. + + If *add_scheme* is false (the default), the return value omits the + ``file:`` scheme prefix. Set *add_scheme* to true to return a complete URL. + + This example shows the function being used on Windows:: >>> from urllib.request import pathname2url >>> path = 'C:\\Program Files' - >>> 'file:' + pathname2url(path) + >>> pathname2url(path, add_scheme=True) 'file:///C:/Program%20Files' .. versionchanged:: 3.14 @@ -168,17 +171,25 @@ The :mod:`urllib.request` module defines the following functions: sections. For example, the path ``/etc/hosts`` is converted to the URL ``///etc/hosts``. + .. versionchanged:: next + The *add_scheme* argument was added. + -.. function:: url2pathname(url) +.. function:: url2pathname(url, *, require_scheme=False) Convert the given ``file:`` URL to a local path. This function uses - :func:`~urllib.parse.unquote` to decode the URL. For historical reasons, - the given value *must* omit the ``file:`` scheme prefix. This example shows - the function being used on Windows:: + :func:`~urllib.parse.unquote` to decode the URL. + + If *require_scheme* is false (the default), the given value should omit a + ``file:`` scheme prefix. If *require_scheme* is set to true, the given + value should include the prefix; a :exc:`~urllib.error.URLError` is raised + if it doesn't. + + This example shows the function being used on Windows:: >>> from urllib.request import url2pathname >>> url = 'file:///C:/Program%20Files' - >>> url2pathname(url.removeprefix('file:')) + >>> url2pathname(url, require_scheme=True) 'C:\\Program Files' .. versionchanged:: 3.14 @@ -193,6 +204,9 @@ The :mod:`urllib.request` module defines the following functions: returned (as before), and on other platforms a :exc:`~urllib.error.URLError` is raised. + .. versionchanged:: next + The *require_scheme* argument was added. + .. function:: getproxies() diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst index 421d12660b7956..0e30500fc9b997 100644 --- a/Doc/whatsnew/3.14.rst +++ b/Doc/whatsnew/3.14.rst @@ -1218,16 +1218,20 @@ urllib supporting SHA-256 digest authentication as specified in :rfc:`7616`. (Contributed by Calvin Bui in :gh:`128193`.) -* Improve standards compliance when parsing and emitting ``file:`` URLs. +* Improve ergonomics and standards compliance when parsing and emitting + ``file:`` URLs. In :func:`urllib.request.url2pathname`: + - Accept a complete URL when the new *require_scheme* argument is set to +true. - Discard URL authorities that resolve to a local IP address. - Raise :exc:`~urllib.error.URLError` if a URL authority doesn't resolve -to ``localhost``, except on Windows where we return a UNC path. +to a local IP address, except on Windows where we return a UNC path. In :func:`urllib.request.pathname2url`: + - Return a complete URL when the new *add_scheme* argument is set to true. - Include an empty URL authority when a path begins with a slash. For example, the path ``/etc/hosts`` is converted to the URL ``///etc/hosts``. diff --git a/Lib/pathlib/__init__.py b/Lib/pathlib/__init__.py index 43a5440e0132ff..12cf9f579cb32d 100644 --- a/Lib
[Python-checkins] [3.13] gh-124986: Fix test_no_leaking in test_subprocess on NetBSD and FreeBSD (GH-132476) (GH-132498)
https://github.com/python/cpython/commit/ff9198dab3b66bd31d33bae674181f2d24124ea2 commit: ff9198dab3b66bd31d33bae674181f2d24124ea2 branch: 3.13 author: Miss Islington (bot) <[email protected]> committer: serhiy-storchaka date: 2025-04-14T06:38:13Z summary: [3.13] gh-124986: Fix test_no_leaking in test_subprocess on NetBSD and FreeBSD (GH-132476) (GH-132498) On platforms where the file descriptor limit is larger than FD_SETSIZE that test was always skipped (FreeBSD) or always failing (NetBSD). (cherry picked from commit f7b24ffefda839f367b048c06879df6bded128a1) Co-authored-by: Serhiy Storchaka files: M Lib/test/test_subprocess.py diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py index bf9b32c8ef..7d72737e9cb066 100644 --- a/Lib/test/test_subprocess.py +++ b/Lib/test/test_subprocess.py @@ -40,6 +40,10 @@ import grp except ImportError: grp = None +try: +import resource +except ImportError: +resource = None try: import fcntl @@ -1210,6 +1214,16 @@ def test_no_leaking(self): max_handles = 1026 # too much for most UNIX systems else: max_handles = 2050 # too much for (at least some) Windows setups +if resource: +# And if it is not too much, try to make it too much. +try: +soft, hard = resource.getrlimit(resource.RLIMIT_NOFILE) +if soft > 1024: +resource.setrlimit(resource.RLIMIT_NOFILE, (1024, hard)) +self.addCleanup(resource.setrlimit, resource.RLIMIT_NOFILE, +(soft, hard)) +except (OSError, ValueError): +pass handles = [] tmpdir = tempfile.mkdtemp() try: @@ -1224,7 +1238,9 @@ def test_no_leaking(self): else: self.skipTest("failed to reach the file descriptor limit " "(tried %d)" % max_handles) -# Close a couple of them (should be enough for a subprocess) +# Close a couple of them (should be enough for a subprocess). +# Close lower file descriptors, so select() will work. +handles.reverse() for i in range(10): os.close(handles.pop()) # Loop creating some subprocesses. If one of them leaks some fds, ___ Python-checkins mailing list -- [email protected] To unsubscribe send an email to [email protected] https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: [email protected]
[Python-checkins] [3.13] gh-132099: Fix documentation for the BTPROTO_HCI protocol (GH-132118) (GH-132482)
https://github.com/python/cpython/commit/54e1b6eef7898b79bafa912623523a5fa0b1 commit: 54e1b6eef7898b79bafa912623523a5fa0b1 branch: 3.13 author: Serhiy Storchaka committer: serhiy-storchaka date: 2025-04-13T16:27:41Z summary: [3.13] gh-132099: Fix documentation for the BTPROTO_HCI protocol (GH-132118) (GH-132482) (cherry picked from commit 1d97488c957f4595f8c3ea42e24c1995b23e39d4) files: M Doc/library/socket.rst diff --git a/Doc/library/socket.rst b/Doc/library/socket.rst index e5baa3a002a01e..52b993bd81e96b 100644 --- a/Doc/library/socket.rst +++ b/Doc/library/socket.rst @@ -143,14 +143,20 @@ created. Socket addresses are represented as follows: - :const:`BTPROTO_RFCOMM` accepts ``(bdaddr, channel)`` where ``bdaddr`` is the Bluetooth address as a string and ``channel`` is an integer. - - :const:`BTPROTO_HCI` accepts ``(device_id,)`` where ``device_id`` is -either an integer or a string with the Bluetooth address of the -interface. (This depends on your OS; NetBSD and DragonFlyBSD expect -a Bluetooth address while everything else expects an integer.) + - :const:`BTPROTO_HCI` accepts a format that depends on your OS. + +- On Linux it accepts a tuple ``(device_id,)`` where ``device_id`` + is an integer specifying the number of the Bluetooth device. +- On FreeBSD, NetBSD and DragonFly BSD it accepts ``bdaddr`` where ``bdaddr`` + is a :class:`bytes` object containing the Bluetooth address in a + string format. (ex. ``b'12:23:34:45:56:67'``) .. versionchanged:: 3.2 NetBSD and DragonFlyBSD support added. +.. versionchanged:: 3.13.3 + FreeBSD support added. + - :const:`BTPROTO_SCO` accepts ``bdaddr`` where ``bdaddr`` is a :class:`bytes` object containing the Bluetooth address in a string format. (ex. ``b'12:23:34:45:56:67'``) This protocol is not @@ -630,10 +636,9 @@ Constants HCI_TIME_STAMP HCI_DATA_DIR - For use with :const:`BTPROTO_HCI`. :const:`HCI_FILTER` is not - available for NetBSD or DragonFlyBSD. :const:`HCI_TIME_STAMP` and - :const:`HCI_DATA_DIR` are not available for FreeBSD, NetBSD, or - DragonFlyBSD. + For use with :const:`BTPROTO_HCI`. :const:`!HCI_FILTER` is only + available on Linux and FreeBSD. :const:`!HCI_TIME_STAMP` and + :const:`!HCI_DATA_DIR` are only available on Linux. .. data:: AF_QIPCRTR ___ Python-checkins mailing list -- [email protected] To unsubscribe send an email to [email protected] https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: [email protected]
[Python-checkins] gh-132111: Document dataclasses.InitVar (#132446)
https://github.com/python/cpython/commit/281fc338fdf57ef119e213bf1b2c772261c359c1 commit: 281fc338fdf57ef119e213bf1b2c772261c359c1 branch: main author: Tapeline committer: ericvsmith date: 2025-04-13T12:47:44-04:00 summary: gh-132111: Document dataclasses.InitVar (#132446) files: M Doc/library/dataclasses.rst diff --git a/Doc/library/dataclasses.rst b/Doc/library/dataclasses.rst index 0bc171da4eefc7..72612211b43d5e 100644 --- a/Doc/library/dataclasses.rst +++ b/Doc/library/dataclasses.rst @@ -344,6 +344,15 @@ Module contents Other attributes may exist, but they are private and must not be inspected or relied on. +.. class:: InitVar + + ``InitVar[T]`` type annotations describe variables that are :ref:`init-only + `. Fields annotated with :class:`!InitVar` + are considered pseudo-fields, and thus are neither returned by the + :func:`fields` function nor used in any way except adding them as + parameters to :meth:`~object.__init__` and an optional + :meth:`__post_init__`. + .. function:: fields(class_or_instance) Returns a tuple of :class:`Field` objects that define the fields for this @@ -600,8 +609,8 @@ Init-only variables Another place where :func:`@dataclass ` inspects a type annotation is to determine if a field is an init-only variable. It does this by seeing -if the type of a field is of type ``dataclasses.InitVar``. If a field -is an ``InitVar``, it is considered a pseudo-field called an init-only +if the type of a field is of type :class:`InitVar`. If a field +is an :class:`InitVar`, it is considered a pseudo-field called an init-only field. As it is not a true field, it is not returned by the module-level :func:`fields` function. Init-only fields are added as parameters to the generated :meth:`~object.__init__` method, and are passed to ___ Python-checkins mailing list -- [email protected] To unsubscribe send an email to [email protected] https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: [email protected]
[Python-checkins] [3.13] gh-132111: Document dataclasses.InitVar (GH-132446) (#132483)
https://github.com/python/cpython/commit/d021b719ed87d4ce6e03913361564c1c79215123 commit: d021b719ed87d4ce6e03913361564c1c79215123 branch: 3.13 author: Miss Islington (bot) <[email protected]> committer: ericvsmith date: 2025-04-13T16:53:40Z summary: [3.13] gh-132111: Document dataclasses.InitVar (GH-132446) (#132483) gh-132111: Document dataclasses.InitVar (GH-132446) (cherry picked from commit 281fc338fdf57ef119e213bf1b2c772261c359c1) Co-authored-by: Tapeline files: M Doc/library/dataclasses.rst diff --git a/Doc/library/dataclasses.rst b/Doc/library/dataclasses.rst index 134ba0fa9b4b9f..47b2d559989696 100644 --- a/Doc/library/dataclasses.rst +++ b/Doc/library/dataclasses.rst @@ -347,6 +347,15 @@ Module contents Other attributes may exist, but they are private and must not be inspected or relied on. +.. class:: InitVar + + ``InitVar[T]`` type annotations describe variables that are :ref:`init-only + `. Fields annotated with :class:`!InitVar` + are considered pseudo-fields, and thus are neither returned by the + :func:`fields` function nor used in any way except adding them as + parameters to :meth:`~object.__init__` and an optional + :meth:`__post_init__`. + .. function:: fields(class_or_instance) Returns a tuple of :class:`Field` objects that define the fields for this @@ -595,8 +604,8 @@ Init-only variables Another place where :func:`@dataclass ` inspects a type annotation is to determine if a field is an init-only variable. It does this by seeing -if the type of a field is of type ``dataclasses.InitVar``. If a field -is an ``InitVar``, it is considered a pseudo-field called an init-only +if the type of a field is of type :class:`InitVar`. If a field +is an :class:`InitVar`, it is considered a pseudo-field called an init-only field. As it is not a true field, it is not returned by the module-level :func:`fields` function. Init-only fields are added as parameters to the generated :meth:`~object.__init__` method, and are passed to ___ Python-checkins mailing list -- [email protected] To unsubscribe send an email to [email protected] https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: [email protected]
[Python-checkins] gh-124986: Fix test_no_leaking in test_subprocess on NetBSD and FreeBSD (GH-132476)
https://github.com/python/cpython/commit/f7b24ffefda839f367b048c06879df6bded128a1
commit: f7b24ffefda839f367b048c06879df6bded128a1
branch: main
author: Serhiy Storchaka
committer: serhiy-storchaka
date: 2025-04-14T09:15:12+03:00
summary:
gh-124986: Fix test_no_leaking in test_subprocess on NetBSD and FreeBSD
(GH-132476)
On platforms where the file descriptor limit is larger than FD_SETSIZE
that test was always skipped (FreeBSD) or always failing (NetBSD).
files:
M Lib/test/test_subprocess.py
diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py
index 81d97a88f07bdd..3cb755cd56cac8 100644
--- a/Lib/test/test_subprocess.py
+++ b/Lib/test/test_subprocess.py
@@ -41,6 +41,10 @@
import grp
except ImportError:
grp = None
+try:
+import resource
+except ImportError:
+resource = None
try:
import fcntl
@@ -1211,6 +1215,16 @@ def test_no_leaking(self):
max_handles = 1026 # too much for most UNIX systems
else:
max_handles = 2050 # too much for (at least some) Windows setups
+if resource:
+# And if it is not too much, try to make it too much.
+try:
+soft, hard = resource.getrlimit(resource.RLIMIT_NOFILE)
+if soft > 1024:
+resource.setrlimit(resource.RLIMIT_NOFILE, (1024, hard))
+self.addCleanup(resource.setrlimit, resource.RLIMIT_NOFILE,
+(soft, hard))
+except (OSError, ValueError):
+pass
handles = []
tmpdir = tempfile.mkdtemp()
try:
@@ -1225,7 +1239,9 @@ def test_no_leaking(self):
else:
self.skipTest("failed to reach the file descriptor limit "
"(tried %d)" % max_handles)
-# Close a couple of them (should be enough for a subprocess)
+# Close a couple of them (should be enough for a subprocess).
+# Close lower file descriptors, so select() will work.
+handles.reverse()
for i in range(10):
os.close(handles.pop())
# Loop creating some subprocesses. If one of them leaks some fds,
___
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: [email protected]
[Python-checkins] GH-115322: fix ctypes call_function audit hook on 32-bit platforms (GH-132496)
https://github.com/python/cpython/commit/7a29c9883f4cf61372895362e865f7d2f99bd4ca
commit: 7a29c9883f4cf61372895362e865f7d2f99bd4ca
branch: main
author: Gregory P. Smith
committer: gpshead
date: 2025-04-14T06:22:29Z
summary:
GH-115322: fix ctypes call_function audit hook on 32-bit platforms (GH-132496)
* GH-115322: fix ctypes call_function audit hook on 32-bit platforms.
It was using a signed conversion to communicate the function id (pointer) value.
files:
M Lib/test/audit-tests.py
M Misc/NEWS.d/next/Security/2024-02-18-02-53-25.gh-issue-115322.Um2Sjx.rst
M Modules/_ctypes/callproc.c
diff --git a/Lib/test/audit-tests.py b/Lib/test/audit-tests.py
index 3d81f27e5cb46d..08b638e4b8d524 100644
--- a/Lib/test/audit-tests.py
+++ b/Lib/test/audit-tests.py
@@ -311,10 +311,10 @@ def test_ctypes_call_function():
with TestHook() as hook:
_ctypes.call_function(ctypes._memmove_addr, (0, 0, 0))
-assert ("ctypes.call_function", (ctypes._memmove_addr, (0, 0, 0))) in
hook.seen
+assert ("ctypes.call_function", (ctypes._memmove_addr, (0, 0, 0))) in
hook.seen, f"{ctypes._memmove_addr=} {hook.seen=}"
ctypes.CFUNCTYPE(ctypes.c_voidp)(ctypes._memset_addr)(1, 0, 0)
-assert ("ctypes.call_function", (ctypes._memset_addr, (1, 0, 0))) in
hook.seen
+assert ("ctypes.call_function", (ctypes._memset_addr, (1, 0, 0))) in
hook.seen, f"{ctypes._memset_addr=} {hook.seen=}"
with TestHook() as hook:
ctypes.cast(ctypes.c_voidp(0), ctypes.POINTER(ctypes.c_char))
diff --git
a/Misc/NEWS.d/next/Security/2024-02-18-02-53-25.gh-issue-115322.Um2Sjx.rst
b/Misc/NEWS.d/next/Security/2024-02-18-02-53-25.gh-issue-115322.Um2Sjx.rst
index a09e1f1fcdcab7..8eb5c3ed04ee2c 100644
--- a/Misc/NEWS.d/next/Security/2024-02-18-02-53-25.gh-issue-115322.Um2Sjx.rst
+++ b/Misc/NEWS.d/next/Security/2024-02-18-02-53-25.gh-issue-115322.Um2Sjx.rst
@@ -1,4 +1,5 @@
The underlying extension modules behind :mod:`readline`:, :mod:`subprocess`,
and :mod:`ctypes` now raise audit events on previously uncovered code paths
that could lead to file system access related to C function calling and
-external binary execution.
+external binary execution. The ``ctypes.call_function`` audit hook has also
+been fixed to use an unsigned value for its ``function pointer``.
diff --git a/Modules/_ctypes/callproc.c b/Modules/_ctypes/callproc.c
index f5db49ff4bc61c..cb8ab7b33a2953 100644
--- a/Modules/_ctypes/callproc.c
+++ b/Modules/_ctypes/callproc.c
@@ -1199,8 +1199,17 @@ PyObject *_ctypes_callproc(ctypes_state *st,
PyObject *retval = NULL;
// Both call_function and call_cdeclfunction call us:
+#if SIZEOF_VOID_P == SIZEOF_LONG
+if (PySys_Audit("ctypes.call_function", "kO",
+(unsigned long)pProc, argtuple) < 0) {
+#elif SIZEOF_VOID_P == SIZEOF_LONG_LONG
+if (PySys_Audit("ctypes.call_function", "KO",
+(unsigned long long)pProc, argtuple) < 0) {
+#else
+# warning "unexpected pointer size, you may see odd values in audit hooks"
if (PySys_Audit("ctypes.call_function", "nO",
(Py_ssize_t)pProc, argtuple) < 0) {
+#endif
return NULL;
}
___
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: [email protected]
[Python-checkins] gh-71339: Use new assertion methods in the urllib tests (GH-129056)
https://github.com/python/cpython/commit/f98b9b4cbb7905c9af45718505389d171ca3c590
commit: f98b9b4cbb7905c9af45718505389d171ca3c590
branch: main
author: Serhiy Storchaka
committer: serhiy-storchaka
date: 2025-04-14T09:24:41+03:00
summary:
gh-71339: Use new assertion methods in the urllib tests (GH-129056)
files:
M Lib/test/test_urllib.py
M Lib/test/test_urllib2.py
M Lib/test/test_urllib2_localnet.py
M Lib/test/test_urllibnet.py
M Lib/test/test_urlparse.py
diff --git a/Lib/test/test_urllib.py b/Lib/test/test_urllib.py
index abfbed8840ca03..da3db2f4e550fb 100644
--- a/Lib/test/test_urllib.py
+++ b/Lib/test/test_urllib.py
@@ -121,9 +121,7 @@ def test_interface(self):
# Make sure object returned by urlopen() has the specified methods
for attr in ("read", "readline", "readlines", "fileno",
"close", "info", "geturl", "getcode", "__iter__"):
-self.assertTrue(hasattr(self.returned_obj, attr),
- "object returned by urlopen() lacks %s attribute" %
- attr)
+self.assertHasAttr(self.returned_obj, attr)
def test_read(self):
self.assertEqual(self.text, self.returned_obj.read())
@@ -544,9 +542,7 @@ def test_interface(self):
# Make sure object returned by urlopen() has the specified methods
for attr in ("read", "readline", "readlines",
"close", "info", "geturl", "getcode", "__iter__"):
-self.assertTrue(hasattr(self.text_url_resp, attr),
- "object returned by urlopen() lacks %s attribute" %
- attr)
+self.assertHasAttr(self.text_url_resp, attr)
def test_info(self):
self.assertIsInstance(self.text_url_resp.info(), email.message.Message)
diff --git a/Lib/test/test_urllib2.py b/Lib/test/test_urllib2.py
index f44d324b3ab763..b1229607c516c7 100644
--- a/Lib/test/test_urllib2.py
+++ b/Lib/test/test_urllib2.py
@@ -1193,15 +1193,15 @@ def test_errors(self):
r = MockResponse(200, "OK", {}, "", url)
newr = h.http_response(req, r)
self.assertIs(r, newr)
-self.assertFalse(hasattr(o, "proto")) # o.error not called
+self.assertNotHasAttr(o, "proto") # o.error not called
r = MockResponse(202, "Accepted", {}, "", url)
newr = h.http_response(req, r)
self.assertIs(r, newr)
-self.assertFalse(hasattr(o, "proto")) # o.error not called
+self.assertNotHasAttr(o, "proto") # o.error not called
r = MockResponse(206, "Partial content", {}, "", url)
newr = h.http_response(req, r)
self.assertIs(r, newr)
-self.assertFalse(hasattr(o, "proto")) # o.error not called
+self.assertNotHasAttr(o, "proto") # o.error not called
# anything else calls o.error (and MockOpener returns None, here)
r = MockResponse(502, "Bad gateway", {}, "", url)
self.assertIsNone(h.http_response(req, r))
@@ -1416,7 +1416,7 @@ def http_open(self, req):
response = opener.open('http://example.com/')
expected = b'GET ' + result + b' '
request = handler.last_buf
-self.assertTrue(request.startswith(expected), repr(request))
+self.assertStartsWith(request, expected)
def test_redirect_head_request(self):
from_url = "http://example.com/a.html";
@@ -1906,9 +1906,9 @@ def test_HTTPError_interface(self):
url = code = fp = None
hdrs = 'Content-Length: 42'
err = urllib.error.HTTPError(url, code, msg, hdrs, fp)
-self.assertTrue(hasattr(err, 'reason'))
+self.assertHasAttr(err, 'reason')
self.assertEqual(err.reason, 'something bad happened')
-self.assertTrue(hasattr(err, 'headers'))
+self.assertHasAttr(err, 'headers')
self.assertEqual(err.headers, 'Content-Length: 42')
expected_errmsg = 'HTTP Error %s: %s' % (err.code, err.msg)
self.assertEqual(str(err), expected_errmsg)
diff --git a/Lib/test/test_urllib2_localnet.py
b/Lib/test/test_urllib2_localnet.py
index 9cb15d61c2ad4d..9186436183aae1 100644
--- a/Lib/test/test_urllib2_localnet.py
+++ b/Lib/test/test_urllib2_localnet.py
@@ -606,8 +606,7 @@ def test_basic(self):
handler = self.start_server()
with urllib.request.urlopen("http://localhost:%s"; % handler.port) as
open_url:
for attr in ("read", "close", "info", "geturl"):
-self.assertTrue(hasattr(open_url, attr), "object returned from
"
- "urlopen lacks the %s attribute" % attr)
+self.assertHasAttr(open_url, attr)
self.assertTrue(open_url.read(), "calling 'read' failed")
def test_info(self):
diff --git a/Lib/test/test_urllibnet.py b/Lib/test/test_urllibnet.py
index ce4e60e3a8011d..1a42c35dc49b9e 100644
--- a/Lib/test/test_urllibnet.py
+++ b/Lib/test/test_urllibnet.py
@@ -71,8 +71,7 @@ d
[Python-checkins] gh-71339: Use new assertion methods in the http tests (GH-129058)
https://github.com/python/cpython/commit/7076d076c27687140adc64ad495ea82f6eb5b3ce
commit: 7076d076c27687140adc64ad495ea82f6eb5b3ce
branch: main
author: Serhiy Storchaka
committer: serhiy-storchaka
date: 2025-04-14T09:24:54+03:00
summary:
gh-71339: Use new assertion methods in the http tests (GH-129058)
files:
M Lib/test/test_http_cookiejar.py
M Lib/test/test_http_cookies.py
M Lib/test/test_httplib.py
M Lib/test/test_httpservers.py
diff --git a/Lib/test/test_http_cookiejar.py b/Lib/test/test_http_cookiejar.py
index cf02c5b43a2e43..6bc33b15ec32e9 100644
--- a/Lib/test/test_http_cookiejar.py
+++ b/Lib/test/test_http_cookiejar.py
@@ -1537,7 +1537,7 @@ def test_netscape_example_1(self):
h = req.get_header("Cookie")
self.assertIn("PART_NUMBER=ROCKET_LAUNCHER_0001", h)
self.assertIn("CUSTOMER=WILE_E_COYOTE", h)
-self.assertTrue(h.startswith("SHIPPING=FEDEX;"))
+self.assertStartsWith(h, "SHIPPING=FEDEX;")
def test_netscape_example_2(self):
# Second Example transaction sequence:
diff --git a/Lib/test/test_http_cookies.py b/Lib/test/test_http_cookies.py
index d945de23493f20..2fbc142de2fd34 100644
--- a/Lib/test/test_http_cookies.py
+++ b/Lib/test/test_http_cookies.py
@@ -180,7 +180,7 @@ def test_special_attrs(self):
C = cookies.SimpleCookie('Customer="WILE_E_COYOTE"')
C['Customer']['expires'] = 0
# can't test exact output, it always depends on current date/time
-self.assertTrue(C.output().endswith('GMT'))
+self.assertEndsWith(C.output(), 'GMT')
# loading 'expires'
C = cookies.SimpleCookie()
diff --git a/Lib/test/test_httplib.py b/Lib/test/test_httplib.py
index 75b748aee05940..38429ad480ff1c 100644
--- a/Lib/test/test_httplib.py
+++ b/Lib/test/test_httplib.py
@@ -273,7 +273,7 @@ def test_ipv6host_header(self):
sock = FakeSocket('')
conn.sock = sock
conn.request('GET', '/foo')
-self.assertTrue(sock.data.startswith(expected))
+self.assertStartsWith(sock.data, expected)
expected = b'GET /foo HTTP/1.1\r\nHost: [2001:102A::]\r\n' \
b'Accept-Encoding: identity\r\n\r\n'
@@ -281,7 +281,7 @@ def test_ipv6host_header(self):
sock = FakeSocket('')
conn.sock = sock
conn.request('GET', '/foo')
-self.assertTrue(sock.data.startswith(expected))
+self.assertStartsWith(sock.data, expected)
expected = b'GET /foo HTTP/1.1\r\nHost: [fe80::]\r\n' \
b'Accept-Encoding: identity\r\n\r\n'
@@ -289,7 +289,7 @@ def test_ipv6host_header(self):
sock = FakeSocket('')
conn.sock = sock
conn.request('GET', '/foo')
-self.assertTrue(sock.data.startswith(expected))
+self.assertStartsWith(sock.data, expected)
expected = b'GET /foo HTTP/1.1\r\nHost: [fe80::]:81\r\n' \
b'Accept-Encoding: identity\r\n\r\n'
@@ -297,7 +297,7 @@ def test_ipv6host_header(self):
sock = FakeSocket('')
conn.sock = sock
conn.request('GET', '/foo')
-self.assertTrue(sock.data.startswith(expected))
+self.assertStartsWith(sock.data, expected)
def test_malformed_headers_coped_with(self):
# Issue 19996
@@ -335,9 +335,9 @@ def test_parse_all_octets(self):
self.assertIsNotNone(resp.getheader('obs-text'))
self.assertIn('obs-text', resp.msg)
for folded in (resp.getheader('obs-fold'), resp.msg['obs-fold']):
-self.assertTrue(folded.startswith('text'))
+self.assertStartsWith(folded, 'text')
self.assertIn(' folded with space', folded)
-self.assertTrue(folded.endswith('folded with tab'))
+self.assertEndsWith(folded, 'folded with tab')
def test_invalid_headers(self):
conn = client.HTTPConnection('example.com')
@@ -1000,8 +1000,7 @@ def test_send_file(self):
sock = FakeSocket(body)
conn.sock = sock
conn.request('GET', '/foo', body)
-self.assertTrue(sock.data.startswith(expected), '%r != %r' %
-(sock.data[:len(expected)], expected))
+self.assertStartsWith(sock.data, expected)
def test_send(self):
expected = b'this is a test this is only a test'
@@ -1564,7 +1563,7 @@ def mypeek(n=-1):
# then unbounded peek
p2 = resp.peek()
self.assertGreaterEqual(len(p2), len(p))
-self.assertTrue(p2.startswith(p))
+self.assertStartsWith(p2, p)
next = resp.read(len(p2))
self.assertEqual(next, p2)
else:
@@ -1589,7 +1588,7 @@ def _verify_readline(self, readline, expected, limit=5):
line = readline(limit)
if line and line != b"foo":
if len(line) < 5:
-self.assertTrue(line.endswith(b"\n"))
+self.assertEndsWith(line,
[Python-checkins] gh-71339: Use new assertion methods in the email tests (GH-129055)
https://github.com/python/cpython/commit/522766aa23b110257d5e31128ff5a5575715e880
commit: 522766aa23b110257d5e31128ff5a5575715e880
branch: main
author: Serhiy Storchaka
committer: serhiy-storchaka
date: 2025-04-14T09:25:58+03:00
summary:
gh-71339: Use new assertion methods in the email tests (GH-129055)
files:
M Lib/test/test_email/test_contentmanager.py
M Lib/test/test_email/test_defect_handling.py
M Lib/test/test_email/test_email.py
M Lib/test/test_mailbox.py
M Lib/test/test_poplib.py
diff --git a/Lib/test/test_email/test_contentmanager.py
b/Lib/test/test_email/test_contentmanager.py
index 694cef4ba7e413..dceb54f15e48f4 100644
--- a/Lib/test/test_email/test_contentmanager.py
+++ b/Lib/test/test_email/test_contentmanager.py
@@ -288,7 +288,7 @@ def
test_get_message_non_rfc822_or_external_body_yields_bytes(self):
The real body is in another message.
"""))
-self.assertEqual(raw_data_manager.get_content(m)[:10], b'To: foo@ex')
+self.assertStartsWith(raw_data_manager.get_content(m), b'To: foo@ex')
def test_set_text_plain(self):
m = self._make_message()
diff --git a/Lib/test/test_email/test_defect_handling.py
b/Lib/test/test_email/test_defect_handling.py
index 781f657418220c..44e76c8ce5e03a 100644
--- a/Lib/test/test_email/test_defect_handling.py
+++ b/Lib/test/test_email/test_defect_handling.py
@@ -57,7 +57,7 @@ def test_same_boundary_inner_outer(self):
msg = self._str_msg(source)
if self.raise_expected: return
inner = msg.get_payload(0)
-self.assertTrue(hasattr(inner, 'defects'))
+self.assertHasAttr(inner, 'defects')
self.assertEqual(len(self.get_defects(inner)), 1)
self.assertIsInstance(self.get_defects(inner)[0],
errors.StartBoundaryNotFoundDefect)
@@ -151,7 +151,7 @@ def test_lying_multipart(self):
with self._raise_point(errors.NoBoundaryInMultipartDefect):
msg = self._str_msg(source)
if self.raise_expected: return
-self.assertTrue(hasattr(msg, 'defects'))
+self.assertHasAttr(msg, 'defects')
self.assertEqual(len(self.get_defects(msg)), 2)
self.assertIsInstance(self.get_defects(msg)[0],
errors.NoBoundaryInMultipartDefect)
diff --git a/Lib/test/test_email/test_email.py
b/Lib/test/test_email/test_email.py
index 724af3b787d38b..7b14305f997e5d 100644
--- a/Lib/test/test_email/test_email.py
+++ b/Lib/test/test_email/test_email.py
@@ -210,8 +210,8 @@ def test_make_boundary(self):
self.assertEqual(msg.items()[0][1], 'multipart/form-data')
# Trigger creation of boundary
msg.as_string()
-self.assertEqual(msg.items()[0][1][:33],
-'multipart/form-data; boundary="==')
+self.assertStartsWith(msg.items()[0][1],
+ 'multipart/form-data; boundary="==')
# XXX: there ought to be tests of the uniqueness of the boundary, too.
def test_message_rfc822_only(self):
@@ -303,7 +303,7 @@ def test_as_string(self):
self.assertEqual(text, str(msg))
fullrepr = msg.as_string(unixfrom=True)
lines = fullrepr.split('\n')
-self.assertTrue(lines[0].startswith('From '))
+self.assertStartsWith(lines[0], 'From ')
self.assertEqual(text, NL.join(lines[1:]))
def test_as_string_policy(self):
@@ -372,7 +372,7 @@ def test_as_bytes(self):
self.assertEqual(data, bytes(msg))
fullrepr = msg.as_bytes(unixfrom=True)
lines = fullrepr.split(b'\n')
-self.assertTrue(lines[0].startswith(b'From '))
+self.assertStartsWith(lines[0], b'From ')
self.assertEqual(data, b'\n'.join(lines[1:]))
def test_as_bytes_policy(self):
@@ -2228,7 +2228,7 @@ def test_same_boundary_inner_outer(self):
msg = self._msgobj('msg_15.txt')
# XXX We can probably eventually do better
inner = msg.get_payload(0)
-self.assertTrue(hasattr(inner, 'defects'))
+self.assertHasAttr(inner, 'defects')
self.assertEqual(len(inner.defects), 1)
self.assertIsInstance(inner.defects[0],
errors.StartBoundaryNotFoundDefect)
@@ -2340,7 +2340,7 @@ def test_no_separating_blank_line(self):
# test_defect_handling
def test_lying_multipart(self):
msg = self._msgobj('msg_41.txt')
-self.assertTrue(hasattr(msg, 'defects'))
+self.assertHasAttr(msg, 'defects')
self.assertEqual(len(msg.defects), 2)
self.assertIsInstance(msg.defects[0],
errors.NoBoundaryInMultipartDefect)
@@ -3684,9 +3684,7 @@ def test_make_msgid_idstring(self):
def test_make_msgid_default_domain(self):
with patch('socket.getfqdn') as mock_getfqdn:
mock_getfqdn.return_value = domain = 'pythontest.example.com'
-self.assertTrue(
-email.utils.make_msgid().
[Python-checkins] gh-120144: Refactor bdb monitoring backend to match settrace behavior (#132484)
https://github.com/python/cpython/commit/084d6dc122c761b90cba620eac2f25dc1660b7f1
commit: 084d6dc122c761b90cba620eac2f25dc1660b7f1
branch: main
author: Tian Gao
committer: gaogaotiantian
date: 2025-04-13T17:49:35-04:00
summary:
gh-120144: Refactor bdb monitoring backend to match settrace behavior (#132484)
files:
M Lib/bdb.py
diff --git a/Lib/bdb.py b/Lib/bdb.py
index ba5cacc2a54cbc..17f79aee41fdef 100644
--- a/Lib/bdb.py
+++ b/Lib/bdb.py
@@ -62,8 +62,7 @@ def start_trace(self, tracefunc):
sys.monitoring.register_callback(self._tool_id, event, callback)
if event != E.INSTRUCTION:
all_events |= event
-self.check_trace_func()
-self.check_trace_opcodes()
+self.update_local_events()
sys.monitoring.set_events(self._tool_id, self.GLOBAL_EVENTS)
self._enabled = True
@@ -74,7 +73,6 @@ def stop_trace(self):
if curr_tool != self._name:
return
sys.monitoring.clear_tool_id(self._tool_id)
-self.check_trace_opcodes()
sys.monitoring.free_tool_id(self._tool_id)
def disable_current_event(self):
@@ -95,7 +93,7 @@ def wrapper(self, *args):
frame = sys._getframe().f_back
ret = func(self, frame, *args)
if self._enabled and frame.f_trace:
-self.check_trace_func()
+self.update_local_events()
if self._disable_current_event:
return sys.monitoring.DISABLE
else:
@@ -159,27 +157,18 @@ def opcode_callback(self, frame, code, offset):
if frame.f_trace and frame.f_trace_opcodes:
frame.f_trace(frame, 'opcode', None)
-def check_trace_opcodes(self, frame=None):
-if frame is None:
-frame = sys._getframe().f_back
-while frame is not None:
-self.set_trace_opcodes(frame, frame.f_trace_opcodes)
-frame = frame.f_back
-
-def set_trace_opcodes(self, frame, trace_opcodes):
+def update_local_events(self, frame=None):
if sys.monitoring.get_tool(self._tool_id) != self._name:
return
-if trace_opcodes:
-sys.monitoring.set_local_events(self._tool_id, frame.f_code,
E.INSTRUCTION)
-else:
-sys.monitoring.set_local_events(self._tool_id, frame.f_code, 0)
-
-def check_trace_func(self, frame=None):
if frame is None:
frame = sys._getframe().f_back
while frame is not None:
if frame.f_trace is not None:
-sys.monitoring.set_local_events(self._tool_id, frame.f_code,
self.LOCAL_EVENTS)
+if frame.f_trace_opcodes:
+events = self.LOCAL_EVENTS | E.INSTRUCTION
+else:
+events = self.LOCAL_EVENTS
+sys.monitoring.set_local_events(self._tool_id, frame.f_code,
events)
frame = frame.f_back
def _get_lineno(self, code, offset):
@@ -544,11 +533,11 @@ def _set_trace_opcodes(self, trace_opcodes):
frame = self.enterframe
while frame is not None:
frame.f_trace_opcodes = trace_opcodes
-if self.monitoring_tracer:
-self.monitoring_tracer.set_trace_opcodes(frame,
trace_opcodes)
if frame is self.botframe:
break
frame = frame.f_back
+if self.monitoring_tracer:
+self.monitoring_tracer.update_local_events()
def _set_stopinfo(self, stopframe, returnframe, stoplineno=0,
opcode=False):
"""Set the attributes for stopping.
@@ -642,8 +631,8 @@ def set_continue(self):
frame = frame.f_back
for frame, (trace_lines, trace_opcodes) in
self.frame_trace_lines_opcodes.items():
frame.f_trace_lines, frame.f_trace_opcodes = trace_lines,
trace_opcodes
-if self.backend == 'monitoring':
-self.monitoring_tracer.set_trace_opcodes(frame,
trace_opcodes)
+if self.backend == 'monitoring':
+self.monitoring_tracer.update_local_events()
self.frame_trace_lines_opcodes = {}
def set_quit(self):
___
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: [email protected]
[Python-checkins] gh-132388: fix typos in `Lib/test/test_hmac.py` (#132480)
https://github.com/python/cpython/commit/a1cd4ca7f46eafe61dc7f26692896a4a95c7e947 commit: a1cd4ca7f46eafe61dc7f26692896a4a95c7e947 branch: main author: abhi-jha committer: picnixz <[email protected]> date: 2025-04-13T22:26:58Z summary: gh-132388: fix typos in `Lib/test/test_hmac.py` (#132480) Fix typos that slipped in GH-132389 (commit 9634085af3670b1eb654e3c7820aca66f358f39f). files: M Lib/test/test_hmac.py diff --git a/Lib/test/test_hmac.py b/Lib/test/test_hmac.py index 3055a036c811b6..8370ba30601fae 100644 --- a/Lib/test/test_hmac.py +++ b/Lib/test/test_hmac.py @@ -1453,7 +1453,7 @@ def test_with_fallback(self): cache.pop('foo') -class BuiiltinMiscellaneousTests(BuiltinModuleMixin, unittest.TestCase): +class BuiltinMiscellaneousTests(BuiltinModuleMixin, unittest.TestCase): """HMAC-BLAKE2 is not standardized as BLAKE2 is a keyed hash function. In particular, there is no official test vectors for HMAC-BLAKE2. @@ -1464,9 +1464,9 @@ class BuiiltinMiscellaneousTests(BuiltinModuleMixin, unittest.TestCase): @classmethod def setUpClass(cls): super().setUpClass() -cls.blake2 = blake2 = import_module("_blake2") -cls.blake2b = blake2.blake2b -cls.blake2s = blake2.blake2s +cls.blake2 = import_module("_blake2") +cls.blake2b = cls.blake2.blake2b +cls.blake2s = cls.blake2.blake2s def assert_hmac_blake_correctness(self, digest, key, msg, hashfunc): self.assertIsInstance(digest, bytes) ___ Python-checkins mailing list -- [email protected] To unsubscribe send an email to [email protected] https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: [email protected]
[Python-checkins] gh-132099: Harmonize Bluetooth address handling (GH-132486)
https://github.com/python/cpython/commit/1fc1df8dcc7a853b0649bc8df37cd07cbd2b6230
commit: 1fc1df8dcc7a853b0649bc8df37cd07cbd2b6230
branch: main
author: Serhiy Storchaka
committer: serhiy-storchaka
date: 2025-04-14T08:58:56+03:00
summary:
gh-132099: Harmonize Bluetooth address handling (GH-132486)
Now all protocols always accept the Bluetooth address as string and
getsockname() always returns the Bluetooth address as string.
* BTPROTO_SCO now accepts not only bytes, but str.
* BTPROTO_SCO now checks address for embedded null.
* On *BSD, BTPROTO_HCI now accepts str instead of bytes.
* On FreeBSD, getsockname() for BTPROTO_HCI now returns str instead of bytes.
* On NetBSD and DragonFly BDS, BTPROTO_HCI now checks address for embedded null.
files:
M Doc/library/socket.rst
M Lib/test/test_socket.py
M Modules/socketmodule.c
diff --git a/Doc/library/socket.rst b/Doc/library/socket.rst
index 2e38101c01d89d..11f7f06c59e873 100644
--- a/Doc/library/socket.rst
+++ b/Doc/library/socket.rst
@@ -158,9 +158,8 @@ created. Socket addresses are represented as follows:
- On Linux it accepts a tuple ``(device_id,)`` where ``device_id``
is an integer specifying the number of the Bluetooth device.
-- On FreeBSD, NetBSD and DragonFly BSD it accepts ``bdaddr`` where
``bdaddr``
- is a :class:`bytes` object containing the Bluetooth address in a
- string format. (ex. ``b'12:23:34:45:56:67'``)
+- On FreeBSD, NetBSD and DragonFly BSD it accepts ``bdaddr``
+ where ``bdaddr`` is the Bluetooth address as a string.
.. versionchanged:: 3.2
NetBSD and DragonFlyBSD support added.
@@ -168,9 +167,9 @@ created. Socket addresses are represented as follows:
.. versionchanged:: 3.13.3
FreeBSD support added.
- - :const:`BTPROTO_SCO` accepts ``bdaddr`` where ``bdaddr`` is a
-:class:`bytes` object containing the Bluetooth address in a
-string format. (ex. ``b'12:23:34:45:56:67'``)
+ - :const:`BTPROTO_SCO` accepts ``bdaddr`` where ``bdaddr`` is
+the Bluetooth address as a string or a :class:`bytes` object.
+(ex. ``'12:23:34:45:56:67'`` or ``b'12:23:34:45:56:67'``)
.. versionchanged:: next
FreeBSD support added.
diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py
index 66cb63daca02ae..93dbcc981591ca 100644
--- a/Lib/test/test_socket.py
+++ b/Lib/test/test_socket.py
@@ -2681,6 +2681,8 @@ def testBadL2capAddr(self):
f.bind(socket.BDADDR_ANY)
with self.assertRaises(OSError):
f.bind((socket.BDADDR_ANY.encode(), 0x1001))
+with self.assertRaises(OSError):
+f.bind(('\ud812', 0x1001))
def testBindRfcommSocket(self):
with socket.socket(socket.AF_BLUETOOTH, socket.SOCK_STREAM,
socket.BTPROTO_RFCOMM) as s:
@@ -2712,6 +2714,8 @@ def testBadRfcommAddr(self):
s.bind((socket.BDADDR_ANY, channel, 0))
with self.assertRaises(OSError):
s.bind((socket.BDADDR_ANY + '\0', channel))
+with self.assertRaises(OSError):
+s.bind('\ud812')
with self.assertRaises(OSError):
s.bind(('invalid', channel))
@@ -2719,7 +2723,7 @@ def testBadRfcommAddr(self):
def testBindHciSocket(self):
with socket.socket(socket.AF_BLUETOOTH, socket.SOCK_RAW,
socket.BTPROTO_HCI) as s:
if sys.platform.startswith(('netbsd', 'dragonfly', 'freebsd')):
-s.bind(socket.BDADDR_ANY.encode())
+s.bind(socket.BDADDR_ANY)
addr = s.getsockname()
self.assertEqual(addr, socket.BDADDR_ANY)
else:
@@ -2738,14 +2742,17 @@ def testBadHciAddr(self):
with socket.socket(socket.AF_BLUETOOTH, socket.SOCK_RAW,
socket.BTPROTO_HCI) as s:
if sys.platform.startswith(('netbsd', 'dragonfly', 'freebsd')):
with self.assertRaises(OSError):
-s.bind(socket.BDADDR_ANY)
+s.bind(socket.BDADDR_ANY.encode())
with self.assertRaises(OSError):
-s.bind((socket.BDADDR_ANY.encode(),))
-if sys.platform.startswith('freebsd'):
-with self.assertRaises(ValueError):
-s.bind(socket.BDADDR_ANY.encode() + b'\0')
-with self.assertRaises(ValueError):
-s.bind(socket.BDADDR_ANY.encode() + b' '*100)
+s.bind((socket.BDADDR_ANY,))
+with self.assertRaises(OSError):
+s.bind(socket.BDADDR_ANY + '\0')
+with self.assertRaises((ValueError, OSError)):
+s.bind(socket.BDADDR_ANY + ' '*100)
+with self.assertRaises(OSError):
+s.bind('\ud812')
+with self.assertRaises(OSError):
+s.bind('invalid')
with self.assertRaises(OSError):
s.bind(b'invalid')
[Python-checkins] GH-115322: Add missing audit hooks (GH-115624)
https://github.com/python/cpython/commit/2666a06d336675247e1602aeb64170b2443602ce commit: 2666a06d336675247e1602aeb64170b2443602ce branch: main author: Robin Jadoul committer: gpshead date: 2025-04-13T21:46:20Z summary: GH-115322: Add missing audit hooks (GH-115624) Add extra audit hooks to catch C function calling from ctypes, reading/writing files through readline and executing external programs through _posixsubprocess. * Make audit-tests for open pass when readline.append_history_file is unavailable * Less direct testing of _posixsubprocess for audit hooks * Also remove the audit hook from call_cdeclfunction now that _ctypes_callproc does it instead. * reword the NEWS entry. * mention readline in NEWS * add versionchanged markers * fix audit_events.rst versionadded * doc lint - Co-authored-by: Gregory P. Smith files: A Misc/NEWS.d/next/Security/2024-02-18-02-53-25.gh-issue-115322.Um2Sjx.rst M Doc/library/audit_events.rst M Doc/library/ctypes.rst M Doc/library/readline.rst M Lib/test/audit-tests.py M Lib/test/test_audit.py M Modules/_ctypes/callproc.c M Modules/_posixsubprocess.c M Modules/readline.c diff --git a/Doc/library/audit_events.rst b/Doc/library/audit_events.rst index a2a90a00d0cfca..d2377a38d78c81 100644 --- a/Doc/library/audit_events.rst +++ b/Doc/library/audit_events.rst @@ -23,25 +23,30 @@ information on handling these events. The following events are raised internally and do not correspond to any public API of CPython: -+--+---+ -| Audit event | Arguments | -+==+===+ -| _winapi.CreateFile | ``file_name``, ``desired_access``,| -| | ``share_mode``, ``creation_disposition``, | -| | ``flags_and_attributes`` | -+--+---+ -| _winapi.CreateJunction | ``src_path``, ``dst_path``| -+--+---+ -| _winapi.CreateNamedPipe | ``name``, ``open_mode``, ``pipe_mode``| -+--+---+ -| _winapi.CreatePipe | | -+--+---+ -| _winapi.CreateProcess| ``application_name``, ``command_line``, | -| | ``current_directory`` | -+--+---+ -| _winapi.OpenProcess | ``process_id``, ``desired_access``| -+--+---+ -| _winapi.TerminateProcess | ``handle``, ``exit_code`` | -+--+---+ -| ctypes.PyObj_FromPtr | ``obj`` | -+--+---+ +++---+ +| Audit event| Arguments | +++===+ +| _winapi.CreateFile | ``file_name``, ``desired_access``,| +|| ``share_mode``, ``creation_disposition``, | +|| ``flags_and_attributes`` | +++---+ +| _winapi.CreateJunction | ``src_path``, ``dst_path``| +++---+ +| _winapi.CreateNamedPipe| ``name``, ``open_mode``, ``pipe_mode``| +++---+ +| _winapi.CreatePipe | | +++---+ +| _winapi.CreateProcess | ``application_name``, ``command_line``, | +|| ``current_directory`` | +++---+ +| _winapi.OpenProcess| ``process_id``, ``desired_access``| +++---+ +| _winapi.TerminateProcess | ``handle``, ``exit_code`` | +++---+ +| _posixsubprocess.fork_exec | ``exec_list``, ``args``, ``env`` | +++---+ +| ctypes.PyObj_FromPtr | ``obj`` | +++---+ + +.. versionadded:: next + The ``_posixsubprocess.fork_exec
[Python-checkins] [3.13] gh-101100: Fix sphinx warnings in `library/plistlib.rst` (GH-132422) (#132485)
https://github.com/python/cpython/commit/f206b98c18a3467477058ae5b5cad54e84f37f13 commit: f206b98c18a3467477058ae5b5cad54e84f37f13 branch: 3.13 author: Miss Islington (bot) <[email protected]> committer: hugovk <[email protected]> date: 2025-04-13T18:41:56Z summary: [3.13] gh-101100: Fix sphinx warnings in `library/plistlib.rst` (GH-132422) (#132485) Co-authored-by: Yuki Kobayashi files: M Doc/library/plistlib.rst M Doc/tools/.nitignore diff --git a/Doc/library/plistlib.rst b/Doc/library/plistlib.rst index c3a133e46a64d6..415c4b45c4f100 100644 --- a/Doc/library/plistlib.rst +++ b/Doc/library/plistlib.rst @@ -147,8 +147,9 @@ The following classes are available: Wraps an :class:`int`. This is used when reading or writing NSKeyedArchiver encoded data, which contains UID (see PList manual). - It has one attribute, :attr:`data`, which can be used to retrieve the int value - of the UID. :attr:`data` must be in the range ``0 <= data < 2**64``. + .. attribute:: data + + Int value of the UID. It must be in the range ``0 <= data < 2**64``. .. versionadded:: 3.8 diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore index 3e56c939e5b2cf..191287d02c79fe 100644 --- a/Doc/tools/.nitignore +++ b/Doc/tools/.nitignore @@ -33,7 +33,6 @@ Doc/library/optparse.rst Doc/library/os.rst Doc/library/pickletools.rst Doc/library/platform.rst -Doc/library/plistlib.rst Doc/library/profile.rst Doc/library/pyexpat.rst Doc/library/resource.rst ___ Python-checkins mailing list -- [email protected] To unsubscribe send an email to [email protected] https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: [email protected]
[Python-checkins] gh-132064: Make annotationlib use __annotate__ if only it is present (#132195)
https://github.com/python/cpython/commit/4d3ad0467e5cb145b1f4bde4be5eb776946a4269 commit: 4d3ad0467e5cb145b1f4bde4be5eb776946a4269 branch: main author: Jelle Zijlstra committer: JelleZijlstra date: 2025-04-13T16:32:44-07:00 summary: gh-132064: Make annotationlib use __annotate__ if only it is present (#132195) files: A Misc/NEWS.d/next/Library/2025-04-06-21-17-14.gh-issue-132064.ktPwDM.rst M Doc/library/annotationlib.rst M Lib/annotationlib.py M Lib/test/test_annotationlib.py M Lib/test/test_functools.py diff --git a/Doc/library/annotationlib.rst b/Doc/library/annotationlib.rst index 140e1aa12e2938..7a6d44069ed005 100644 --- a/Doc/library/annotationlib.rst +++ b/Doc/library/annotationlib.rst @@ -317,11 +317,22 @@ Functions Compute the annotations dict for an object. *obj* may be a callable, class, module, or other object with - :attr:`~object.__annotate__` and :attr:`~object.__annotations__` attributes. - Passing in an object of any other type raises :exc:`TypeError`. + :attr:`~object.__annotate__` or :attr:`~object.__annotations__` attributes. + Passing any other object raises :exc:`TypeError`. The *format* parameter controls the format in which annotations are returned, and must be a member of the :class:`Format` enum or its integer equivalent. + The different formats work as follows: + + * VALUE: :attr:`!object.__annotations__` is tried first; if that does not exist, + the :attr:`!object.__annotate__` function is called if it exists. + * FORWARDREF: If :attr:`!object.__annotations__` exists and can be evaluated successfully, + it is used; otherwise, the :attr:`!object.__annotate__` function is called. If it + does not exist either, :attr:`!object.__annotations__` is tried again and any error + from accessing it is re-raised. + * STRING: If :attr:`!object.__annotate__` exists, it is called first; + otherwise, :attr:`!object.__annotations__` is used and stringified + using :func:`annotations_to_string`. Returns a dict. :func:`!get_annotations` returns a new dict every time it's called; calling it twice on the same object will return two diff --git a/Lib/annotationlib.py b/Lib/annotationlib.py index 237b3470b831fd..e1c96298426283 100644 --- a/Lib/annotationlib.py +++ b/Lib/annotationlib.py @@ -640,12 +640,18 @@ def get_annotations( ): """Compute the annotations dict for an object. -obj may be a callable, class, or module. -Passing in an object of any other type raises TypeError. - -Returns a dict. get_annotations() returns a new dict every time -it's called; calling it twice on the same object will return two -different but equivalent dicts. +obj may be a callable, class, module, or other object with +__annotate__ or __annotations__ attributes. +Passing any other object raises TypeError. + +The *format* parameter controls the format in which annotations are returned, +and must be a member of the Format enum or its integer equivalent. +For the VALUE format, the __annotations__ is tried first; if it +does not exist, the __annotate__ function is called. The +FORWARDREF format uses __annotations__ if it exists and can be +evaluated, and otherwise falls back to calling the __annotate__ function. +The SOURCE format tries __annotate__ first, and falls back to +using __annotations__, stringified using annotations_to_string(). This function handles several details for you: @@ -687,24 +693,29 @@ def get_annotations( match format: case Format.VALUE: -# For VALUE, we only look at __annotations__ +# For VALUE, we first look at __annotations__ ann = _get_dunder_annotations(obj) + +# If it's not there, try __annotate__ instead +if ann is None: +ann = _get_and_call_annotate(obj, format) case Format.FORWARDREF: # For FORWARDREF, we use __annotations__ if it exists try: -return dict(_get_dunder_annotations(obj)) +ann = _get_dunder_annotations(obj) except NameError: pass +else: +if ann is not None: +return dict(ann) # But if __annotations__ threw a NameError, we try calling __annotate__ ann = _get_and_call_annotate(obj, format) -if ann is not None: -return ann - -# If that didn't work either, we have a very weird object: evaluating -# __annotations__ threw NameError and there is no __annotate__. In that case, -# we fall back to trying __annotations__ again. -return dict(_get_dunder_annotations(obj)) +if ann is None: +# If that didn't work either, we have a very weird object: evaluating +# __annotations__ threw NameError and there is no __annotate__. In that case, +#
[Python-checkins] gh-132435: Test syntax warnings in a finally block (GH-132436)
https://github.com/python/cpython/commit/887eabc5a74316708460120d60d0fa4f8bdf5960
commit: 887eabc5a74316708460120d60d0fa4f8bdf5960
branch: main
author: Tomas R.
committer: serhiy-storchaka
date: 2025-04-13T20:44:00Z
summary:
gh-132435: Test syntax warnings in a finally block (GH-132436)
files:
A
Misc/NEWS.d/next/Core_and_Builtins/2025-04-13-10-34-27.gh-issue-131927.otp80n.rst
M Lib/test/test_compile.py
diff --git a/Lib/test/test_compile.py b/Lib/test/test_compile.py
index 0377b3f954f44b..57e5f29b015637 100644
--- a/Lib/test/test_compile.py
+++ b/Lib/test/test_compile.py
@@ -1664,6 +1664,26 @@ def test_compile_warnings(self):
self.assertEqual(len(caught), 2)
+def test_compile_warning_in_finally(self):
+# Ensure that warnings inside finally blocks are
+# only emitted once despite the block being
+# compiled twice (for normal execution and for
+# exception handling).
+source = textwrap.dedent("""
+try:
+pass
+finally:
+1 is 1
+""")
+
+with warnings.catch_warnings(record=True) as caught:
+warnings.simplefilter("default")
+compile(source, '', 'exec')
+
+self.assertEqual(len(caught), 1)
+self.assertEqual(caught[0].category, SyntaxWarning)
+self.assertIn("\"is\" with 'int' literal", str(caught[0].message))
+
class TestBooleanExpression(unittest.TestCase):
class Value:
def __init__(self):
diff --git
a/Misc/NEWS.d/next/Core_and_Builtins/2025-04-13-10-34-27.gh-issue-131927.otp80n.rst
b/Misc/NEWS.d/next/Core_and_Builtins/2025-04-13-10-34-27.gh-issue-131927.otp80n.rst
new file mode 100644
index 00..9aa940a10daa69
--- /dev/null
+++
b/Misc/NEWS.d/next/Core_and_Builtins/2025-04-13-10-34-27.gh-issue-131927.otp80n.rst
@@ -0,0 +1,3 @@
+Compiler warnings originating from the same module and line number are now
+only emitted once, matching the behaviour of warnings emitted from user
+code. This can also be configured with :mod:`warnings` filters.
___
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: [email protected]
[Python-checkins] gh-101100: Fix sphinx warnings in `library/plistlib.rst` (#132422)
https://github.com/python/cpython/commit/fc7e4e7bbd5d459b76b96991413569a5b7889fbe commit: fc7e4e7bbd5d459b76b96991413569a5b7889fbe branch: main author: Yuki Kobayashi committer: hugovk <[email protected]> date: 2025-04-13T18:35:26Z summary: gh-101100: Fix sphinx warnings in `library/plistlib.rst` (#132422) files: M Doc/library/plistlib.rst M Doc/tools/.nitignore diff --git a/Doc/library/plistlib.rst b/Doc/library/plistlib.rst index c3a133e46a64d6..415c4b45c4f100 100644 --- a/Doc/library/plistlib.rst +++ b/Doc/library/plistlib.rst @@ -147,8 +147,9 @@ The following classes are available: Wraps an :class:`int`. This is used when reading or writing NSKeyedArchiver encoded data, which contains UID (see PList manual). - It has one attribute, :attr:`data`, which can be used to retrieve the int value - of the UID. :attr:`data` must be in the range ``0 <= data < 2**64``. + .. attribute:: data + + Int value of the UID. It must be in the range ``0 <= data < 2**64``. .. versionadded:: 3.8 diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore index f43dba19d1340c..926d2cd42bdf02 100644 --- a/Doc/tools/.nitignore +++ b/Doc/tools/.nitignore @@ -32,7 +32,6 @@ Doc/library/optparse.rst Doc/library/os.rst Doc/library/pickletools.rst Doc/library/platform.rst -Doc/library/plistlib.rst Doc/library/profile.rst Doc/library/pyexpat.rst Doc/library/resource.rst ___ Python-checkins mailing list -- [email protected] To unsubscribe send an email to [email protected] https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: [email protected]
[Python-checkins] gh-86513: improve docs of loop.call_exception_handler (#132466)
https://github.com/python/cpython/commit/ce753517a87eec776c176f3245ce5d1554a59341 commit: ce753517a87eec776c176f3245ce5d1554a59341 branch: main author: Kumar Aditya committer: kumaraditya303 date: 2025-04-13T21:39:24Z summary: gh-86513: improve docs of loop.call_exception_handler (#132466) files: M Doc/library/asyncio-eventloop.rst M Lib/asyncio/base_events.py diff --git a/Doc/library/asyncio-eventloop.rst b/Doc/library/asyncio-eventloop.rst index fae68803107639..8f561744fe4981 100644 --- a/Doc/library/asyncio-eventloop.rst +++ b/Doc/library/asyncio-eventloop.rst @@ -1440,6 +1440,8 @@ Allows customizing how exceptions are handled in the event loop. * 'protocol' (optional): :ref:`Protocol ` instance; * 'transport' (optional): :ref:`Transport ` instance; * 'socket' (optional): :class:`socket.socket` instance; + * 'source_traceback' (optional): Traceback of the source; + * 'handle_traceback' (optional): Traceback of the handle; * 'asyncgen' (optional): Asynchronous generator that caused the exception. diff --git a/Lib/asyncio/base_events.py b/Lib/asyncio/base_events.py index 7b4e92aed682d5..29b872ce00ec81 100644 --- a/Lib/asyncio/base_events.py +++ b/Lib/asyncio/base_events.py @@ -1879,6 +1879,8 @@ def call_exception_handler(self, context): - 'protocol' (optional): Protocol instance; - 'transport' (optional): Transport instance; - 'socket' (optional): Socket instance; +- 'source_traceback' (optional): Traceback of the source; +- 'handle_traceback' (optional): Traceback of the handle; - 'asyncgen' (optional): Asynchronous generator that caused the exception. ___ Python-checkins mailing list -- [email protected] To unsubscribe send an email to [email protected] https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: [email protected]
[Python-checkins] [3.13] gh-131927: Prevent emitting compiler warnings twice (GH-131993) (GH-132463)
https://github.com/python/cpython/commit/4ff5d88fb1416d347bfd8bb53b0945adadc924ef
commit: 4ff5d88fb1416d347bfd8bb53b0945adadc924ef
branch: 3.13
author: Tomas R.
committer: serhiy-storchaka
date: 2025-04-13T08:42:04Z
summary:
[3.13] gh-131927: Prevent emitting compiler warnings twice (GH-131993)
(GH-132463)
(cherry picked from commit 3d08c8ad20dfabd4864be139cd9c2eb5602ccdfe)
files:
M Include/cpython/warnings.h
M Lib/test/test_compile.py
M Python/_warnings.c
M Python/compile.c
diff --git a/Include/cpython/warnings.h b/Include/cpython/warnings.h
index 4e3eb88e8ff447..8731fd2e96b716 100644
--- a/Include/cpython/warnings.h
+++ b/Include/cpython/warnings.h
@@ -18,3 +18,9 @@ PyAPI_FUNC(int) PyErr_WarnExplicitFormat(
// DEPRECATED: Use PyErr_WarnEx() instead.
#define PyErr_Warn(category, msg) PyErr_WarnEx((category), (msg), 1)
+
+int _PyErr_WarnExplicitObjectWithContext(
+PyObject *category,
+PyObject *message,
+PyObject *filename,
+int lineno);
diff --git a/Lib/test/test_compile.py b/Lib/test/test_compile.py
index ed4e6265eac438..b57adfadb5af5f 100644
--- a/Lib/test/test_compile.py
+++ b/Lib/test/test_compile.py
@@ -1512,6 +1512,24 @@ async def name_4():
pass
[[]]
+def test_compile_warnings(self):
+# See gh-131927
+# Compile warnings originating from the same file and
+# line are now only emitted once.
+with warnings.catch_warnings(record=True) as caught:
+warnings.simplefilter("default")
+compile('1 is 1', '', 'eval')
+compile('1 is 1', '', 'eval')
+
+self.assertEqual(len(caught), 1)
+
+with warnings.catch_warnings(record=True) as caught:
+warnings.simplefilter("always")
+compile('1 is 1', '', 'eval')
+compile('1 is 1', '', 'eval')
+
+self.assertEqual(len(caught), 2)
+
@requires_debug_ranges()
class TestSourcePositions(unittest.TestCase):
# Ensure that compiled code snippets have correct line and column numbers
diff --git a/Python/_warnings.c b/Python/_warnings.c
index 4bb83b214ae6cc..5bbd4a9c19f6c9 100644
--- a/Python/_warnings.c
+++ b/Python/_warnings.c
@@ -1317,6 +1317,28 @@ PyErr_WarnExplicitObject(PyObject *category, PyObject
*message,
return 0;
}
+/* Like PyErr_WarnExplicitObject, but automatically sets up context */
+int
+_PyErr_WarnExplicitObjectWithContext(PyObject *category, PyObject *message,
+ PyObject *filename, int lineno)
+{
+PyObject *unused_filename, *module, *registry;
+int unused_lineno;
+int stack_level = 1;
+
+if (!setup_context(stack_level, NULL, &unused_filename, &unused_lineno,
+ &module, ®istry)) {
+return -1;
+}
+
+int rc = PyErr_WarnExplicitObject(category, message, filename, lineno,
+ module, registry);
+Py_DECREF(unused_filename);
+Py_DECREF(registry);
+Py_DECREF(module);
+return rc;
+}
+
int
PyErr_WarnExplicit(PyObject *category, const char *text,
const char *filename_str, int lineno,
diff --git a/Python/compile.c b/Python/compile.c
index ba780927eff9d6..bb2c2293a38c9a 100644
--- a/Python/compile.c
+++ b/Python/compile.c
@@ -6616,8 +6616,8 @@ compiler_warn(struct compiler *c, location loc,
if (msg == NULL) {
return ERROR;
}
-if (PyErr_WarnExplicitObject(PyExc_SyntaxWarning, msg, c->c_filename,
- loc.lineno, NULL, NULL) < 0)
+if (_PyErr_WarnExplicitObjectWithContext(PyExc_SyntaxWarning, msg,
+ c->c_filename, loc.lineno) < 0)
{
if (PyErr_ExceptionMatches(PyExc_SyntaxWarning)) {
/* Replace the SyntaxWarning exception with a SyntaxError
___
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: [email protected]
[Python-checkins] Docs: Fix a typo in `Doc/c-api/unicode.rst` (#132318)
https://github.com/python/cpython/commit/03b18e0d8cebdf4bef85cbfbfcb2cb4d25ac5241 commit: 03b18e0d8cebdf4bef85cbfbfcb2cb4d25ac5241 branch: main author: Yongzi Li <[email protected]> committer: picnixz <[email protected]> date: 2025-04-13T07:16:59Z summary: Docs: Fix a typo in `Doc/c-api/unicode.rst` (#132318) files: M Doc/c-api/unicode.rst diff --git a/Doc/c-api/unicode.rst b/Doc/c-api/unicode.rst index 31063962ae51c5..e07121f17d9c29 100644 --- a/Doc/c-api/unicode.rst +++ b/Doc/c-api/unicode.rst @@ -622,7 +622,7 @@ APIs: On error, set *\*p_left* to ``NULL`` and set an exception. - On sucess, set *\*p_left* to a new strong reference to the result. + On success, set *\*p_left* to a new strong reference to the result. .. c:function:: void PyUnicode_AppendAndDel(PyObject **p_left, PyObject *right) ___ Python-checkins mailing list -- [email protected] To unsubscribe send an email to [email protected] https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: [email protected]
[Python-checkins] Fix a typo in c-api/typeobj.rst (#132317)
https://github.com/python/cpython/commit/f69b344e0944bd8d59d2dc4d98e988cc4dbfadf3 commit: f69b344e0944bd8d59d2dc4d98e988cc4dbfadf3 branch: main author: Yongzi Li <[email protected]> committer: AA-Turner <[email protected]> date: 2025-04-13T07:18:58Z summary: Fix a typo in c-api/typeobj.rst (#132317) files: M Doc/c-api/typeobj.rst diff --git a/Doc/c-api/typeobj.rst b/Doc/c-api/typeobj.rst index 6d2201d02f685d..3b9f07778d5ace 100644 --- a/Doc/c-api/typeobj.rst +++ b/Doc/c-api/typeobj.rst @@ -611,7 +611,7 @@ and :c:data:`PyType_Type` effectively act as defaults.) Note that the :c:member:`~PyVarObject.ob_size` field may later be used for other purposes. For example, :py:type:`int` instances use the bits of :c:member:`~PyVarObject.ob_size` in an implementation-defined - way; the underlying storage and its size should be acessed using + way; the underlying storage and its size should be accessed using :c:func:`PyLong_Export`. .. note:: ___ Python-checkins mailing list -- [email protected] To unsubscribe send an email to [email protected] https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: [email protected]
[Python-checkins] [3.13] Fix a typo in c-api/typeobj.rst (GH-132317) (#132464)
https://github.com/python/cpython/commit/244a64244396cb1c5c04323471a22157b839ef14 commit: 244a64244396cb1c5c04323471a22157b839ef14 branch: 3.13 author: Miss Islington (bot) <[email protected]> committer: picnixz <[email protected]> date: 2025-04-13T07:24:46Z summary: [3.13] Fix a typo in c-api/typeobj.rst (GH-132317) (#132464) Fix a typo in c-api/typeobj.rst (GH-132317) (cherry picked from commit f69b344e0944bd8d59d2dc4d98e988cc4dbfadf3) Co-authored-by: Yongzi Li <[email protected]> files: M Doc/c-api/typeobj.rst diff --git a/Doc/c-api/typeobj.rst b/Doc/c-api/typeobj.rst index f531e326862a17..93c377c54bc73b 100644 --- a/Doc/c-api/typeobj.rst +++ b/Doc/c-api/typeobj.rst @@ -611,7 +611,7 @@ and :c:data:`PyType_Type` effectively act as defaults.) Note that the :c:member:`~PyVarObject.ob_size` field may later be used for other purposes. For example, :py:type:`int` instances use the bits of :c:member:`~PyVarObject.ob_size` in an implementation-defined - way; the underlying storage and its size should be acessed using + way; the underlying storage and its size should be accessed using :c:func:`PyLong_Export`. .. note:: ___ Python-checkins mailing list -- [email protected] To unsubscribe send an email to [email protected] https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: [email protected]
[Python-checkins] gh-132354: document return value for `asyncio.Task.cancel` (#132374)
https://github.com/python/cpython/commit/64b066ad298506f715647c9a2524c9fbbc764cc2 commit: 64b066ad298506f715647c9a2524c9fbbc764cc2 branch: main author: Felix Scherz committer: kumaraditya303 date: 2025-04-13T13:05:44+05:30 summary: gh-132354: document return value for `asyncio.Task.cancel` (#132374) files: M Doc/library/asyncio-task.rst M Misc/ACKS diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst index b6ae443860843b..59acce1990ae04 100644 --- a/Doc/library/asyncio-task.rst +++ b/Doc/library/asyncio-task.rst @@ -1381,7 +1381,10 @@ Task Object Request the Task to be cancelled. - This arranges for a :exc:`CancelledError` exception to be thrown + If the Task is already *done* or *cancelled*, return ``False``, + otherwise, return ``True``. + + The method arranges for a :exc:`CancelledError` exception to be thrown into the wrapped coroutine on the next cycle of the event loop. The coroutine then has a chance to clean up or even deny the diff --git a/Misc/ACKS b/Misc/ACKS index c3e8530d5b36c2..25542d01de695c 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1663,6 +1663,7 @@ Andreas Schawo Neil Schemenauer David Scherer Wolfgang Scherer +Felix Scherz Hynek Schlawack Bob Schmertz Gregor Schmid ___ Python-checkins mailing list -- [email protected] To unsubscribe send an email to [email protected] https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: [email protected]
[Python-checkins] gh-132106: Ensure that running `logging.handlers.QueueListener` cannot be started again (GH-132444)
https://github.com/python/cpython/commit/5863cd70b8782313b52bb8c71a4127d7ea4c50e9 commit: 5863cd70b8782313b52bb8c71a4127d7ea4c50e9 branch: main author: Charles Machalow committer: vsajip date: 2025-04-13T08:53:13+01:00 summary: gh-132106: Ensure that running `logging.handlers.QueueListener` cannot be started again (GH-132444) Prevents a thread leak Co-authored-by: Bénédikt Tran <[email protected]> files: A Misc/NEWS.d/next/Library/2025-04-12-09-30-24.gh-issue-132106.OxUds3.rst M Doc/library/logging.handlers.rst M Doc/whatsnew/3.14.rst M Lib/logging/handlers.py M Lib/test/test_logging.py diff --git a/Doc/library/logging.handlers.rst b/Doc/library/logging.handlers.rst index b737fe311dfb6e..72312b512a5884 100644 --- a/Doc/library/logging.handlers.rst +++ b/Doc/library/logging.handlers.rst @@ -1186,6 +1186,10 @@ possible, while any potentially slow operations (such as sending an email via This starts up a background thread to monitor the queue for LogRecords to process. + .. versionchanged:: next + Raises :exc:`RuntimeError` if called and the listener is already + running. + .. method:: stop() Stops the listener. diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst index 762d53eeb2df1a..421d12660b7956 100644 --- a/Doc/whatsnew/3.14.rst +++ b/Doc/whatsnew/3.14.rst @@ -819,6 +819,10 @@ logging.handlers manager protocol, allowing it to be used in a :keyword:`with` statement. (Contributed by Charles Machalow in :gh:`132106`.) +* :meth:`QueueListener.start ` now + raises a :exc:`RuntimeError` if the listener is already started. + (Contributed by Charles Machalow in :gh:`132106`.) + mimetypes - diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py index 0571ed2356345a..2748b5941eade2 100644 --- a/Lib/logging/handlers.py +++ b/Lib/logging/handlers.py @@ -1561,6 +1561,9 @@ def start(self): This starts up a background thread to monitor the queue for LogRecords to process. """ +if self._thread is not None: +raise RuntimeError("Listener already started") + self._thread = t = threading.Thread(target=self._monitor) t.daemon = True t.start() diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py index 11f6b64abe28fb..9305844829a500 100644 --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -4356,6 +4356,17 @@ def test_queue_listener_context_manager(self): listener.stop() self.assertIsNone(listener._thread) +def test_queue_listener_multi_start(self): +handler = TestHandler(support.Matcher()) +with logging.handlers.QueueListener(self.queue, handler) as listener: +self.assertRaises(RuntimeError, listener.start) + +with listener: +self.assertRaises(RuntimeError, listener.start) + +listener.start() +listener.stop() + def test_queue_listener_with_StreamHandler(self): # Test that traceback and stack-info only appends once (bpo-34334, bpo-46755). listener = logging.handlers.QueueListener(self.queue, self.root_hdlr) diff --git a/Misc/NEWS.d/next/Library/2025-04-12-09-30-24.gh-issue-132106.OxUds3.rst b/Misc/NEWS.d/next/Library/2025-04-12-09-30-24.gh-issue-132106.OxUds3.rst new file mode 100644 index 00..b6d58a29f9b42f --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-04-12-09-30-24.gh-issue-132106.OxUds3.rst @@ -0,0 +1,2 @@ +:meth:`QueueListener.start ` now +raises a :exc:`RuntimeError` if the listener is already started. ___ Python-checkins mailing list -- [email protected] To unsubscribe send an email to [email protected] https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: [email protected]
[Python-checkins] gh-131624: Fix posix_spawn tests failing on NetBSD with stack limit assertions (GH-131625)
https://github.com/python/cpython/commit/c7f6535e4a3b447fbd67bf98eea82fd243e780be commit: c7f6535e4a3b447fbd67bf98eea82fd243e780be branch: main author: Furkan Onder committer: serhiy-storchaka date: 2025-04-13T14:06:38+03:00 summary: gh-131624: Fix posix_spawn tests failing on NetBSD with stack limit assertions (GH-131625) Fix recursive limit assertions on NetBSD for posix_spawn. files: M Python/ceval.c diff --git a/Python/ceval.c b/Python/ceval.c index e4a63ad9287783..278d9e36045da2 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -437,7 +437,7 @@ _Py_InitializeRecursionLimits(PyThreadState *tstate) _tstate->c_stack_soft_limit = _tstate->c_stack_hard_limit + PYOS_STACK_MARGIN_BYTES; #else uintptr_t here_addr = _Py_get_machine_stack_pointer(); -# if defined(HAVE_PTHREAD_GETATTR_NP) && !defined(_AIX) +# if defined(HAVE_PTHREAD_GETATTR_NP) && !defined(_AIX) && !defined(__NetBSD__) size_t stack_size, guard_size; void *stack_addr; pthread_attr_t attr; ___ Python-checkins mailing list -- [email protected] To unsubscribe send an email to [email protected] https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: [email protected]
