What does `exit` keyword do in Python3 with Jupyter Notebook? - python

I am currently using Python3 in Jupyter Notebook and I just ran into a keyword exit. What does this keyword do ?
with open("some_file.txt") as f:
for lines in f:
print(lines)
exit

The exit lines in your loop do nothing. Why they do nothing is a bit more complicated than the usual reason exit would do nothing in Python, though.
Normally, exit on a line by its own wouldn't exit Python. At most, in interactive mode, it would print a message telling you how to quit Python (message implemented in _sitebuiltins.Quitter.__repr__):
>>> exit
Use exit() or Ctrl-D (i.e. EOF) to exit
IPython does something different. Among the many extra systems IPython has for interactive convenience is a system to autocall instances of a certain type, IPython.core.autocall.IPyAutocall. (This is similar to but distinct from the %autocall magic.)
In IPython, exit and quit are set to instances of IPython.core.autocall.ExitAutocall, a subclass of IPyAutocall. IPython recognizes objects of this type, so when a line containing just exit or quit is executed, IPython actually exits.
In [1]: exit
[IPython dies here]
A Jupyter notebook's IPython kernel has exit and quit set to instances of the very closely related IPython.core.autocall.ZMQExitAutocall, which has some extra functionality to support a keep_kernel argument, but is otherwise the same.
This functionality only triggers when a line referring to the autocallable object is the entire content of the cell, though. Inside a loop, the autocall functionality doesn't trigger, so we're back to nothing happening.
In fact, even less happens than what would happen in normal interactive mode - in a normal, non-IPython interactive session, this loop would print the "Use exit()..." message on each iteration, due to differences in how IPython and the regular interactive mode handle expression auto-printing.

When exit (sic, with no parentheses) is used in iPython in a loop or a branch of a conditional statement, it is doing nothing because it is simply a reference to an instance of IPython.core.autocall.ExitAutocall:
for i in range(10):
exit
print(i)
# 9
if i==9:
exit
print(exit)
# <IPython.core.autocall.ExitAutocall object at 0x7f76ad78a4a8>
It does not restart the kernel:
print(i)
# 9
However, when used on the command line alone, it is treated as a kind of magic (though without a %) and terminates the kernel.

On my simple test,
Cell 1
a = 3
Cell 2
exit
cell 3
print(a)
resulted in
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-1-3f786850e387> in <module>
----> 1 a
NameError: name 'a' is not defined
exit just kills the kernel that the notebook is relying on for execution.
Interestingly enough however, There seems to be a parameter you can pass to modify that behaviour as well.
Test 2:
Cell 1
a = 3
Cell 2
exit(keep_kernel=True)
cell 3
print(a)
resulted in
3
EDIT: And looks like #user2357112's answer fills in the missing pieces.
EDIT2: Actually, it seems to be an instance of IPython.core.autocall.ZMQExitAutocall
class IPython.core.autocall.ZMQExitAutocall(ip=None)
Bases: IPython.core.autocall.ExitAutocall
Exit IPython. Autocallable, so it needn’t be explicitly called.
Parameters: keep_kernel (bool) – If True, leave the kernel alive. Otherwise, tell the kernel to exit too (default).

Related

How to run Anki-Qt script without requiring a breakpoint?

If I run the toy script below as shown:
import sys
sys.path.append('/usr/share/anki')
import aqt
app = aqt._run(argv=['/usr/bin/anki', '--profile=test'], exec=False)
# breakpoint()
print(repr(aqt.mw.col))
aqt.mw.cleanupAndExit()
...I get the following output, which is not right:
$ python3 /tmp/ankiq.py
None
If I uncomment the commented statement, however, and re-run the modified script, I get the correct output (eventually):
$ python3 /tmp/ankiq.py
> /tmp/ankiq.py(8)<module>()
-> print(repr(aqt.mw.col))
(Pdb) c
<anki.collection._Collection object at 0x7f32ec1417b8>
I would like to avoid the need for the breakpoint() statement (and for having to hit c whenever I want to run such code).
My guess is that, when the breakpoint() statement is commented out, the print statement happens before aqt.mw has been fully initialized.
(I tried replacing the breakpoint() statement with time.sleep(1), but when I run the script with this modification, it hangs before ever printing any output.)
Q: How can I modify the toy script above so that, by the time the print statement executes, aqt.mw.col has its correct value?
It seems that calling aqt._run(*args, exec=False) returns a QApplication object - but without starting its event-loop. To manually process pending events, you could therefore try calling app.processEvents().
From the comments, it appears the exact solution is as follows:
while aqt.mw.col is None:
app.processEvents()

