Compare commits

...

10 commits

Author SHA1 Message Date
Thomas Wouters
115ee7ba5c Post 3.13.9 2025-10-14 20:35:49 +02:00
Thomas Wouters
e40f1619ec Python 3.13.9
-----BEGIN PGP SIGNATURE-----
 
 iQKTBAABCgB9FiEEcWlgX2LHUTVtBUomqCHmgOX6YwUFAmjuVaJfFIAAAAAALgAo
 aXNzdWVyLWZwckBub3RhdGlvbnMub3BlbnBncC5maWZ0aGhvcnNlbWFuLm5ldDcx
 Njk2MDVGNjJDNzUxMzU2RDA1NEEyNkE4MjFFNjgwRTVGQTYzMDUACgkQqCHmgOX6
 YwXJow//cfFrVV9JbaBvZhMPnVAdjPfLd1sskCzTEvM/SkNmUqqmjUGh6TgCf9uZ
 ujSDe8sZ+ihDSPMFEWg7uQQULn2qKioCvGptVMHIWIKaWjutb3qZJBfXKIFxpvr4
 jZyLnRsTVQZ3RllPGjlb0WzBrazmCLmVOsZyHCAmRpeSPPE77KJXn9dsz5PlA+KH
 8n2LsvuG2hqF46NBZu0ro43d6rX16TrBI7CGMZQMTMkDGe75vIQrhk/2Ek66UZtA
 6Y5grca1vsnSEPNaVXLKpC+Ndosf6ziI23YLoAnsE8q15lEsEwAiS8Rx2rqiWVgb
 MwrUccveyiqm5/bv0v+MHXOXzuipEchR/YfdyJPBm1JyeOEvYX+Zsp0sMe5nVIV8
 WHWgnrb0A0pIbCLL5LqoPdCrksOq23NYkE/ayvHmaOhFsQ62vedts/RFLpnyPlVl
 9iY/XE098MUvngsDkkCVqNwkZNYWymqnDRm2hqPWNqQlDSCPGhpR4dcPLr0FW8Ji
 iJUdYJ0Q5h6YJOMLZyfRkqlPUxay7PSw6+PjaKyHChpAAPlhqPqjsYcLSjxRJ3QX
 R5A7V1gavRV0opHnQzDoQxMacjmCA3ELnAXqBly8YyjOB+OuRg5UP1xDlwYkaHF4
 mwMMw731XM98MXphu4Q0PW594TQplLbDsdpmcWimFtAJu2NVW4U=
 =hm/l
 -----END PGP SIGNATURE-----

Python 3.13.9
2025-10-14 20:33:45 +02:00
Serhiy Storchaka
92f7965cf6
[3.13] gh-139640: Fix swallowing syntax warnings in different modules (GH-139755) (GH-140119)
Revert GH-131993.

Fix swallowing some syntax warnings in different modules if they accidentally
have the same message and are emitted from the same line.

Fix duplicated warnings in the "finally" block.

(cherry picked from commit 279db6bede)
2025-10-14 15:46:11 +00:00
Stan Ulbrych
c5ec267311
[3.13] gh-101828: Fix jisx0213 codecs removing null characters (gh-139340) (gh-140112)
* [3.13] gh-101828: Fix `jisx0213` codecs removing null characters (gh-139340)
(cherry picked from commit 87eadce3e0)

Co-authored-by: Stan Ulbrych <89152624+StanFromIreland@users.noreply.github.com>

