bpo-34008: Allow to call Py_Main() after Py_Initialize() (GH-8043) (G… · python/cpython@03ec4df

5 files changed

lines changed

Original file line numberDiff line numberDiff line change

@@ -238,6 +238,14 @@ def test_initialize_twice(self):

238238

self.assertEqual(out, '')

239239

self.assertEqual(err, '')

240240
241+

def test_initialize_pymain(self):

242+

"""

243+

bpo-34008: Calling Py_Main() after Py_Initialize() must not fail.

244+

"""

245+

out, err = self.run_embedded_interpreter("initialize_pymain")

246+

self.assertEqual(out.rstrip(), "Py_Main() after Py_Initialize: sys.argv=['-c', 'arg2']")

247+

self.assertEqual(err, '')

248+
241249
242250

if __name__ == "__main__":

243251

unittest.main()

Original file line numberDiff line numberDiff line change

@@ -0,0 +1 @@

1+

Py_Main() can again be called after Py_Initialize(), as in Python 3.6.

Original file line numberDiff line numberDiff line change

@@ -2647,9 +2647,13 @@ pymain_main(_PyMain *pymain)

26472647
26482648

pymain_init_stdio(pymain);

26492649
2650-

pymain->err = _Py_InitializeCore(&pymain->config);

2651-

if (_Py_INIT_FAILED(pymain->err)) {

2652-

_Py_FatalInitError(pymain->err);

2650+

/* bpo-34008: For backward compatibility reasons, calling Py_Main() after

2651+

Py_Initialize() ignores the new configuration. */

2652+

if (!_PyRuntime.initialized) {

2653+

pymain->err = _Py_InitializeCore(&pymain->config);

2654+

if (_Py_INIT_FAILED(pymain->err)) {

2655+

_Py_FatalInitError(pymain->err);

2656+

}

26532657

}

26542658
26552659

if (pymain_init_python_main(pymain) < 0) {

Original file line numberDiff line numberDiff line change

@@ -276,6 +276,21 @@ static int test_initialize_twice(void)

276276

return 0;

277277

}

278278
279+

static int test_initialize_pymain(void)

280+

{

281+

wchar_t *argv[] = {L"PYTHON", L"-c",

282+

L"import sys; print(f'Py_Main() after Py_Initialize: sys.argv={sys.argv}')",

283+

L"arg2"};

284+

_testembed_Py_Initialize();

285+
286+

/* bpo-34008: Calling Py_Main() after Py_Initialize() must not crash */

287+

Py_Main(Py_ARRAY_LENGTH(argv), argv);

288+
289+

Py_Finalize();

290+
291+

return 0;

292+

}

293+
279294
280295

/* *********************************************************

281296

* List of test cases and the function that implements it.

@@ -302,6 +317,7 @@ static struct TestCase TestCases[] = {

302317

{ "pre_initialization_sys_options", test_pre_initialization_sys_options },

303318

{ "bpo20891", test_bpo20891 },

304319

{ "initialize_twice", test_initialize_twice },

320+

{ "initialize_pymain", test_initialize_pymain },

305321

{ NULL, NULL }

306322

};

307323
Original file line numberDiff line numberDiff line change

@@ -775,6 +775,22 @@ _Py_InitializeCore(const _PyCoreConfig *core_config)

775775

return _Py_INIT_OK();

776776

}

777777
778+

/* Py_Initialize() has already been called: update the main interpreter

779+

configuration. Example of bpo-34008: Py_Main() called after

780+

Py_Initialize(). */

781+

static _PyInitError

782+

_Py_ReconfigureMainInterpreter(PyInterpreterState *interp,

783+

const _PyMainInterpreterConfig *config)

784+

{

785+

if (config->argv != NULL) {

786+

int res = PyDict_SetItemString(interp->sysdict, "argv", config->argv);

787+

if (res < 0) {

788+

return _Py_INIT_ERR("fail to set sys.argv");

789+

}

790+

}

791+

return _Py_INIT_OK();

792+

}

793+
778794

/* Update interpreter state based on supplied configuration settings

779795

*

780796

* After calling this function, most of the restrictions on the interpreter

@@ -796,9 +812,6 @@ _Py_InitializeMainInterpreter(const _PyMainInterpreterConfig *config)

796812

if (!_PyRuntime.core_initialized) {

797813

return _Py_INIT_ERR("runtime core not initialized");

798814

}

799-

if (_PyRuntime.initialized) {

800-

return _Py_INIT_ERR("main interpreter already initialized");

801-

}

802815
803816

/* Get current thread state and interpreter pointer */

804817

tstate = PyThreadState_GET();

@@ -813,6 +826,10 @@ _Py_InitializeMainInterpreter(const _PyMainInterpreterConfig *config)

813826

return _Py_INIT_ERR("failed to copy main interpreter config");

814827

}

815828
829+

if (_PyRuntime.initialized) {

830+

return _Py_ReconfigureMainInterpreter(interp, config);

831+

}

832+
816833

if (interp->core_config._disable_importlib) {

817834

/* Special mode for freeze_importlib: run with no import system

818835

*