Franck Dernoncourt
Franck Dernoncourt

Reputation: 83377

Configuring the Python interpreter so that it stops executing a list of commands whenever one command fails

I sometimes paste a list of commands to be executed in the Python interpreter (Interactive Mode (mirror)). By default, if one command fails (i.e., raises an error), the Python interpreter indicates the command has failed, then executes the subsequent commands.

Is there any way to configure the Python interpreter (Interactive Mode) so that it stops executing a list of commands whenever one command fails?


Answering the comments:

Upvotes: 2

Views: 84

Answers (3)

Andrew Guy
Andrew Guy

Reputation: 9978

Borrowing heavily from @alfasin's answer, you can extend the InteractiveConsole class.

To keep the interactive session running, but ignore the rest of the pasted commands, you can discard the input for a short while (I've used 1 second) after an exception. This means that the rest of the pasted commands are ignored, while leaving you with the session still running.

from code import InteractiveConsole
import sys
import time

WAIT_TIME = 1

class Shell(InteractiveConsole):
    def __init__(self):
        self.stdout = sys.stdout
        InteractiveConsole.__init__(self)
        return
    def runcode(self, code):        
        try:
            exec(code, self.locals)
        except SystemExit:
            raise
        except:
            self.showtraceback()
            t_end = time.time() + WAIT_TIME
            while time.time() < t_end:
                _ = self.raw_input()  # Extra pasted commands are discarded


if __name__ == '__main__':
     sh = Shell()
     sh.interact()

Note that the extra commands are still printed to the terminal, but aren't actually run.

Upvotes: 1

Nir Alfasi
Nir Alfasi

Reputation: 53535

You can extend InteractiveConsole and create your own shell which bails out on error. You can even run it from within interactive-mode :)

Here's a small example:

from code import InteractiveConsole
import sys


class Shell(InteractiveConsole):
    def __init__(self):
        self.stdout = sys.stdout
        InteractiveConsole.__init__(self)
        return

    def runcode(self, code):        
        try:
            exec code in self.locals
        except:
            self.showtraceback()
            sys.exit(1)  # <-- this is the secret sauce!


if __name__ == '__main__':
     sh = Shell()
     sh.interact()

OUTPUT

>>> sh = Shell()
>>> sh.interact()
Python 2.7.6 (default, Jan 26 2016, 22:37:40)
[GCC 4.2.1 Compatible Apple LLVM 7.0.2 (clang-700.1.81)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
(Shell)
>>> 1
1
>>> 1+1
2
>>> 1/0
Traceback (most recent call last):
  File "<console>", line 1, in <module>
ZeroDivisionError: integer division or modulo by zero
alfasi:~/Desktop >

Upvotes: 2

cs95
cs95

Reputation: 402872

I'm not sure how to fix this on a standard Python REPL, but you can definitely achieve this with IPython.

In IPython, when you paste code, it is treated as a single code block, rather than a bunch of individual statements.

For example, open an IPython interactive session on your terminal and paste this:

x = [1]
y = [1 for _ in range(100)]] # <------ SyntaxError
z = x + y

This is what it looks like when pasted:

In [136]: x = [1]
     ...: y = [1 for _ in range(100)]]
     ...: z = x + y

Now hit enter:

  File "<ipython-input-136-20c7b020310a>", line 2
    y = [1 for _ in range(100)]]
                               ^
SyntaxError: invalid syntax

In contrast, on the standard REPL interpreter:

>>> x = [1]
>>> y = [1 for _ in range(100)]]
  File "<stdin>", line 1
    y = [1 for _ in range(100)]]
                               ^
SyntaxError: invalid syntax
>>> z = x + y
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'y' is not defined

Upvotes: 1

Related Questions