-
-
Notifications
You must be signed in to change notification settings - Fork 32.1k
bpo-32030: Split Py_Main() into subfunctions #4399
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Hum, test_capi fails on Windows. |
test_capi failed on the "gcc C" job of Travis CI:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice! This looks really good to me - just a couple of minor suggestions inline.
Include/pylifecycle.h
Outdated
@@ -21,17 +21,17 @@ PyAPI_FUNC(int) Py_SetStandardStreamEncoding(const char *encoding, | |||
const char *errors); | |||
|
|||
/* PEP 432 Multi-phase initialization API (Private while provisional!) */ | |||
PyAPI_FUNC(void) _Py_InitializeCore(const _PyCoreConfig *); | |||
PyAPI_FUNC(const char*) _Py_InitializeCore(const _PyCoreConfig *); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm wondering if a typedef char _Py_InitErrorMessage;
might make these API signatures a bit clearer:
PyAPI_FUNC(const _Py_InitErrorMessage*) _Py_InitializeCore(const _PyCoreConfig *);
While I currently guessed "Oh, that will be an error message" in the context of the patch, I'm not sure I would have without that extra context.
Using a typedef also leaves the door open to upgrading to a struct later if we find a reason for doing that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't see the need for a structure, but after converting more code to avoid calling Py_FatalError(), I found two places where we exit Python but don't want to exit with abort():
if (Py_ReadHashSeed(seed_text, &use_hash_seed, &hash_seed) < 0) {
Py_FatalError("PYTHONHASHSEED must be \"random\" or an integer "
"in range [0; 4294967295]");
}
and
m = PyImport_ImportModule("site");
if (m == NULL) {
fprintf(stderr, "Failed to import the site module\n");
PyErr_Print();
Py_Finalize();
exit(1);
}
These errors are more on the user side, they are not "bugs" of Python itself.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So I implemented a new _PyInitError "type" (technically a structure) to indicate if it's an "user error" or another error. Moreover, I added the name of the function where the error was raised, to the error message.
Modules/main.c
Outdated
@@ -35,9 +35,11 @@ | |||
extern "C" { | |||
#endif | |||
|
|||
extern void _PyMem_GetDefaultRawAllocator(PyMemAllocatorEx *alloc); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When I used this technique for the locale coercion APIs, I ended up causing a build failure on Cygwin: https://bugs.python.org/issue31877
Assuming that's a general concern, PyAPI_FUNC
will be needed here as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
One general comment: while I didn't spot any particular instances of this going wrong, it's important to keep in mind that the various global flags (Py_IsolatedFlag, etc) are part of the embedding configuration API. This means that even as we add the more explicit configuration structs and use those to pass settings from Py_Main into the CPython runtime, we still need to account for other applications that are passing in the settings via the global variables instead (and either keep that model working, or else provide explicit porting guidance). |
The PR compiles correctly on macOS and the following tests passed:
|
* Don't use "Python runtime" anymore to parse command line options or to get environment variables: pymain_init() is now a strict separation. * Use an error message rather than "crashing" directly with Py_FatalError(). Limit the number of calls to Py_FatalError(). It prepares the code to handle errors more nicely later. * Warnings options (-W, PYTHONWARNINGS) and "XOptions" (-X) are now only added to the sys module once Python core is properly initialized. * _PyMain is now the well identified owner of some important strings like: warnings options, XOptions, and the "program name". The program name string is now properly freed at exit. pymain_free() is now responsible to free the "command" string. * Rename most methods in Modules/main.c to use a "pymain_" prefix to avoid conflits and ease debug. * Replace _Py_CommandLineDetails_INIT with memset(0) * Reorder a lot of code to fix the initialization ordering. For example, initializing standard streams now comes before parsing PYTHONWARNINGS. * Py_Main() now handles errors when adding warnings options and XOptions. * Add _PyMem_GetDefaultRawAllocator() private function. * Cleanup _PyMem_Initialize(): remove useless global constants: move them into _PyMem_Initialize(). * Call _PyRuntime_Initialize() as soon as possible: _PyRuntime_Initialize() now returns an error message on failure. * Add _PyInitError structure and following macros: * _Py_INIT_OK() * _Py_INIT_ERR(msg) * _Py_INIT_USER_ERR(msg): "user" error, don't abort() in that case * _Py_INIT_FAILED(err)
Ok, I changed my code to set Py_xxx flags as soon as possible, and use Py_xxx flags rather than using pymain. |
and
Oh, I expect PyMem_RawMalloc() to be usable directly, but this changed recently: _PyRuntime_Initialize() must now be called before the first call to PyMem_RawMalloc(). I fixed that as well. |
Call _PyRuntime_Initialize() and copy core config before calling _PyMem_SetupAllocators().
Programs/python.c now uses internals/pystate.h which requires Py_BUILD_CORE.
Haven't looked closely, but this looks like overall goodness! If you want one extra case to keep in mind, see how I implemented my spython.c for my PEP 551 implementation. There's obviously no compatibility requirement, but I'd want to be able to keep doing the same things after this change. |
@zooba: "Haven't looked closely, but this looks like overall goodness!" Oh thanks. With @ncoghlan and you who know the topic, I'm now confident enough to merge my change (I already merged it ;-)). "If you want one extra case to keep in mind, see how I implemented my spython.c for my PEP 551 implementation. There's obviously no compatibility requirement, but I'd want to be able to keep doing the same things after this change." My change shouldn't break this code. @ncoghlan: would you mind to double-check? In the first version of this change, I overrided Py_xxx flags from the command lines, ignoring their previous value. @ncoghlan warned me about Py_xxx flags set when Python is embedded. So I fixed my code. |
* 'master' of https://github.com/python/cpython: (550 commits) bpo-31867: Remove duplicates in default mimetypes. (python#4388) tokenizer: Remove unused tabs options (python#4422) bpo-31691: Specify where to find build instructions for the Windows installer (python#4426) Fix typo in atexit documentation. (pythonGH-4419) bpo-31702: Allow to specify rounds for SHA-2 hashing in crypt.mksalt(). (python#4110) bpo-32043: New "developer mode": "-X dev" option (python#4413) bpo-30349: Raise FutureWarning for nested sets and set operations (python#1553) bpo-32037: Use the INT opcode for 32-bit integers in protocol 0 pickles. (python#4407) bpo-30143: 2to3 now generates a code that uses abstract collection classes (python#1262) bpo-32030: Enhance Py_Main() (python#4412) bpo-32030: Split Py_Main() into subfunctions (python#4399) bpo-32034: Make IncompleteReadError & LimitOverrunError pickleable python#4409 bpo-32025: Add time.thread_time() (python#4410) bpo-32018: Fix inspect.signature repr to follow PEP 8 (python#4408) bpo-30399: Get rid of trailing comma in the repr of BaseException. (python#1650) bpo-30950: Convert round() to Argument Clinic. (python#2740) bpo-32011: Revert "Issue python#15480: Remove the deprecated and unused TYPE_INT64 code from marshal." (python#4381) bpo-32023: Disallow genexprs without parenthesis in class definitions. (python#4400) bpo-31949: Fixed several issues in printing tracebacks (PyTraceBack_Print()). (python#4289) bpo-32032: Test both implementations of module-level pickle API. (python#4401) ...
to get environment variables: pymain_init() is now a strict
separation.
Py_FatalError(). Limit the number of calls to Py_FatalError(). It
prepares the code to handle errors more nicely later.
only added to the sys module once Python core is properly
initialized.
like: warnings options, XOptions, and the "program name". The
program name string is now properly freed at exit.
pymain_free() is now responsible to free the "command" string.
avoid conflits and ease debug.
example, initializing standard streams now comes before parsing
PYTHONWARNINGS.
Py_xxx global configuration variables. For example, replace
Py_UnbufferedStdioFlag with cmdline.use_unbuffered_io.
XOptions.
https://bugs.python.org/issue32030