[3.13] gh-126925: Modify how iOS test results are gathered (GH-127592) (#127754)

Adds a `use_system_log` config item to enable stdout/stderr redirection for
Apple platforms. This log streaming is then used by a new iOS test runner
script, allowing the display of test suite output at runtime. The iOS test
runner script can be used by any Python project, not just the CPython test
suite.
(cherry picked from commit 2041a95e68)
This commit is contained in:
Russell Keith-Magee 2024-12-09 14:39:11 +08:00 committed by GitHub
parent b56100c77a
commit 075c41d5f5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 782 additions and 58 deletions

View file

@ -129,6 +129,10 @@ static const PyConfigSpec PYCONFIG_SPEC[] = {
#ifdef Py_DEBUG
SPEC(run_presite, WSTR_OPT),
#endif
#ifdef __APPLE__
SPEC(use_system_logger, BOOL),
#endif
{NULL, 0, 0},
};
@ -744,6 +748,9 @@ config_check_consistency(const PyConfig *config)
assert(config->cpu_count != 0);
// config->use_frozen_modules is initialized later
// by _PyConfig_InitImportConfig().
#ifdef __APPLE__
assert(config->use_system_logger >= 0);
#endif
#ifdef Py_STATS
assert(config->_pystats >= 0);
#endif
@ -846,6 +853,9 @@ _PyConfig_InitCompatConfig(PyConfig *config)
config->_is_python_build = 0;
config->code_debug_ranges = 1;
config->cpu_count = -1;
#ifdef __APPLE__
config->use_system_logger = 0;
#endif
#ifdef Py_GIL_DISABLED
config->enable_gil = _PyConfig_GIL_DEFAULT;
#endif
@ -874,6 +884,9 @@ config_init_defaults(PyConfig *config)
#ifdef MS_WINDOWS
config->legacy_windows_stdio = 0;
#endif
#ifdef __APPLE__
config->use_system_logger = 0;
#endif
}
@ -909,6 +922,9 @@ PyConfig_InitIsolatedConfig(PyConfig *config)
#ifdef MS_WINDOWS
config->legacy_windows_stdio = 0;
#endif
#ifdef __APPLE__
config->use_system_logger = 0;
#endif
}

View file

@ -43,7 +43,9 @@
#endif
#if defined(__APPLE__)
# include <AvailabilityMacros.h>
# include <mach-o/loader.h>
# include <os/log.h>
#endif
#ifdef HAVE_SIGNAL_H
@ -73,6 +75,9 @@ static PyStatus init_sys_streams(PyThreadState *tstate);
#ifdef __ANDROID__
static PyStatus init_android_streams(PyThreadState *tstate);
#endif
#if defined(__APPLE__)
static PyStatus init_apple_streams(PyThreadState *tstate);
#endif
static void wait_for_thread_shutdown(PyThreadState *tstate);
static void finalize_subinterpreters(void);
static void call_ll_exitfuncs(_PyRuntimeState *runtime);
@ -1253,6 +1258,14 @@ init_interp_main(PyThreadState *tstate)
return status;
}
#endif
#if defined(__APPLE__)
if (config->use_system_logger) {
status = init_apple_streams(tstate);
if (_PyStatus_EXCEPTION(status)) {
return status;
}
}
#endif
#ifdef Py_DEBUG
run_presite(tstate);
@ -2920,6 +2933,75 @@ done:
#endif // __ANDROID__
#if defined(__APPLE__)
static PyObject *
apple_log_write_impl(PyObject *self, PyObject *args)
{
int logtype = 0;
const char *text = NULL;
if (!PyArg_ParseTuple(args, "iy", &logtype, &text)) {
return NULL;
}
// Call the underlying Apple logging API. The os_log unified logging APIs
// were introduced in macOS 10.12, iOS 10.0, tvOS 10.0, and watchOS 3.0;
// this call is a no-op on older versions.
#if TARGET_OS_IPHONE || (TARGET_OS_OSX && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12)
// Pass the user-provided text through explicit %s formatting
// to avoid % literals being interpreted as a formatting directive.
os_log_with_type(OS_LOG_DEFAULT, logtype, "%s", text);
#endif
Py_RETURN_NONE;
}
static PyMethodDef apple_log_write_method = {
"apple_log_write", apple_log_write_impl, METH_VARARGS
};
static PyStatus
init_apple_streams(PyThreadState *tstate)
{
PyStatus status = _PyStatus_OK();
PyObject *_apple_support = NULL;
PyObject *apple_log_write = NULL;
PyObject *result = NULL;
_apple_support = PyImport_ImportModule("_apple_support");
if (_apple_support == NULL) {
goto error;
}
apple_log_write = PyCFunction_New(&apple_log_write_method, NULL);
if (apple_log_write == NULL) {
goto error;
}
// Initialize the logging streams, sending stdout -> Default; stderr -> Error
result = PyObject_CallMethod(
_apple_support, "init_streams", "Oii",
apple_log_write, OS_LOG_TYPE_DEFAULT, OS_LOG_TYPE_ERROR);
if (result == NULL) {
goto error;
}
goto done;
error:
_PyErr_Print(tstate);
status = _PyStatus_ERR("failed to initialize Apple log streams");
done:
Py_XDECREF(result);
Py_XDECREF(apple_log_write);
Py_XDECREF(_apple_support);
return status;
}
#endif // __APPLE__
static void
_Py_FatalError_DumpTracebacks(int fd, PyInterpreterState *interp,

View file

@ -6,6 +6,7 @@ static const char* _Py_stdlib_module_names[] = {
"_abc",
"_aix_support",
"_android_support",
"_apple_support",
"_ast",
"_asyncio",
"_bisect",