Py_RunMain without finalizing

PEP 587 added Py_RunMain to separate initialization out of Py_Main, however it still finalizes. It seems unfortunately asymmetrical that there isn’t an API that only runs the REPL and doesn’t also finalize. I looked at the source a little and there doesn’t seem to be a good way to run the main loop without finalizing.

My particular use case is to initialize the interpreter then import some modules and set up the environment for the user before starting the REPL. After Py_RunMain returns I’m left holding references to objects that I can no longer clean up. Granted, this isn’t the biggest problem in the typical case where the process is about to end anyway. It’s more a case of always making sure that the cleanup code doesn’t run to avoid the crash.

Would there be any interest in adding yet another API that doesn’t finalize, or even changing the behavior or Py_RunMain?

If you’re in an interactive situation, any reason why sitecustomize.py[1] or PYTHONSTARTUP would not be suitable here?

I doubt we’d add an API for this specific case. More likely we’d guide you towards implementing what you want in terms of the building-block APIs, but first let’s make sure that you have a need for something other than a few startup options.


  1. An absent-by-default module, that is imported by site on regular startup, including for interactive use. ↩︎

If you’re in an interactive situation, any reason why sitecustomize.py or PYTHONSTARTUPwould not be suitable here?

That could maybe work. I would likely have to expose more functionality in my modules to set up the environment from a Python script instead of doing it all internally in C++.

For context, this is both an embedded and an interactive application. The interactive mode is less important and is mostly about allowing the user to experiment with the API interactively and run plugin scripts in batch mode.

More likely we’d guide you towards implementing what you want in terms of the building-block APIs, but first let’s make sure that you have a need for something other than a few startup options.

I did find the implementation of Py_RunMain in main.c. It ultimately seems to devolve into PyRun_AnyFile on stdin after trying to run a file. I suppose that I can distill that to public APIs. I gather that I will also have to take care to set up readline for history/completion/etc. Is there a better template?

There are a number of examples at Python Initialization Configuration — Python 3.12.0 documentation but I don’t think there’s necessarily a better template. We’re in the middle of planning to redesign these APIs, so we’re not really investing in making the current ones more obvious right now.

For embedding, you probably want to avoid our mechanisms for input and manage them yourself - so read input from the user and pass it along to Python. The stdin “support” hasn’t really grown with the rest of the API.

You might also consider running a Jupyter kernel behind your app and integrating with that using their protocol. I know a few projects that have done that successfully.

Actually, I’m also finding that if the user types quit() in interactive mode, the main function doesn’t return. It just finalizes and calls exit. So I guess what I’m looking for isn’t even possible in general.