[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/python/cpython/3.12/Programs/_testembed.c [Back]  [Original]

#ifndef Py_BUILD_CORE_MODULE
#  define Py_BUILD_CORE_MODULE
#endif

/* Always enable assertion (even in release mode) */
#undef NDEBUG

#include 
#include "pycore_initconfig.h"    // _PyConfig_InitCompatConfig()
#include "pycore_runtime.h"       // _PyRuntime
#include "pycore_import.h"        // _PyImport_FrozenBootstrap
#include 
#include 
#include                // putenv()
#include 

int main_argc;
char **main_argv;

/*********************************************************
 * Embedded interpreter tests that need a custom exe
 *
 * Executed via Lib/test/test_embed.py
 *********************************************************/

// Use to display the usage
#define PROGRAM "test_embed"

/* Use path starting with "./" avoids a search along the PATH */
#define PROGRAM_NAME L"./_testembed"

#define INIT_LOOPS 4

// Ignore Py_DEPRECATED() compiler warnings: deprecated functions are
// tested on purpose here.
_Py_COMP_DIAG_PUSH
_Py_COMP_DIAG_IGNORE_DEPR_DECLS


static void error(const char *msg)
{
    fprintf(stderr, "ERROR: %s\n", msg);
    fflush(stderr);
}


static void config_set_string(PyConfig *config, wchar_t **config_str, const wchar_t *str)
{
    PyStatus status = PyConfig_SetString(config, config_str, str);
    if (PyStatus_Exception(status)) {
        PyConfig_Clear(config);
        Py_ExitStatusException(status);
    }
}


static void config_set_program_name(PyConfig *config)
{
    const wchar_t *program_name = PROGRAM_NAME;
    config_set_string(config, &config->program_name, program_name);
}


static void init_from_config_clear(PyConfig *config)
{
    PyStatus status = Py_InitializeFromConfig(config);
    PyConfig_Clear(config);
    if (PyStatus_Exception(status)) {
        Py_ExitStatusException(status);
    }
}


static void _testembed_Py_InitializeFromConfig(void)
{
    PyConfig config;
    _PyConfig_InitCompatConfig(&config);
    config_set_program_name(&config);
    init_from_config_clear(&config);
}

static void _testembed_Py_Initialize(void)
{
   Py_SetProgramName(PROGRAM_NAME);
   Py_Initialize();
}


/*****************************************************
 * Test repeated initialisation and subinterpreters
 *****************************************************/

static void print_subinterp(void)
{
    /* Output information about the interpreter in the format
       expected in Lib/test/test_capi.py (test_subinterps). */
    PyThreadState *ts = PyThreadState_Get();
    PyInterpreterState *interp = ts->interp;
    int64_t id = PyInterpreterState_GetID(interp);
    printf("interp %" PRId64 " , thread state : ",
            id, (uintptr_t)interp, (uintptr_t)ts);
    fflush(stdout);
    PyRun_SimpleString(
        "import sys;"
        "print('id(modules) =', id(sys.modules));"
        "sys.stdout.flush()"
    );
}

static int test_repeated_init_and_subinterpreters(void)
{
    PyThreadState *mainstate, *substate;
    PyGILState_STATE gilstate;

    for (int i=1; i  3) {
            code = main_argv[i+2];
        }

        _testembed_Py_InitializeFromConfig();
        int err = PyRun_SimpleString(code);
        Py_Finalize();
        if (err) {
            return 1;
        }
    }
    return 0;
}

/****************************************************************************
 * Test the Py_Initialize(Ex) convenience/compatibility wrappers
 ***************************************************************************/
