Skip to content

Commit d16f298

Browse files
authored
Merge branch 'main' into branch-unique-reference-tracking
2 parents bd70ebd + ffa6852 commit d16f298

File tree

175 files changed

+8512
-4513
lines changed

Some content is hidden

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

175 files changed

+8512
-4513
lines changed

.gitattributes

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ Python/executor_cases.c.h generated
106106
Python/generated_cases.c.h generated
107107
Python/optimizer_cases.c.h generated
108108
Python/opcode_targets.h generated
109+
Python/record_functions.c.h generated
109110
Python/stdlib_module_names.h generated
110111
Tools/peg_generator/pegen/grammar_parser.py generated
111112
aclocal.m4 generated

.github/ISSUE_TEMPLATE/documentation.md

Lines changed: 0 additions & 9 deletions
This file was deleted.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
name: Documentation
2+
description: Report a problem with the documentation
3+
labels: ["docs"]
4+
body:
5+
- type: markdown
6+
attributes:
7+
value: |
8+
> [!NOTE]
9+
> Trivial changes (for example typos) don’t require an issue before opening a PR.
10+
- type: textarea
11+
attributes:
12+
label: "Documentation"
13+
description: "A clear and concise description of the issue."
14+
validations:
15+
required: true

.github/workflows/build.yml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -655,11 +655,14 @@ jobs:
655655
matrix:
656656
sanitizer:
657657
- address
658-
- undefined
659-
- memory
660658
oss-fuzz-project-name:
661659
- cpython3
662660
- python3-libraries
661+
include:
662+
- sanitizer: undefined
663+
oss-fuzz-project-name: cpython3
664+
- sanitizer: memory
665+
oss-fuzz-project-name: cpython3
663666
exclude:
664667
# Note that the 'no-exclude' sentinel below is to prevent
665668
# an empty string value from excluding all jobs and causing

Android/android.py

Lines changed: 80 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
from asyncio import wait_for
1616
from contextlib import asynccontextmanager
1717
from datetime import datetime, timezone
18+
from enum import IntEnum, auto
1819
from glob import glob
1920
from os.path import abspath, basename, relpath
2021
from pathlib import Path
@@ -61,6 +62,19 @@
6162
hidden_output = []
6263

6364

65+
# Based on android/log.h in the NDK.
66+
class LogPriority(IntEnum):
67+
UNKNOWN = 0
68+
DEFAULT = auto()
69+
VERBOSE = auto()
70+
DEBUG = auto()
71+
INFO = auto()
72+
WARN = auto()
73+
ERROR = auto()
74+
FATAL = auto()
75+
SILENT = auto()
76+
77+
6478
def log_verbose(context, line, stream=sys.stdout):
6579
if context.verbose:
6680
stream.write(line)
@@ -505,47 +519,47 @@ async def logcat_task(context, initial_devices):
505519
pid = await wait_for(find_pid(serial), startup_timeout)
506520

507521
# `--pid` requires API level 24 or higher.
508-
args = [adb, "-s", serial, "logcat", "--pid", pid, "--format", "tag"]
522+
#
523+
# `--binary` mode is used in order to detect which messages end with a
524+
# newline, which most of the other modes don't indicate (except `--format
525+
# long`). For example, every time pytest runs a test, it prints a "." and
526+
# flushes the stream. Each "." becomes a separate log message, but we should
527+
# show them all on the same line.
528+
args = [adb, "-s", serial, "logcat", "--pid", pid, "--binary"]
509529
logcat_started = False
510530
async with async_process(
511-
*args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
531+
*args, stdout=subprocess.PIPE, stderr=None
512532
) as process:
513-
while line := (await process.stdout.readline()).decode(*DECODE_ARGS):
514-
if match := re.fullmatch(r"([A-Z])/(.*)", line, re.DOTALL):
533+
while True:
534+
try:
535+
priority, tag, message = await read_logcat(process.stdout)
515536
logcat_started = True
516-
level, message = match.groups()
517-
else:
518-
# If the regex doesn't match, this is either a logcat startup
519-
# error, or the second or subsequent line of a multi-line
520-
# message. Python won't produce multi-line messages, but other
521-
# components might.
522-
level, message = None, line
537+
except asyncio.IncompleteReadError:
538+
break
523539