quit() works differently in Python-3.x and IPython

The built-in function quit() behaves differently in Python-3.x and IPython 3. The following code prints Hello if executed in IPython, but does not print anything in Python:
quit()
print("Hello")
What is the purpose of quit() in IPython? What was the reason for changing its behavior?
It looks like IPython's quit/exit "function" simplifies to just setting a flag to say "you should exit when this is next checked". It doesn't raise SystemExit itself, so it's presumably dependent on an intermittent check that, if you queue both commands at once, isn't performed until the second command finishes.
You can check it yourself at the IPython prompt, first run quit?? to see that it's a callable class whose __call__ delegates to self._ip.ask_exit(). Next, run quit._ip.ask_exit?? and you'll see that ask_exit just sets a flag, self.exit_now = True (and it's a plain attribute if you check it, not a property with hidden code execution).
You're welcome to track down where IPython is checking that; I'm guessing it's done after any given line or cell of IPython completes.
Fundamentally, the difference is that quit in IPython has never been the same as quit in regular Python's interactive interpeter; quit/exit as a built-in is intended to be replaced for alternate interactive interpreters, and needn't behave exactly the same. If you want a consistent exit behavior, import sys and run sys.exit(), which is also the correct way to exit early inside a script, and is not intended as a hook for the interactive prompt.

LLDB: silently continue after python script is done executing

I've written a python script that I am attaching to a watchpoint in LLDB, such as:
def wpCallback(frame, wp, internal_dict):
...
and I am attaching the callback with:
watchpoint command add -F commands.wpCallback watchpointID
I would like execution of the program to immediately resume after wpCallback is finished. Currently, execution halts as the watchpoint normally would. Is it possible to silently continue after the function is done? Based on this answer it seems like you can do something like this in GDB:
break foo if x>0
commands
silent
do something...
cont
end
You should be able to call SBProcess.Continue() on your process in your watchpoint callback. I.e. if you called the first argument to your callback frame do:
frame.thread.process.Continue()
That works for breakpoints, but seems to be broken for watchpoints in current TOT lldb. It looks like it disables the watchpoint. That's:
https://llvm.org/bugs/show_bug.cgi?id=28055

Python IDLE shell keystroke to signal end of statement and return to prompt

In interactive mode, is there a way to signal the end of a statement (such as a class definition) and return to the prompt in order to then instantiate objects?
I've gone through simple exercises - calculations, ifs, loops, while statements. And the interpreter "gets" that the statement is complete.
It seems a simple question, but I've had no luck searching either in stackoverflow or the web generally.
(More generally, are there limitations re: what you can do in interactive mode vs via a script. Or should one be able, in theory, to experiment with all aspects of the language?) Thanks.
You can type anything in the IDLE console. Function and class definitions, like loops, are multi-line statements. A blank line at the IDLE prompt (also at the regular commandline python prompt) terminates a statement.
The main differences between scripts and the python prompt are:
a) In a script, a function or class definition, a loop, or even the inside of a pair of parentheses can contain empty lines; on the IDLE console, a blank line will terminate and execute a statement. E.g., You can't successfully type the following at the IDLE prompt:
def something():
x =0
return x
b) The IDLE console will print the value of any expression evaluated at the command prompt. In a script, you need to use print or the value will disappear.
>>> 2 + 2
4
Note for completeness: A blank line will not terminate a syntactically incomplete statement (e.g., unmatched parentheses). But never mind that.

