Skip to content

Commit b83c966

Browse files
committed
Merge branch 'main' into utf-8-mode
# Conflicts: # Doc/whatsnew/3.15.rst
2 parents 3226e1d + 1a87b6e commit b83c966

48 files changed

Lines changed: 644 additions & 291 deletions

Some content is hidden

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

Doc/library/datetime.rst

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,22 @@ A :class:`timedelta` object represents a duration, the difference between two
261261
>>> (d.days, d.seconds, d.microseconds)
262262
(-1, 86399, 999999)
263263

264+
Since the string representation of :class:`!timedelta` objects can be confusing,
265+
use the following recipe to produce a more readable format:
266+
267+
.. code-block:: pycon
268+
269+
>>> def pretty_timedelta(td):
270+
... if td.days >= 0:
271+
... return str(td)
272+
... return f'-({-td!s})'
273+
...
274+
>>> d = timedelta(hours=-1)
275+
>>> str(d) # not human-friendly
276+
'-1 day, 23:00:00'
277+
>>> pretty_timedelta(d)
278+
'-(1:00:00)'
279+
264280
265281
Class attributes:
266282

Doc/library/shutil.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,10 @@ Directory and files operations
454454
:envvar:`PATH` environment variable is read from :data:`os.environ`,
455455
falling back to :data:`os.defpath` if it is not set.
456456

457+
If *cmd* contains a directory component, :func:`!which` only checks the
458+
specified path directly and does not search the directories listed in
459+
*path* or in the system's :envvar:`PATH` environment variable.
460+
457461
On Windows, the current directory is prepended to the *path* if *mode* does
458462
not include ``os.X_OK``. When the *mode* does include ``os.X_OK``, the
459463
Windows API ``NeedCurrentDirectoryForExePathW`` will be consulted to

Doc/using/windows.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ When you first install a runtime, you will likely be prompted to add a directory
9191
to your :envvar:`PATH`. This is optional, if you prefer to use the ``py``
9292
command, but is offered for those who prefer the full range of aliases (such
9393
as ``python3.14.exe``) to be available. The directory will be
94-
:file:`%LocalAppData%\Python\bin` by default, but may be customized by an
94+
:file:`%LocalAppData%\\Python\\bin` by default, but may be customized by an
9595
administrator. Click Start and search for "Edit environment variables for your
9696
account" for the system settings page to add the path.
9797

Doc/whatsnew/3.14.rst

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ and improvements in user-friendliness and correctness.
8888
* :ref:`PEP 758: Allow except and except* expressions without parentheses <whatsnew314-pep758>`
8989
* :ref:`PEP 761: Discontinuation of PGP signatures <whatsnew314-pep761>`
9090
* :ref:`PEP 765: Disallow return/break/continue that exit a finally block <whatsnew314-pep765>`
91+
* :ref:`Free-threaded mode improvements <whatsnew314-free-threaded-cpython>`
9192
* :ref:`PEP 768: Safe external debugger interface for CPython <whatsnew314-pep768>`
9293
* :ref:`PEP 784: Adding Zstandard to the standard library <whatsnew314-pep784>`
9394
* :ref:`A new type of interpreter <whatsnew314-tail-call>`
@@ -794,6 +795,27 @@ For further information on how to build Python, see
794795
(Contributed by Ken Jin in :gh:`128563`, with ideas on how to implement this
795796
in CPython by Mark Shannon, Garrett Gu, Haoran Xu, and Josh Haberman.)
796797