524540
# Exclude high-volume messages which are rarely useful.
525541
if context.verbose < 2 and "from python test_syslog" in message:
526542
continue
527543

528544
# Put high-level messages on stderr so they're highlighted in the
529545
# buildbot logs. This will include Python's own stderr.
530-
stream = (
531-
sys.stderr
532-
if level in ["W", "E", "F"] # WARNING, ERROR, FATAL (aka ASSERT)
533-
else sys.stdout
534-
)
535-
536-
# To simplify automated processing of the output, e.g. a buildbot
537-
# posting a failure notice on a GitHub PR, we strip the level and
538-
# tag indicators from Python's stdout and stderr.
539-
for prefix in ["python.stdout: ", "python.stderr: "]:
540-
if message.startswith(prefix):
541-
global python_started
542-
python_started = True
543-
stream.write(message.removeprefix(prefix))
544-
break
546+
stream = sys.stderr if priority >= LogPriority.WARN else sys.stdout
547+
548+
# The app's stdout and stderr should be passed through transparently
549+
# to our own corresponding streams.
550+
if tag in ["python.stdout", "python.stderr"]:
551+
global python_started
552+
python_started = True
553+
stream.write(message)
554+
stream.flush()
545555
else:
546556
# Non-Python messages add a lot of noise, but they may
547-
# sometimes help explain a failure.
548-
log_verbose(context, line, stream)
557+
# sometimes help explain a failure. Format them in the same way
558+
# as `logcat --format tag`.
559+
formatted = f"{priority.name[0]}/{tag}: {message}"
560+
if not formatted.endswith("\n"):
561+
formatted += "\n"
562+
log_verbose(context, formatted, stream)
549563

550564
# If the device disconnects while logcat is running, which always
551565
# happens in --managed mode, some versions of adb return non-zero.
@@ -556,6 +570,44 @@ async def logcat_task(context, initial_devices):
556570
raise CalledProcessError(status, args)
557571

558572

573+
# Read one binary log message from the given StreamReader. The message format is
574+
# described at https://android.stackexchange.com/a/74660. All supported versions
575+
# of Android use format version 2 or later.
576+
async def read_logcat(stream):
577+
async def read_bytes(size):
578+
return await stream.readexactly(size)
579+
580+
async def read_int(size):
581+
return int.from_bytes(await read_bytes(size), "little")
582+
583+
payload_len = await read_int(2)
584+
if payload_len < 2:
585+
# 1 byte for priority, 1 byte for null terminator of tag.
586+
raise ValueError(f"payload length {payload_len} is too short")
587+
588+
header_len = await read_int(2)
589+
if header_len < 4:
590+
raise ValueError(f"header length {header_len} is too short")
591+
await read_bytes(header_len - 4) # Ignore other header fields.
592+
593+
priority_int = await read_int(1)
594+
try:
595+
priority = LogPriority(priority_int)
596+
except ValueError:
597+
priority = LogPriority.UNKNOWN
598+
599+
payload_fields = (await read_bytes(payload_len - 1)).split(b"\0")
600+
if len(payload_fields) < 2:
601+
raise ValueError(
602+
f"payload {payload!r} does not contain at least 2 "
603+
f"null-separated fields"
604+
)
605+
tag, message, *_ = [
606+
field.decode(*DECODE_ARGS) for field in payload_fields
607+
]
608+
return priority, tag, message
609+
610+
559611
def stop_app(serial):
560612
run([adb, "-s", serial, "shell", "am", "force-stop", APP_ID], log=False)
561613

Android/testbed/app/build.gradle.kts

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -94,10 +94,13 @@ android {
9494
}
9595

