Skip to content

Commit bf5447b

Browse files
authored
Merge branch 'main' into pep750-concat-update
2 parents 8aeb512 + c49dc3b commit bf5447b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

59 files changed

+341
-176
lines changed

Doc/howto/logging-cookbook.rst

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4140,6 +4140,42 @@ The script, when run, prints something like:
41404140
2025-07-02 13:54:47,234 DEBUG fool me ...
41414141
2025-07-02 13:54:47,234 DEBUG can't get fooled again
41424142
4143+
If, on the other hand, you are concerned about `log injection
4144+
<https://owasp.org/www-community/attacks/Log_Injection>`_, you can use a
4145+
formatter which escapes newlines, as per the following example:
4146+
4147+
.. code-block:: python
4148+
4149+
import logging
4150+
4151+
logger = logging.getLogger(__name__)
4152+
4153+
class EscapingFormatter(logging.Formatter):
4154+
def format(self, record):
4155+
s = super().format(record)
4156+
return s.replace('\n', r'\n')
4157+
4158+
if __name__ == '__main__':
4159+
h = logging.StreamHandler()
4160+
h.setFormatter(EscapingFormatter('%(asctime)s %(levelname)-9s %(message)s'))
4161+
logging.basicConfig(level=logging.DEBUG, handlers = [h])
4162+
logger.debug('Single line')
4163+
logger.debug('Multiple lines:\nfool me once ...')
4164+
logger.debug('Another single line')
4165+
logger.debug('Multiple lines:\n%s', 'fool me ...\ncan\'t get fooled again')
4166+
4167+
You can, of course, use whatever escaping scheme makes the most sense for you.
4168+
The script, when run, should produce output like this:
4169+
4170+
.. code-block:: text
4171+
4172+
2025-07-09 06:47:33,783 DEBUG Single line
4173+
2025-07-09 06:47:33,783 DEBUG Multiple lines:\nfool me once ...
4174+
2025-07-09 06:47:33,783 DEBUG Another single line
4175+
2025-07-09 06:47:33,783 DEBUG Multiple lines:\nfool me ...\ncan't get fooled again
4176+
4177+
Escaping behaviour can't be the stdlib default , as it would break backwards
4178+
compatibility.
41434179

41444180
.. patterns-to-avoid:
41454181

Doc/library/codecs.rst

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,20 @@ wider range of codecs when working with binary files:
265265
:func:`iterencode`.
266266

267267

268+
.. function:: readbuffer_encode(buffer, errors=None, /)
269+
270+
Return a :class:`tuple` containing the raw bytes of *buffer*, a
271+
:ref:`buffer-compatible object <bufferobjects>` or :class:`str`
272+
(encoded to UTF-8 before processing), and their length in bytes.
273+
274+
The *errors* argument is ignored.
275+
276+
.. code-block:: pycon
277+
278+
>>> codecs.readbuffer_encode(b"Zito")
279+
(b'Zito', 4)
280+
281+
268282
The module also provides the following constants which are useful for reading
269283
and writing to platform dependent files:
270284

Doc/library/os.path.rst

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -298,9 +298,10 @@ the :mod:`glob` module.)
298298
device than *path*, or whether :file:`{path}/..` and *path* point to the same
299299
i-node on the same device --- this should detect mount points for all Unix
300300
and POSIX variants. It is not able to reliably detect bind mounts on the
301-
same filesystem. On Windows, a drive letter root and a share UNC are
302-
always mount points, and for any other path ``GetVolumePathName`` is called
303-
to see if it is different from the input path.
301+
same filesystem. On Linux systems, it will always return ``True`` for btrfs
302+
subvolumes, even if they aren't mount points. On Windows, a drive letter root
303+
and a share UNC are always mount points, and for any other path
304+
``GetVolumePathName`` is called to see if it is different from the input path.
304305

305306
.. versionchanged:: 3.4
306307
Added support for detecting non-root mount points on Windows.

Doc/library/sqlite3.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2288,7 +2288,7 @@ This section shows recipes for common adapters and converters.
22882288

22892289
def adapt_datetime_iso(val):
22902290
"""Adapt datetime.datetime to timezone-naive ISO 8601 date."""
2291-
return val.isoformat()
2291+
return val.replace(tzinfo=None).isoformat()
22922292

22932293
def adapt_datetime_epoch(val):
22942294
"""Adapt datetime.datetime to Unix timestamp."""

Doc/library/unittest.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2563,7 +2563,7 @@ To add cleanup code that must be run even in the case of an exception, use
25632563
.. versionadded:: 3.8
25642564

25652565

2566-
.. classmethod:: enterModuleContext(cm)
2566+
.. function:: enterModuleContext(cm)
25672567

25682568
Enter the supplied :term:`context manager`. If successful, also
25692569
add its :meth:`~object.__exit__` method as a cleanup function by

Lib/asyncio/__init__.py

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -51,15 +51,24 @@
5151
def __getattr__(name: str):
5252
import warnings
5353