798+
.. _whatsnew314-free-threaded-cpython:
799+
800+
Free-threaded mode
801+
------------------
802+
803+
Free-threaded mode (:pep:`703`), initially added in 3.13, has been significantly improved.
804+
The implementation described in PEP 703 was finished, including C API changes,
805+
and temporary workarounds in the interpreter were replaced with more permanent solutions.
806+
The specializing adaptive interpreter (:pep:`659`) is now enabled in free-threaded mode,
807+
which along with many other optimizations greatly improves its performance.
808+
The performance penalty on single-threaded code in free-threaded mode is now roughly 5-10%,
809+
depending on platform and C compiler used.
810+
811+
This work was done by many contributors: Sam Gross, Matt Page, Neil Schemenauer,
812+
Thomas Wouters, Donghee Na, Kirill Podoprigora, Ken Jin, Itamar Oren,
813+
Brett Simmers, Dino Viehland, Nathan Goldbaum, Ralf Gommers, Lysandros Nikolaou,
814+
Kumar Aditya, Edgar Margffoy, and many others.
815+
816+
Some of these contributors are employed by Meta, which has continued to provide
817+
significant engineering resources to support this project.
818+
797819

798820
.. _whatsnew314-pyrepl-highlighting:
799821

Doc/whatsnew/3.15.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,10 @@ Other language changes
100100

101101
(Contributed by Adam Turner in :gh:`133711`; PEP 686 written by Inada Naoki.)
102102

103+
* Several error messages incorrectly using the term "argument" have been corrected.
104+
(Contributed by Stan Ulbrych in :gh:`133382`.)
105+
106+
103107
New modules
104108
===========
105109

Grammar/python.gram

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1305,7 +1305,7 @@ invalid_dict_comprehension:
13051305
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "dict unpacking cannot be used in dict comprehension") }
13061306
invalid_parameters:
13071307
| a="/" ',' {
1308-
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "at least one argument must precede /") }
1308+
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "at least one parameter must precede /") }
13091309
| (slash_no_default | slash_with_default) param_maybe_default* a='/' {
13101310
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "/ may appear only once") }
13111311
| slash_no_default? param_no_default* invalid_parameters_helper a=param_no_default {
@@ -1319,21 +1319,21 @@ invalid_parameters:
13191319
invalid_default:
13201320
| a='=' &(')'|',') { RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "expected default value expression") }
13211321
invalid_star_etc:
1322-
| a='*' (')' | ',' (')' | '**')) { RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "named arguments must follow bare *") }
1322+
| a='*' (')' | ',' (')' | '**')) { RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "named parameters must follow bare *") }
13231323
| '*' ',' TYPE_COMMENT { RAISE_SYNTAX_ERROR("bare * has associated type comment") }
1324-
| '*' param a='=' { RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "var-positional argument cannot have default value") }
1324+
| '*' param a='=' { RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "var-positional parameter cannot have default value") }
13251325
| '*' (param_no_default | ',') param_maybe_default* a='*' (param_no_default | ',') {
1326-
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "* argument may appear only once") }
1326+
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "* may appear only once") }
13271327
invalid_kwds:
1328-
| '**' param a='=' { RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "var-keyword argument cannot have default value") }
1329-
| '**' param ',' a=param { RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "arguments cannot follow var-keyword argument") }
1330-
| '**' param ',' a[Token*]=('*'|'**'|'/') { RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "arguments cannot follow var-keyword argument") }
1328+
| '**' param a='=' { RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "var-keyword parameter cannot have default value") }
1329+
| '**' param ',' a=param { RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "parameters cannot follow var-keyword parameter") }
1330+
| '**' param ',' a[Token*]=('*'|'**'|'/') { RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "parameters cannot follow var-keyword parameter") }
13311331
invalid_parameters_helper: # This is only there to avoid type errors
13321332
| a=slash_with_default { _PyPegen_singleton_seq(p, a) }
13331333
| param_with_default+
13341334
invalid_lambda_parameters:
13351335
| a="/" ',' {
1336-
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "at least one argument must precede /") }
1336+
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "at least one parameter must precede /") }
13371337
| (lambda_slash_no_default | lambda_slash_with_default) lambda_param_maybe_default* a='/' {
13381338
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "/ may appear only once") }
13391339
| lambda_slash_no_default? lambda_param_no_default* invalid_lambda_parameters_helper a=lambda_param_no_default {
@@ -1348,14 +1348,14 @@ invalid_lambda_parameters_helper:
13481348
| a=lambda_slash_with_default { _PyPegen_singleton_seq(p, a) }
13491349
| lambda_param_with_default+
13501350
invalid_lambda_star_etc:
1351-
| '*' (':' | ',' (':' | '**')) { RAISE_SYNTAX_ERROR("named arguments must follow bare *") }
1352-
| '*' lambda_param a='=' { RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "var-positional argument cannot have default value") }
1351+
| '*' (':' | ',' (':' | '**')) { RAISE_SYNTAX_ERROR("named parameters must follow bare *") }
1352+
| '*' lambda_param a='=' { RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "var-positional parameter cannot have default value") }
13531353
| '*' (lambda_param_no_default | ',') lambda_param_maybe_default* a='*' (lambda_param_no_default | ',') {
1354-
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "* argument may appear only once") }
1354+
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "* may appear only once") }
13551355
invalid_lambda_kwds:
1356-
| '**' lambda_param a='=' { RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "var-keyword argument cannot have default value") }
1357-
| '**' lambda_param ',' a=lambda_param { RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "arguments cannot follow var-keyword argument") }
1358-
| '**' lambda_param ',' a[Token*]=('*'|'**'|'/') { RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "arguments cannot follow var-keyword argument") }
1356+
| '**' lambda_param a='=' { RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "var-keyword parameter cannot have default value") }
1357+
| '**' lambda_param ',' a=lambda_param { RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "parameters cannot follow var-keyword parameter") }
1358+
| '**' lambda_param ',' a[Token*]=('*'|'**'|'/') { RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "parameters cannot follow var-keyword parameter") }
13591359
invalid_double_type_comments:
13601360
| TYPE_COMMENT NEWLINE TYPE_COMMENT NEWLINE INDENT {
13611361
RAISE_SYNTAX_ERROR("Cannot have two type comments on def") }

