2

I'd like to call a separate non-child python program from a python script and have it run externally in a new shell instance. The original python script doesn't need to be aware of the instance it launches, it shouldn't block when the launched process is running and shouldn't care if it dies. This is what I have tried which returns no error but seems to do nothing...

import subprocess

python_path = '/usr/bin/python'

args = [python_path, '&']

p =  subprocess.Popen(args, shell=True)

What should I be doing differently

EDIT

The reason for doing this is I have an application with a built in version of python, I have written some python tools that should be run separately alongside this application but there is no assurance that the user will have python installed on their system outside the application with the builtin version I'm using. Because of this I can get the python binary path from the built in version programatically and I'd like to launch an external version of the built in python. This eliminates the need for the user to install python themselves. So in essence I need a simple way to call an external python script using my current running version of python programatically.

I don't need to catch any output into the original program, in fact once launched I'd like it to have nothing to do with the original program

EDIT 2

So it seems that my original question was very unclear so here are more details, I think I was trying to over simplify the question:

I'm running OSX but the code should also work on windows machines.

The main application that has a built in version of CPython is a compiled c++ application that ships with a python framework that it uses at runtime. You can launch the embedded version of this version of python by doing this in a Terminal window on OSX

/my_main_app/Contents/Frameworks/Python.framework/Versions/2.7/bin/python

From my main application I'd like to be able to run a command in the version of python embedded in the main app that launches an external copy of a python script using the above python version just like I would if I did the following command in a Terminal window. The new launched orphan process should have its own Terminal window so the user can interact with it.

/my_main_app/Contents/Frameworks/Python.framework/Versions/2.7/bin/python my_python_script

I would like the child python instance not to block the main application and I'd like it to have its own terminal window so the user can interact with it. The main application doesn't need to be aware of the child once its launched in any way. The only reason I would do this is to automate launching an external application using a Terminal for the user

Community
  • 1
  • 1
jonathan topf
  • 7,897
  • 17
  • 55
  • 85
  • What are you trying to do this for? If you explained that, it would be easier to explain how to do what you actually want. – abarnert Jan 15 '14 at 23:42
  • As a side note, the way to "get the python binary path from the built in version programatically" is just `sys.executable`. – abarnert Jan 15 '14 at 23:50
  • @abarnert I tried this actually but in this case its not so simple, as the python is embedded into another app this command returns the path to the 'main' process, which in this case isn't a python instance – jonathan topf Jan 15 '14 at 23:53
  • Your edit _still_ doesn't say that you want to run _a new terminal window_ and then run Python inside that window. Since that's the whole point of the problem, and it's not mentioned anywhere in the question, you need to edit it again. – abarnert Jan 15 '14 at 23:58
  • If you're actually running Python embedded in some other C program, there may not _be_ a Python executable, or it may not work normally. If you only care about one particular app that happens to have a usable normal Python executable alongside it, that's fine… – abarnert Jan 16 '14 at 00:02
  • Your latest edit _still_ says nothing about terminals or windows. "A new shell instance"—that is, a new copy of `bash` or `cmd` or whatever—is just like Python, a command-line program that runs in whatever stdin/out/err it's given. My first answer already shows you how to create a new shell instance. Besides, you don't actually have any need for a shell at all, as far as I can tell; you can run Python directly in a terminal window. (On Windows, cmd.exe happens to be both the shell and the terminal, because… Microsoft. But in general, they are entirely separate things.) – abarnert Jan 16 '14 at 00:04
  • If this isn't clear to you, see [What is the exact difference between a 'terminal', a 'shell', a 'tty' and a 'console'?](http://unix.stackexchange.com/questions/4126/what-is-the-exact-difference-between-a-terminal-a-shell-a-tty-and-a-con) and [Are terminal and shell the same?](http://askubuntu.com/questions/111144/are-terminal-and-shell-the-same), and maybe read a basic primer on using Unix. (None of this is specific to Unix, but Unix gets the terminology straight, and I'm guessing you're on a Unix-like system, even though you still haven't said.) – abarnert Jan 16 '14 at 00:06
  • one more edit... I hope that makes things clearer. I think I didn't quite understand the question I was asking – jonathan topf Jan 16 '14 at 00:35
  • See [Execute terminal command from python in new terminal window?](http://stackoverflow.com/questions/19308415/execute-terminal-command-from-python-in-new-terminal-window), and the various Related and Linked questions there. The hard part of all of those questions is the same as the hard part of yours, so the answers all apply, even if (at least I think…) your question isn't really a duplicate of any of them. – abarnert Jan 16 '14 at 00:59

4 Answers4

2

If you're trying to launch a new terminal window to run a new Python in (which isn't what your question asks for, but from a comment it sounds like it's what you actually want):

You can't. At least not in a general-purpose, cross-platform way.

Python is just a command-line program that runs with whatever stdin/stdout/stderr it's given. If those happen to be from a terminal, then it's running in a terminal. It doesn't know anything about the terminal beyond that.

If you need to do this for some specific platform and some specific terminal program—e.g., Terminal.app on OS X, iTerm on OS X, the "DOS prompt" on Windows, gnome-terminal on any X11 system, etc.—that's generally doable, but the way to do it is by launching or scripting the terminal program and telling it to open a new window and run Python in that window. And, needless to say, they all have completely different ways of doing that.

And even then, it's not going to be possible in all cases. For example, if you ssh in to a remote machine and run Python on that machine, there is no way it can reach back to your machine and open a new terminal window.

On most platforms that have multiple possible terminals, you can write some heuristic code that figures out which terminal you're currently running under by just walking os.getppid() until you find something that looks like a terminal you know how to deal with (and if you get to init/launchd/etc. without finding one, then you weren't running in a terminal).