54-
deprecated = {
55-
"AbstractEventLoopPolicy",
56-
"DefaultEventLoopPolicy",
57-
"WindowsSelectorEventLoopPolicy",
58-
"WindowsProactorEventLoopPolicy",
59-
}
60-
if name in deprecated:
61-
warnings._deprecated(f"asyncio.{name}", remove=(3, 16))
62-
# deprecated things have underscores in front of them
63-
return globals()["_" + name]
54+
match name:
55+
case "AbstractEventLoopPolicy":
56+
warnings._deprecated(f"asyncio.{name}", remove=(3, 16))
57+
return events._AbstractEventLoopPolicy
58+
case "DefaultEventLoopPolicy":
59+
warnings._deprecated(f"asyncio.{name}", remove=(3, 16))
60+
if sys.platform == 'win32':
61+
return windows_events._DefaultEventLoopPolicy
62+
return unix_events._DefaultEventLoopPolicy
63+
case "WindowsSelectorEventLoopPolicy":
64+
if sys.platform == 'win32':
65+
warnings._deprecated(f"asyncio.{name}", remove=(3, 16))
66+
return windows_events._WindowsSelectorEventLoopPolicy
67+
# Else fall through to the AttributeError below.
68+
case "WindowsProactorEventLoopPolicy":
69+
if sys.platform == 'win32':
70+
warnings._deprecated(f"asyncio.{name}", remove=(3, 16))
71+
return windows_events._WindowsProactorEventLoopPolicy
72+
# Else fall through to the AttributeError below.
6473

6574
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")

Lib/asyncio/__main__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ def callback():
6464
except BaseException as exc:
6565
future.set_exception(exc)
6666

67-
loop.call_soon_threadsafe(callback, context=self.context)
67+
self.loop.call_soon_threadsafe(callback, context=self.context)
6868

6969
try:
7070
return future.result()

Lib/asyncio/events.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,11 @@
55
# SPDX-FileCopyrightText: Copyright (c) 2015-2021 MagicStack Inc. http://magic.io
66

77
__all__ = (
8-
"_AbstractEventLoopPolicy",
98
"AbstractEventLoop",
109
"AbstractServer",
1110
"Handle",
1211
"TimerHandle",
13-
"_get_event_loop_policy",
1412
"get_event_loop_policy",
15-
"_set_event_loop_policy",
1613
"set_event_loop_policy",
1714
"get_event_loop",
1815
"set_event_loop",
@@ -791,7 +788,10 @@ def _init_event_loop_policy():
791788
global _event_loop_policy
792789
with _lock:
793790
if _event_loop_policy is None: # pragma: no branch
794-
from . import _DefaultEventLoopPolicy
791+
if sys.platform == 'win32':
792+
from .windows_events import _DefaultEventLoopPolicy
793+
else:
794+
from .unix_events import _DefaultEventLoopPolicy
795795
_event_loop_policy = _DefaultEventLoopPolicy()
796796

797797

Lib/asyncio/unix_events.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828

2929
__all__ = (
3030
'SelectorEventLoop',
31-
'_DefaultEventLoopPolicy',
3231
'EventLoop',
3332
)
3433

Lib/random.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -844,8 +844,8 @@ def binomialvariate(self, n=1, p=0.5):
844844
# BTRS: Transformed rejection with squeeze method by Wolfgang Hörmann
845845
# https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.47.8407&rep=rep1&type=pdf
846846
assert n*p >= 10.0 and p <= 0.5
847-
setup_complete = False
848847

848+
setup_complete = False
849849
spq = _sqrt(n * p * (1.0 - p)) # Standard deviation of the distribution
850850
b = 1.15 + 2.53 * spq
851851
a = -0.0873 + 0.0248 * b + 0.01 * p
@@ -860,22 +860,23 @@ def binomialvariate(self, n=1, p=0.5):
860860
k = _floor((2.0 * a / us + b) * u + c)
861861
if k < 0 or k > n:
862862
continue
863+
v = random()
863864

864865
# The early-out "squeeze" test substantially reduces
865866
# the number of acceptance condition evaluations.
866-
v = random()
867867
if us >= 0.07 and v <= vr:
868868
return k
869869

870-
# Acceptance-rejection test.
871-
# Note, the original paper erroneously omits the call to log(v)
872-
# when comparing to the log of the rescaled binomial distribution.
873870
if not setup_complete:
874871
alpha = (2.83 + 5.1 / b) * spq
875872
lpq = _log(p / (1.0 - p))
876873
m = _floor((n + 1) * p) # Mode of the distribution
877874
h = _lgamma(m + 1) + _lgamma(n - m + 1)
878875
setup_complete = True # Only needs to be done once
876+
877+
# Acceptance-rejection test.
878+
# Note, the original paper erroneously omits the call to log(v)
879+
# when comparing to the log of the rescaled binomial distribution.
879880
v *= alpha / (a / (us * us) + b)
880881
if _log(v) <= h - _lgamma(k + 1) - _lgamma(n - k + 1) + (k - m) * lpq:
881882
return k

0 commit comments

Comments
 (0)