Include/internal/pycore_interpframe.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,13 +48,13 @@ static inline _PyStackRef *_PyFrame_Stackbase(_PyInterpreterFrame *f) {
4848
}
4949

5050
static inline _PyStackRef _PyFrame_StackPeek(_PyInterpreterFrame *f) {
51-
assert(f->stackpointer > f->localsplus + _PyFrame_GetCode(f)->co_nlocalsplus);
51+
assert(f->stackpointer > _PyFrame_Stackbase(f));
5252
assert(!PyStackRef_IsNull(f->stackpointer[-1]));
5353
return f->stackpointer[-1];
5454
}
5555

5656
static inline _PyStackRef _PyFrame_StackPop(_PyInterpreterFrame *f) {
57-
assert(f->stackpointer > f->localsplus + _PyFrame_GetCode(f)->co_nlocalsplus);
57+
assert(f->stackpointer > _PyFrame_Stackbase(f));
5858
f->stackpointer--;
5959
return *f->stackpointer;
6060
}

Lib/compression/zstd/_zstdfile.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,6 @@ def __init__(self, file, /, mode="r", *,
8989
raw = _streams.DecompressReader(
9090
self._fp,
9191
ZstdDecompressor,
92-
trailing_error=ZstdError,
9392
zstd_dict=zstd_dict,
9493
options=options,
9594
)

Lib/html/parser.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,7 @@ def goahead(self, end):
260260
else:
261261
assert 0, "interesting.search() lied"
262262
# end while
263-
if end and i < n and not self.cdata_elem:
263+
if end and i < n:
264264
if self.convert_charrefs and not self.cdata_elem:
265265
self.handle_data(unescape(rawdata[i:n]))
266266
else:
@@ -278,7 +278,7 @@ def parse_html_declaration(self, i):
278278
if rawdata[i:i+4] == '<!--':
279279
# this case is actually already handled in goahead()
280280
return self.parse_comment(i)
281-
elif rawdata[i:i+3] == '<![':
281+
elif rawdata[i:i+9] == '<![CDATA[':
282282
return self.parse_marked_section(i)
283283
elif rawdata[i:i+9].lower() == '<!doctype':
284284
# find the closing >
@@ -295,7 +295,7 @@ def parse_html_declaration(self, i):
295295
def parse_bogus_comment(self, i, report=1):
296296
rawdata = self.rawdata
297297
assert rawdata[i:i+2] in ('<!', '</'), ('unexpected call to '
298-
'parse_comment()')
298+
'parse_bogus_comment()')
299299
pos = rawdata.find('>', i+2)
300300
if pos == -1:
301301
return -1

