C API: Migrate embedded Python to PyConfig and PyInitConfig APIs

Hi,

I removed 21 deprecated global configuration variables and 4 deprecated functions in Python 3.16 C API. If your project embeds Python, it may affected if it doesn’t use PyConfig or PyInitConfig C API yet. I created this thread to share experience with updating code bases to these C APIs. Tell me if you need guidance (documentation?) for this update, or if you need help directly with your code base.

I worked on the C API to configure the Python initialization over the last years. In Python 3.8, I implemented PEP 587 “Python Initialization Configuration”: PyConfig C API. In Python 3.14, I implemented PEP 741 “Python Configuration C API”: PyInitConfig C API.

PyConfig uses wide character strings (wchar_t*), has a “preconfiguration” stage, has “Python” and “Isolated” profiles, and has a separated PyStatus API to handle errors.

PyInitConfig uses UTF-8 encoded strings, has a unified configuration API, has a single “Isolated” profile, and also unifies the error handling API. PyInitConfig was designed to be used in the stable ABI, but it’s not yet part of it. It should be a little bit simpler to use than PyConfig.

The “Isolated” profile ignores global configuration variables, environment variables, command line arguments (argv is not parsed) and user site directory. You should opt-in to enable these features if you need them.

Since Python 3.11, I deprecated the “legacy” APIs to configure the Python initialization: functions and variables. These functions/variables are removed between Python 3.13 and Python 3.16.

If your project uses the deprecated/removed legacy API, I would recommend adding a new implementation for Python 3.14 and newer using PyInitConfig. Your existing code can be kept for older Python versions.

If your project reads global configuration variables at runtime (and not only during initialization), PyConfig_Get() and PyConfig_GetInt() functions can be used instead.

Deprecated/removed functions with their PyInitConfig replacement options:

  • PySys_AddWarnOption(): Use "warnoptions" instead.
  • PySys_AddWarnOptionUnicode(): Use "warnoptions" instead.
  • PySys_HasWarnOptions(): Use "warnoptions" instead.
  • PySys_AddXOption(): Use "xoptions" instead.
  • PySys_ResetWarnOptions(): Use "xoptions" instead.
  • PySys_SetArgv(): Use "argv" instead.
  • PySys_SetArgvEx(): Use "argv" instead.
  • PySys_SetPath(): Use "module_search_paths" instead.
  • Py_SetPath(): Use "module_search_paths" instead.
  • Py_SetProgramName(): Use "program_name" instead.
  • Py_SetPythonHome(): Use "home" instead.
  • Py_SetStandardStreamEncoding(): Use "stdio_encoding" instead (and maybe also "legacy_windows_stdio" on Windows).
  • _Py_SetProgramFullPath(): Use "executable" instead.

21 global configuration variables with their PyInitConfig replacement options

  • Py_DebugFlag: Use "parser_debug" instead.
  • Py_VerboseFlag: Use "verbose" instead.
  • Py_QuietFlag: Use "quiet" instead.
  • Py_InteractiveFlag: Use "interactive" instead.
  • Py_InspectFlag: Use "inspect" instead.
  • Py_OptimizeFlag: Use "optimization_level" instead.
  • Py_NoSiteFlag: Use "site_import" instead (opposite value).
  • Py_BytesWarningFlag: Use "bytes_warning" instead.
  • Py_FrozenFlag: Use "pathconfig_warnings" instead (opposite value).
  • Py_IgnoreEnvironmentFlag: Use "use_environment" instead (opposite value).
  • Py_DontWriteBytecodeFlag: Use "write_bytecode" instead (opposite value).
  • Py_NoUserSiteDirectory: Use "user_site_directory" instead (opposite value).
  • Py_UnbufferedStdioFlag: Use "buffered_stdio" instead (opposite value).
  • Py_HashRandomizationFlag: Use "hash_seed" instead.
  • Py_IsolatedFlag: Use "isolated" instead.
  • Py_LegacyWindowsFSEncodingFlag: Use "legacy_windows_fs_encoding" instead.
  • Py_LegacyWindowsStdioFlag: Use "legacy_windows_stdio" instead.
  • Py_FileSystemDefaultEncoding: Use "filesystem_encoding" instead.
  • Py_HasFileSystemDefaultEncoding: Use "filesystem_encoding" instead.
  • Py_FileSystemDefaultEncodeErrors: Use "filesystem_errors" instead.
  • Py_UTF8Mode: Use "utf8_mode" instead.

Other initialization functions which do not change:

  • PyImport_AppendInittab()
  • PyImport_ExtendInittab()
  • PyMem_SetAllocator()
  • PyMem_SetupDebugHooks()
  • PyObject_SetArenaAllocator()

Note: functions and variables which were part of the stable ABI remain available at the ABI level (C extensions built with old Python versions can still be loaded), but are removed from the C API.

Victor