Skip to content

Commit 778f525

Browse files
authored
Merge branch 'main' into build-details
2 parents 1a1d30e + cac4b04 commit 778f525

25 files changed

+487
-169
lines changed

Android/android.py

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
ANDROID_DIR.name == "Android" and (PYTHON_DIR / "pyconfig.h.in").exists()
3030
)
3131

32+
ENV_SCRIPT = ANDROID_DIR / "android-env.sh"
3233
TESTBED_DIR = ANDROID_DIR / "testbed"
3334
CROSS_BUILD_DIR = PYTHON_DIR / "cross-build"
3435

@@ -129,12 +130,11 @@ def android_env(host):
129130
sysconfig_filename = next(sysconfig_files).name
130131
host = re.fullmatch(r"_sysconfigdata__android_(.+).py", sysconfig_filename)[1]
131132

132-
env_script = ANDROID_DIR / "android-env.sh"
133133
env_output = subprocess.run(
134134
f"set -eu; "
135135
f"HOST={host}; "
136136
f"PREFIX={prefix}; "
137-
f". {env_script}; "
137+
f". {ENV_SCRIPT}; "
138138
f"export",
139139
check=True, shell=True, capture_output=True, encoding='utf-8',
140140
).stdout
@@ -151,7 +151,7 @@ def android_env(host):
151151
env[key] = value
152152