abarnert
  • 354,177
  • 51
  • 601
  • 671
  • Is there any way to use `os.startfile` for this? – mhlester Jan 15 '14 at 23:55
  • @mhlester: Since that function only exists on Windows, there is obviously no cross-platform solution using it… – abarnert Jan 15 '14 at 23:57
  • @mhlester: And given that the OP is trying to use Unix-style shell syntax, I suspect he's not on Windows. But I could be wrong… – abarnert Jan 15 '14 at 23:58
  • didn't even realize that was Windows-only. My python experience on the user-facing front has only been Windows. I'll shut up now :) – mhlester Jan 16 '14 at 00:01
  • I guess you could try to create your own terminal emulator window in python in a 3rd python process that communicates with the 2nd process, thus being cross-platform. But I doubt many people would really want to do that. – Dan Getz Jan 16 '14 at 00:07
  • @DanGetz: Well, IDLE and IPython both sort of do something like that. But yeah, as you imply, I suspect that's not what the OP wants. – abarnert Jan 16 '14 at 00:12
0

The problem is that you're running Python with the argument &. Python has no idea what to do with that. It's like typing this at the shell:

/usr/bin/python '&'

In fact, if you pay attention, you're almost certainly getting something like this through your stderr:

python: can't open file '&': [Errno 2] No such file or directory

… which is exactly what you'd get from doing the equivalent at the shell.

What you presumably wanted was the equivalent of this shell command:

/usr/bin/python &

But the & there isn't an argument at all, it's part of sh syntax. The subprocess module doesn't know anything about sh syntax, and you're telling it not to use a shell, so there's nobody to interpret that &.

You could tell subprocess to use a shell, so it can do this for you:

cmdline = '{} &'.format(python_path)
p = subprocess.Popen(cmdline, shell=True)

But really, there's no good reason to. Just opening a subprocess and not calling communicate or wait on it already effectively "puts it in the background", just like & does on the shell. So:

args = [python_path]
p = subprocess.Popen(args)

This will start a new Python interpreter that sits there running in the background, trying to use the same stdin/stdout/stderr as your parent. I'm not sure why you want that, but it's the same thing that using & in the shell would have done.

abarnert
  • 354,177
  • 51
  • 601
  • 671
0

Actually I think there might be a solution to your problem, I found a useful solution at another question here. This way subprocess.popen starts a new python shell instance and runs the second script from there. It worked perfectly for me on Windows 10.

Community
  • 1
  • 1
Soma
  • 1
  • 1
0

You can try using screen command

with this command a new shell instance created and the current instance runs in the background.

# screen; python script1.py

After running above command, a new shell prompt will be seen where we can run another script and script1.py will be running in the background.

Hope it helps.

SunilThorat
  • 1,672
  • 2
  • 13
  • 15