How to silence "sys.excepthook is missing" error?

NB: I have not attempted to reproduce the problem described below under Windows, or with versions of Python other than 2.7.3.
The most reliable way to elicit the problem in question is to pipe the output of the following test script through : (under bash):
try:
for n in range(20):
print n
except:
pass
I.e.:
% python testscript.py | :
close failed in file object destructor:
sys.excepthook is missing
lost sys.stderr
My question is:
How can I modify the test script above to avoid the error message when the script is run as shown (under Unix/bash)?
(As the test script shows, the error cannot be trapped with a try-except.)
The example above is, admittedly, highly artificial, but I'm running into the same problem sometimes when the output of a script of mine is piped through some 3rd party software.
The error message is certainly harmless, but it is disconcerting to end-users, so I would like to silence it.
EDIT: The following script, which differs from the original one above only in that it redefines sys.excepthook, behaves exactly like the one given above.
import sys
STDERR = sys.stderr
def excepthook(*args):
print >> STDERR, 'caught'
print >> STDERR, args
sys.excepthook = excepthook
try:
for n in range(20):
print n
except:
pass
How can I modify the test script above to avoid the error message when the script is run as shown (under Unix/bash)?
You will need to prevent the script from writing anything to standard output. That means removing any print statements and any use of sys.stdout.write, as well as any code that calls those.
The reason this is happening is that you're piping a nonzero amount of output from your Python script to something which never reads from standard input. This is not unique to the : command; you can get the same result by piping to any command which doesn't read standard input, such as
python testscript.py | cd .
Or for a simpler example, consider a script printer.py containing nothing more than
print 'abcde'
Then
python printer.py | python printer.py
will produce the same error.
When you pipe the output of one program into another, the output produced by the writing program gets backed up in a buffer, and waits for the reading program to request that data from the buffer. As long as the buffer is nonempty, any attempt to close the writing file object is supposed to fail with an error. This is the root cause of the messages you're seeing.
The specific code that triggers the error is in the C language implementation of Python, which explains why you can't catch it with a try/except block: it runs after the contents of your script has finished processing. Basically, while Python is shutting itself down, it attempts to close stdout, but that fails because there is still buffered output waiting to be read. So Python tries to report this error as it would normally, but sys.excepthook has already been removed as part of the finalization procedure, so that fails. Python then tries to print a message to sys.stderr, but that has already been deallocated so again, it fails. The reason you see the messages on the screen is that the Python code does contain a contingency fprintf to write out some output to the file pointer directly, even if Python's output object doesn't exist.
Technical details
For those interested in the details of this procedure, let's take a look at the Python interpreter's shutdown sequence, which is implemented in the Py_Finalize function of pythonrun.c.
After invoking exit hooks and shutting down threads, the finalization code calls PyImport_Cleanup to finalize and deallocate all imported modules. The next-to-last task performed by this function is removing the sys module, which mainly consists of calling _PyModule_Clear to clear all the entries in the module's dictionary - including, in particular, the standard stream objects (the Python objects) such as stdout and stderr.
When a value is removed from a dictionary or replaced by a new value, its reference count is decremented using the Py_DECREF macro. Objects whose reference count reaches zero become eligible for deallocation. Since the sys module holds the last remaining references to the standard stream objects, when those references are unset by _PyModule_Clear, they are then ready to be deallocated.1
Deallocation of a Python file object is accomplished by the file_dealloc function in fileobject.c. This first invokes the Python file object's close method using the aptly-named close_the_file function:
ret = close_the_file(f);
For a standard file object, close_the_file(f) delegates to the C fclose function, which sets an error condition if there is still data to be written to the file pointer. file_dealloc then checks for that error condition and prints the first message you see:
if (!ret) {
PySys_WriteStderr("close failed in file object destructor:\n");
PyErr_Print();
}
else {
Py_DECREF(ret);
}
After printing that message, Python then attempts to display the exception using PyErr_Print. That delegates to PyErr_PrintEx, and as part of its functionality, PyErr_PrintEx attempts to access the Python exception printer from sys.excepthook.
hook = PySys_GetObject("excepthook");
This would be fine if done in the normal course of a Python program, but in this situation, sys.excepthook has already been cleared.2 Python checks for this error condition and prints the second message as a notification.
if (hook && hook != Py_None) {
...
} else {
PySys_WriteStderr("sys.excepthook is missing\n");
PyErr_Display(exception, v, tb);
}
After notifying us about the missing excepthook, Python then falls back to printing the exception info using PyErr_Display, which is the default method for displaying a stack trace. The very first thing this function does is try to access sys.stderr.
PyObject *f = PySys_GetObject("stderr");
In this case, that doesn't work because sys.stderr has already been cleared and is inaccessible.3 So the code invokes fprintf directly to send the third message to the C standard error stream.
if (f == NULL || f == Py_None)
fprintf(stderr, "lost sys.stderr\n");
Interestingly, the behavior is a little different in Python 3.4+ because the finalization procedure now explicitly flushes the standard output and error streams before builtin modules are cleared. This way, if you have data waiting to be written, you get an error that explicitly signals that condition, rather than an "accidental" failure in the normal finalization procedure. Also, if you run
python printer.py | python printer.py
using Python 3.4 (after putting parentheses on the print statement of course), you don't get any error at all. I suppose the second invocation of Python may be consuming standard input for some reason, but that's a whole separate issue.
1Actually, that's a lie. Python's import mechanism caches a copy of each imported module's dictionary, which is not released until _PyImport_Fini runs, later in the implementation of Py_Finalize, and that's when the last references to the standard stream objects disappear. Once the reference count reaches zero, Py_DECREF deallocates the objects immediately. But all that matters for the main answer is that the references are removed from the sys module's dictionary and then deallocated sometime later.
2Again, this is because the sys module's dictionary is cleared completely before anything is really deallocated, thanks to the attribute caching mechanism. You can run Python with the -vv option to see all the module's attributes being unset before you get the error message about closing the file pointer.
3This particular piece of behavior is the only part that doesn't make sense unless you know about the attribute caching mechanism mentioned in previous footnotes.
I ran into this sort of issue myself today and went looking for an answer. I think a simple workaround here is to ensure you flush stdio first, so python blocks instead of failing during script shutdown. For example:
--- a/testscript.py
+++ b/testscript.py
## -9,5 +9,6 ## sys.excepthook = excepthook
try:
for n in range(20):
print n
+ sys.stdout.flush()
except:
pass
Then with this script nothing happens, as the exception (IOError: [Errno 32] Broken pipe) is suppressed by the try...except.
$ python testscript.py | :
$
In your program throws an exception that can not be caught using try/except block. To catch him, override function sys.excepthook:
import sys
sys.excepthook = lambda *args: None
From documentation:
sys.excepthook(type, value, traceback)
When an exception is raised and uncaught, the interpreter calls
sys.excepthook with three arguments, the exception class, exception
instance, and a traceback object. In an interactive session this
happens just before control is returned to the prompt; in a Python
program this happens just before the program exits. The handling of
such top-level exceptions can be customized by assigning another
three-argument function to sys.excepthook.
Illustrative example:
import sys
import logging
def log_uncaught_exceptions(exception_type, exception, tb):
logging.critical(''.join(traceback.format_tb(tb)))
logging.critical('{0}: {1}'.format(exception_type, exception))
sys.excepthook = log_uncaught_exceptions
I realize that this is an old question, but I found it in a Google search for the error. In my case it was a coding error. One of my last statements was:
print "Good Bye"
The solution was simply fixing the syntax to:
print ("Good Bye")
[Raspberry Pi Zero, Python 2.7.9]

Categories

Resources