Skip to content

Commit 5992976

Browse files
Merge branch 'main' into fix/pickle-reduce-args-tuple-check
2 parents c94ad8b + 45d00a0 commit 5992976

25 files changed

+235
-185
lines changed

Doc/library/stdtypes.rst

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2163,6 +2163,8 @@ expression support in the :mod:`re` module).
21632163

21642164
.. doctest::
21652165

2166+
>>> 'spam, spam, spam'.index('spam')
2167+
0
21662168
>>> 'spam, spam, spam'.index('eggs')
21672169
Traceback (most recent call last):
21682170
File "<python-input-0>", line 1, in <module>
@@ -2546,6 +2548,20 @@ expression support in the :mod:`re` module).
25462548

25472549
Like :meth:`rfind` but raises :exc:`ValueError` when the substring *sub* is not
25482550
found.
2551+
For example:
2552+
2553+
.. doctest::
2554+
2555+
>>> 'spam, spam, spam'.rindex('spam')
2556+
12
2557+
>>> 'spam, spam, spam'.rindex('eggs')
2558+
Traceback (most recent call last):
2559+
File "<stdin-0>", line 1, in <module>
2560+
'spam, spam, spam'.rindex('eggs')
2561+
~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^
2562+
ValueError: substring not found
2563+
2564+
See also :meth:`index` and :meth:`find`.
25492565

25502566

25512567
.. method:: str.rjust(width, fillchar=' ', /)

Doc/library/tomllib.rst

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,25 @@
44
.. module:: tomllib
55
:synopsis: Parse TOML files.
66

7-
.. versionadded:: 3.11
8-
97
.. moduleauthor:: Taneli Hukkinen
108
.. sectionauthor:: Taneli Hukkinen
119

1210
**Source code:** :source:`Lib/tomllib`
1311

1412
--------------
1513

