Skip to content

Remove _Py_InitializeMain() private function #129033

Closed

Description

@vstinner

PEP 587 "Python Initialization Configuration" added a "Multi-Phase Initialization Private Provisional API":

The plan was to make the "core phase" more usable. But since Python 3.8, Python doesn't use this "Multi-Phase Initialization" API and I failed to find any user in 3rd party code.

I propose to remove this API in Python 3.14 without any deprecation since the feature was provisional and it's a private API.

Provisional:

A provisional API is one which has been deliberately excluded from the standard library’s backwards compatibility guarantees.

Linked PRs

Activity

  1. added 2 commits that reference this issue on Jan 19, 2025
  2. vstinner commented on Jan 19, 2025

    @vstinner
    MemberAuthor
  3. vstinner commented on Jan 19, 2025

    @vstinner
    MemberAuthor

    _PyInterpreterState_SetConfig() and _PyInterpreterState_GetConfigCopy() can also be removed if _Py_InitializeMain() is removed. PEP 741 "Python Configuration C API" added a public API for that: PyConfig_Set().

  4. ncoghlan commented on Jan 20, 2025

    @ncoghlan
    Contributor

    Makes sense to me. If an embedding application wants to split up interpreter initialisation and main module execution they can:

    1. Pass an empty string in run_command during initialisation
    2. Execute the relevant code in __main__.__dict__ later
  5. added 4 commits that reference this issue on Jan 20, 2025
  6. added 2 commits that reference this issue on Jan 21, 2025
  7. added 2 commits that reference this issue on Aug 4, 2025
  8. added a commit that references this issue on Aug 4, 2025
  9. added a commit that references this issue on Aug 19, 2025
  10. added a commit that references this issue on Sep 8, 2025
  11. added a commit that references this issue on Sep 9, 2025
  12. kovidgoyal commented on Dec 8, 2025

    @kovidgoyal

    This totally breaks multi-phase initialization. With no deprecation period and no warning! This code was used in the wild by multiple projects. To name just two that I am personally aware of: PyOxidizer and bypy. Both of these are on github so I dont know how you failed to find them in 3rd party code.

    More importantly you have removed this capability without providing any viable alternative. Multi-phase initialization was not only about separating initialization from main module execution. It was also about having a hook point between the "core" and "main" initialization phases of the interpreter. There appears to be no way to do that anymore. Indeed I would argue that the latter is the main use case for multi phase initialization.

    This makes it impossible, as far as I can tell, to insert a meta importer into sys.meta_path before the "main" initialization phase. The main initialization phase tries to load the encodings module, so it is now impossible to have this module (and any other modules initialization may depend on) not available on the filesystem as separate py files. My applications that embed python in a larger program rely on bundling all python code into a single mmaped() file containing pre-compiled bytecode for performance.

    Furthermore you have removed _Py_MainInitialize() but left PyConfig._init_main. How is one supposed to use _init_main without _Py_MainInitialize()?

    Please re-open this and either revert this removal or provide some way to achieve the usecase of enabling embedding applications to override where imports happen during the "main" initialization phase.

  13. vstinner commented on Dec 8, 2025

    @vstinner
    MemberAuthor

    Hi,

    First of all, this issue is closed. Would you mind to open a new issue?

    This totally breaks multi-phase initialization. With no deprecation period and no warning!

    Right, https://docs.python.org/3.13/c-api/init_config.html#multi-phase-initialization-private-provisional-api was a Provisional API:

    A provisional API is one which has been deliberately excluded from the standard library’s backwards compatibility guarantees.

    @kovidgoyal:

    This code was used in the wild by multiple projects. To name just two that I am personally aware of: PyOxidizer and bypy. Both of these are on github so I dont know how you failed to find them in 3rd party code.

    I just ran a code search on PyPI top 15,000 projects and it returns a single match in orjson which is irrelevant:

    PYPI-2025-09-22/orjson-3.11.3.tar.gz: orjson-3.11.3/include/cargo/pyo3-ffi-0.25.1/src/cpython/pylifecycle.rs: pub fn _Py_InitializeMain() -> PyStatus;
    

    I cannot find PyOxidizer and bypy with my methodology. I'm not sure why.

    This makes it impossible, as far as I can tell, to insert a meta importer into sys.meta_path before the "main" initialization phase.

    Would you mind to elaborate your use case? Do you use such meta importer to import stdlib modules?

    Furthermore you have removed _Py_MainInitialize() but left PyConfig._init_main. How is one supposed to use _init_main without _Py_MainInitialize()?

    Programs/_freeze_module.c still uses _init_main = 0. I kept the option for this file which doesn't need the main phase. It's just to "bootstrap" Python build.

    I'm sorry that you're affected by these removals, I wasn't aware of any users of this feature. Again, please reply by opening a new issue.

  14. kovidgoyal commented on Dec 8, 2025

    @kovidgoyal
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions