[Idle-dev] Fwd: atexit handler in IDLE?

Terry Reedy tjreedy at udel.edu
Thu Jan 17 16:22:50 CET 2013


On 1/17/2013 1:44 AM, Roger Serwy wrote:
> IDLE implicitly runs a script

from the editor window

 > as if you specified "-i" when using
> regular python from the command line. Perhaps this behavior needs to be
> documented.

I agree, as part of documenting the behavior itself. It should be 
obvious to anyone who understands -i. That is why one can interactively 
poke around at the result of running the script and one reason I use 
IDLE to develop code. But many (most?) have never used -i from the 
command line and have not read the command line documentation carefully.

That said, I wonder: does your proposed patch makes the IDLE behavior 
more, or less, like that of "python xxx -i"? If a file, such Steve's, is 
run like so, from the command line with -i, does atexit processing 
automatically happen before switching to interactive mode, or not? 
Perhaps one of you can test. If yes, then IDLE should do the same before 
it switches and prints the interactive '>>>' prompt. If not, then I 
think IDLE should not either.

In the same circumstance, does ending the file with 'raise SystemExit' 
make any difference. In particular, if the answer above is No, is that 
answer changed? Does explicit SystemExit get printed as IDLE does now, 
or does it abort -i mode?

As with the interpreter, atexit processing should not happen when 
running a statement entered in response to the prompt and a patch should 
not change this.

My general idea is that we first match normal atexit behavior and be 
explicit about any deviations we decide on.

> For what it's worth, this would make the exitfuncs run on the 3.x series:

Only if there is no exception, even SystemExit, whereas at least the 
latter and probably any uncaught exception *should* trigger atexit. The 
doc says

"Note: The functions registered via this module are not called when the 
program is killed by a signal not handled by Python, when a Python fatal 
internal error is detected, or when os._exit() is called."

Termination by an exception that is not caught in user code (which *is* 
caught by the unwritten try: except: that prints a traceback) seems not 
included in the above (unless they internally trigger os._exit, but I am 
pretty sure not). In any case adding 1/0 to Steve's file and running 
from a command line would tell. In any case:

"At normal program termination (for instance, if sys.exit() is called or 
the main module’s execution completes), all functions registered are 
called ..."

I do not complete understand the following, or if we can imitate the 
behavior it specifies with the undocumented ._run_exitfuncs.

"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."

> diff -r be8e6b81284e Lib/idlelib/run.py

This is current 3.4a0 (default branch)

> --- a/Lib/idlelib/run.py        Wed Jan 09 19:00:26 2013 +0100
> +++ b/Lib/idlelib/run.py        Thu Jan 17 00:41:22 2013 -0600
> @@ -381,6 +381,8 @@
>               if jit:
>                   self.rpchandler.interp.open_remote_stack_viewer()
>           else:
> +            import atexit

I assume below that actual patch does import at top of file.

> +            atexit._run_exitfuncs()

As long as this works, it is a nice alternative to my idea of forcing 
atexit by actually exiting and restarting user process. The question is 
where and when to do it. See questions above and below.

>               flush_stdout()

Below is the full code of the class Executive(object) method, with 
comments and possible changes, and a question.

     def runcode(self, code):
         global interruptable
         try:
             self.usr_exc_info = None
             interruptable = True
             try:
                 exec(code, self.locals)
             finally:
                 interruptable = False
-         except:

#This bare except should be changed to an explicit 'except 
BaseException' (unless we decide that is wrong ;-) or rather 'except 
BaseException as e' (see below). The code comment below about even 
catching SystemExit, which is a BaseException, but not an Exception, 
makes the intention clear.

+         except BaseException as e:
             self.usr_exc_info = sys.exc_info()
             if quitting:
                 exit()

# quitting is global set False initially and True at 277, 347, 353.

+           atexit._run_exitfuncs()

# perhaps this should be conditioned on isinstance(e, SystemExit)
# but as noted above, I think not

             # even print a user code SystemExit exception, continue
             print_exception()
             jit = self.rpchandler.console.getvar(
                         "<<toggle-jit-stack-viewer>>")
             if jit:
                 self.rpchandler.interp.open_remote_stack_viewer()
         else:
+           atexit._run_exitfuncs()
             flush_stdout()

# The else block only runs if there is no exception in the exec statement.

I am guessing that Executive is instantiated in the user process and 
that runcode runs usercode in the user process. Is runcode only used for 
running scripts? Or is it also used to run interactive statements? If 
the latter, does or could runcode know which, so atexit can be run in 
the former case but not the latter? In particular, registering an atexit 
function should not cause its immediate execution.

-- 
Terry Jan Reedy




More information about the IDLE-dev mailing list