* Accidentally removed line
2025-10-14 14:48:29 +00:00
Miss Islington (bot)
2f27098b42
[3.13] gh-106318: Add examples for str.istitle() (GH-140046) (#140114)
Co-authored-by: Adorilson Bezerra <adorilson@gmail.com>
2025-10-14 14:25:57 +00:00
Miss Islington (bot)
bc3f2885f4
[3.13] gh-114827: clarify threading.Event.wait timeout behavior (GH-114834) (#140099)
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
Co-authored-by: Kumar Aditya <kumaraditya@python.org>
2025-10-14 14:13:31 +00:00
Thomas Wouters
8183fa5e3f Python 3.13.9 2025-10-14 15:52:31 +02:00
Miss Islington (bot)
bc2c8d748c [3.13] gh-139783: Fix inspect.getsourcelines() for the case when a decorator is followed by a comment or an empty line (GH-139836) (GH-139890)
(cherry picked from commit f4104f5d74)

Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
2025-10-14 15:47:20 +02:00
Sergey B Kirpichev
bfb9639352
[3.13] gh-102431: Clarify constraints on operands of Decimal logical operations (GH-102836) (#140106)
* [3.13] gh-102431: Clarify constraints on operands of Decimal logical operations (GH-102836)

Sync C/Python implementation of the decimal: logical_ops for contexts.
(cherry picked from commit 6ecf77dbde)

Co-authored-by: Sergey B Kirpichev <skirpichev@gmail.com>
2025-10-14 15:45:02 +02:00
Miss Islington (bot)
7992a29512
[3.13] GH-140058: Clear key and value if PyTuple_New fails in dictiter_iternextitem (GH-140059) (#140108)
GH-140058: Clear key and value if `PyTuple_New` fails in `dictiter_iternextitem` (GH-140059)
(cherry picked from commit ded59f7e8e)

Co-authored-by: Sergey Miryanov <sergey.miryanov@gmail.com>
2025-10-14 13:40:13 +00:00
19 changed files with 228 additions and 72 deletions

View file

@ -2021,6 +2021,19 @@ expression support in the :mod:`re` module).
character, for example uppercase characters may only follow uncased characters
and lowercase characters only cased ones. Return ``False`` otherwise.
For example:
.. doctest::
>>> 'Spam, Spam, Spam'.istitle()
True
>>> 'spam, spam, spam'.istitle()
False
>>> 'SPAM, SPAM, SPAM'.istitle()
False
See also :meth:`title`.
.. method:: str.isupper()
@ -2398,6 +2411,8 @@ expression support in the :mod:`re` module).
>>> titlecase("they're bill's friends.")
"They're Bill's Friends."
See also :meth:`istitle`.
.. method:: str.translate(table, /)

View file

@ -18,9 +18,3 @@ 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);

View file

@ -18,12 +18,12 @@
/*--start constants--*/
#define PY_MAJOR_VERSION 3
#define PY_MINOR_VERSION 13
#define PY_MICRO_VERSION 8
#define PY_MICRO_VERSION 9
#define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_FINAL
#define PY_RELEASE_SERIAL 0
/* Version as a string */
#define PY_VERSION "3.13.8+"
#define PY_VERSION "3.13.9+"
/*--end constants--*/
/* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2.

View file

@ -3302,7 +3302,10 @@ def _fill_logical(self, context, opa, opb):
return opa, opb
def logical_and(self, other, context=None):
"""Applies an 'and' operation between self and other's digits."""
"""Applies an 'and' operation between self and other's digits.
Both self and other must be logical numbers.
"""
if context is None:
context = getcontext()
@ -3319,14 +3322,20 @@ def logical_and(self, other, context=None):
return _dec_from_triple(0, result.lstrip('0') or '0', 0)
def logical_invert(self, context=None):
"""Invert all its digits."""
"""Invert all its digits.
The self must be logical number.
"""
if context is None:
context = getcontext()
return self.logical_xor(_dec_from_triple(0,'1'*context.prec,0),
context)
def logical_or(self, other, context=None):
"""Applies an 'or' operation between self and other's digits."""
"""Applies an 'or' operation between self and other's digits.
Both self and other must be logical numbers.
"""
if context is None:
context = getcontext()
@ -3343,7 +3352,10 @@ def logical_or(self, other, context=None):
return _dec_from_triple(0, result.lstrip('0') or '0', 0)
def logical_xor(self, other, context=None):
"""Applies an 'xor' operation between self and other's digits."""
"""Applies an 'xor' operation between self and other's digits.
Both self and other must be logical numbers.
"""
if context is None:
context = getcontext()

View file

@ -1,4 +1,4 @@
# Autogenerated by Sphinx on Tue Oct 7 14:01:47 2025
# Autogenerated by Sphinx on Tue Oct 14 15:52:27 2025
# as part of the release process.
topics = {

View file

@ -282,6 +282,23 @@ def test_incrementalencoder_del_segfault(self):
with self.assertRaises(AttributeError):
del e.errors
def test_null_terminator(self):
# see gh-101828
text = "フルーツ"
try:
text.encode(self.encoding)
except UnicodeEncodeError:
text = "Python is cool"
encode_w_null = (text + "\0").encode(self.encoding)
encode_plus_null = text.encode(self.encoding) + "\0".encode(self.encoding)
self.assertTrue(encode_w_null.endswith(b'\x00'))
self.assertEqual(encode_w_null, encode_plus_null)
encode_w_null_2 = (text + "\0" + text + "\0").encode(self.encoding)
encode_plus_null_2 = encode_plus_null + encode_plus_null
self.assertEqual(encode_w_null_2.count(b'\x00'), 2)
self.assertEqual(encode_w_null_2, encode_plus_null_2)
class TestBase_Mapping(unittest.TestCase):
pass_enctest = []

View file

@ -1528,22 +1528,21 @@ async def name_4():
[[]]
def test_compile_warnings(self):
# See gh-131927
# Compile warnings originating from the same file and
# line are now only emitted once.
# Each invocation of compile() emits compiler warnings, even if they
# have the same message and line number.
source = textwrap.dedent(r"""
# tokenizer
1or 0 # line 3
# code generator
1 is 1 # line 5
""")
with warnings.catch_warnings(record=True) as caught:
warnings.simplefilter("default")
compile('1 is 1', '<stdin>', 'eval')
compile('1 is 1', '<stdin>', 'eval')
for i in range(2):
# Even if compile() is at the same line.
compile(source, '<stdin>', 'exec')
self.assertEqual(len(caught), 1)
with warnings.catch_warnings(record=True) as caught:
warnings.simplefilter("always")
compile('1 is 1', '<stdin>', 'eval')
compile('1 is 1', '<stdin>', 'eval')
self.assertEqual(len(caught), 2)
self.assertEqual([wm.lineno for wm in caught], [3, 5] * 2)
def test_compile_warning_in_finally(self):
# Ensure that warnings inside finally blocks are
@ -1554,16 +1553,47 @@ def test_compile_warning_in_finally(self):
try:
pass
finally:
1 is 1
1 is 1 # line 5
try:
pass
finally: # nested
1 is 1 # line 9
""")
with warnings.catch_warnings(record=True) as caught:
warnings.simplefilter("default")
warnings.simplefilter("always")
compile(source, '<stdin>', 'exec')
self.assertEqual(len(caught), 1)
self.assertEqual(caught[0].category, SyntaxWarning)
self.assertIn("\"is\" with 'int' literal", str(caught[0].message))
self.assertEqual(sorted(wm.lineno for wm in caught), [5, 9])
for wm in caught:
self.assertEqual(wm.category, SyntaxWarning)
self.assertIn("\"is\" with 'int' literal", str(wm.message))
# Other code path is used for "try" with "except*".
source = textwrap.dedent("""
try:
pass
except *Exception:
pass
finally:
1 is 1 # line 7
try:
pass
except *Exception:
pass
finally: # nested
1 is 1 # line 13
""")
with warnings.catch_warnings(record=True) as caught:
warnings.simplefilter("always")
compile(source, '<stdin>', 'exec')
self.assertEqual(sorted(wm.lineno for wm in caught), [7, 13])
for wm in caught:
self.assertEqual(wm.category, SyntaxWarning)
self.assertIn("\"is\" with 'int' literal", str(wm.message))
@requires_debug_ranges()
class TestSourcePositions(unittest.TestCase):

View file

@ -650,7 +650,8 @@ def wait(self, timeout=None):
(or fractions thereof).
This method returns the internal flag on exit, so it will always return
True except if a timeout is given and the operation times out.
``True`` except if a timeout is given and the operation times out, when
it will return ``False``.
"""
with self._cond:

8
Misc/NEWS.d/3.13.9.rst Normal file
View file

@ -0,0 +1,8 @@
.. date: 2025-10-09-13-48-28
.. gh-issue: 139783
.. nonce: __NUgo
.. release date: 2025-10-14
.. section: Library
Fix :func:`inspect.getsourcelines` for the case when a decorator is followed
by a comment or an empty line.

View file

@ -0,0 +1,3 @@
Fix swallowing some syntax warnings in different modules if they
accidentally have the same message and are emitted from the same line.
Fix duplicated warnings in the ``finally`` block.

View file

@ -0,0 +1,2 @@
Clarify constraints for "logical" arguments in methods of
:class:`decimal.Context`.

View file

@ -0,0 +1,3 @@
Fix ``'shift_jisx0213'``, ``'shift_jis_2004'``, ``'euc_jisx0213'`` and
``'euc_jis_2004'`` codecs truncating null chars
as they were treated as part of multi-character sequences.

View file

@ -282,22 +282,26 @@ an infinity then Decimal('Infinity') is returned.\n\
PyDoc_STRVAR(doc_logical_and,
"logical_and($self, /, other, context=None)\n--\n\n\
Return the digit-wise 'and' of the two (logical) operands.\n\
Applies an 'and' operation between self and other's digits.\n\n\
Both self and other must be logical numbers.\n\
\n");
PyDoc_STRVAR(doc_logical_invert,
"logical_invert($self, /, context=None)\n--\n\n\
Return the digit-wise inversion of the (logical) operand.\n\
Invert all its digits.\n\n\
The self must be logical number.\n\
\n");
PyDoc_STRVAR(doc_logical_or,
"logical_or($self, /, other, context=None)\n--\n\n\
Return the digit-wise 'or' of the two (logical) operands.\n\
Applies an 'or' operation between self and other's digits.\n\n\
Both self and other must be logical numbers. \n\
\n");
PyDoc_STRVAR(doc_logical_xor,
"logical_xor($self, /, other, context=None)\n--\n\n\
Return the digit-wise 'exclusive or' of the two (logical) operands.\n\
Applies an 'xor' operation between self and other's digits.\n\n\
Both self and other must be logical numbers.\n\
\n");
PyDoc_STRVAR(doc_max,
@ -702,22 +706,90 @@ Return the exponent of the magnitude of the operand's MSD.\n\
PyDoc_STRVAR(doc_ctx_logical_and,
"logical_and($self, x, y, /)\n--\n\n\
Digit-wise and of x and y.\n\
Applies the logical operation 'and' between each operand's digits.\n\n\
The operands must be both logical numbers.\n\n\
>>> ExtendedContext.logical_and(Decimal('0'), Decimal('0'))\n\
Decimal('0')\n\
>>> ExtendedContext.logical_and(Decimal('0'), Decimal('1'))\n\
Decimal('0')\n\
>>> ExtendedContext.logical_and(Decimal('1'), Decimal('0'))\n\
Decimal('0')\n\
>>> ExtendedContext.logical_and(Decimal('1'), Decimal('1'))\n\
Decimal('1')\n\
>>> ExtendedContext.logical_and(Decimal('1100'), Decimal('1010'))\n\
Decimal('1000')\n\
>>> ExtendedContext.logical_and(Decimal('1111'), Decimal('10'))\n\
Decimal('10')\n\
>>> ExtendedContext.logical_and(110, 1101)\n\
Decimal('100')\n\
>>> ExtendedContext.logical_and(Decimal(110), 1101)\n\
Decimal('100')\n\
>>> ExtendedContext.logical_and(110, Decimal(1101))\n\
Decimal('100')\n\
\n");
PyDoc_STRVAR(doc_ctx_logical_invert,
"logical_invert($self, x, /)\n--\n\n\
Invert all digits of x.\n\
Invert all the digits in the operand.\n\n\
The operand must be a logical number.\n\n\
>>> ExtendedContext.logical_invert(Decimal('0'))\n\
Decimal('111111111')\n\
>>> ExtendedContext.logical_invert(Decimal('1'))\n\
Decimal('111111110')\n\
>>> ExtendedContext.logical_invert(Decimal('111111111'))\n\
Decimal('0')\n\
>>> ExtendedContext.logical_invert(Decimal('101010101'))\n\
Decimal('10101010')\n\
>>> ExtendedContext.logical_invert(1101)\n\
Decimal('111110010')\n\
\n");
PyDoc_STRVAR(doc_ctx_logical_or,
"logical_or($self, x, y, /)\n--\n\n\
Digit-wise or of x and y.\n\
Applies the logical operation 'or' between each operand's digits.\n\n\
The operands must be both logical numbers.\n\n\
>>> ExtendedContext.logical_or(Decimal('0'), Decimal('0'))\n\
Decimal('0')\n\
>>> ExtendedContext.logical_or(Decimal('0'), Decimal('1'))\n\
Decimal('1')\n\
>>> ExtendedContext.logical_or(Decimal('1'), Decimal('0'))\n\
Decimal('1')\n\
>>> ExtendedContext.logical_or(Decimal('1'), Decimal('1'))\n\
Decimal('1')\n\
>>> ExtendedContext.logical_or(Decimal('1100'), Decimal('1010'))\n\
Decimal('1110')\n\
>>> ExtendedContext.logical_or(Decimal('1110'), Decimal('10'))\n\
Decimal('1110')\n\
>>> ExtendedContext.logical_or(110, 1101)\n\
Decimal('1111')\n\
>>> ExtendedContext.logical_or(Decimal(110), 1101)\n\
Decimal('1111')\n\
>>> ExtendedContext.logical_or(110, Decimal(1101))\n\
Decimal('1111')\n\
\n");
PyDoc_STRVAR(doc_ctx_logical_xor,
"logical_xor($self, x, y, /)\n--\n\n\
Digit-wise xor of x and y.\n\
Applies the logical operation 'xor' between each operand's digits.\n\n\
The operands must be both logical numbers.\n\n\
>>> ExtendedContext.logical_xor(Decimal('0'), Decimal('0'))\n\
Decimal('0')\n\
>>> ExtendedContext.logical_xor(Decimal('0'), Decimal('1'))\n\
Decimal('1')\n\
>>> ExtendedContext.logical_xor(Decimal('1'), Decimal('0'))\n\
Decimal('1')\n\
>>> ExtendedContext.logical_xor(Decimal('1'), Decimal('1'))\n\
Decimal('0')\n\
>>> ExtendedContext.logical_xor(Decimal('1100'), Decimal('1010'))\n\
Decimal('110')\n\
>>> ExtendedContext.logical_xor(Decimal('1111'), Decimal('10'))\n\
Decimal('1101')\n\
>>> ExtendedContext.logical_xor(110, 1101)\n\
Decimal('1011')\n\
>>> ExtendedContext.logical_xor(Decimal(110), 1101)\n\
Decimal('1011')\n\
>>> ExtendedContext.logical_xor(110, Decimal(1101))\n\
Decimal('1011')\n\
\n");
PyDoc_STRVAR(doc_ctx_max,

View file

@ -802,10 +802,13 @@ jisx0213_encoder(const MultibyteCodec *codec, const Py_UCS4 *data,
return coded;
case 2: /* second character of unicode pair */
coded = find_pairencmap((ucs2_t)data[0], (ucs2_t)data[1],
jisx0213_pair_encmap, JISX0213_ENCPAIRS);
if (coded != DBCINV)
return coded;
if (data[1] != 0) { /* Don't consume null char as part of pair */
coded = find_pairencmap((ucs2_t)data[0], (ucs2_t)data[1],
jisx0213_pair_encmap, JISX0213_ENCPAIRS);
if (coded != DBCINV) {
return coded;
}
}
/* fall through */
case -1: /* flush unterminated */

View file

@ -192,8 +192,11 @@ ENCODER(euc_jis_2004)
JISX0213_ENCPAIRS);
if (code == DBCINV)
return 1;
} else
}
else if (c2 != 0) {
/* Don't consume null char as part of pair */
insize = 2;
}
}
}
}
@ -611,8 +614,10 @@ ENCODER(shift_jis_2004)
if (code == DBCINV)
return 1;
}
else
else if (ch2 != 0) {
/* Don't consume null char as part of pair */
insize = 2;
}
}
}
}

