views:

2313

answers:

9

I need to be able to open a document using it's default application in Windows and Mac OS. Basically, I want to do the same thing that happens when you double click on the document icon in Explorer or Finder. What is the best way to do this in Python?

+10  A: 

In Mac OS, you can use the "open" command. There is a Windows API call that does something similar, but I don't remember it offhand.

Update

Okay, the "start" command will do it, so this should work.

Mac OS/X:

os.system("open "+filename);

Windows:

os.system("start "+filename);
Charlie Martin
Depending where `filename` comes form, this is a perfect example of why os.system() is insecure and bad. subprocess is better.
Devin Jeanpierre
not to mention the wonders that could be done by changing the default binding for the filetype. Get a grip: this was to show in a simple example how open and start would be used. details of Popen.subprocess would just be in the way.
Charlie Martin
Nick's answer looked fine to me. Nothing got in the way. Explaining things using wrong examples isn't easily justifiable.
Devin Jeanpierre
Claiming it's wrong isn't easily justifiable either.
Charlie Martin
It's less secure and less flexible than using subprocess. That sounds wrong to me.
Devin Jeanpierre
Then you're confused.
Charlie Martin
Then you're resorting to argument against the person. Stick to the actual issue. It doesn't matter if I'm confused or not.
Devin Jeanpierre
Security issues of this sort affect not only the original programmer, not just the people who use the program, but potentially everybody on the internet. You need a damn good reason to justify such an educational shortcut, and since this one is trivial to do right... there's no excuse.
Rhamphoryncus
and it still doesn't matter a bit to answering the original question. Nor, since open/start have MASSIVE security issues of their own, does it make a lot of difference. If you want to deprecate os.system, take it to Guido.
Charlie Martin
Of course it matters. It's the difference between a good answer and a bad answer (or a terrible answer). The docs for os.system() themselves say "Use the subprocess module." What more is needed? That's deprecation enough for me.
Devin Jeanpierre
Devin, I suspect we've reached a point of impass. At this point I'd suggest obtaining $2 in change, calling directory assistance, and then calling someone who agrees with you.
Charlie Martin
os.system() is a mapping of the C API. There's a lot of existing code built on it (not all of which is vulnerable.) Marking it deprecated wouldn't change anything, as you'd simply ignore what you're told and continue advocating it.
Rhamphoryncus
OMG, it's a mapping of the C library. That tears it.
Charlie Martin
Juvenile retorts are not the best way to deal with criticism.
Devin Jeanpierre
irrelevant code prissiness isn't the best kind of criticism, so figure it's value given for value received.
Charlie Martin
A: 

on mac os you can call 'open'

import os
os.popen("open myfile.txt")

this would open the file with TextEdit, or whatever app is set as default for this filetype

lcvinny
+3  A: 

I prefer:

os.startfile(path, 'open')

(python docs) 'open' does not have to be added (it is the default). The docs specifically mention that this is like double-clicking on a file's icon in Windows Explorer.

Edit: Windows only

DrBloodmoney
This is windoze only.
Noah
Thanks. I didn't notice the availability, since the docs have it appended to the last paragraph. In most other sections, the availability note occupies its own line.
DrBloodmoney
+10  A: 

Just for completeness (it wasn't in the question), xdg-open will do the same on Linux.

dF
+12  A: 

Use the subprocess module available on Python 2.4+, not os.system, so you don't have to deal with shell escaping.

import subprocess, os
if os.name = 'mac':
    subprocess.call(('open', filepath))
elif os.name = 'nt':
    subprocess.call(('start', filepath))
elif os.name = 'posix':
    subprocess.call(('xdg-open', filepath))

The double parentheses are because subprocess.call wants a sequence as its first argument, so we're using a tuple here. On Linux systems with Gnome there is also a "gnome-open" command that does the same thing.

Nick
Using 'start' in subprocess.call() doesn't work on Windows -- start is not really an executable.
Tomas Sedovic
nitpick: on all linuxen (and I guess most BSDs) you should use `xdg-open` - http://linux.die.net/man/1/xdg-open
gnud
+9  A: 
import os
import subprocess

def click_on_file(filename):
    try:
        os.startfile(filename):
    except AttributeError:
        subprocess.call(['open', filename])
nosklo
Huh, I didn't know about startfile. It would be nice if the Mac and Linux versions of Python picked up similar semantics.
Nick
Relevant python bug: http://bugs.python.org/issue3177 - provide a nice patch, and it might get accepted =)
gnud
A: 

If you want to specify the app to open the file with on Mac OS X, use this: os.system("open -a [app name] [file name]")

A: 

If you want to go the sybprocess.call() way, it should look like this on Windows:

import subprocess
subprocess.call(('cmd', '/C', 'start', '', FILE_NAME))

You can't just use:

supbrocess.call(('start', FILE_NAME))

because start is not an executable but a command of the cmd.exe program. This works:

subprocess.call(('cmd', '/C', 'start', FILE_NAME))

but only if there are no spaces in the FILE_NAME.

While subprocess.call method enquotes the parameters properly, the start command has a rather strange syntax, where:

start notes.txt

does something else than:

start "notes.txt"

The first quoted string should set the title of the window. To make it work with spaces, we have to do:

start "" "my notes.txt"

which is what the code on top does.

Tomas Sedovic
A: 

Start does not support long path names and white spaces. You have to convert it to 8.3 compatible paths.

import subprocess
import win32api

filename = "C:\\Documents and Settings\\user\\Desktop\file.avi"
filename_short = win32api.GetShortPathName(filename)

subprocess.Popen('start ' + filename_short, shell=True )

The file has to exist in order to work with the API call.