// This is here to help ensure there are no wrapper resource leaks (gh-96853)
static int test_repeated_simple_init(void)
{
    for (int i=1; i parse_argv = 1;

    config_set_argv(config, Py_ARRAY_LENGTH(argv), argv);
    config_set_string(config, &config->program_name, L"./python3");
}


static int test_init_run_main(void)
{
    PyConfig config;
    PyConfig_InitPythonConfig(&config);

    configure_init_main(&config);
    init_from_config_clear(&config);

    return Py_RunMain();
}


static int test_init_main(void)
{
    PyConfig config;
    PyConfig_InitPythonConfig(&config);

    configure_init_main(&config);
    config._init_main = 0;
    init_from_config_clear(&config);

    /* sys.stdout don't exist yet: it is created by _Py_InitializeMain() */
    int res = PyRun_SimpleString(
        "import sys; "
        "print('Run Python code before _Py_InitializeMain', "
               "file=sys.stderr)");
    if (res < 0) {
        exit(1);
    }

    PyStatus status = _Py_InitializeMain();
    if (PyStatus_Exception(status)) {
        Py_ExitStatusException(status);
    }

    return Py_RunMain();
}


static int test_run_main(void)
{
    PyConfig config;
    PyConfig_InitPythonConfig(&config);

    wchar_t *argv[] = {L"python3", L"-c",
                       (L"import sys; "
                        L"print(f'Py_RunMain(): sys.argv={sys.argv}')"),
                       L"arg2"};
    config_set_argv(&config, Py_ARRAY_LENGTH(argv), argv);
    config_set_string(&config, &config.program_name, L"./python3");
    init_from_config_clear(&config);

    return Py_RunMain();
}


static int test_run_main_loop(void)
{
    // bpo-40413: Calling Py_InitializeFromConfig()+Py_RunMain() multiple
    // times must not crash.
    for (int i=0; icalloc(allocator->ctx, nelem, elsize);
}

static void *
realloc_wrapper(void *ctx, void *ptr, size_t new_size)
{
    PyMemAllocatorEx *allocator = (PyMemAllocatorEx *)ctx;
    return allocator->realloc(allocator->ctx, ptr, new_size);
}

static void
free_wrapper(void *ctx, void *ptr)
{
    PyMemAllocatorEx *allocator = (PyMemAllocatorEx *)ctx;
    allocator->free(allocator->ctx, ptr);
}

static void
wrap_allocator(PyMemAllocatorEx *allocator)
{
    PyMem_GetAllocator(PYMEM_DOMAIN_OBJ, allocator);
    PyMemAllocatorEx wrapper = {
        .malloc = &malloc_wrapper,
        .calloc = &calloc_wrapper,
        .realloc = &realloc_wrapper,
        .free = &free_wrapper,
        .ctx = allocator,
    };
    PyMem_SetAllocator(PYMEM_DOMAIN_OBJ, &wrapper);
}

static void
unwrap_allocator(PyMemAllocatorEx *allocator)
{
    PyMem_SetAllocator(PYMEM_DOMAIN_OBJ, allocator);
}

static int
test_get_incomplete_frame(void)
{
    _testembed_Py_InitializeFromConfig();
    PyMemAllocatorEx allocator;
    wrap_allocator(&allocator);
    // Force an allocation with an incomplete (generator) frame:
    int result = PyRun_SimpleString("(_ for _ in ())");
    unwrap_allocator(&allocator);
    Py_Finalize();
    return result;
}


/* *********************************************************
 * List of test cases and the function that implements it.
 *
 * Names are compared case-sensitively with the first
 * argument. If no match is found, or no first argument was
 * provided, the names of all test cases are printed and
 * the exit code will be -1.
 *
 * The int returned from test functions is used as the exit
 * code, and test_capi treats all non-zero exit codes as a
 * failed test.
 *********************************************************/
struct TestCase
{
    const char *name;
    int (*func)(void);
};

static struct TestCase TestCases[] = {
    // Python initialization
    {"test_repeated_init_exec", test_repeated_init_exec},
    {"test_repeated_simple_init", test_repeated_simple_init},
    {"test_forced_io_encoding", test_forced_io_encoding},
    {"test_repeated_init_and_subinterpreters", test_repeated_init_and_subinterpreters},
    {"test_repeated_init_and_inittab", test_repeated_init_and_inittab},
    {"test_pre_initialization_api", test_pre_initialization_api},
    {"test_pre_initialization_sys_options", test_pre_initialization_sys_options},
    {"test_bpo20891", test_bpo20891},
    {"test_initialize_twice", test_initialize_twice},
    {"test_initialize_pymain", test_initialize_pymain},
    {"test_init_initialize_config", test_init_initialize_config},
    {"test_preinit_compat_config", test_preinit_compat_config},
    {"test_init_compat_config", test_init_compat_config},
    {"test_init_global_config", test_init_global_config},
    {"test_init_from_config", test_init_from_config},
    {"test_init_parse_argv", test_init_parse_argv},
    {"test_init_dont_parse_argv", test_init_dont_parse_argv},
    {"test_init_compat_env", test_init_compat_env},
    {"test_init_python_env", test_init_python_env},
    {"test_init_env_dev_mode", test_init_env_dev_mode},
    {"test_init_env_dev_mode_alloc", test_init_env_dev_mode_alloc},
    {"test_init_dont_configure_locale", test_init_dont_configure_locale},
    {"test_init_dev_mode", test_init_dev_mode},
    {"test_init_isolated_flag", test_init_isolated_flag},
    {"test_preinit_isolated_config", test_preinit_isolated_config},
    {"test_init_isolated_config", test_init_isolated_config},
    {"test_preinit_python_config", test_preinit_python_config},
    {"test_init_python_config", test_init_python_config},
    {"test_preinit_isolated1", test_preinit_isolated1},
    {"test_preinit_isolated2", test_preinit_isolated2},
    {"test_preinit_parse_argv", test_preinit_parse_argv},
    {"test_preinit_dont_parse_argv", test_preinit_dont_parse_argv},
    {"test_init_read_set", test_init_read_set},
    {"test_init_run_main", test_init_run_main},
    {"test_init_main", test_init_main},
    {"test_init_sys_add", test_init_sys_add},
    {"test_init_setpath", test_init_setpath},
    {"test_init_setpath_config", test_init_setpath_config},
    {"test_init_setpythonhome", test_init_setpythonhome},
    {"test_init_is_python_build", test_init_is_python_build},
    {"test_init_warnoptions", test_init_warnoptions},
    {"test_init_set_config", test_init_set_config},
    {"test_run_main", test_run_main},
    {"test_run_main_loop", test_run_main_loop},
    {"test_get_argc_argv", test_get_argc_argv},
    {"test_init_use_frozen_modules", test_init_use_frozen_modules},
    {"test_init_main_interpreter_settings", test_init_main_interpreter_settings},

    // Audit
    {"test_open_code_hook", test_open_code_hook},
    {"test_audit", test_audit},
    {"test_audit_subinterpreter", test_audit_subinterpreter},
    {"test_audit_run_command", test_audit_run_command},
    {"test_audit_run_file", test_audit_run_file},
    {"test_audit_run_interactivehook", test_audit_run_interactivehook},
    {"test_audit_run_startup", test_audit_run_startup},
    {"test_audit_run_stdin", test_audit_run_stdin},

    // Specific C API
    {"test_unicode_id_init", test_unicode_id_init},
#ifndef MS_WINDOWS
    {"test_frozenmain", test_frozenmain},
#endif
    {"test_get_incomplete_frame", test_get_incomplete_frame},

    {NULL, NULL}
};


int main(int argc, char *argv[])
{
    main_argc = argc;
    main_argv = argv;

    if (argc > 1) {
        for (struct TestCase *tc = TestCases; tc && tc->name; tc++) {
            if (strcmp(argv[1], tc->name) == 0)
                return (*tc->func)();
        }
    }

    /* No match found, or no test name provided, so display usage */
    printf("Python " PY_VERSION " _testembed executable for embedded interpreter tests\n"
           "Normally executed via 'EmbeddingTests' in Lib/test/test_embed.py\n\n"
           "Usage: %s TESTNAME\n\nAll available tests:\n", argv[0]);
    for (struct TestCase *tc = TestCases; tc && tc->name; tc++) {
        printf("  %s\n", tc->name);
    }

    /* Non-zero exit code will cause test_embed.py tests to fail.
       This is intentional. */
    return -1;
}

Web Proxy Viewer  |  New URL  |  Original Page