Skip to content

Commit b221e2e

Browse files
authored
Merge branch 'main' into cleanup/315/typed-dict-133823
2 parents 6a88cbc + c5e1775 commit b221e2e

Some content is hidden

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

43 files changed

+567
-518
lines changed

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/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: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,9 @@ New features
7575
Other language changes
7676
======================
7777

78+
* Several error messages incorrectly using the term "argument" have been corrected.
79+
(Contributed by Stan Ulbrych in :gh:`133382`.)
80+
7881

7982

8083
New modules
@@ -121,6 +124,12 @@ Removed
121124
typing
122125
------
123126

127+
* The undocumented keyword argument syntax for creating
128+
:class:`~typing.NamedTuple` classes (for example,
129+
``Point = NamedTuple("Point", x=int, y=int)``).
130+
Use the class-based syntax or the functional syntax instead.
131+
(Contributed by Bénédikt Tran in :gh:`133817`.)
132+
124133
* Using ``TD = TypedDict("TD")`` or ``TD = TypedDict("TD", None)`` to
125134
construct a :class:`~typing.TypedDict` type with zero field is no
126135
longer supported. Use ``class TD(TypedDict): pass``

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") }

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/test/datetimetester.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -773,6 +773,9 @@ def test_str(self):
773773
microseconds=999999)),
774774
"999999999 days, 23:59:59.999999")
775775

776+
# test the Doc/library/datetime.rst recipe
777+
eq(f'-({-td(hours=-1)!s})', "-(1:00:00)")
778+
776779
def test_repr(self):
777780
name = 'datetime.' + self.theclass.__name__
778781
self.assertEqual(repr(self.theclass(1)),

Lib/test/test_ast/test_ast.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1315,6 +1315,15 @@ def test_replace_reject_missing_field(self):
13151315
self.assertIs(repl.id, 'y')
13161316
self.assertIs(repl.ctx, context)
13171317

1318+
def test_replace_accept_missing_field_with_default(self):
1319+
node = ast.FunctionDef(name="foo", args=ast.arguments())
1320+
self.assertIs(node.returns, None)
1321+
self.assertEqual(node.decorator_list, [])
1322+
node2 = copy.replace(node, name="bar")
1323+
self.assertEqual(node2.name, "bar")
1324+
self.assertIs(node2.returns, None)
1325+
self.assertEqual(node2.decorator_list, [])
1326+
13181327
def test_replace_reject_known_custom_instance_fields_commits(self):
13191328
node = ast.parse('x').body[0].value
13201329
node.extra = extra = object() # add instance 'extra' field

Lib/test/test_codeop.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,7 @@ def test_syntax_errors(self):
322322
dedent("""\
323323
def foo(x,x):
324324
pass
325-
"""), "duplicate argument 'x' in function definition")
325+
"""), "duplicate parameter 'x' in function definition")
326326

327327

328328

Lib/test/test_dict.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1039,10 +1039,8 @@ class C:
10391039
a = C()
10401040
a.x = 1
10411041
d = a.__dict__
1042-
before_resize = sys.getsizeof(d)
10431042
d[2] = 2 # split table is resized to a generic combined table
10441043

1045-
self.assertGreater(sys.getsizeof(d), before_resize)
10461044
self.assertEqual(list(d), ['x', 2])
10471045

10481046
def test_iterator_pickling(self):

0 commit comments

Comments
 (0)