Skip to content

Commit e50c26f

Browse files
Merge branch 'main' into envvars-manpage
2 parents d087c6a + fda87c0 commit e50c26f

32 files changed

+318
-172
lines changed

.github/workflows/build.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -658,6 +658,7 @@ jobs:
658658
build_asan,
659659
build_tsan,
660660
test_hypothesis,
661+
cross-build-linux,
661662
'
662663
|| ''
663664
}}

.github/workflows/tail-call.yml

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ jobs:
4141
- aarch64-apple-darwin/clang
4242
- x86_64-unknown-linux-gnu/gcc
4343
- aarch64-unknown-linux-gnu/gcc
44+
- free-threading
4445
llvm:
4546
- 19
4647
include:
@@ -65,6 +66,9 @@ jobs:
6566
- target: aarch64-unknown-linux-gnu/gcc
6667
architecture: aarch64
6768
runner: ubuntu-22.04-arm
69+
- target: free-threading
70+
architecture: x86_64
71+
runner: ubuntu-24.04
6872
steps:
6973
- uses: actions/checkout@v4
7074
with:
@@ -105,11 +109,20 @@ jobs:
105109
./python.exe -m test --multiprocess 0 --timeout 4500 --verbose2 --verbose3
106110
107111
- name: Native Linux (release)
108-
if: runner.os == 'Linux'
112+
if: runner.os == 'Linux' && matrix.target != 'free-threading'
109113
run: |
110114
sudo bash -c "$(wget -O - https://apt.llvm.org/llvm.sh)" ./llvm.sh ${{ matrix.llvm }}
111115
export PATH="$(llvm-config-${{ matrix.llvm }} --bindir):$PATH"
112116
CC=clang-19 ./configure --with-tail-call-interp
113117
make all --jobs 4
114118
./python -m test --multiprocess 0 --timeout 4500 --verbose2 --verbose3
115119
120+
- name: Native Linux with free-threading (release)
121+
if: matrix.target == 'free-threading'
122+
run: |
123+
sudo bash -c "$(wget -O - https://apt.llvm.org/llvm.sh)" ./llvm.sh ${{ matrix.llvm }}
124+
export PATH="$(llvm-config-${{ matrix.llvm }} --bindir):$PATH"
125+
CC=clang-19 ./configure --with-tail-call-interp --disable-gil
126+
make all --jobs 4
127+
./python -m test --multiprocess 0 --timeout 4500 --verbose2 --verbose3
128+

Doc/using/configure.rst

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -575,9 +575,6 @@ also be used to improve performance.
575575
.. versionchanged:: 3.12
576576
Use ThinLTO as the default optimization policy on Clang if the compiler accepts the flag.
577577

578-
.. versionchanged:: next
579-
Revert to using full LTO as the default optimization policy on Clang.
580-
581578
.. option:: --enable-bolt
582579

