20

I have a python script that I like to run with python -i script.py, which runs the script and then enters interactive mode so that I can play around with the results.

Is it possible to have the script itself invoke this option, such that I can just run python script.py and the script will enter interactive mode after running?

Of course, I can simply add the -i, or if that is too much effort, I can write a shell script to invoke this.

Matthew Moisen
  • 16,701
  • 27
  • 128
  • 231
  • 5
    Unrequested Public Service Announcement: If you use 'python -i' and like tab-completion, you owe it to yourself to check out [iPython](https://en.wikipedia.org/wiki/IPython) (Fan, no affiliation.) – JS. Aug 26 '16 at 00:04
  • I usually use `import IPython; IPython.embed()` if I want to play around with the state of my application. You might find it useful. – Blender Aug 26 '16 at 01:28
  • 1
    @Blender why not add that to the answers? Also, OP I think the edit is unnecessary, if a user sees this question, he'll scroll down to see the answers. – Dimitris Fasarakis Hilliard Aug 26 '16 at 02:01
  • @Jim: It's not that much different from `code.interact(local=locals())`, the interpreter is just prettier. You still have to add code to the end of your script to embed it. – Blender Aug 26 '16 at 02:06
  • @Blender fair enough, I'll add it as an addendum to my answer in order to have it in a more visible place. – Dimitris Fasarakis Hilliard Aug 26 '16 at 02:39

5 Answers5

22

From within script.py, set the PYTHONINSPECT environment variable to any nonempty string. Python will recheck this environment variable at the end of the program and enter interactive mode.

import os
# This can be placed at top or bottom of the script, unlike code.interact
os.environ['PYTHONINSPECT'] = 'TRUE'  
Matthew Moisen
  • 16,701
  • 27
  • 128
  • 231
user2357112
  • 260,549
  • 28
  • 431
  • 505
8

In addition to all the above answers, you can run the script as simply ./script.py by making the file executable and setting the shebang line, e.g.

#!/usr/bin/python -i
this = "A really boring program"

If you want to use this with the env command in order to get the system default python, then you can try using a shebang like @donkopotamus suggested in the comments

#!/usr/bin/env PYTHONINSPECT=1 python

The success of this may depend on the version of env installed on your platform however.

Community
  • 1
  • 1
porglezomp
  • 1,333
  • 12
  • 24
  • This is great! Would you know how to get it working with `#!/usr/bin/env python -i` ? I'm getting a `/usr/bin/env: python -i: No such file or directory` – Matthew Moisen Aug 26 '16 at 01:28
  • @MatthewMoisen There are some platform-specific ways to do it nicely, and also some horrendous hacks that will potentially work in more places. For the full details see: http://stackoverflow.com/questions/3306518/cannot-pass-an-argument-to-python-with-usr-bin-env-python – porglezomp Aug 26 '16 at 01:30
  • `#!/usr/bin/env PYTHONINSPECT=1 python` – donkopotamus Aug 26 '16 at 02:18
  • @donkopotamus as the comments in the answer I linked mention, that seems to work on some platforms but not on others. – porglezomp Aug 26 '16 at 02:56
6

You could use an instance of code.InteractiveConsole to get this to work:

from code import InteractiveConsole
i = 20
d = 30
InteractiveConsole(locals=locals()).interact()

running this with python script.py will launch an interactive interpreter as the final statement and make the local names defined visible via locals=locals().

>>> i
20

Similarly, a convenience function named code.interact can be used:

from code import interact
i = 20
d = 30
interact(local=locals())

This creates the instance for you, with the only caveat that locals is named local instead.


In addition to this, as @Blender stated in the comments, you could also embed the IPython REPL by using:

import IPython
IPython.embed()

which has the added benefit of not requiring the namespace that has been populated in your script to be passed with locals.

Community
  • 1
  • 1
Dimitris Fasarakis Hilliard
  • 150,925
  • 31
  • 268
  • 253
3

I think you're looking for this?

import code
foo = 'bar'
print foo
code.interact(local=locals())
Matthew Moisen
  • 16,701
  • 27
  • 128
  • 231
Philip Rollins
  • 1,271
  • 8
  • 19
1

I would simply accompany the script with a shell script that invokes it.

exec python -i "$(dirname "$0")/script.py"
Random832
  • 37,415
  • 3
  • 44
  • 63