Skip to content

bpo-34206: Improve docs and test coverage for pre-init functions #8023

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

Merged
merged 29 commits into from
Oct 8, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
6fd7a02
bpo-34008: Py_Main and Py_IsInitialized are preinit functions
ncoghlan Jun 30, 2018
90aea92
Add news entry
ncoghlan Jun 30, 2018
6708545
Fix directive markup
ncoghlan Jun 30, 2018
c2e12cc
Reword Py_Main docs
ncoghlan Jun 30, 2018
eb855e1
Replace note with NEWS entry for Py_Main docs move
ncoghlan Jul 4, 2018
68e37d1
Further pre-initialization test improvements
ncoghlan Jul 4, 2018
f0c8c9d
Adjust wording to be more accurate for 3.6 and 3.7
ncoghlan Aug 23, 2019
e652a86
Add missing word
ncoghlan Aug 23, 2019
225bc42
Fix typo
ncoghlan Aug 23, 2019
036f6f3
Update NEWS entry
ncoghlan Aug 23, 2019
24586e5
Merge remote-tracking branch 'origin/master' into bpo-34008-py-main-a…
ncoghlan Aug 25, 2019
8310a1a
Tweak wording of Py_Main and Py_BytesMain docs
ncoghlan Aug 25, 2019
f3d9713
Tweak presentation order of init functions
ncoghlan Aug 25, 2019
e32d458
Further integrate old and new init API docs
ncoghlan Aug 25, 2019
6b50669
Merge in online PR changes, move InitalizeFromConfig to main init sec…
ncoghlan Aug 25, 2019
fd8d763
Merge branch 'master' into bpo-34008-py-main-after-py-initialize
ncoghlan Jun 28, 2020
70e43bd
Merge remote-tracking branch 'origin/main' into bpo-34008-py-main-aft…
ncoghlan Sep 26, 2024
31b00fb
Merge branch 'main' into bpo-34008-py-main-after-py-initialize
ncoghlan Sep 26, 2024
c6838ca
Fix merge error
ncoghlan Sep 26, 2024
634f1a0
Fix up NEWS entries
ncoghlan Sep 26, 2024
2d75186
Actually reference the init-from-config anchor
ncoghlan Sep 26, 2024
54e5391
Eliminate Py_RunMain docs duplication
ncoghlan Sep 26, 2024
9a6fec5
Fix anchor syntax
ncoghlan Sep 26, 2024
e875817
Replace stale reference to Py_Finalize
ncoghlan Sep 27, 2024
e42ebb5
Fix typo
ncoghlan Sep 27, 2024
0a58fcd
Remove trailing whitespace
ncoghlan Oct 7, 2024
b54aa49
Merge branch 'main' into bpo-34008-py-main-after-py-initialize
ncoghlan Oct 7, 2024
c5bb626
Add back Py_Finalize docs (presumably lost in a merge error)
ncoghlan Oct 7, 2024
aad97ee
Apply suggestions from code review
ncoghlan Oct 8, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions Doc/c-api/init.rst
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ a few functions and the :ref:`global configuration variables

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

* Functions that initialize the interpreter:

* :c:func:`Py_Initialize`
* :c:func:`Py_InitializeEx`
* :c:func:`Py_Main`

* Configuration functions:

* :c:func:`PyImport_AppendInittab`
Expand All @@ -44,6 +50,7 @@ The following functions can be safely called before Python is initialized:
* :c:func:`Py_GetCopyright`
* :c:func:`Py_GetPlatform`
* :c:func:`Py_GetVersion`
* :c:func:`Py_IsInitialized`

* Utilities:

Expand Down Expand Up @@ -307,6 +314,44 @@ Initializing and finalizing the interpreter
disregards the return value.


.. c:function:: int Py_Main(int argc, wchar_t **argv)

The main program for the standard interpreter, encapsulating a full
:c:func:`Py_Initialize`/:c:func:`Py_Finalize` cycle, as well as additional
behaviour to implement reading configurations settings from the environment
and command line, and then executing ``__main__`` in accordance with
:ref:`using-on-cmdline`.

This is made available for programs which wish to support the full CPython
command line interface, rather than just embedding a Python runtime in a
larger application.

The *argc* and *argv* parameters should be prepared exactly as those which
are passed to a C program's :c:func:`main` function (converted to ``wchar_t``
:c:func:`Py_DecodeLocale`). It is important to note that the argument list
may be modified (but the contents of the strings pointed to by the argument
list are not).

The return value will be ``0`` if the interpreter exits normally (i.e.,
without an exception), ``1`` if the interpreter exits due to an exception,
or ``2`` if the argument list does not represent a valid Python command
line.

Note that if an otherwise unhandled :exc:`SystemExit` is raised, this
function will not return ``1``, but exit the process, as long as
``Py_InspectFlag`` is not set. If ``Py_InspectFlag`` is set, execution will
drop into interactive Python prompt, at which point a second otherwise
unhandled :exc:`SystemExit` will still exit the process, while any other
means of exiting will set the return value as described above.

If this function is called after a separate :c:func:`Py_Initialize` or
:c:func:`Py_InitializeEx` call, then exactly which environmental and
command line configuration settings will be respected is version dependent
(since it depends on which settings are handled in the now skipped implicit
call to ``Py_Initialize``, and which are handled directly in ``Py_Main``
itself).


Process-wide parameters
=======================

Expand Down
18 changes: 3 additions & 15 deletions Doc/c-api/veryhigh.rst
Original file line number Diff line number Diff line change
Expand Up @@ -24,22 +24,10 @@ use different libraries, so care should be taken that :c:type:`FILE\*` parameter
are only passed to these functions if it is certain that they were created by
the same library that the Python runtime is using.

.. _note:

.. c:function:: int Py_Main(int argc, wchar_t **argv)

The main program for the standard interpreter. This is made available for
programs which embed Python. The *argc* and *argv* parameters should be
prepared exactly as those which are passed to a C program's :c:func:`main`
function (converted to wchar_t according to the user's locale). It is
important to note that the argument list may be modified (but the contents of
the strings pointed to by the argument list are not). The return value will
be ``0`` if the interpreter exits normally (i.e., without an exception),
``1`` if the interpreter exits due to an exception, or ``2`` if the parameter
list does not represent a valid Python command line.

Note that if an otherwise unhandled :exc:`SystemExit` is raised, this
function will not return ``1``, but exit the process, as long as
``Py_InspectFlag`` is not set.
The documentation for :c:func:`Py_Main` that previously appeared in this
section has been moved to :ref:`initialization`.


.. c:function:: int PyRun_AnyFile(FILE *fp, const char *filename)
Expand Down
8 changes: 8 additions & 0 deletions Lib/test/test_embed.py
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,10 @@ def test_pre_initialization_api(self):
"""
env = dict(os.environ, PYTHONPATH=os.pathsep.join(sys.path))
out, err = self.run_embedded_interpreter("pre_initialization_api", env=env)
if support.verbose > 1:
print()
print(out)
print(err)
if sys.platform == "win32":
expected_path = self.test_exe
else:
Expand All @@ -211,6 +215,10 @@ def test_pre_initialization_sys_options(self):
env = dict(os.environ, PYTHONPATH=os.pathsep.join(sys.path))
out, err = self.run_embedded_interpreter(
"pre_initialization_sys_options", env=env)
if support.verbose > 1:
print()
print(out)
print(err)
expected_output = (
"sys.warnoptions: ['once', 'module', 'default']\n"
"sys._xoptions: {'not_an_option': '1', 'also_not_an_option': '2'}\n"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Clearly document that we expect Py_Main to be called instead of
Py_Initialize rather than after it (since Py_Main makes its own call to
Py_Initialize).

Add Py_IsInitialized to the list of APIs that are safe to call before the
interpreter is initialized.
7 changes: 7 additions & 0 deletions Programs/_testembed.c
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,13 @@ static int test_pre_initialization_api(void)
_Py_EMBED_PREINIT_CHECK("Checking Py_SetProgramName\n");
Py_SetProgramName(program);

_Py_EMBED_PREINIT_CHECK("Checking Py_IsInitialized\n");
if (Py_IsInitialized()) {
fprintf(stderr, "Fatal error: initialized before initialization!\n");
return 1;
}


_Py_EMBED_PREINIT_CHECK("Initializing interpreter\n");
Py_Initialize();
_Py_EMBED_PREINIT_CHECK("Check sys module contents\n");
Expand Down