View file

@ -5611,8 +5611,11 @@ dictiter_iternextitem(PyObject *self)
}
else {
result = PyTuple_New(2);
if (result == NULL)
if (result == NULL) {
Py_DECREF(key);
Py_DECREF(value);
return NULL;
}
PyTuple_SET_ITEM(result, 0, key);
PyTuple_SET_ITEM(result, 1, value);
}

View file

@ -1317,28 +1317,6 @@ 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, &registry)) {
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,

View file

@ -291,6 +291,7 @@ struct compiler {
bool c_save_nested_seqs; /* if true, construct recursive instruction sequences
* (including instructions for nested code objects)
*/
int c_disable_warning;
};
#define INSTR_SEQUENCE(C) ((C)->u->u_instr_sequence)
@ -1437,6 +1438,9 @@ compiler_push_fblock(struct compiler *c, location loc,
f->fb_loc = loc;
f->fb_exit = exit;
f->fb_datum = datum;
if (t == FINALLY_END) {
c->c_disable_warning++;
}
return SUCCESS;
}
@ -1448,6 +1452,9 @@ compiler_pop_fblock(struct compiler *c, enum fblocktype t, jump_target_label blo
u->u_nfblocks--;
assert(u->u_fblock[u->u_nfblocks].fb_type == t);
assert(SAME_LABEL(u->u_fblock[u->u_nfblocks].fb_block, block_label));
if (t == FINALLY_END) {
c->c_disable_warning--;
}
}
static int
@ -6609,6 +6616,9 @@ static int
compiler_warn(struct compiler *c, location loc,
const char *format, ...)
{
if (c->c_disable_warning) {
return SUCCESS;
}
va_list vargs;
va_start(vargs, format);
PyObject *msg = PyUnicode_FromFormatV(format, vargs);
@ -6616,8 +6626,8 @@ compiler_warn(struct compiler *c, location loc,
if (msg == NULL) {
return ERROR;
}
if (_PyErr_WarnExplicitObjectWithContext(PyExc_SyntaxWarning, msg,
c->c_filename, loc.lineno) < 0)
if (PyErr_WarnExplicitObject(PyExc_SyntaxWarning, msg,
c->c_filename, loc.lineno, NULL, NULL) < 0)
{
if (PyErr_ExceptionMatches(PyExc_SyntaxWarning)) {
/* Replace the SyntaxWarning exception with a SyntaxError

View file

@ -1,4 +1,4 @@
This is Python version 3.13.8
This is Python version 3.13.9
=============================
.. image:: https://github.com/python/cpython/workflows/Tests/badge.svg