Skip to content

Commit 2f54908

Browse files
authored
bpo-36471: Add _Py_RunMain() (GH-12618)
* Add config_read_cmdline() subfunction. Remove _PyCmdline structure. * _PyCoreConfig_Read() now also parses config->argv command line arguments
1 parent 5f45979 commit 2f54908

File tree

5 files changed

+152
-114
lines changed

5 files changed

+152
-114
lines changed

Include/cpython/pylifecycle.h

+3
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@ PyAPI_FUNC(_PyInitError) _Py_InitializeFromWideArgs(
4141
int argc,
4242
wchar_t **argv);
4343

44+
PyAPI_FUNC(int) _Py_RunMain(void);
45+
46+
4447
PyAPI_FUNC(void) _Py_NO_RETURN _Py_ExitInitError(_PyInitError err);
4548

4649
/* Py_PyAtExit is for the atexit module, Py_AtExit is for low-level

Lib/test/test_embed.py

+13-2
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,12 @@ def run_embedded_interpreter(self, *args, env=None):
5353
stderr=subprocess.PIPE,
5454
universal_newlines=True,
5555
env=env)
56-
(out, err) = p.communicate()
56+
try:
57+
(out, err) = p.communicate()
58+
except:
59+
p.terminate()
60+
p.wait()
61+
raise
5762
if p.returncode != 0 and support.verbose:
5863
print(f"--- {cmd} failed ---")
5964
print(f"stdout:\n{out}")
@@ -254,6 +259,11 @@ def test_initialize_pymain(self):
254259
self.assertEqual(out.rstrip(), "Py_Main() after Py_Initialize: sys.argv=['-c', 'arg2']")
255260
self.assertEqual(err, '')
256261

262+
def test_run_main(self):
263+
out, err = self.run_embedded_interpreter("run_main")
264+
self.assertEqual(out.rstrip(), "_Py_RunMain(): sys.argv=['-c', 'arg2']")
265+
self.assertEqual(err, '')
266+
257267

258268
class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
259269
maxDiff = 4096
@@ -549,10 +559,11 @@ def test_init_from_config(self):
549559

550560
'pycache_prefix': 'conf_pycache_prefix',
551561
'program_name': './conf_program_name',
552-
'argv': ['-c', 'pass'],
562+
'argv': ['-c', 'arg2'],
553563
'program': 'conf_program',
554564
'xoptions': ['core_xoption1=3', 'core_xoption2=', 'core_xoption3'],
555565
'warnoptions': ['error::ResourceWarning', 'default::BytesWarning'],
566+
'run_command': 'pass\n',
556567

557568
'site_import': 0,
558569
'bytes_warning': 1,

Modules/main.c

+22-12
Original file line numberDiff line numberDiff line change
@@ -567,20 +567,22 @@ exit_sigint(void)
567567
}
568568

569569

570-
static int
571-
pymain_main(_PyArgv *args)
570+
static void _Py_NO_RETURN
571+
pymain_exit_error(_PyInitError err)
572572
{
573-
_PyInitError err;
573+
pymain_free();
574+
_Py_ExitInitError(err);
575+
}
574576

575-
err = pymain_init(args);
576-
if (_Py_INIT_FAILED(err)) {
577-
goto exit_init_error;
578-
}
579577

578+
int
579+
_Py_RunMain(void)
580+
{
580581
int exitcode = 0;
581-
err = pymain_run_python(&exitcode);
582+
583+
_PyInitError err = pymain_run_python(&exitcode);
582584
if (_Py_INIT_FAILED(err)) {
583-
goto exit_init_error;
585+
pymain_exit_error(err);
584586
}
585587

586588
if (Py_FinalizeEx() < 0) {
@@ -596,10 +598,18 @@ pymain_main(_PyArgv *args)
596598
}
597599

598600
return exitcode;
601+
}
599602

600-
exit_init_error:
601-
pymain_free();
602-
_Py_ExitInitError(err);
603+
604+
static int
605+
pymain_main(_PyArgv *args)
606+
{
607+
_PyInitError err = pymain_init(args);
608+
if (_Py_INIT_FAILED(err)) {
609+
pymain_exit_error(err);
610+
}
611+
612+
return _Py_RunMain();
603613
}
604614

605615

Programs/_testembed.c

+25-2
Original file line numberDiff line numberDiff line change
@@ -447,9 +447,11 @@ static int test_init_from_config(void)
447447
Py_SetProgramName(L"./globalvar");
448448
config.program_name = L"./conf_program_name";
449449

450-
static wchar_t* argv[2] = {
450+
static wchar_t* argv[] = {
451+
L"python3",
451452
L"-c",
452453
L"pass",
454+
L"arg2",
453455
};
454456
config.argv.length = Py_ARRAY_LENGTH(argv);
455457
config.argv.items = argv;
@@ -528,7 +530,6 @@ static int test_init_from_config(void)
528530
config._frozen = 1;
529531

530532
err = _Py_InitializeFromConfig(&config);
531-
/* Don't call _PyCoreConfig_Clear() since all strings are static */
532533
if (_Py_INIT_FAILED(err)) {
533534
_Py_ExitInitError(err);
534535
}
@@ -712,6 +713,27 @@ static int test_init_dev_mode(void)
712713
}
713714

714715

716+
static int test_run_main(void)
717+
{
718+
_PyCoreConfig config = _PyCoreConfig_INIT;
719+
720+
wchar_t *argv[] = {L"python3", L"-c",
721+
(L"import sys; "
722+
L"print(f'_Py_RunMain(): sys.argv={sys.argv}')"),
723+
L"arg2"};
724+
config.argv.length = Py_ARRAY_LENGTH(argv);
725+
config.argv.items = argv;
726+
config.program_name = L"./python3";
727+
728+
_PyInitError err = _Py_InitializeFromConfig(&config);
729+
if (_Py_INIT_FAILED(err)) {
730+
_Py_ExitInitError(err);
731+
}
732+
733+
return _Py_RunMain();
734+
}
735+
736+
715737
/* *********************************************************
716738
* List of test cases and the function that implements it.
717739
*
@@ -748,6 +770,7 @@ static struct TestCase TestCases[] = {
748770
{ "init_isolated", test_init_isolated },
749771
{ "preinit_isolated1", test_preinit_isolated1 },
750772
{ "preinit_isolated2", test_preinit_isolated2 },
773+
{ "run_main", test_run_main },
751774
{ NULL, NULL }
752775
};
753776

0 commit comments

Comments
 (0)