153153
if not env:
154-
raise ValueError(f"Found no variables in {env_script.name} output:\n"
154+
raise ValueError(f"Found no variables in {ENV_SCRIPT.name} output:\n"
155155
+ env_output)
156156
return env
157157

@@ -281,15 +281,30 @@ def clean_all(context):
281281

282282

283283
def setup_ci():
284-
# https://github.blog/changelog/2024-04-02-github-actions-hardware-accelerated-android-virtualization-now-available/
285-
if "GITHUB_ACTIONS" in os.environ and platform.system() == "Linux":
286-
run(
287-
["sudo", "tee", "/etc/udev/rules.d/99-kvm4all.rules"],
288-
input='KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"\n',
289-
text=True,
290-
)
291-
run(["sudo", "udevadm", "control", "--reload-rules"])
292-
run(["sudo", "udevadm", "trigger", "--name-match=kvm"])
284+
if "GITHUB_ACTIONS" in os.environ:
285+
# Enable emulator hardware acceleration
286+
# (https://github.blog/changelog/2024-04-02-github-actions-hardware-accelerated-android-virtualization-now-available/).
287+
if platform.system() == "Linux":
288+
run(
289+
["sudo", "tee", "/etc/udev/rules.d/99-kvm4all.rules"],
290+
input='KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"\n',
291+
text=True,
292+
)
293+
run(["sudo", "udevadm", "control", "--reload-rules"])
294+
run(["sudo", "udevadm", "trigger", "--name-match=kvm"])
295+
296+
# Free up disk space by deleting unused versions of the NDK
297+
# (https://github.com/freakboy3742/pyspamsum/pull/108).
298+
for line in ENV_SCRIPT.read_text().splitlines():
299+
if match := re.fullmatch(r"ndk_version=(.+)", line):
300+
ndk_version = match[1]
301+
break
302+
else:
303+
raise ValueError(f"Failed to find NDK version in {ENV_SCRIPT.name}")
304+
305+
for item in (android_home / "ndk").iterdir():
306+
if item.name[0].isdigit() and item.name != ndk_version:
307+
delete_glob(item)
293308

294309

295310
def setup_sdk():

Android/testbed/app/build.gradle.kts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ android {
7979
val androidEnvFile = file("../../android-env.sh").absoluteFile
8080

8181
namespace = "org.python.testbed"
82-
compileSdk = 34
82+
compileSdk = 35
8383

8484
defaultConfig {
8585
applicationId = "org.python.testbed"
@@ -92,7 +92,7 @@ android {
9292
}
9393
throw GradleException("Failed to find API level in $androidEnvFile")
9494
}
95-
targetSdk = 34
95+
targetSdk = 35
9696

9797
versionCode = 1
9898
versionName = "1.0"

Doc/library/readline.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,15 @@ Startup hooks
246246
if Python was compiled for a version of the library that supports it.
247247

248248

249+
.. function:: get_pre_input_hook()
250+
251+
Get the current pre-input hook function, or ``None`` if no pre-input hook
252+
function has been set. This function only exists if Python was compiled
253+
for a version of the library that supports it.
254+
255+
.. versionadded:: next
256+
257+
249258
.. _readline-completion:
250259

251260
Completion

Include/modsupport.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ PyAPI_FUNC(int) PyABIInfo_Check(PyABIInfo *info, const char *module_name);
132132
) \
133133
/////////////////////////////////////////////////////////
134134

135-
#define _PyABIInfo_DEFAULT() { \
135+
#define _PyABIInfo_DEFAULT { \
136136
1, 0, \
137137
PyABIInfo_DEFAULT_FLAGS, \
138138
PY_VERSION_HEX, \

Lib/dataclasses.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -550,7 +550,12 @@ def __annotate__(format, /):
550550

551551
new_annotations = {}
552552
for k in annotation_fields:
553-
new_annotations[k] = cls_annotations[k]
553+
# gh-142214: The annotation may be missing in unusual dynamic cases.
554+
# If so, just skip it.
555+
try:
556+
new_annotations[k] = cls_annotations[k]
557+
except KeyError:
558+
pass
554559

555560
if return_type is not MISSING:
556561
if format == Format.STRING:
@@ -1399,9 +1404,10 @@ def _add_slots(cls, is_frozen, weakref_slot, defined_fields):
13991404
f.type = ann
14001405

14011406
# Fix the class reference in the __annotate__ method
1402-
init_annotate = newcls.__init__.__annotate__
1403-
if getattr(init_annotate, "__generated_by_dataclasses__", False):
1404-
_update_func_cell_for__class__(init_annotate, cls, newcls)
1407+
init = newcls.__init__
1408+
if init_annotate := getattr(init, "__annotate__", None):
1409+
if getattr(init_annotate, "__generated_by_dataclasses__", False):
1410+
_update_func_cell_for__class__(init_annotate, cls, newcls)
14051411

14061412
return newcls
14071413

Lib/test/datetimetester.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6300,21 +6300,21 @@ def test_vilnius_1941_fromutc(self):
63006300

63016301
gdt = datetime(1941, 6, 23, 20, 59, 59, tzinfo=timezone.utc)
63026302
ldt = gdt.astimezone(Vilnius)
6303-
self.assertEqual(ldt.strftime("%c %Z%z"),
6303+
self.assertEqual(ldt.strftime("%a %b %d %H:%M:%S %Y %Z%z"),
63046304
'Mon Jun 23 23:59:59 1941 MSK+0300')
63056305
self.assertEqual(ldt.fold, 0)
63066306
self.assertFalse(ldt.dst())
63076307

63086308
gdt = datetime(1941, 6, 23, 21, tzinfo=timezone.utc)
63096309
ldt = gdt.astimezone(Vilnius)
6310-
self.assertEqual(ldt.strftime("%c %Z%z"),
6310+
self.assertEqual(ldt.strftime("%a %b %d %H:%M:%S %Y %Z%z"),
63116311
'Mon Jun 23 23:00:00 1941 CEST+0200')
63126312
self.assertEqual(ldt.fold, 1)
63136313
self.assertTrue(ldt.dst())
63146314

63156315
gdt = datetime(1941, 6, 23, 22, tzinfo=timezone.utc)
63166316
ldt = gdt.astimezone(Vilnius)
6317-
self.assertEqual(ldt.strftime("%c %Z%z"),
6317+
self.assertEqual(ldt.strftime("%a %b %d %H:%M:%S %Y %Z%z"),
63186318
'Tue Jun 24 00:00:00 1941 CEST+0200')
63196319
self.assertEqual(ldt.fold, 0)
63206320
self.assertTrue(ldt.dst())
@@ -6324,22 +6324,22 @@ def test_vilnius_1941_toutc(self):
63246324

63256325
ldt = datetime(1941, 6, 23, 22, 59, 59, tzinfo=Vilnius)
63266326
gdt = ldt.astimezone(timezone.utc)
6327-
self.assertEqual(gdt.strftime("%c %Z"),
6327+
self.assertEqual(gdt.strftime("%a %b %d %H:%M:%S %Y %Z"),
63286328
'Mon Jun 23 19:59:59 1941 UTC')
63296329

63306330
ldt = datetime(1941, 6, 23, 23, 59, 59, tzinfo=Vilnius)
63316331
gdt = ldt.astimezone(timezone.utc)
6332-
self.assertEqual(gdt.strftime("%c %Z"),
6332+
self.assertEqual(gdt.strftime("%a %b %d %H:%M:%S %Y %Z"),
63336333
'Mon Jun 23 20:59:59 1941 UTC')
63346334

63356335
ldt = datetime(1941, 6, 23, 23, 59, 59, tzinfo=Vilnius, fold=1)
63366336
gdt = ldt.astimezone(timezone.utc)
6337-
self.assertEqual(gdt.strftime("%c %Z"),
6337+
self.assertEqual(gdt.strftime("%a %b %d %H:%M:%S %Y %Z"),
63386338
'Mon Jun 23 21:59:59 1941 UTC')
63396339

63406340
ldt = datetime(1941, 6, 24, 0, tzinfo=Vilnius)
63416341
gdt = ldt.astimezone(timezone.utc)
6342-
self.assertEqual(gdt.strftime("%c %Z"),
6342+
self.assertEqual(gdt.strftime("%a %b %d %H:%M:%S %Y %Z"),
63436343
'Mon Jun 23 22:00:00 1941 UTC')
63446344

63456345
def test_constructors(self):

Lib/test/test_dataclasses/__init__.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -927,6 +927,20 @@ class C:
927927

928928
validate_class(C)
929929

930+
def test_incomplete_annotations(self):
931+
# gh-142214
932+
@dataclass
933+
class C:
934+
"doc" # needed because otherwise we fetch the annotations at the wrong time
935+
x: int
936+
937+
C.__annotate__ = lambda _: {}
938+
939+
self.assertEqual(
940+
annotationlib.get_annotations(C.__init__),
941+
{"return": None}
942+
)
943+
930944
def test_missing_default(self):
931945
# Test that MISSING works the same as a default not being
932946
# specified.
@@ -2578,6 +2592,20 @@ def __init__(self, x: int) -> None:
25782592

25792593
self.assertFalse(hasattr(E.__init__.__annotate__, "__generated_by_dataclasses__"))
25802594

2595+
def test_slots_true_init_false(self):
2596+
# Test that slots=True and init=False work together and
2597+
# that __annotate__ is not added to __init__.
2598+
2599+
@dataclass(slots=True, init=False)
2600+
class F:
2601+
x: int
2602+
2603+
f = F()
2604+
f.x = 10
2605+
self.assertEqual(f.x, 10)
2606+
2607+
self.assertFalse(hasattr(F.__init__, "__annotate__"))
2608+
25812609
def test_init_false_forwardref(self):
25822610
# Test forward references in fields not required for __init__ annotations.
25832611

Lib/test/test_generated_cases.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2115,6 +2115,7 @@ def test_validate_uop_unused_input(self):
21152115
"""
21162116
output = """
21172117
case OP: {
2118+
CHECK_STACK_BOUNDS(-1);
21182119
stack_pointer += -1;
21192120
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
21202121
break;
@@ -2132,6 +2133,7 @@ def test_validate_uop_unused_input(self):
21322133
"""
21332134
output = """
21342135
case OP: {
2136+
CHECK_STACK_BOUNDS(-1);
21352137
stack_pointer += -1;
21362138
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
21372139
break;
@@ -2153,6 +2155,7 @@ def test_validate_uop_unused_output(self):
21532155
case OP: {
21542156
JitOptRef foo;
21552157
foo = NULL;
2158+
CHECK_STACK_BOUNDS(1);
21562159
stack_pointer[0] = foo;
21572160
stack_pointer += 1;
21582161
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
@@ -2172,6 +2175,7 @@ def test_validate_uop_unused_output(self):
21722175
"""
21732176
output = """
21742177
case OP: {
2178+
CHECK_STACK_BOUNDS(1);
21752179
stack_pointer += 1;
21762180
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
21772181
break;

Lib/test/test_readline.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,24 @@ def test_write_read_limited_history(self):
413413
# So, we've only tested that the read did not fail.
414414
# See TestHistoryManipulation for the full test.
415415

416+
@unittest.skipUnless(hasattr(readline, "get_pre_input_hook"),
417+
"get_pre_input_hook not available")
418+
def test_get_pre_input_hook(self):
419+
# Save and restore the original hook to avoid side effects
420+
original_hook = readline.get_pre_input_hook()
421+
self.addCleanup(readline.set_pre_input_hook, original_hook)
422+
423+
# Test that get_pre_input_hook returns None when no hook is set
424+
readline.set_pre_input_hook(None)
425+
self.assertIsNone(readline.get_pre_input_hook())
426+
427+
# Set a hook and verify we can retrieve it
428+
def my_hook():
429+
pass
430+
431+
readline.set_pre_input_hook(my_hook)
432+
self.assertIs(readline.get_pre_input_hook(), my_hook)
433+
416434

417435
@unittest.skipUnless(support.Py_GIL_DISABLED, 'these tests can only possibly fail with GIL disabled')
418436
class FreeThreadingTest(unittest.TestCase):
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
``RUNSHARED`` is no longer cleared when cross-compiling. Previously,
2+
``RUNSHARED`` was cleared when cross-compiling, which breaks PGO when using
3+
``--enabled-shared`` on systems where the cross-compiled CPython is otherwise
4+
executable (e.g., via transparent emulation).

0 commit comments

Comments
 (0)