George King added the comment:

The documentation for atexit.register clearly states that a SystemExit raised 
inside of the registered function is a special case:

'''
If an exception is raised during execution of the exit handlers, a traceback is 
printed (unless SystemExit is raised) and the exception information is saved. 
After all exit handlers have had a chance to run the last exception to be 
raised is re-raised.
'''

Python 2.7.11 behaves as described; Python 3.5.2 does not.

I believe there is a clear argument for allowing atexit functions to set an 
exit status code: Ultimately, it is the responsibility of the application 
programmer to return an appropriate code for all execution paths, and it is up 
to the programmer to decide what is appropriate. I can easily imagine cases 
where the atexit function encounters a critical error and the appropriate 
behavior is to return an error status to the parent process.

In many large systems, returning the correct code is the most critical behavior 
of a process, and so if atexit prevents the programmer from doing so then its 
utility is greatly diminished.

I disagree that calling _exit is "equally broken". Calling _exit completely 
breaks the atexit unwinding contract, and if an error code is necessary, then 
this is exactly what I am forced to do!

In my mind the correct behavior would be that the process exit code is 
determined from the last exception that occurs in the exit process.
- If the program begins exiting with 0, and then an atexit handler raises 
SystemExit(1), then code 1 should be returned.
- If the program begins exiting with 1, and then an atexit handler raises 
SystemExit(0), then code 0 should be returned (this may seem strange, but 
handlers can do all manner of strange things!).
- If successive handlers raise multiple exceptions, the last one determines the 
code.
- If the program is exiting with any code, and an exception other than 
SystemExit is raised, then we should return the code that would result from 
raising that exception in normal execution (usually 1).

I expect this last case to be most contentious, because it changes behavior for 
both python2 and python3. However I think it is desirable because it gives the 
handlers precise capabilities (and responsibilities) regarding process status. 
The point of atexit is to allow modules to execute code in a deferred manner; 
the design already specifies a 'last exception wins' policy, and the problem is 
that we are unnecessarily suppressing the exit code that would result from that 
last exception.

----------
nosy: +George.King

_______________________________________
Python tracker <rep...@bugs.python.org>
<http://bugs.python.org/issue27035>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to