Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
e97e3ec
Initialize staticmethod/classmethod callables in tp_new
Aniketsy Jan 31, 2026
a81471a
Merge branch 'main' into fix-144330
Aniketsy Jan 31, 2026
623d522
Update Objects/funcobject.c
Aniketsy Feb 3, 2026
fc67291
Update Objects/funcobject.c
Aniketsy Feb 3, 2026
56f8640
Update Lib/test/test_descr.py
Aniketsy Feb 3, 2026
ab784f0
Update Lib/test/test_descr.py
Aniketsy Feb 3, 2026
270d183
Update Lib/test/test_descr.py
Aniketsy Feb 3, 2026
c2dd91b
Update Lib/test/test_descr.py
Aniketsy Feb 3, 2026
0eb94d2
Fix unused variable 'COLORS' warning in optimizer.c (#144373)
aisk Feb 1, 2026
250efa2
gh-144348: annotationlib: fix test that relies on set ordering (#144359)
JelleZijlstra Feb 1, 2026
11281c0
gh-143904: Raise OverflowError instead of IndexError for too large of…
serhiy-storchaka Feb 1, 2026
0a02e4f
gh-144277: Fix usage of free-threaded terminology in the documentatio…
ZeroIntensity Feb 2, 2026
d8d92b7
gh-144380: Fix incorrect type check in `buffered_iternext()` (#144381)
ruiyangke Feb 2, 2026
02ad4c9
docs: update dangling reference to `LOAD_METHOD` in dis.rst (#144358)
guilhermeleobas Feb 2, 2026
a09aa1e
gh-115231: Fill __module__ for built-in staticmethods (#115232)
skirpichev Feb 2, 2026
2e5794e
gh-144001: Simplify Base64 decoding with altchars and ignorechars spe…
serhiy-storchaka Feb 2, 2026
1f9b093
gh-144145: Revert PR#144122 for performance and potential bugs. (GH-1…
cocolato Feb 2, 2026
b9a7530
gh-134160: "First extension module" tutorial improvements (GH-144183)
encukou Feb 2, 2026
4ffc8fe
gh-142555: Fix null pointer dereference in array.__setitem__ via re-e…
aisk Feb 2, 2026
c5fa3a9
gh-144242: Note that issues aren't needed for typos in docs template …
StanFromIreland Feb 2, 2026
65cee10
gh-144376: Only run 'address' fuzzer for python3-libraries (#144398)
sethmlarson Feb 2, 2026
c6f9612
GH-144179: Add value recording to JIT tracing front-end (GH-144303)
markshannon Feb 2, 2026
9c07998
gh-139109: Replace `_CHECK_STACK_SPACE` with `_CHECK_STACK_SPACE_OPER…
cocolato Feb 2, 2026
20535dc
gh-75572: Speed up test_xpickle (GH-144393)
serhiy-storchaka Feb 2, 2026
a01abdb
gh-144415: Android testbed fixes (#142912)
mhsmith Feb 3, 2026
79abde1
gh-139103: use `METH_FASTCALL` for tp_new_wrapper (#144406)
colesbury Feb 3, 2026
487ebdf
gh-132888: Fix Windows API error checking in pyrepl.windows_console (…
aisk Feb 3, 2026
baa7fd2
gh-144377: Clean up sqlite3 Connection's list of weakrefs to Cursor o…
takluyver Feb 3, 2026
cc363d5
gh-142956: Update `tomllib` to parse TOML 1.1.0 (#144243)
hukkin Feb 3, 2026
de7cedc
gh-106318: Add examples for str.rindex() method (#143887)
adorilson Feb 3, 2026
c3b31ea
gh-74453: Add stronger security warning to os.path.commonprefix (GH-1…
sethmlarson Feb 3, 2026
6f4730c
Initialize staticmethod/classmethod callables in tp_new
Aniketsy Feb 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ Python/executor_cases.c.h generated
Python/generated_cases.c.h generated
Python/optimizer_cases.c.h generated
Python/opcode_targets.h generated
Python/record_functions.c.h generated
Python/stdlib_module_names.h generated
Tools/peg_generator/pegen/grammar_parser.py generated
aclocal.m4 generated
Expand Down
9 changes: 0 additions & 9 deletions .github/ISSUE_TEMPLATE/documentation.md

This file was deleted.

15 changes: 15 additions & 0 deletions .github/ISSUE_TEMPLATE/documentation.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
name: Documentation
description: Report a problem with the documentation
labels: ["docs"]
body:
- type: markdown
attributes:
value: |
> [!NOTE]
> Trivial changes (for example typos) don’t require an issue before opening a PR.
- type: textarea
attributes:
label: "Documentation"
description: "A clear and concise description of the issue."
validations:
required: true
7 changes: 5 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -655,11 +655,14 @@ jobs:
matrix:
sanitizer:
- address
- undefined
- memory
oss-fuzz-project-name:
- cpython3
- python3-libraries
include:
- sanitizer: undefined
oss-fuzz-project-name: cpython3
- sanitizer: memory
oss-fuzz-project-name: cpython3
exclude:
# Note that the 'no-exclude' sentinel below is to prevent
# an empty string value from excluding all jobs and causing
Expand Down
108 changes: 80 additions & 28 deletions Android/android.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from asyncio import wait_for
from contextlib import asynccontextmanager
from datetime import datetime, timezone
from enum import IntEnum, auto
from glob import glob
from os.path import abspath, basename, relpath
from pathlib import Path
Expand Down Expand Up @@ -61,6 +62,19 @@
hidden_output = []


# Based on android/log.h in the NDK.
class LogPriority(IntEnum):
UNKNOWN = 0
DEFAULT = auto()
VERBOSE = auto()
DEBUG = auto()
INFO = auto()
WARN = auto()
ERROR = auto()
FATAL = auto()
SILENT = auto()


def log_verbose(context, line, stream=sys.stdout):
if context.verbose:
stream.write(line)
Expand Down Expand Up @@ -505,47 +519,47 @@ async def logcat_task(context, initial_devices):
pid = await wait_for(find_pid(serial), startup_timeout)

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

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

# Put high-level messages on stderr so they're highlighted in the
# buildbot logs. This will include Python's own stderr.
stream = (
sys.stderr
if level in ["W", "E", "F"] # WARNING, ERROR, FATAL (aka ASSERT)
else sys.stdout
)

# To simplify automated processing of the output, e.g. a buildbot
# posting a failure notice on a GitHub PR, we strip the level and
# tag indicators from Python's stdout and stderr.
for prefix in ["python.stdout: ", "python.stderr: "]:
if message.startswith(prefix):
global python_started
python_started = True
stream.write(message.removeprefix(prefix))
break
stream = sys.stderr if priority >= LogPriority.WARN else sys.stdout

# The app's stdout and stderr should be passed through transparently
# to our own corresponding streams.
if tag in ["python.stdout", "python.stderr"]:
global python_started
python_started = True
stream.write(message)
stream.flush()
else:
# Non-Python messages add a lot of noise, but they may
# sometimes help explain a failure.
log_verbose(context, line, stream)
# sometimes help explain a failure. Format them in the same way
# as `logcat --format tag`.
formatted = f"{priority.name[0]}/{tag}: {message}"
if not formatted.endswith("\n"):
formatted += "\n"
log_verbose(context, formatted, stream)

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


# Read one binary log message from the given StreamReader. The message format is
# described at https://android.stackexchange.com/a/74660. All supported versions
# of Android use format version 2 or later.
async def read_logcat(stream):
async def read_bytes(size):
return await stream.readexactly(size)

async def read_int(size):
return int.from_bytes(await read_bytes(size), "little")

payload_len = await read_int(2)
if payload_len < 2:
# 1 byte for priority, 1 byte for null terminator of tag.
raise ValueError(f"payload length {payload_len} is too short")

header_len = await read_int(2)
if header_len < 4:
raise ValueError(f"header length {header_len} is too short")
await read_bytes(header_len - 4) # Ignore other header fields.

priority_int = await read_int(1)
try:
priority = LogPriority(priority_int)
except ValueError:
priority = LogPriority.UNKNOWN

payload_fields = (await read_bytes(payload_len - 1)).split(b"\0")
if len(payload_fields) < 2:
raise ValueError(
f"payload {payload!r} does not contain at least 2 "
f"null-separated fields"
)
tag, message, *_ = [
field.decode(*DECODE_ARGS) for field in payload_fields
]
return priority, tag, message


def stop_app(serial):
run([adb, "-s", serial, "shell", "am", "force-stop", APP_ID], log=False)

Expand Down
24 changes: 17 additions & 7 deletions Android/testbed/app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -94,10 +94,13 @@ android {
}

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

versionCode = 1
versionName = "1.0"
Expand Down Expand Up @@ -130,9 +133,10 @@ android {
path("src/main/c/CMakeLists.txt")
}

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

compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
Expand Down Expand Up @@ -234,6 +238,12 @@ androidComponents.onVariants { variant ->
from(cwd)
}
}

// A filename ending with .gz will be automatically decompressed
// while building the APK. Avoid this by adding a dash to the end,
// and add an extra dash to any filenames that already end with one.
// This will be undone in MainActivity.kt.
rename(""".*(\.gz|-)""", "$0-")
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,9 @@ class PythonTestRunner(val context: Context) {
continue
}
input.use {
File(targetSubdir, name).outputStream().use { output ->
// Undo the .gz workaround from build.gradle.kts.
val outputName = name.replace(Regex("""(.*)-"""), "$1")
File(targetSubdir, outputName).outputStream().use { output ->
input.copyTo(output)
}
}
Expand Down
8 changes: 4 additions & 4 deletions Doc/c-api/object.rst
Original file line number Diff line number Diff line change
Expand Up @@ -711,10 +711,10 @@ Object Protocol

:c:func:`PyUnstable_EnableTryIncRef` must have been called
earlier on *obj* or this function may spuriously return ``0`` in the
:term:`free threading` build.
:term:`free-threaded build`.

This function is logically equivalent to the following C code, except that
it behaves atomically in the :term:`free threading` build::
it behaves atomically in the :term:`free-threaded build`::

if (Py_REFCNT(op) > 0) {
Py_INCREF(op);
Expand Down Expand Up @@ -791,10 +791,10 @@ Object Protocol
On GIL-enabled builds, this function is equivalent to
:c:expr:`Py_REFCNT(op) == 1`.

On a :term:`free threaded <free threading>` build, this checks if *op*'s
On a :term:`free-threaded build`, this checks if *op*'s
:term:`reference count` is equal to one and additionally checks if *op*
is only used by this thread. :c:expr:`Py_REFCNT(op) == 1` is **not**
thread-safe on free threaded builds; prefer this function.
thread-safe on free-threaded builds; prefer this function.

The caller must hold an :term:`attached thread state`, despite the fact
that this function doesn't call into the Python interpreter. This function
Expand Down
2 changes: 1 addition & 1 deletion Doc/c-api/refcounting.rst
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ of Python objects.
.. note::
On :term:`free threaded <free threading>` builds of Python, returning 1
On :term:`free-threaded builds <free-threaded build>` of Python, returning 1
isn't sufficient to determine if it's safe to treat *o* as having no
access by other threads. Use :c:func:`PyUnstable_Object_IsUniquelyReferenced`
for that instead.
Expand Down
Loading
Loading