Lib/sqlite3/__main__.py

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,10 @@
1010
from argparse import ArgumentParser
1111
from code import InteractiveConsole
1212
from textwrap import dedent
13+
from _colorize import get_theme, theme_no_color
1314

1415

15-
def execute(c, sql, suppress_errors=True):
16+
def execute(c, sql, suppress_errors=True, theme=theme_no_color):
1617
"""Helper that wraps execution of SQL code.
1718
1819
This is used both by the REPL and by direct execution from the CLI.
@@ -25,29 +26,36 @@ def execute(c, sql, suppress_errors=True):
2526
for row in c.execute(sql):
2627
print(row)
2728
except sqlite3.Error as e:
29+
t = theme.traceback
2830
tp = type(e).__name__
2931
try:
30-
print(f"{tp} ({e.sqlite_errorname}): {e}", file=sys.stderr)
32+
tp += f" ({e.sqlite_errorname})"
3133
except AttributeError:
32-
print(f"{tp}: {e}", file=sys.stderr)
34+
pass
35+
print(
36+
f"{t.type}{tp}{t.reset}: {t.message}{e}{t.reset}", file=sys.stderr
37+
)
3338
if not suppress_errors:
3439
sys.exit(1)
3540

3641

3742
class SqliteInteractiveConsole(InteractiveConsole):
3843
"""A simple SQLite REPL."""
3944

40-
def __init__(self, connection):
45+
def __init__(self, connection, use_color=False):
4146
super().__init__()
4247
self._con = connection
4348
self._cur = connection.cursor()
49+
self._use_color = use_color
4450

4551
def runsource(self, source, filename="<input>", symbol="single"):
4652
"""Override runsource, the core of the InteractiveConsole REPL.
4753
4854
Return True if more input is needed; buffering is done automatically.
4955
Return False if input is a complete statement ready for execution.
5056
"""
57+
theme = get_theme(force_no_color=not self._use_color)
58+
5159
if not source or source.isspace():
5260
return False
5361
if source[0] == ".":
@@ -61,12 +69,13 @@ def runsource(self, source, filename="<input>", symbol="single"):
6169
case "":
6270
pass
6371
case _ as unknown:
64-
self.write("Error: unknown command or invalid arguments:"
65-
f' "{unknown}".\n')
72+
t = theme.traceback
73+
self.write(f'{t.type}Error{t.reset}:{t.message} unknown'
74+
f'command or invalid arguments: "{unknown}".\n{t.reset}')
6675
else:
6776
if not sqlite3.complete_statement(source):
6877
return True
69-
execute(self._cur, source)
78+
execute(self._cur, source, theme=theme)
7079
return False
7180

7281

@@ -113,17 +122,21 @@ def main(*args):
113122
Each command will be run using execute() on the cursor.
114123
Type ".help" for more information; type ".quit" or {eofkey} to quit.
115124
""").strip()
116-
sys.ps1 = "sqlite> "
117-
sys.ps2 = " ... "
125+
126+
theme = get_theme()
127+
s = theme.syntax
128+
129+
sys.ps1 = f"{s.prompt}sqlite> {s.reset}"
130+
sys.ps2 = f"{s.prompt} ... {s.reset}"
118131

119132
con = sqlite3.connect(args.filename, isolation_level=None)
120133
try:
121134
if args.sql:
122135
# SQL statement provided on the command-line; execute it directly.
123-
execute(con, args.sql, suppress_errors=False)
136+
execute(con, args.sql, suppress_errors=False, theme=theme)
124137
else:
125138
# No SQL provided; start the REPL.
126-
console = SqliteInteractiveConsole(con)
139+
console = SqliteInteractiveConsole(con, use_color=True)
127140
try:
128141
import readline # noqa: F401
129142
except ImportError:

0 commit comments

Comments
 (0)