9696
// This controls the API level of the maxVersion managed emulator, which is used
97-
// by CI and cibuildwheel. 34 takes up too much disk space (#142289), 35 has
98-
// issues connecting to the internet (#142387), and 36 and later are not
99-
// available as aosp_atd images yet.
100-
targetSdk = 33
97+
// by CI and cibuildwheel.
98+
// * 33 has excessive buffering in the logcat client
99+
// (https://cs.android.com/android/_/android/platform/system/logging/+/d340721894f223327339010df59b0ac514308826).
100+
// * 34 consumes too much disk space on GitHub Actions (#142289).
101+
// * 35 has issues connecting to the internet (#142387).
102+
// * 36 and later are not available as aosp_atd images yet.
103+
targetSdk = 32
101104

102105
versionCode = 1
103106
versionName = "1.0"
@@ -130,9 +133,10 @@ android {
130133
path("src/main/c/CMakeLists.txt")
131134
}
132135

133-
// Set this property to something non-empty, otherwise it'll use the default
134-
// list, which ignores asset directories beginning with an underscore.
135-
aaptOptions.ignoreAssetsPattern = ".git"
136+
// Set this property to something nonexistent but non-empty. Otherwise it'll use the
137+
// default list, which ignores asset directories beginning with an underscore, and
138+
// maybe also other files required by tests.
139+
aaptOptions.ignoreAssetsPattern = "android-testbed-dont-ignore-anything"
136140

137141
compileOptions {
138142
sourceCompatibility = JavaVersion.VERSION_1_8
@@ -234,6 +238,12 @@ androidComponents.onVariants { variant ->
234238
from(cwd)
235239
}
236240
}
241+
242+
// A filename ending with .gz will be automatically decompressed
243+
// while building the APK. Avoid this by adding a dash to the end,
244+
// and add an extra dash to any filenames that already end with one.
245+
// This will be undone in MainActivity.kt.
246+
rename(""".*(\.gz|-)""", "$0-")
237247
}
238248
}
239249