583580
Enable usage of the `BOLT post-link binary optimizer

Doc/whatsnew/3.14.rst

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1279,10 +1279,6 @@ Build changes
12791279
* GNU Autoconf 2.72 is now required to generate :file:`configure`.
12801280
(Contributed by Erlend Aasland in :gh:`115765`.)
12811281

1282-
* CPython now uses Full LTO as the default link time optimization policy
1283-
on Clang. This reverts an earlier change in CPython 3.12.
1284-
(Contributed by Ken Jin in :gh:`130049`.)
1285-
12861282
.. _whatsnew314-pep761:
12871283

12881284
PEP 761: Discontinuation of PGP signatures

Grammar/python.gram

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ import_name[stmt_ty]: 'import' a=dotted_as_names { _PyAST_Import(a, EXTRA) }
207207
# note below: the ('.' | '...') is necessary because '...' is tokenized as ELLIPSIS
208208
import_from[stmt_ty]:
209209
| 'from' a=('.' | '...')* b=dotted_name 'import' c=import_from_targets {
210-
_PyAST_ImportFrom(b->v.Name.id, c, _PyPegen_seq_count_dots(a), EXTRA) }
210+
_PyPegen_checked_future_import(p, b->v.Name.id, c, _PyPegen_seq_count_dots(a), EXTRA) }
211211
| 'from' a=('.' | '...')+ 'import' b=import_from_targets {
212212
_PyAST_ImportFrom(NULL, b, _PyPegen_seq_count_dots(a), EXTRA) }
213213
import_from_targets[asdl_alias_seq*]:

Include/internal/pycore_object.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ PyAPI_FUNC(int) _PyObject_IsFreed(PyObject *);
7474
{ \
7575
.ob_ref_local = _Py_IMMORTAL_REFCNT_LOCAL, \
7676
.ob_flags = _Py_STATICALLY_ALLOCATED_FLAG, \
77+
.ob_gc_bits = _PyGC_BITS_DEFERRED, \
7778
.ob_type = (type) \
7879
}
7980
#else
@@ -612,7 +613,7 @@ _Py_TryIncrefCompare(PyObject **src, PyObject *op)
612613
static inline int
613614
_Py_TryIncrefCompareStackRef(PyObject **src, PyObject *op, _PyStackRef *out)
614615
{
615-
if (_Py_IsImmortal(op) || _PyObject_HasDeferredRefcount(op)) {
616+
if (_PyObject_HasDeferredRefcount(op)) {
616617
*out = (_PyStackRef){ .bits = (intptr_t)op | Py_TAG_DEFERRED };
617618
return 1;
618619
}

Include/internal/pycore_pylifecycle.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ extern PyStatus _Py_PreInitializeFromConfig(
7575

7676
extern wchar_t * _Py_GetStdlibDir(void);
7777

78-
extern int _Py_HandleSystemExit(int *exitcode_p);
78+
extern int _Py_HandleSystemExitAndKeyboardInterrupt(int *exitcode_p);
7979

8080
extern PyObject* _PyErr_WriteUnraisableDefaultHook(PyObject *unraisable);
8181

Include/internal/pycore_stackref.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ PyStackRef_FromPyObjectNew(PyObject *obj)
219219
// Make sure we don't take an already tagged value.
220220
assert(((uintptr_t)obj & Py_TAG_BITS) == 0);
221221
assert(obj != NULL);
222-
if (_Py_IsImmortal(obj) || _PyObject_HasDeferredRefcount(obj)) {
222+
if (_PyObject_HasDeferredRefcount(obj)) {
223223
return (_PyStackRef){ .bits = (uintptr_t)obj | Py_TAG_DEFERRED };
224224
}
225225
else {

Lib/test/test_flufl.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,32 @@ def test_guido_as_bdfl(self):
3434
# parser reports the start of the token
3535
self.assertEqual(cm.exception.offset, 3)
3636

37+
def test_barry_as_bdfl_look_ma_with_no_compiler_flags(self):
38+
# Check that the future import is handled by the parser
39+
# even if the compiler flags are not passed.
40+
code = "from __future__ import barry_as_FLUFL;2 {0} 3"
41+
compile(code.format('<>'), '<BDFL test>', 'exec')
42+
with self.assertRaises(SyntaxError) as cm:
43+
compile(code.format('!='), '<FLUFL test>', 'exec')
44+
self.assertRegex(str(cm.exception), "with Barry as BDFL, use '<>' instead of '!='")
45+
self.assertIn('2 != 3', cm.exception.text)
46+
self.assertEqual(cm.exception.filename, '<FLUFL test>')
47+
self.assertEqual(cm.exception.lineno, 1)
48+
self.assertEqual(cm.exception.offset, len(code) - 4)
49+
50+
def test_barry_as_bdfl_relative_import(self):
51+
code = "from .__future__ import barry_as_FLUFL;2 {0} 3"
52+
compile(code.format('!='), '<FLUFL test>', 'exec')
53+
with self.assertRaises(SyntaxError) as cm:
54+
compile(code.format('<>'), '<BDFL test>', 'exec')
55+
self.assertRegex(str(cm.exception), "<BDFL test>")
56+
self.assertIn('2 <> 3', cm.exception.text)
57+
self.assertEqual(cm.exception.filename, '<BDFL test>')
58+
self.assertEqual(cm.exception.lineno, 1)
59+
self.assertEqual(cm.exception.offset, len(code) - 4)
60+
61+
62+
3763

3864
if __name__ == '__main__':
3965
unittest.main()

Lib/test/test_gettext.py

Lines changed: 0 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@
1010

1111
# TODO:
1212
# - Add new tests, for example for "dgettext"
13-
# - Remove dummy tests, for example testing for single and double quotes
14-
# has no sense, it would have if we were testing a parser (i.e. pygettext)
1513
# - Tests should have only one assert.
1614

1715
GNU_MO_DATA = b'''\
@@ -175,30 +173,6 @@ def test_some_translations_with_context(self):
175173
eq(pgettext('my other context', 'nudge nudge'),
176174
'wink wink (in "my other context")')
177175

178-
def test_double_quotes(self):
179-
eq = self.assertEqual
180-
# double quotes
181-
eq(_("albatross"), 'albatross')
182-
eq(_("mullusk"), 'bacon')
183-
eq(_(r"Raymond Luxury Yach-t"), 'Throatwobbler Mangrove')
184-
eq(_(r"nudge nudge"), 'wink wink')
185-
186-
def test_triple_single_quotes(self):
187-
eq = self.assertEqual
188-
# triple single quotes
189-
eq(_('''albatross'''), 'albatross')
190-
eq(_('''mullusk'''), 'bacon')
191-
eq(_(r'''Raymond Luxury Yach-t'''), 'Throatwobbler Mangrove')
192-
eq(_(r'''nudge nudge'''), 'wink wink')
193-
194-
def test_triple_double_quotes(self):
195-
eq = self.assertEqual
196-
# triple double quotes
197-
eq(_("""albatross"""), 'albatross')
198-
eq(_("""mullusk"""), 'bacon')
199-
eq(_(r"""Raymond Luxury Yach-t"""), 'Throatwobbler Mangrove')
200-
eq(_(r"""nudge nudge"""), 'wink wink')
201-
202176
def test_multiline_strings(self):
203177
eq = self.assertEqual
204178
# multiline strings
@@ -285,30 +259,6 @@ def test_some_translations_with_context_and_domain(self):
285259
eq(gettext.dpgettext('gettext', 'my other context', 'nudge nudge'),
286260
'wink wink (in "my other context")')
287261

288-
def test_double_quotes(self):
289-
eq = self.assertEqual
290-
# double quotes
291-
eq(self._("albatross"), 'albatross')
292-
eq(self._("mullusk"), 'bacon')
293-
eq(self._(r"Raymond Luxury Yach-t"), 'Throatwobbler Mangrove')
294-
eq(self._(r"nudge nudge"), 'wink wink')
295-
296-
def test_triple_single_quotes(self):
297-
eq = self.assertEqual
298-
# triple single quotes
299-
eq(self._('''albatross'''), 'albatross')
300-
eq(self._('''mullusk'''), 'bacon')
301-
eq(self._(r'''Raymond Luxury Yach-t'''), 'Throatwobbler Mangrove')
302-
eq(self._(r'''nudge nudge'''), 'wink wink')
303-
304-
def test_triple_double_quotes(self):
305-
eq = self.assertEqual
306-
# triple double quotes
307-
eq(self._("""albatross"""), 'albatross')
308-
eq(self._("""mullusk"""), 'bacon')
309-
eq(self._(r"""Raymond Luxury Yach-t"""), 'Throatwobbler Mangrove')
310-
eq(self._(r"""nudge nudge"""), 'wink wink')
311-
312262
def test_multiline_strings(self):
313263
eq = self.assertEqual
314264
# multiline strings

0 commit comments

Comments
 (0)