16-
This module provides an interface for parsing TOML 1.0.0 (Tom's Obvious Minimal
14+
This module provides an interface for parsing TOML 1.1.0 (Tom's Obvious Minimal
1715
Language, `https://toml.io <https://toml.io/en/>`_). This module does not
1816
support writing TOML.
1917

18+
.. versionadded:: 3.11
19+
The module was added with support for TOML 1.0.0.
20+
21+
.. versionchanged:: next
22+
Added TOML 1.1.0 support.
23+
See the :ref:`What's New <whatsnew315-tomllib-1-1-0>` for details.
24+
25+
2026
.. seealso::
2127

2228
The :pypi:`Tomli-W package <tomli-w>`

Doc/whatsnew/3.15.rst

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -867,6 +867,56 @@ tkinter
867867
with outdated names.
868868
(Contributed by Serhiy Storchaka in :gh:`143754`)
869869

870+
871+
.. _whatsnew315-tomllib-1-1-0:
872+
873+
tomllib
874+
-------
875+
876+
* The :mod:`tomllib` module now supports TOML 1.1.0.
877+
This is a backwards compatible update, meaning that all valid TOML 1.0.0
878+
documents are parsed the same way.
879+
880+
The changes, according to the `official TOML changelog`_, are:
881+
882+
- Allow newlines and trailing commas in inline tables.
883+
884+
Previously an inline table had to be on a single line and couldn't end
885+
with a trailing comma. This is now relaxed so that the following is valid:
886+
887+
.. syntax highlighting needs TOML 1.1.0 support in Pygments,
888+
see https://github.com/pygments/pygments/issues/3026
889+
890+
.. code-block:: text
891+
892+
tbl = {
893+
key = "a string",
894+
moar-tbl = {
895+
key = 1,
896+
},
897+
}
898+
899+
- Add ``\xHH`` notation to basic strings for codepoints under 255,
900+
and the ``\e`` escape for the escape character:
901+
902+
.. code-block:: text
903+
904+
null = "null byte: \x00; letter a: \x61"
905+
csi = "\e["
906+
907+
- Seconds in datetime and time values are now optional.
908+
The following are now valid:
909+
910+
.. code-block:: text
911+
912+
dt = 2010-02-03 14:15
913+
t = 14:15
914+
915+
(Contributed by Taneli Hukkinen in :gh:`142956`.)
916+
917+
.. _official TOML changelog: https://github.com/toml-lang/toml/blob/main/CHANGELOG.md
918+
919+
870920
types
871921
------
872922

Lib/_pyrepl/windows_console.py

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -43,14 +43,11 @@
4343
from .windows_eventqueue import EventQueue
4444

4545
try:
46-
from ctypes import get_last_error, GetLastError, WinDLL, windll, WinError # type: ignore[attr-defined]
46+
from ctypes import get_last_error, WinDLL, windll, WinError # type: ignore[attr-defined]
4747
except:
4848
# Keep MyPy happy off Windows
4949
from ctypes import CDLL as WinDLL, cdll as windll
5050

51-
def GetLastError() -> int:
52-
return 42
53-
5451
def get_last_error() -> int:
5552
return 42
5653

@@ -149,16 +146,18 @@ def __init__(
149146

150147
# Save original console modes so we can recover on cleanup.
151148
original_input_mode = DWORD()
152-
GetConsoleMode(InHandle, original_input_mode)
149+
if not GetConsoleMode(InHandle, original_input_mode):
150+
raise WinError(get_last_error())
153151
trace(f'saved original input mode 0x{original_input_mode.value:x}')
154152
self.__original_input_mode = original_input_mode.value
155153

156-
SetConsoleMode(
154+
if not SetConsoleMode(
157155
OutHandle,
158156
ENABLE_WRAP_AT_EOL_OUTPUT
159157
| ENABLE_PROCESSED_OUTPUT
160158
| ENABLE_VIRTUAL_TERMINAL_PROCESSING,
161-
)
159+
):
160+
raise WinError(get_last_error())
162161

163162
self.screen: list[str] = []
164163
self.width = 80
@@ -301,7 +300,7 @@ def _scroll(
301300
if not ScrollConsoleScreenBuffer(
302301
OutHandle, scroll_rect, None, destination_origin, fill_info
303302
):
304-
raise WinError(GetLastError())
303+
raise WinError(get_last_error())
305304

306305
def _hide_cursor(self):
307306
self.__write("\x1b[?25l")
@@ -335,7 +334,7 @@ def __write(self, text: str) -> None:
335334
def screen_xy(self) -> tuple[int, int]:
336335
info = CONSOLE_SCREEN_BUFFER_INFO()
337336
if not GetConsoleScreenBufferInfo(OutHandle, info):
338-
raise WinError(GetLastError())
337+
raise WinError(get_last_error())
339338
return info.dwCursorPosition.X, info.dwCursorPosition.Y
340339

341340
def _erase_to_end(self) -> None:
@@ -350,14 +349,16 @@ def prepare(self) -> None:
350349
self.__offset = 0
351350

352351
if self.__vt_support:
353-
SetConsoleMode(InHandle, self.__original_input_mode | ENABLE_VIRTUAL_TERMINAL_INPUT)
352+
if not SetConsoleMode(InHandle, self.__original_input_mode | ENABLE_VIRTUAL_TERMINAL_INPUT):
353+
raise WinError(get_last_error())
354354
self._enable_bracketed_paste()
355355

356356
def restore(self) -> None:
357357
if self.__vt_support:
358358
# Recover to original mode before running REPL
359359
self._disable_bracketed_paste()
360-
SetConsoleMode(InHandle, self.__original_input_mode)
360+
if not SetConsoleMode(InHandle, self.__original_input_mode):
361+
raise WinError(get_last_error())
361362

362363
def _move_relative(self, x: int, y: int) -> None:
363364
"""Moves relative to the current posxy"""
@@ -394,7 +395,7 @@ def getheightwidth(self) -> tuple[int, int]:
394395
and width of the terminal window in characters."""
395396
info = CONSOLE_SCREEN_BUFFER_INFO()
396397
if not GetConsoleScreenBufferInfo(OutHandle, info):
397-
raise WinError(GetLastError())
398+
raise WinError(get_last_error())
398399
return (
399400
info.srWindow.Bottom - info.srWindow.Top + 1,
400401
info.srWindow.Right - info.srWindow.Left + 1,
@@ -403,15 +404,15 @@ def getheightwidth(self) -> tuple[int, int]:
403404
def _getscrollbacksize(self) -> int:
404405
info = CONSOLE_SCREEN_BUFFER_INFO()
405406
if not GetConsoleScreenBufferInfo(OutHandle, info):
406-
raise WinError(GetLastError())
407+
raise WinError(get_last_error())
407408

408409
return info.srWindow.Bottom # type: ignore[no-any-return]
409410

410411
def _read_input(self) -> INPUT_RECORD | None:
411412
rec = INPUT_RECORD()
412413
read = DWORD()
413414
if not ReadConsoleInput(InHandle, rec, 1, read):
414-
raise WinError(GetLastError())
415+
raise WinError(get_last_error())
415416

416417
return rec
417418

@@ -421,7 +422,7 @@ def _read_input_bulk(
421422
rec = (n * INPUT_RECORD)()
422423
read = DWORD()
423424
if not ReadConsoleInput(InHandle, rec, n, read):
424-
raise WinError(GetLastError())
425+
raise WinError(get_last_error())
425426

426427
return rec, read.value
427428

@@ -523,7 +524,7 @@ def flushoutput(self) -> None:
523524
def forgetinput(self) -> None:
524525
"""Forget all pending, but not yet processed input."""
525526
if not FlushConsoleInputBuffer(InHandle):
526-
raise WinError(GetLastError())
527+
raise WinError(get_last_error())
527528

528529
def getpending(self) -> Event:
529530
"""Return the characters that have been typed but not yet

Lib/test/test_pyrepl/test_windows_console.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
from test.support import force_not_colorized_test_class
1111
from typing import Iterable
1212
from unittest import TestCase
13-
from unittest.mock import MagicMock, call
13+
from unittest.mock import MagicMock, call, patch
1414

1515
from .support import handle_all_events, code_to_events
1616
from .support import prepare_reader as default_prepare_reader
@@ -30,7 +30,21 @@
3030
pass
3131

3232

33+
def _mock_console_init(self, f_in=0, f_out=1, term="", encoding="utf-8"):
34+
"""Mock __init__ to avoid real Windows API calls in headless environments."""
35+
super(WindowsConsole, self).__init__(f_in, f_out, term, encoding)
36+
self.screen = []
37+
self.width = 80
38+
self.height = 25
39+
self._WindowsConsole__offset = 0
40+
self.posxy = (0, 0)
41+
self._WindowsConsole__vt_support = False
42+
self._WindowsConsole_original_input_mode = 0
43+
self.event_queue = wc.EventQueue('utf-8')
44+
45+
3346
@force_not_colorized_test_class
47+
@patch.object(WindowsConsole, '__init__', _mock_console_init)
3448
class WindowsConsoleTests(TestCase):
3549
def console(self, events, **kwargs) -> Console:
3650
console = WindowsConsole()
@@ -373,6 +387,7 @@ def test_multiline_ctrl_z(self):
373387
con.restore()
374388

375389

390+
@patch.object(WindowsConsole, '__init__', _mock_console_init)
376391
class WindowsConsoleGetEventTests(TestCase):
377392
# Virtual-Key Codes: https://learn.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes
378393
VK_BACK = 0x08

Lib/test/test_tomllib/burntsushi.py

Lines changed: 8 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,8 @@
77
import datetime
88
from typing import Any
99

10-
# Aliases for converting TOML compliance format [1] to BurntSushi format [2]
11-
# [1] https://github.com/toml-lang/compliance/blob/db7c3211fda30ff9ddb10292f4aeda7e2e10abc4/docs/json-encoding.md # noqa: E501
12-
# [2] https://github.com/BurntSushi/toml-test/blob/4634fdf3a6ecd6aaea5f4cdcd98b2733c2694993/README.md # noqa: E501
13-
_aliases = {
14-
"boolean": "bool",
15-
"offset datetime": "datetime",
16-
"local datetime": "datetime-local",
17-
"local date": "date-local",
18-
"local time": "time-local",
19-
}
20-
21-
22-
def convert(obj): # noqa: C901
10+
11+
def convert(obj):
2312
if isinstance(obj, str):
2413
return {"type": "string", "value": obj}
2514
elif isinstance(obj, bool):
@@ -53,31 +42,25 @@ def convert(obj): # noqa: C901
5342
def normalize(obj: Any) -> Any:
5443
"""Normalize test objects.
5544
56-
This normalizes primitive values (e.g. floats), and also converts from
57-
TOML compliance format [1] to BurntSushi format [2].
58-
59-
[1] https://github.com/toml-lang/compliance/blob/db7c3211fda30ff9ddb10292f4aeda7e2e10abc4/docs/json-encoding.md # noqa: E501
60-
[2] https://github.com/BurntSushi/toml-test/blob/4634fdf3a6ecd6aaea5f4cdcd98b2733c2694993/README.md # noqa: E501
61-
"""
45+
This normalizes primitive values (e.g. floats)."""
6246
if isinstance(obj, list):
6347
return [normalize(item) for item in obj]
6448
if isinstance(obj, dict):
6549
if "type" in obj and "value" in obj:
6650
type_ = obj["type"]
67-
norm_type = _aliases.get(type_, type_)
6851
value = obj["value"]
69-
if norm_type == "float":
52+
if type_ == "float":
7053
norm_value = _normalize_float_str(value)
71-
elif norm_type in {"datetime", "datetime-local"}:
54+
elif type_ in {"datetime", "datetime-local"}:
7255
norm_value = _normalize_datetime_str(value)
73-
elif norm_type == "time-local":
56+
elif type_ == "time-local":
7457
norm_value = _normalize_localtime_str(value)
7558
else:
7659
norm_value = value
7760

78-
if norm_type == "array":
61+
if type_ == "array":
7962
return [normalize(item) for item in value]
80-
return {"type": norm_type, "value": norm_value}
63+
return {"type": type_, "value": norm_value}
8164
return {k: normalize(v) for k, v in obj.items()}
8265
raise AssertionError("Burntsushi fixtures should be dicts/lists only")
8366

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
{
22
"local-dt": {"type":"datetime-local","value":"1988-10-27t01:01:01"},
3+
"local-dt-no-seconds": {"type":"datetime-local","value":"2025-04-18t20:05:00"},
34
"zulu-dt": {"type":"datetime","value":"1988-10-27t01:01:01z"}
45
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
local-dt=1988-10-27t01:01:01
2+
local-dt-no-seconds=2025-04-18T20:05
23
zulu-dt=1988-10-27t01:01:01z
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
11
{"t":
2-
{"type":"time-local","value":"00:00:00.999999"}}
2+
{"type":"time-local","value":"00:00:00.999999"},
3+
"t2":
4+
{"type":"time-local","value":"00:00:00"}}
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
t=00:00:00.99999999999999
1+
t=00:00:00.99999999999999
2+
t2=00:00

0 commit comments

Comments
 (0)