summaryrefslogtreecommitdiffstats
path: root/Python
diff options
context:
space:
mode:
authorRussell Keith-Magee <russell@keith-magee.com>2024-12-09 05:28:57 (GMT)
committerGitHub <noreply@github.com>2024-12-09 05:28:57 (GMT)
commit2041a95e68ebf6d13f867e214ada28affa830669 (patch)
treeca4fbf70b3557908e77de8ea2b66e99847145dda /Python
parentd8d12b37b5e5acb354db84b07dab8de64a6b9475 (diff)
downloadcpython-2041a95e68ebf6d13f867e214ada28affa830669.zip
cpython-2041a95e68ebf6d13f867e214ada28affa830669.tar.gz
cpython-2041a95e68ebf6d13f867e214ada28affa830669.tar.bz2
gh-126925: Modify how iOS test results are gathered (#127592)
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.
Diffstat (limited to 'Python')
-rw-r--r--Python/initconfig.c15
-rw-r--r--Python/pylifecycle.c82
-rw-r--r--Python/stdlib_module_names.h1
3 files changed, 98 insertions, 0 deletions
diff --git a/Python/initconfig.c b/Python/initconfig.c
index 438f8a5..7851b86 100644
--- a/Python/initconfig.c
+++ b/Python/initconfig.c
@@ -168,6 +168,9 @@ static const PyConfigSpec PYCONFIG_SPEC[] = {
SPEC(tracemalloc, UINT, READ_ONLY, NO_SYS),
SPEC(use_frozen_modules, BOOL, READ_ONLY, NO_SYS),
SPEC(use_hash_seed, BOOL, READ_ONLY, NO_SYS),
+#ifdef __APPLE__
+ SPEC(use_system_logger, BOOL, PUBLIC, NO_SYS),
+#endif
SPEC(user_site_directory, BOOL, READ_ONLY, NO_SYS), // sys.flags.no_user_site
SPEC(warn_default_encoding, BOOL, READ_ONLY, NO_SYS),
@@ -884,6 +887,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
@@ -986,6 +992,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;
config->tlbc_enabled = 1;
@@ -1015,6 +1024,9 @@ config_init_defaults(PyConfig *config)
#ifdef MS_WINDOWS
config->legacy_windows_stdio = 0;
#endif
+#ifdef __APPLE__
+ config->use_system_logger = 0;
+#endif
}
@@ -1049,6 +1061,9 @@ PyConfig_InitIsolatedConfig(PyConfig *config)
#ifdef MS_WINDOWS
config->legacy_windows_stdio = 0;
#endif
+#ifdef __APPLE__
+ config->use_system_logger = 0;
+#endif
}
diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c
index ceb30e9..0641812 100644
--- a/Python/pylifecycle.c
+++ b/Python/pylifecycle.c
@@ -45,7 +45,9 @@
#endif
#if defined(__APPLE__)
+# include <AvailabilityMacros.h>
# include <mach-o/loader.h>
+# include <os/log.h>
#endif
#ifdef HAVE_SIGNAL_H
@@ -75,6 +77,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);
@@ -1257,6 +1262,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);
@@ -2933,6 +2946,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,
diff --git a/Python/stdlib_module_names.h b/Python/stdlib_module_names.h
index c8cdb93..584b050 100644
--- a/Python/stdlib_module_names.h
+++ b/Python/stdlib_module_names.h
@@ -6,6 +6,7 @@ static const char* _Py_stdlib_module_names[] = {
"_abc",
"_aix_support",
"_android_support",
+"_apple_support",
"_ast",
"_asyncio",
"_bisect",