I have a Python script, and I want to execute it up to a certain point, then stop, and keep the interpreter open, so I can see the variables it defines, etc.
I know I could generate an exception, or I could invoke the debugger by running pdb.set_trace(), then stop the debugger, which is what I currently use.
...but is there a command that will just stop the script, as if it had simply reached its end? This would be equivalent to commenting the entire rest of the script (but I would not like doing that), or putting an early return statement in a function.
It seems as if something like this has to exist but I have not found it so far.
Edit: Some more details of my usecase
I'm normally using the regular Python consoles in Spyder. IPython seems like a good thing but ( at least for the version I'm currently on, 2.2.5) some of the normal console's features don't work well in IPython (introspection, auto-completion).
More often than not, my code generates matplotlib figures. In debug mode, those cannot be updated (to my knowledge), which is why I need to get completely out of the script, but not the interpreter).
Another limit of the debugger is that I can't execute loops in it: you can copy/paste the code for a loop into the regular console and have it execute, but that won't work in the debugger (at least in my Spyder version).
If you invoke your program with python -i <script>, the interpreter will remain active after the script ends. raise SystemExit would be the easiest way to force it to end at an arbitrary point.
If you have ipython (highly, highly recommended), you can go to any point in your program and add the following lines
import IPython
IPython.embed()
Once your program reaches that point, the embed command will open up a new IPython shell within that context.
I really like to do that for things where I don't want to go the full pdb route.
If you are using the Python Shell, just press CTRL + C to throw a KeyboardInterrupt. You can then check out the state of the program at the time the exception was throw.
x = 0
while True:
x += 1
Running the script...
Python 2.7.6 (default, Nov 10 2013, 19:24:18) [MSC v.1500 32 bit (Intel)] on win32
Type "copyright", "credits" or "license()" for more information.
>>> ================================ RESTART ================================
Traceback (most recent call last):
File "C:/Python27/test.py", line 2, in
while True:
KeyboardInterrupt
>>> x
15822387
Related
I have a data processing pipeline setup that I want to debug.
The pipeline consists of a bash script that calls a python script.
I usually use iPython's embed() function for debugging. However, when calling the python script from the bash file, the embed() function is called but immediately exited, without me being able to interfere. When running the same python program directly from the command line I don't observe this kind of behavior. Is this intended behavior or am I doing something wrong?
Python 2.7.6 (default, Oct 26 2016, 20:30:19)
Type "copyright", "credits" or "license" for more information.
IPython 2.4.1 -- An enhanced Interactive Python.
? -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help -> Python's own help system.
object? -> Details about 'object', use 'object??' for extra details.
In [1]:
Do you really want to exit ([y]/n)?
'follow up code prints here'
I can replicate the problem like this:
# test.py
import IPython
import sys
print(sys.stdin.read())
IPython.embed()
# session
❯ echo 'foo' | python test.py
foo
Python 3.6.8 (default, Oct 7 2019, 12:59:55)
Type 'copyright', 'credits' or 'license' for more information
IPython 7.10.1 -- An enhanced Interactive Python. Type '?' for help.
In [1]: Do you really want to exit ([y]/n)?
❯ # I didn't quit on purpose, it happened automatically
STDIN is not a TTY, so I'm thinking that IPython is worried that the inbound text (via the pipe) won't be a user typing. It doesn't want foo (from my example above) to spew into the IPython shell and do something unexpected.
You can work around this by getting your terminal id via the tty command, and redirecting stdin to the calling terminal after it has finished reading from the pipe, something like this:
with open('/dev/pts/16') as user_tty:
sys.stdin=user_tty
IPython.embed()
For more on ttys, see this post. Note also that if you put the wrong tty in there, input from some other terminal will control IPython.
I'm not sure if it's possible for IPython to know what the calling tty would have been, had it not been overwritten by bash to be the output-side of the pipe.
Edit: Here's my workaround put more simply: How do I debug a script that uses stdin with ipython?
I ran some experiments to see the behaviour. I noticed that IPython shows the console if any of the ancestor process is terminal.
Following are the files in /tmp directory:
x.py
import IPython
IPython.embed()
call.sh
/usr/bin/python /tmp/x.py
call2.sh
/tmp/call.sh
Experiment 1
Running python x.py does open the IPython shell and waits.
Experiment 2
Running bash call.sh also opens the IPython shell and waits.
Experiment 3
Running bash call2.sh also opens the IPython shell and waits.
As you can see, it does not matter how deep is your IPython.embed call is. It always starts the interactive console and waits.
Lets try if it also works when we fork a new process.
fork.sh
/usr/bin/python /tmp/x.py &
Experiment 4
In this case, IPython shell started but immediately exited. Notice the & at the end. It starts a different process. IPython was not able to access the terminal in this case and hence exited gracefully.
I don't know about the meaning of calculator mode in Python, and I've put the portion of documentation below.
If you quit from the Python interpreter and enter it again, the definitions you have made (functions and variables) are lost. Therefore, if you want to write a somewhat longer program, you are better off using a text editor to prepare the input for the interpreter and running it with that file as input instead. This is known as creating a script. As your program gets longer, you may want to split it into several files for easier maintenance. You may also want to use a handy function that you’ve written in several programs without copying its definition into each program.
To support this, Python has a way to put definitions in a file and use them in a script or in an interactive instance of the interpreter. Such a file is called a module; definitions from a module can be imported into other modules or into the main module (the collection of variables that you have access to in a script executed at the top level and in calculator mode).
(Emphasis mine)
Here's the original document.
Interactive mode and Calculator mode are the same thing. This is a mode that comes with Python. If you have installed Python then you have also installed something called the Python Shell.
There are two ways you can access the Python Shell:
Typing python or python[version-number] in your command
prompt/terminal window:
Assuming that you have python in your PATH variable, you can access
the Python Shell by simply typing python or python[version-number]
in your command prompt/terminal window.
Running the Python Shell in the Python IDLE(Integrated Development Environment) GUI:
To run the Python Shell in the Python IDLE GUI, you can type(again i'm assuming that the path to your python installation folder, is in your PATH variable), just type idle into your command prompt\terminal window and this should start the Python Shell in the Python IDLE GUI.
Of course the exact text for the Python Shell heading will vary between OS's, but all of them look very similar. Here is an example of what the heading appears like on my Mac:
Python 2.7.5 (default, Mar 9 2014, 22:15:05)
[GCC 4.2.1 Compatible Apple LLVM 5.0 (clang-500.0.68)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>>
As you can tell from the text above, a newline in the Python Shell is denoted by three caret symbols: >>>. For each newline three new carets are printed. Using Python Shell is different from typing a script because the script is predefined and the shell is written line-by-line.
Here is an example to illustrate my point further:
>>> xyz = 100
>>> for i in range(1, 10):
... xyz += i
... print(xyz)
...
101
103
106
110
115
121
128
136
145
As you can tell from the above program, indention is noted by three dots: ..., and the only time the Python Shell shows only one line at a time unless it is 'echoing' back what you typed in.
Why is it called interactive?
One of the main reason it's called interactive is that to display variable values or run the module in general you don't have to explicitly invoke the Python interpreter. Take the example below:
>>> name = "some name"
>>> print(name)
some name
>>> name
'some name'
As displayed above, you can access the values of a variable without needing to call print on the variable. This can be very useful when debugging or trying to understand your code.
The Python Shell is not really a practical way to write long/complex programs. A better choice would be to use the Python IDLE built-in script editor or another text-editor or IDE.
I previously thought that was the issue with IPython, but today I tested again, here is what I did:
Run emacs -Q in cmd window
Open a .py file
M-x, then run python-shell-switch-to-shell, RET, and RET. Then I have the Python shell ready
I in put the following code then:
Python 2.7.3 (default, Apr 10 2012, 23:31:26) [MSC v.1500 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import matplotlib.pyplot as plt
>>> plt.ion()
>>> plt.plot([1,2,3])
[<matplotlib.lines.Line2D object at 0x03068610>]
>>>
Actually after this, no figure shows up, and the shell is frozen, e.g., when I input:
>>> print("hello")
nothing happened...I haven't tested other plotting tools but matplotlib. I don't know if it is a bug. I've searched for a while, here and though Google, but no luck. My system is: Emacs 24.3 32 bit for Windows, under Windows 7. If others can duplicate same issue as here, I will report this as a bug.
I used IPython as the Python shell by:
C:/Python27/python.exe -i C:/Python27/Scripts/ipython-script.py --pylab
Then, I input figure(); plot([1,2,3]), as expected, the figure popup and freezes. Then I did: C-c C-d which runs comint-send-eof, and the figure actually get updated! But my IPython shell session is also terminated with the following message:
In [6]:
Do you really want to exit ([y]/n)?
Traceback (most recent call last):
File "C:/Python27/Scripts/ipython-script.py", line 9, in <module>
load_entry_point('ipython==0.13.1', 'console_scripts', 'ipython')()
SystemExit
If you suspect this is an IPython bug, please report it at:
https://github.com/ipython/ipython/issues
or send an email to the mailing list at ipython-dev#scipy.org
You can print a more detailed traceback right now with "%tb", or use "%debug"
to interactively debug it.
Extra-detailed tracebacks for bug-reporting purposes can be enabled via:
%config Application.verbose_crash=True
Any helpful clue here?!
one solution is:
(setq python-shell-interpreter "C:\\YourPython3Dist\\python.exe"
python-shell-interpreter-args "-i C:\\YourPython3Dist\\Scripts\\ipython3-script.py console --pylab=qt")
The Argument console in the call of ipython-script.py is the important one!
In Python 3 with qt backend it works for me. I don't know how it works with py 2.7. (should be no problem if these arguments are supported for ipytho-script.py)
I think it would take sometime until the problem is fixed. Until some Windows user actually debugs python.el.
Until then, why not try Emacs IPython Notebook? It is a better IPython binding for Emacs. You don't need to use the notebook part. You can think it as a replacement for python shell in python.el. (disclaimer: I am the author)
Steps to repeat:
gfixler#gigabox:/autodesk/maya2012-x64/bin$ ./mayapy
Python 2.6.4 (r264:75706, Nov 3 2009, 14:09:42)
[GCC 4.1.2 20070626 (Red Hat 4.1.2-14)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import maya.standalone
>>> maya.standalone.initialize() # this hangs until I ^C
^CResult: untitled
Fatal Error. Attempting to save in /usr/tmp/gfixler.20120908.1953.ma
gfixler#gigabox:/autodesk/maya2012-x64/bin$
I think it's a library path issue of some sort, but I don't know how to find out.
I figured out the issue.
In trying to solve this I learned about python -m trace --trace script.py, and also a bit about pdb, a Python debugger. I tied these together by calling a trace on a file containing this:
pdb.run(maya.standalone.initialize(), globals(), locals())
I don't know if that was using either incorrectly, or overkill (trace alone was hanging after printing out a tremendous amount of information, which redirected into a file yielded nothing useful), but after hitting n (next) and s (step) followed by hundreds of enter keypresses in pdb got me nowhere, on a whim I typed help and got a help menu. I decided to try the listed EOF command, and it ran until it crashed with a message about being unable to load the commandPort. I remembered I set that value to autoload (Preferences window, Applications section) last week while fighting with nose, and apparently that was causing it to hang on a bad entry (":12345"), with absolutely no messages about anything. I opened UI Maya, deleted that preference, and now mayapy initializes fine. Phwew.
this is the first time I have used Python.
I downloaded the file ActivePython-2.7.1.4-win32-x86
and installed it on my computer; I'm using Win7.
So when I tried to run a python program, it appears and disappears very quickly. I don't have enough time to see anything on the screen. I just downloaded the file and double-cliked on it.
How do I launch this file? I know that it is a long file for a first Python tutorial.
Add the line
input()
to the end of the program, with the correct indentation. The issue is that after the data is printed to the console the program finishes, so the console goes away. input tells the program to wait for input, so the console won't be closed when it finishes printing.
I hope you're not using that program to learn Python; it's pretty complicated!
go to Start > All programs > Accessories and click on Command Prompt. then drag the python file from the explorer view into this command line and press Enter...
now you can watch the output of the script execution !
run it from a command prompt:
> python myscript.py
You can also start only the python interpreter from the command prompt (or by running python.exe) and then try some commands:
> python
Python 2.6.6 (r266:84297, Aug 24 2010, 18:46:32) [MSC v.1500 32 bit (Intel)] on win32
Type "copyright", "credits" or "license()" for more information.
>>>
>>> a = 2
>>> b = 7
>>> print a+b
9
>>>
Or run it from a batch file:
myprog.py
pause
Has the advantage that you can specify a different version of Python too.
Just a bit more on this.
You have a script myscript.py in a folder C:\myscripts. This is how to set up Windows 7 so that you can type > myscript into a CMD window and the script will run.
1) Set your PATH variable to include the Python Interpreter.
Control Panel > System and Security > System > Advanced Settings > Environment Variables. You can set either the System Variables or the User Variables. Scroll down till you find PATH, select it, click Edit.The Path appears selected in a new dialog. I always copy it into Notepad to edit it though all you need do is add ;C:\Python27 to the end of the list. Save this.
2) Set your PATH variable to include C:\myscripts
3) Set your PATHEXT variable to include ;.PY. (This is the bit that saves you from typing myscript.py)
This may now just work. Try opening a command window and typing myscript
But it may not. Windows can still mess you about. I had installed and then uninstalled a Python package and when I typed myscript Windows opened a box asking me which program to use. I browsed for C:\python27\python.exe and clicked that. Windows opened another command window ran the script and closed it before I could see what my script had done! To fix this when Windows opens its dialog select your Python and click the "Always do this" checkbox at the bottom. Then it doesn't open and close another window and things work as they should. Or they did for me.
Added: Above does not say how to pass arguments to your script. For this see answer Windows fails to pass arguments to python script