I am trying to understand how the SystemExit exception influences module unloading. The situation that I am facing is that a Python application behaves just fine upon exiting when executed using the standard Python interpreter, but when run as a frozen executable, modules are unloaded unexpectedly as a result of sys.exit() being called. This wouldn't be an issue at all except that callbacks registered with the atexit module have to re-import all modules that they want to use, and this can be rather unwieldy.
I have narrowed it down to the SystemExit exception by determining that the problem does not occur if my __main__ module catches SystemExit and allows the script to terminate by reaching the end of __main__. If the exception is not caught or is re-raised, then the problem occurs. Since SystemExit influences the shutdown of threads, it seems that I need to let it be raised to keep the application from deadlocking on exit. I am working with Python 2.6.1, and I saw this behavior with 2.5 as well. It happens on Windows, Mac OS X, and Linux. The code that I am using for the frozen executable is generated by sib.py from VendorID 1.0.0. The fact that VendorID is being used is inconsequential. I have verified that its use in the executable is not causing this behavior by removing all references to it. I have reduced this to the minimum amount of code required to reproduce the problem and attached the Python script an the C code generated by sib.py for the application main() function. My guess is that the code that sib.py generates is failing to do something that Py_Main() would normally do. To that end, I have tried modifying the main() function in a variety of ways to get it as close to Py_Main() as I can, but it still exhibits the undesirable behavior when sys.exit() is called. That pretty much leaves me thinking that PyImport_ExecCodeModule() or PyImport_ImportFrozenModule() (I have also looked at Py_FrozenMain() for insight) is the culprit. Can anyone point me in the right direction for understanding how the SystemExit exception results in this behavior? My hope is that there is a change (simple or not) that can be made to the C code for the frozen executable to resolve the problem. Thanks in advance. -Patrick -- Patrick L. Hartling http://www.137.org/patrick/
/*==========================================================================*/ /* Main startup code for test */ /* This is generated code; Do not modify it! */ /*--------------------------------------------------------------------------*/ #include <stdarg.h> #include <Python.h> #include <marshal.h> /* #include <vendorid.h> */ extern unsigned char M___main__[]; static struct _frozen _PyImport_FrozenModules[] = { {0, 0, 0} /* sentinel */ }; int main(int argc, char **argv) { PyObject *v, *co; PyImport_FrozenModules = _PyImport_FrozenModules; Py_SetProgramName((char *)"test"); /* vendorid_init(); */ Py_Initialize(); PySys_SetArgv(argc, argv); co = PyMarshal_ReadObjectFromString((char *)M___main__, 655); v = PyImport_ExecCodeModule((char *)"__main__", co); if(v == NULL) { PyErr_Print(); return -1; } Py_DECREF(v); Py_Finalize(); return 0; } /*==========================================================================*/ /* EOF */ /*--------------------------------------------------------------------------*/
import atexit import os import sys def onExit(): print os.listdir(".") def main(): atexit.register(onExit) sys.exit() if __name__ == "__main__": try: main() except SystemExit: #pass raise
-- http://mail.python.org/mailman/listinfo/python-list