Android/testbed/app/src/main/java/org/python/testbed/MainActivity.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,9 @@ class PythonTestRunner(val context: Context) {
8080
continue
8181
}
8282
input.use {
83-
File(targetSubdir, name).outputStream().use { output ->
83+
// Undo the .gz workaround from build.gradle.kts.
84+
val outputName = name.replace(Regex("""(.*)-"""), "$1")
85+
File(targetSubdir, outputName).outputStream().use { output ->
8486
input.copyTo(output)
8587
}
8688
}

Doc/c-api/intro.rst

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,35 @@ complete listing.
167167

168168
.. versionadded:: 3.3
169169

170+
.. c:macro:: Py_ALIGNED(num)
171+
172+
Specify alignment to *num* bytes on compilers that support it.
173+
174+
Consider using the C11 standard ``_Alignas`` specifier over this macro.
175+
176+
.. c:macro:: Py_ARITHMETIC_RIGHT_SHIFT(type, integer, positions)
177+
178+
Similar to ``integer >> positions``, but forces sign extension, as the C
179+
standard does not define whether a right-shift of a signed integer will
180+
perform sign extension or a zero-fill.
181+
182+
*integer* should be any signed integer type.
183+
*positions* is the number of positions to shift to the right.
184+
185+
Both *integer* and *positions* can be evaluated more than once;
186+
consequently, avoid directly passing a function call or some other
187+
operation with side-effects to this macro. Instead, store the result as a
188+
variable and then pass it.
189+
190+
*type* is unused and only kept for backwards compatibility. Historically,
191+
*type* was used to cast *integer*.
192+
193+
.. versionchanged:: 3.1
194+
195+
This macro is now valid for all signed integer types, not just those for
196+
which ``unsigned type`` is legal. As a result, *type* is no longer
197+
used.
198+
170199
.. c:macro:: Py_ALWAYS_INLINE
171200
172201
Ask the compiler to always inline a static inline function. The compiler can
@@ -189,6 +218,15 @@ complete listing.
189218

190219
.. versionadded:: 3.11
191220

221+
.. c:macro:: Py_CAN_START_THREADS
222+
223+
If this macro is defined, then the current system is able to start threads.
224+
225+
Currently, all systems supported by CPython (per :pep:`11`), with the
226+
exception of some WebAssembly platforms, support starting threads.
227+
228+
.. versionadded:: 3.13
229+
192230
.. c:macro:: Py_CHARMASK(c)
193231
194232
Argument must be a character or an integer in the range [-128, 127] or [0,
@@ -206,11 +244,35 @@ complete listing.
206244
.. versionchanged:: 3.8
207245
MSVC support was added.
208246

247+
.. c:macro:: Py_FORCE_EXPANSION(X)
248+
249+
This is equivalent to ``X``, which is useful for token-pasting in
250+
macros, as macro expansions in *X* are forcefully evaluated by the
251+
preprocessor.
252+
253+
.. c:macro:: Py_GCC_ATTRIBUTE(name)
254+
255+
Use a GCC attribute *name*, hiding it from compilers that don't support GCC
256+
attributes (such as MSVC).
257+
258+
This expands to ``__attribute__((name))`` on a GCC compiler, and expands
259+
to nothing on compilers that don't support GCC attributes.
260+
209261
.. c:macro:: Py_GETENV(s)
210262
211263
Like ``getenv(s)``, but returns ``NULL`` if :option:`-E` was passed on the
212264
command line (see :c:member:`PyConfig.use_environment`).
213265

266+
.. c:macro:: Py_LL(number)
267+
268+
Use *number* as a ``long long`` integer literal.
269+
270+
This usally expands to *number* followed by ``LL``, but will expand to some
271+
compiler-specific suffixes (such as ``I64``) on older compilers.
272+
273+
In modern versions of Python, this macro is not very useful, as C99 and
274+
later require the ``LL`` suffix to be valid for an integer.
275+
214276
.. c:macro:: Py_LOCAL(type)
215277
216278
Declare a function returning the specified *type* using a fast-calling
@@ -268,13 +330,37 @@ complete listing.
268330

269331
.. versionadded:: 3.11
270332

333+
.. c:macro:: Py_SAFE_DOWNCAST(value, larger, smaller)
334+
335+
Cast *value* to type *smaller* from type *larger*, validating that no
336+
information was lost.
337+
338+
On release builds of Python, this is roughly equivalent to
339+
``(smaller) value`` (in C++, ``static_cast<smaller>(value)`` will be
340+
used instead).
341+
342+
On debug builds (implying that :c:macro:`Py_DEBUG` is defined), this asserts
343+
that no information was lost with the cast from *larger* to *smaller*.
344+
345+
*value*, *larger*, and *smaller* may all be evaluated more than once in the
346+
expression; consequently, do not pass an expression with side-effects directly to
347+
this macro.
348+
271349
.. c:macro:: Py_STRINGIFY(x)
272350
273351
Convert ``x`` to a C string. E.g. ``Py_STRINGIFY(123)`` returns
274352
``"123"``.
275353

276354
.. versionadded:: 3.4
277355

356+
.. c:macro:: Py_ULL(number)
357+
358+
Similar to :c:macro:`Py_LL`, but *number* will be an ``unsigned long long``
359+
literal instead. This is done by appending ``U`` to the result of ``Py_LL``.
360+
361+
In modern versions of Python, this macro is not very useful, as C99 and
362+
later require the ``ULL``/``LLU`` suffixes to be valid for an integer.
363+
278364
.. c:macro:: Py_UNREACHABLE()
279365
280366
Use this when you have a code path that cannot be reached by design.
@@ -415,6 +501,16 @@ complete listing.
415501
This macro is intended for defining CPython's C API itself;
416502
extension modules should not use it for their own symbols.
417503

504+
.. c:macro:: Py_VA_COPY
505+
506+
This is a :term:`soft deprecated` alias to the C99-standard ``va_copy``
507+
function.
508+
509+
Historically, this would use a compiler-specific method to copy a ``va_list``.
510+
511+
.. versionchanged:: 3.6
512+
This is now an alias to ``va_copy``.
513+
418514

419515
.. _api-objects:
420516

0 commit comments

Comments
 (0)