Skip to content

Commit 6439136

Browse files
ncoghlanwillingc
andauthored
[3.13] bpo-34206: Improve docs and test coverage for pre-init functions (GH-8023) (#125092)
- move the Py_Main documentation from the very high level API section to the initialization and finalization section - make it clear that it encapsulates a full Py_Initialize/Finalize cycle of its own - point out that exactly which settings will be read and applied correctly when Py_Main is called after a separate runtime initialization call is version dependent - be explicit that Py_IsInitialized can be called prior to initialization - actually test that Py_IsInitialized can be called prior to initialization - flush stdout in the embedding tests that run code so it appears in the expected order when running with "-vv" - make "-vv" on the subinterpreter embedding tests less spammy --------- (cherry picked from commit 7c4b6a6) Co-authored-by: Carol Willing <[email protected]>
1 parent 9e61aa9 commit 6439136

File tree

7 files changed

+199
-78
lines changed

7 files changed

+199
-78
lines changed

Doc/c-api/init.rst

Lines changed: 142 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
Initialization, Finalization, and Threads
88
*****************************************
99

10-
See also :ref:`Python Initialization Configuration <init-config>`.
10+
See :ref:`Python Initialization Configuration <init-config>` for details
11+
on how to configure the interpreter prior to initialization.
1112

1213
.. _pre-init-safe:
1314

@@ -21,6 +22,15 @@ a few functions and the :ref:`global configuration variables
2122

2223
The following functions can be safely called before Python is initialized:
2324

25+
* Functions that initialize the interpreter:
26+
27+
* :c:func:`Py_Initialize`
28+
* :c:func:`Py_InitializeEx`
29+
* :c:func:`Py_InitializeFromConfig`
30+
* :c:func:`Py_BytesMain`
31+
* :c:func:`Py_Main`
32+
* the runtime pre-initialization functions covered in :ref:`init-config`
33+
2434
* Configuration functions:
2535

2636
* :c:func:`PyImport_AppendInittab`
@@ -32,6 +42,7 @@ The following functions can be safely called before Python is initialized:
3242
* :c:func:`Py_SetProgramName`
3343
* :c:func:`Py_SetPythonHome`
3444
* :c:func:`PySys_ResetWarnOptions`
45+
* the configuration functions covered in :ref:`init-config`
3546

3647
* Informative functions:
3748

@@ -43,10 +54,12 @@ The following functions can be safely called before Python is initialized:
4354
* :c:func:`Py_GetCopyright`
4455
* :c:func:`Py_GetPlatform`
4556
* :c:func:`Py_GetVersion`
57+
* :c:func:`Py_IsInitialized`
4658

4759
* Utilities:
4860

4961
* :c:func:`Py_DecodeLocale`
62+
* the status reporting and utility functions covered in :ref:`init-config`
5063

5164
* Memory allocators:
5265

@@ -62,11 +75,13 @@ The following functions can be safely called before Python is initialized:
6275

6376
.. note::
6477

65-
The following functions **should not be called** before
66-
:c:func:`Py_Initialize`: :c:func:`Py_EncodeLocale`, :c:func:`Py_GetPath`,
78+
Despite their apparent similarity to some of the functions listed above,
79+
the following functions **should not be called** before the interpreter has
80+
been initialized: :c:func:`Py_EncodeLocale`, :c:func:`Py_GetPath`,
6781
:c:func:`Py_GetPrefix`, :c:func:`Py_GetExecPrefix`,
6882
:c:func:`Py_GetProgramFullPath`, :c:func:`Py_GetPythonHome`,
69-
:c:func:`Py_GetProgramName` and :c:func:`PyEval_InitThreads`.
83+
:c:func:`Py_GetProgramName`, :c:func:`PyEval_InitThreads`, and
84+
:c:func:`Py_RunMain`.
7085

7186

7287
.. _global-conf-vars:
@@ -346,34 +361,42 @@ Initializing and finalizing the interpreter
346361
this should be called before using any other Python/C API functions; see
347362
:ref:`Before Python Initialization <pre-init-safe>` for the few exceptions.
348363

349-
This initializes
350-
the table of loaded modules (``sys.modules``), and creates the fundamental
351-
modules :mod:`builtins`, :mod:`__main__` and :mod:`sys`. It also initializes
352-
the module search path (``sys.path``). It does not set ``sys.argv``; use
353-
the new :c:type:`PyConfig` API of the :ref:`Python Initialization
354-
Configuration <init-config>` for that. This is a no-op when called for a
355-
second time
356-
(without calling :c:func:`Py_FinalizeEx` first). There is no return value; it is a
357-
fatal error if the initialization fails.
358-
359-
Use the :c:func:`Py_InitializeFromConfig` function to customize the
364+
This initializes the table of loaded modules (``sys.modules``), and creates
365+
the fundamental modules :mod:`builtins`, :mod:`__main__` and :mod:`sys`.
366+
It also initializes the module search path (``sys.path``). It does not set
367+
``sys.argv``; use the :ref:`Python Initialization Configuration <init-config>`
368+
API for that. This is a no-op when called for a second time (without calling
369+
:c:func:`Py_FinalizeEx` first). There is no return value; it is a fatal
370+
error if the initialization fails.
371+
372+
Use :c:func:`Py_InitializeFromConfig` to customize the
360373
:ref:`Python Initialization Configuration <init-config>`.
361374

362375
.. note::
363-
On Windows, changes the console mode from ``O_TEXT`` to ``O_BINARY``, which will
364-
also affect non-Python uses of the console using the C Runtime.
376+
On Windows, changes the console mode from ``O_TEXT`` to ``O_BINARY``,
377+
which will also affect non-Python uses of the console using the C Runtime.
365378

366379

367380
.. c:function:: void Py_InitializeEx(int initsigs)
368381
369382
This function works like :c:func:`Py_Initialize` if *initsigs* is ``1``. If
370-
*initsigs* is ``0``, it skips initialization registration of signal handlers, which
371-
might be useful when Python is embedded.
383+
*initsigs* is ``0``, it skips initialization registration of signal handlers,
384+
which may be useful when CPython is embedded as part of a larger application.
372385
373-
Use the :c:func:`Py_InitializeFromConfig` function to customize the
386+
Use :c:func:`Py_InitializeFromConfig` to customize the
374387
:ref:`Python Initialization Configuration <init-config>`.
375388
376389
390+
.. c:function:: PyStatus Py_InitializeFromConfig(const PyConfig *config)
391+
392+
Initialize Python from *config* configuration, as described in
393+
:ref:`init-from-config`.
394+
395+
See the :ref:`init-config` section for details on pre-initializing the
396+
interpreter, populating the runtime configuration structure, and querying
397+
the returned status structure.
398+
399+
377400
.. c:function:: int Py_IsInitialized()
378401
379402
Return true (nonzero) when the Python interpreter has been initialized, false
@@ -430,12 +453,111 @@ Initializing and finalizing the interpreter
430453
431454
.. versionadded:: 3.6
432455
456+
433457
.. c:function:: void Py_Finalize()
434458
435459
This is a backwards-compatible version of :c:func:`Py_FinalizeEx` that
436460
disregards the return value.
437461
438462
463+
.. c:function:: int Py_BytesMain(int argc, char **argv)
464+
465+
Similar to :c:func:`Py_Main` but *argv* is an array of bytes strings,
466+
allowing the calling application to delegate the text decoding step to
467+
the CPython runtime.
468+
469+
.. versionadded:: 3.8
470+
471+
472+
.. c:function:: int Py_Main(int argc, wchar_t **argv)
473+
474+
The main program for the standard interpreter, encapsulating a full
475+
initialization/finalization cycle, as well as additional
476+
behaviour to implement reading configurations settings from the environment
477+
and command line, and then executing ``__main__`` in accordance with
478+
:ref:`using-on-cmdline`.
479+
480+
This is made available for programs which wish to support the full CPython
481+
command line interface, rather than just embedding a Python runtime in a
482+
larger application.
483+
484+
The *argc* and *argv* parameters are similar to those which are passed to a
485+
C program's :c:func:`main` function, except that the *argv* entries are first
486+
converted to ``wchar_t`` using :c:func:`Py_DecodeLocale`. It is also
487+
important to note that the argument list entries may be modified to point to
488+
strings other than those passed in (however, the contents of the strings
489+
pointed to by the argument list are not modified).
490+
491+
The return value will be ``0`` if the interpreter exits normally (i.e.,
492+
without an exception), ``1`` if the interpreter exits due to an exception,
493+
or ``2`` if the argument list does not represent a valid Python command
494+
line.
495+
496+
Note that if an otherwise unhandled :exc:`SystemExit` is raised, this
497+
function will not return ``1``, but exit the process, as long as
498+
``Py_InspectFlag`` is not set. If ``Py_InspectFlag`` is set, execution will
499+
drop into the interactive Python prompt, at which point a second otherwise
500+
unhandled :exc:`SystemExit` will still exit the process, while any other
501+
means of exiting will set the return value as described above.
502+
503+
In terms of the CPython runtime configuration APIs documented in the
504+
:ref:`runtime configuration <init-config>` section (and without accounting
505+
for error handling), ``Py_Main`` is approximately equivalent to::
506+
507+
PyConfig config;
508+
PyConfig_InitPythonConfig(&config);
509+
PyConfig_SetArgv(&config, argc, argv);
510+
Py_InitializeFromConfig(&config);
511+
PyConfig_Clear(&config);
512+
513+
Py_RunMain();
514+
515+
In normal usage, an embedding application will call this function
516+
*instead* of calling :c:func:`Py_Initialize`, :c:func:`Py_InitializeEx` or
517+
:c:func:`Py_InitializeFromConfig` directly, and all settings will be applied
518+
as described elsewhere in this documentation. If this function is instead
519+
called *after* a preceding runtime initialization API call, then exactly
520+
which environmental and command line configuration settings will be updated
521+
is version dependent (as it depends on which settings correctly support
522+
being modified after they have already been set once when the runtime was
523+
first initialized).
524+
525+
526+
.. c:function:: int Py_RunMain(void)
527+
528+
Executes the main module in a fully configured CPython runtime.
529+
530+
Executes the command (:c:member:`PyConfig.run_command`), the script
531+
(:c:member:`PyConfig.run_filename`) or the module
532+
(:c:member:`PyConfig.run_module`) specified on the command line or in the
533+
configuration. If none of these values are set, runs the interactive Python
534+
prompt (REPL) using the ``__main__`` module's global namespace.
535+
536+
If :c:member:`PyConfig.inspect` is not set (the default), the return value
537+
will be ``0`` if the interpreter exits normally (that is, without raising
538+
an exception), or ``1`` if the interpreter exits due to an exception. If an
539+
otherwise unhandled :exc:`SystemExit` is raised, the function will immediately
540+
exit the process instead of returning ``1``.
541+
542+
If :c:member:`PyConfig.inspect` is set (such as when the :option:`-i` option
543+
is used), rather than returning when the interpreter exits, execution will
544+
instead resume in an interactive Python prompt (REPL) using the ``__main__``
545+
module's global namespace. If the interpreter exited with an exception, it
546+
is immediately raised in the REPL session. The function return value is
547+
then determined by the way the *REPL session* terminates: returning ``0``
548+
if the session terminates without raising an unhandled exception, exiting
549+
immediately for an unhandled :exc:`SystemExit`, and returning ``1`` for
550+
any other unhandled exception.
551+
552+
This function always finalizes the Python interpreter regardless of whether
553+
it returns a value or immediately exits the process due to an unhandled
554+
:exc:`SystemExit` exception.
555+
556+
See :ref:`Python Configuration <init-python-config>` for an example of a
557+
customized Python that always runs in isolated mode using
558+
:c:func:`Py_RunMain`.
559+
560+
439561
Process-wide parameters
440562
=======================
441563

Doc/c-api/init_config.rst

Lines changed: 4 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1348,14 +1348,13 @@ the :option:`-X` command line option.
13481348
The ``show_alloc_count`` field has been removed.
13491349
13501350
1351+
.. _init-from-config:
1352+
13511353
Initialization with PyConfig
13521354
============================
13531355
1354-
Function to initialize Python:
1355-
1356-
.. c:function:: PyStatus Py_InitializeFromConfig(const PyConfig *config)
1357-
1358-
Initialize Python from *config* configuration.
1356+
Initializing the interpreter from a populated configuration struct is handled
1357+
by calling :c:func:`Py_InitializeFromConfig`.
13591358
13601359
The caller is responsible to handle exceptions (error or exit) using
13611360
:c:func:`PyStatus_Exception` and :c:func:`Py_ExitStatusException`.
@@ -1585,26 +1584,6 @@ The ``__PYVENV_LAUNCHER__`` environment variable is used to set
15851584
:c:member:`PyConfig.base_executable`.
15861585
15871586
1588-
Py_RunMain()
1589-
============
1590-
1591-
.. c:function:: int Py_RunMain(void)
1592-
1593-
Execute the command (:c:member:`PyConfig.run_command`), the script
1594-
(:c:member:`PyConfig.run_filename`) or the module
1595-
(:c:member:`PyConfig.run_module`) specified on the command line or in the
1596-
configuration.
1597-
1598-
By default and when if :option:`-i` option is used, run the REPL.
1599-
1600-
Finally, finalizes Python and returns an exit status that can be passed to
1601-
the ``exit()`` function.
1602-
1603-
See :ref:`Python Configuration <init-python-config>` for an example of
1604-
customized Python always running in isolated mode using
1605-
:c:func:`Py_RunMain`.
1606-
1607-
16081587
Py_GetArgcArgv()
16091588
================
16101589

Doc/c-api/veryhigh.rst

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -25,30 +25,6 @@ are only passed to these functions if it is certain that they were created by
2525
the same library that the Python runtime is using.
2626

2727

28-
.. c:function:: int Py_Main(int argc, wchar_t **argv)
29-
30-
The main program for the standard interpreter. This is made available for
31-
programs which embed Python. The *argc* and *argv* parameters should be
32-
prepared exactly as those which are passed to a C program's :c:func:`main`
33-
function (converted to wchar_t according to the user's locale). It is
34-
important to note that the argument list may be modified (but the contents of
35-
the strings pointed to by the argument list are not). The return value will
36-
be ``0`` if the interpreter exits normally (i.e., without an exception),
37-
``1`` if the interpreter exits due to an exception, or ``2`` if the parameter
38-
list does not represent a valid Python command line.
39-
40-
Note that if an otherwise unhandled :exc:`SystemExit` is raised, this
41-
function will not return ``1``, but exit the process, as long as
42-
:c:member:`PyConfig.inspect` is zero.
43-
44-
45-
.. c:function:: int Py_BytesMain(int argc, char **argv)
46-
47-
Similar to :c:func:`Py_Main` but *argv* is an array of bytes strings.
48-
49-
.. versionadded:: 3.8
50-
51-
5228
.. c:function:: int PyRun_AnyFile(FILE *fp, const char *filename)
5329
5430
This is a simplified interface to :c:func:`PyRun_AnyFileExFlags` below, leaving

Lib/test/test_embed.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,8 @@ def run_repeated_init_and_subinterpreters(self):
168168
# Parse the line from the loop. The first line is the main
169169
# interpreter and the 3 afterward are subinterpreters.
170170
interp = Interp(*match.groups())
171-
if support.verbose > 1:
171+
if support.verbose > 2:
172+
# 5 lines per pass is super-spammy, so limit that to -vvv
172173
print(interp)
173174
self.assertTrue(interp.interp)
174175
self.assertTrue(interp.tstate)
@@ -279,6 +280,10 @@ def test_pre_initialization_api(self):
279280
"""
280281
env = dict(os.environ, PYTHONPATH=os.pathsep.join(sys.path))
281282
out, err = self.run_embedded_interpreter("test_pre_initialization_api", env=env)
283+
if support.verbose > 1:
284+
print()
285+
print(out)
286+
print(err)
282287
if MS_WINDOWS:
283288
expected_path = self.test_exe
284289
else:
@@ -296,6 +301,10 @@ def test_pre_initialization_sys_options(self):
296301
env['PYTHONPATH'] = os.pathsep.join(sys.path)
297302
out, err = self.run_embedded_interpreter(
298303
"test_pre_initialization_sys_options", env=env)
304+
if support.verbose > 1:
305+
print()
306+
print(out)
307+
print(err)
299308
expected_output = (
300309
"sys.warnoptions: ['once', 'module', 'default']\n"
301310
"sys._xoptions: {'not_an_option': '1', 'also_not_an_option': '2'}\n"
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Added ``Py_IsInitialized`` to the list of APIs that are safe to call before
2+
the interpreter is initialized, and updated the embedding tests to cover it.
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
The :c:func:`Py_Main` documentation moved from the "Very High Level API" section to the
2+
"Initialization and Finalization" section.
3+
4+
Also make it explicit that we expect ``Py_Main`` to typically be called instead
5+
of ``Py_Initialize`` rather than after it (since ``Py_Main`` makes its own
6+
call to ``Py_Initialize``). Document that calling both is
7+
supported but is version dependent on which settings
8+
will be applied correctly.

0 commit comments

Comments
 (0)