This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: desktop module (providing startfile as open, all platforms)
Type: Stage:
Components: Library (Lib) Versions:
process
Status: closed Resolution:
Dependencies: Superseder:
Assigned To: Nosy List: eric.araujo, jjlee, mwm, pboddie
Priority: normal Keywords: patch

Created on 2005-09-23 16:30 by pboddie, last changed 2022-04-11 14:56 by admin. This issue is now closed.

Messages (28)
msg48766 - (view) Author: Paul Boddie (pboddie) Date: 2005-09-23 16:30
Currently, in Python's standard library, there is   
apparently no coherent, cross-platform way of getting   
the user's environment to "open" files or resources   
(ie. show such files in browsers, editors) when   
requested by a Python program. There is an   
os.startfile function which works for Windows, but no   
equivalent function for other desktop environments -   
the webbrowser module seems to employ alternative   
mechanisms in choosing and running external   
programs and presumably does not seek to provide   
general support for non-URL resources anyway.  
  
Since desktop environments like KDE and GNOME   
provide mechanisms for running browsers and editors   
according to the identified type of a file or resource,   
just as Windows "runs" files or resources, it is   
appropriate to have a module which accesses these   
mechanisms. Attached is a simple module which   
seeks to support KDE, GNOME and Windows - the   
latter using the existing os.startfile support - and   
which could be extended to support other desktop   
environments such as Mac OS X, XFCE, CDE (along   
with others deemed important and feasible enough to   
support).  
  
Note that this approach is arguably better than that   
employed by the webbrowser module since most   
desktop environments already provide mechanisms   
for configuring and choosing the user's preferred   
programs for various activities, whereas the   
webbrowser module makes relatively uninformed   
guesses (eg. opening Firefox on a KDE desktop   
configured to use Konqueror as the default browser).   
   
Note also that the startfile function is arguably   
misplaced in the os module; thus, this functionality is   
supplied as a new module rather than as a patch to   
the os module, and the name of the function is  
"open" (like in the webbrowser module) rather than  
"startfile" which is a fairly Windows specific term. One 
could also envisage the desktop module residing 
within the os package to avoid top-level namespace 
pollution. 
   
Recent discussion in the comp.lang.python thread  
"Open PDF" covering this issue can   
be found here:   
http://groups.google.no/group/comp.lang.python/browse_frm/thread/8e00f7c1ccfae166/6168b6728cf64cb7  
msg48767 - (view) Author: John J Lee (jjlee) Date: 2005-09-24 12:13
Logged In: YES 
user_id=261020

+1 on the idea, but a slight change to the implementation
for KDE...

I wrote a detailed bug report below, then discovered the
solution to what I assume is a bug.

Here's the solution: For KDE, use 'exec' instead of
'openURL' as the first argument to kfmclient.

Here's the detailed report:

I tried setting up KDE 3.2.2 to associate text files in the
order:

Emacs
KWrite
KEdit
Kate

I used Control Center->KDE Components->File Associations to
do that.  All of those editors are installed on my machine.

Then I attempted to open this text file:

$ file /home/john/test.txt
/home/john/test.txt: ASCII text
$ cat /home/john/test.txt
hello, world

$

When I open it by clicking on it from a Konqueror directory
listing, GNU emacs running in an X11 window starts up, with
the specified file opened.

When I use your module:

$ python2.4
Python 2.4 (#1, Feb 19 2005, 23:54:54)
[GCC 3.3.2 20031218 (Gentoo Linux 3.3.2-r5,
propolice-3.3-7)] on linux2
Type "help", "copyright", "credits" or "license" for more
information.
>>> import desktop
>>> desktop.open("/home/john/blocking.txt")
>>>

...it opens in Konqueror with some embedded editor (KEdit or
KWrite, I assume), not directly in any of the editors I
specified, and certainly not in emacs.

Same applies if I use a URL:

>>> desktop.open("file:///home/john/test.txt")


This doesn't seem to be the intended behaviour of your module.
msg48768 - (view) Author: John J Lee (jjlee) Date: 2005-09-24 12:28
Logged In: YES 
user_id=261020

I guess there are probably security implications with using
kfmclient exec (risk of running arbitrary code)... but then
I guess the same applies to os.startfile().
msg48769 - (view) Author: John J Lee (jjlee) Date: 2005-09-24 12:47
Logged In: YES 
user_id=261020

Looking at the thread you reference, I guess it would be
nice if the desktop module supported returning a process handle.

On Windows, I imagine os.startfile could be extended in
Python 2.5 to use StartFileEx() (win32 function suggested by
Thomas Heller) and return a process handle.  I guess it's
worth asking whether that's actually very useful without
ctypes or win32all, though.

Anybody know how you'd get a pid out of KDE or GNOME?
msg48770 - (view) Author: Paul Boddie (pboddie) Date: 2005-09-24 16:33
Logged In: YES 
user_id=226443

Configuring KDE to open different types of files requires 
some magic that I don't fully understand. Nevertheless, I 
find that if I create a shell script with executable 
permissions then "kfmclient exec" will run that script, 
whereas "kfmclient openURL" will ask whether I want to run 
it first. That said, "kfmclient exec" probably has closer 
semantics to the win32-supported os.startfile function. 
 
I've uploaded a new version of the module which returns 
the process identifier, along with some exception handling 
around os.startfile. 
 
See this page for related discussion of KDE and GNOME 
application launching: 
http://my.opera.com/community/forums/topic.dml?id=83890 
 
See this thread for upcoming standards: 
http://thread.gmane.org/gmane.linux.xdg.devel/2524 
 
See this page for details of such standards: 
http://www.freedesktop.org/Standards/mime-actions-spec 
msg48771 - (view) Author: Paul Boddie (pboddie) Date: 2005-09-24 18:23
Logged In: YES 
user_id=226443

Other related material: 
http://www.freedesktop.org/wiki/Software_2fpyxdg 
msg48772 - (view) Author: Mike Meyer (mwm) Date: 2005-09-24 18:49
Logged In: YES 
user_id=93910

The code to support Mac OS X is:



While the commentary that webbrowser does it wrong is on
target, the proposed code resembles that more than one would
like. Both webbrowser and desktop poke around the system to
make a guess as to what application they should be using.
This is fine, so long as they guess right. The problems is
if they guess wrong. webbrowser allows for this by allowing
the user to specify a file opener in the environment
variable OPENER. I'd suggest supporting that. I started to
add support, then decided that
msg48773 - (view) Author: Mike Meyer (mwm) Date: 2005-09-24 18:53
Logged In: YES 
user_id=93910

The code to support Mac OS X is:

if sys.platform == 'darwin':
     cmd = ['open']

etc.

While the commentary that webbrowser does it wrong is on
target, the proposed code resembles that more than one would
like. Both webbrowser and desktop poke around the system to
make a guess as to what application they should be using.
This is fine, so long as they guess right. The problems is
if they guess wrong. There's an OSS replacement for open on
the Mac, and just because a box isn't running GNOME or KDE
doesn't mean it's Windows, or doesn't have a file opener.

webbrowser allows for this by allowing the user to specify a
file opener in an environment variable. Gnome (or was it
KDE?) uses OPENER for that. I'd suggest supporting that. I
started to add support, then noticed that cmd was a list of
strings, and you can't really specify that in an environment
variable, so it needs to be encoded somehow. I'm going to
leave that to someone more interested in the problem.

    <mike
msg48774 - (view) Author: John J Lee (jjlee) Date: 2005-09-24 21:28
Logged In: YES 
user_id=261020

Oops, s/StartFileEx()/ShellExecuteEx()/

Paul: What are we actually trying to do here?  1) Open
arbitrary files (possibly by means of a URL) using the
method that the desktop user has configured his desktop /
OS?  Or 2) open arbitrary URLs in the web browser he has
configured (possibly making use of GUI components embedded
in the browser)?  Or 3) something else?

If 1) (which is what I had gathered from your initial
comment and the c.l.py thread you referenced), then I guess
ShellExecute (os.startfile) is right, as is kfmclient exec,
and we just have to accept there are security implications
that need to be borne in mind and acted upon appropriately
(I'm not certain what that entails).  Are there really major
security differences between kfmclient exec and ShellExecute
here?

If 2). then it seems that we're doing two different things
on the two different desktops we're talking about: kfmclient
has openUrl, but ShellExecute doesn't have any equivalent (I
assume the "explore" verb always lands you in IE / Windows
Explorer, never firefox, for example).  Perhaps unavoidable,
but weakens the case for the module.
msg48775 - (view) Author: Paul Boddie (pboddie) Date: 2005-09-24 21:39
Logged In: YES 
user_id=226443

Several good points, Mike! (And I wondered where your 
own open program would fit in here.) The major problem 
with webbrowser is that it either uses obsolete techniques 
or just leaves most of the work to the caller. Moreover, it 
has to keep pace with the range of applicable programs, 
which is more work than just keeping up with relevant 
desktop environments even for such a restricted domain. 
   
Mike, John: the motivation for this module was that 
os.startfile hooks into the Windows API in order to follow 
the user preferences reliably stored elsewhere, yet there 
aren't equivalent functions for other systems, despite the 
fact that such functions have been around for some time. I 
think "kfmclient exec" may be the way to go for KDE, by the 
way. 
 
As for Windows, I do recall entering URLs at the command 
line, but I don't recall whether Windows observed my 
desktop preferences, although I do seem to remember it 
launching Acrobat Reader for remote PDF resources. 
Someone else would have to verify that, though. 
msg48776 - (view) Author: Mike Meyer (mwm) Date: 2005-09-25 01:01
Logged In: YES 
user_id=93910

open is a desktop-independent variation on gnome-open and
kfmclient. So it's something that desktop could be set up to
run, using cmd = ["open", url].

On the other hand, it also exposes an API to Python progams,
so you could (in theory) replace Unix-specific parts of
desktop with (using the development version):

from open import run
run(filename, have = ['open'])

except that it'd use the users "open" preferences instead of
their desktop preferences. This is why I proposed the OPENER
environment variable. I don't run a desktop, so the proposed
version would default to trying os.startfile.  I'd rather it
use open.

   <mike

Sorry 'bout the previous double post. I accidently tabbed to
the submit button...
msg48777 - (view) Author: Paul Boddie (pboddie) Date: 2005-09-25 14:26
Logged In: YES 
user_id=226443

I've uploaded a version which supports OPENER, although I 
can't find any references to that variable anywhere. By the 
way, I wonder if the open program's preferences couldn't 
somehow work with the various freedesktop.org standards 
if they don't already. 
msg48778 - (view) Author: John J Lee (jjlee) Date: 2005-09-25 15:57
Logged In: YES 
user_id=261020

If OPENER is not standard in any way (ad hoc or otherwise),
why add it?  Moght not doing that without talking to other
people about it (presumably on freedesktop, including GNOME,
KDE. etc. people) be positively harmful? 

Mike: is this Python version of Apple's "open" actually
published on the web somewhere?  I can't find it.  I also
notice that "open" is already in use as a shell wrapper
around open (2) the system call.  "start" seems unused, FWTW
here.
msg48779 - (view) Author: Mike Meyer (mwm) Date: 2005-09-25 22:01
Logged In: YES 
user_id=93910

I suggested OPENER because I saw it in use somewhere while
looking for things for open. I couldn't find it when I went
looking for it to reply to this. Clearly, the desktop module
needs some way for the user to say "I don't care what you
think the system looks like - use *this*." If there's a
standard for that, we should use it. If there isn't a
standard, we get to establish one. Putting it in the beta
version so people can play with it is a good idea. Until the
module is accepted, nothing is wired down, and testers
should know that.

Open has been announced in a number of places. It doesn't
have it's own web page yet. You can find a link to the
tarball at http://www.mired.org/downloads/. It's also listed
in PyPI.

Other than it's existence showing that desktop needs a way
for user to override the guesses the module makes (which the
OSS launch tool does for OS X as well), this isn't really
the place to discuss open. I've addressed the issues raised
here about open in the README file that was posted in the
0.3 version. Further discussion should go to me directly, or
to the Python list/newsgroup. If you think it belongs in
another forum, please let me know.
msg48780 - (view) Author: John J Lee (jjlee) Date: 2005-09-25 23:34
Logged In: YES 
user_id=261020

Why does the desktop module need something more than Paul's
"desktop" argument?  (Though perhaps "desktop" is not a
sufficiently general name, as I think you said.)

I don't think it's desirable for Python to start introducing
half-baked and nonstandard environment variable conventions,
especially in this area.

1. Why should other people start following *Python*'s
convention here?

2. Any such convention may be overtaken by efforts with more
backing (such as freedesktop), leaving us with cruft in the
stdlib, perhaps even cruft that's in conflict with the new
standards (what if somebody with actual clout mandates START
instead?  something will break).

3. Any program that wants to can follow this supposed OPENER
convention, without needing to bake it into the stdlib.

Having said all that, if you can get agreement from people
at freedesktop to agree on OPENER (which might well be
possible), and I guess set a useful default at desktop
startup, I will worship at your feet ;-)

I'm not sure what you mean by "the guesses that the module
makes".  It makes exactly one guess: which opener to use,
and that guess is overridable with the "desktop" argument to
open().
msg48781 - (view) Author: Paul Boddie (pboddie) Date: 2005-09-26 00:14
Logged In: YES 
user_id=226443

Actually, "desktop" just provides a way of saying "I'm on KDE 
not GNOME!" or something similar; the decisions then 
made by the function aren't themselves configurable, but 
then a developer would arguably be better off using 
os.system at that point. 
 
The module is really supposed to encapsulate knowledge 
about how to start programs in various desktop 
environments, along with a means to detect those 
environments in the first place. If you as a programmer 
disagree with the detection, override it; if you as a 
programmer know better, don't use the function... but do 
send a patch! 
 
As for user overrides, something like OPENER might be 
needed to get around the decisions taken in the module, 
although something "lighter" like DESKTOP might also be 
useful to override just the detection. It astounds me that 
such simple things haven't been agreed on by the 
freedesktop people, or at least not in any obvious way. 
msg48782 - (view) Author: Paul Boddie (pboddie) Date: 2005-09-26 00:45
Logged In: YES 
user_id=226443

On environment variables, here's a thread discussing them: 
http://lists.freedesktop.org/archives/xdg/2004-December/005553.html 
 
The discussion ranges from environment variables referring 
to the desktop (DESKTOP) and a launcher 
(DESKTOP_LAUNCH) or some kind of information program 
(DESKTOP_CTL), all the way to such variables 
referencing .so files which are then dlopened. The 
abstraction elevator/escalator is thankfully stopped before 
things get any more complicated. 
 
A previous thread (mentioned in the above thread) 
proposes the DESKTOP variable and the alternative 
DESKTOP_OPEN variable: 
http://lists.freedesktop.org/archives/xdg/2004-May/003942.html 
 
The above thread continues here, proposing DESKTOP 
again along with a desktop-open script, later shifting to 
some people favouring DESKTOP_LAUNCH and some 
favouring a desktop-launch script: 
http://lists.freedesktop.org/archives/xdg/2004-May/003995.html 
 
A standards document mentioned in the last thread: 
http://primates.ximian.com/~michael/desktop.txt 
msg48783 - (view) Author: Paul Boddie (pboddie) Date: 2005-09-26 00:55
Logged In: YES 
user_id=226443

Oh, and after the DESKTOP specification, there was the 
DESKTOP_LAUNCH specification: 
http://lists.freedesktop.org/archives/xdg/2004-August/004489.html 
 
Things happen slowly in desktop standardisation land. 
 
Searching for usage of DESKTOP_LAUNCH revealed this 
interesting script: 
http://www.mail-archive.com/dashboard-hackers%40gnome.org/msg00762/desktop-launch 
msg48784 - (view) Author: Mike Meyer (mwm) Date: 2005-09-26 02:25
Logged In: YES 
user_id=93910

Actually, the guess that the module makes is which desktop
the user is on - and that's overridable by the "desktop"
argument. The pre-OPENER version of desktop.py had no way to
override it's choice of opener - the best you can do is tell
it to use the default opener for some desktop it knows
about. Further, the "desktop" argument is really only
applicable to the application developer. The end-user - the
person who actually chooses the launcher to use - can't use
it without editing the source to the application. While you
may consider this an acceptable configuration mechanism, I
don't.

The standard Unix mechanism for setting things like this -
dating back to the 70s - is an environment variable that
names the command to use. If you want to suggest a better
mechanism, feel free to do so. Until then the question is
what the name should be. Based on what the freedesktop talk,
maybe it shold be DESKTOP_OPEN or DESKTOP_LAUNCH. On the
other hand, the freedesktop folks seem much better at
generating discussion than specifications - and neither of
those carries as much weight with me  as running code.

Part of this does depend on the point of the desktop module.
I thought it was to make os.startfile functionality
available in a platform-independent manner. If so, it needs
to deal with things other than the tools provided by a
couple of common desktops. If instead it's supposed to
provide access to the knowledge built into the most popular
desktops, then ignoring user preferences is reasonable. But
that makes it much less usefull.
msg48785 - (view) Author: Paul Boddie (pboddie) Date: 2005-09-26 13:08
Logged In: YES 
user_id=226443

I've now attached another version of the module which 
observes DESKTOP_LAUNCH, does a bit more verification, 
and exposes the desktop detection. I'll probably do a bit 
more reading of the fd.o mailing lists and possibly try and 
get some answers from the interested parties. 
msg48786 - (view) Author: John J Lee (jjlee) Date: 2005-09-27 00:20
Logged In: YES 
user_id=261020

Quite correct about desktop meaning (roughly) what it says,
rather than "opener": my mistake.

And I see we are all in agreement about what environment
variables are for.  But, as Paul says,

"""the decisions then made by the function aren't themselves
configurable, but then a developer would arguably be better
off using  os.system at that point."""

The correct way of dealing with things like these proposed
opener environment vars in the Python stdlib at this point
in time (in the absence of anything very close to an
accepted wider standard) is for applications to do this:

if os.environ.has_key("USER_KNOWS_BETTER"): obey_user(fn)
else: desktop.open(fn)

where one would expect obey_user() to be a one-liner:

def obey_user(fn):
subprocess.Popen(os.environ["DESKTOP_OPENER"])

So what is to be gained by baking some random new "standard"
into the Python stdlib?  Clearly, any individual application
obeying some such environment var gains little without
others following suit with the *same* env var, but that is
no reason to include code knowing about eg. OPENER in the
stdlib; in fact, that's precisely the reason such code
shouldn't be included right now: we don't know what env var
(or other mechanism) other apps will end up using.  I don't
think de facto semi-standardisation across "applications
using Python 2.5 and the desktop module" is likely to gain
much momentum or prove very useful to the vast majority of
end users, but it does make life that extra little bit more
complicated for future users and maintainers of Python, and
for users and maintainers of applications wishing to "start"
files.

I suppose you could try and argue that OPENER is simply an
implementation detail of open() that should be changed when
and if some standard env var name or other mechanism becomes
popular, but that doesn't make sense to me: first, we would
be exposing this detail to "end-users" (or else what use is
it), and second, the presence of code such as the if
os.environ.has_key("OPENER") in the last version of
desktop.py I looked at makes life slightly *harder* for
applications who know about newer, more widespread
conventions than some old version of desktop.py knows about.

Finally, I don't know what to make of your (Mike) comment
that "neither of those carries as much weight with me  as
running code".  Writing code is simply not the problem here:
the (obey_user()) code is almost as simple as it gets.  The
problem here is almost entirely about getting agreement with
other people, which, yes, means sometimes-tiresome
discussions.  Sometimes it means trying to generate de-facto
standards and leave those tiresome discussions in the dust,
agreed: I guess I'm stating my opinion here that the Python
stdlib is not the place to do that, for the reasons I
enumerated above and in my ealier post (2005-09-26 00:34). 
Foolishly trusting in the sanity of humankind, I think that
KDE and GNOME will *eventually* get their act together.

Am I just totally wrongheaded about this?

OK, I must stop this nonsense, perhaps this is just one of
those bikesheds...
msg48787 - (view) Author: Mike Meyer (mwm) Date: 2005-09-27 01:14
Logged In: YES 
user_id=93910

I purposely avoided dealing with the "better off using
os.system" before, because I didn't think it was relevant.
Since you seem to think it's right, let's deal with it.

First of all, the code isn't that simple. You want a
convention for your environment variable that's flexible
enough to deal with the three cases (kde, gnome and OS X) we
already have. Just tossing a string to Popen won't cut it.
The split() done by the current implementation is
problematical - OS X at the very least comes with standard
directories with spaces in their names. I'm not proposing a
solution to  that here - just pointing out the problem.

You're advocating that, instead of putting this
functionality in desktop, we leave it up to every
application writer to write it. That means - at the very
least - that every application writer now has to write

if os.environ.has_key("DESKTOP_LAUNCH"):
     <do something>
else:
     desktop.open(filename)

rather than simply doing:

desktop.open(filename)

It also means that every application writer has to decide
how they're going to deal with possible spaces in the file
name in the environment variable, or if they are at all. And
they also get to decide which of the various proposed
environment variable names they want to use. If the user is
lucky, they won't have two applications that use the same
name with different conventions. If not, well, that would
just suck.

Second, if another a standard does emerge, you can fix all
the applications by fixing *one* file in stdlib. Better yet,
ithe fix can be transitioned in smoothly for all
applications by working with that one file.

Basically, *not* providing this hook is simply poor software
engineering - it makes things harder on the developers,
harder on the users, and harder on the maintainers in the
future. While not wanting to push forward standards may be a
good thing, it's certainly not a reason for doing a wrong thing.
msg48788 - (view) Author: Paul Boddie (pboddie) Date: 2005-09-27 10:07
Logged In: YES 
user_id=226443

Well, the latest attachment (the first in the list) goes some 
way towards providing user override support. I've since 
posted to the xdg mailing list asking for clarification about 
environment variables. 
 
As for the code, I've now changed the way the environment 
variable is used - it must be a shell-quoted command plus 
optional arguments. 
msg48789 - (view) Author: John J Lee (jjlee) Date: 2005-09-27 10:50
Logged In: YES 
user_id=261020

Mike: I'm unpersuaded, but I've nothing to add to what I've
already said, so I'll shut up now :-)
msg48790 - (view) Author: Paul Boddie (pboddie) Date: 2005-09-30 23:54
Logged In: YES 
user_id=226443

I've removed the attachments from this item and uploaded 
a proper package to PyPI: 
 
http://www.python.org/pypi/desktop 
 
I still think it's worth keeping this item open, even though it 
was never really a patch as such, because I still believe the 
need is there for the standard library. Moreover, I've 
licensed the code according to the PSF criteria in order to 
satisfy that eventual objective. 
msg48791 - (view) Author: Paul Boddie (pboddie) Date: 2005-11-11 17:47
Logged In: YES 
user_id=226443

Another reference to DESKTOP_LAUNCH: 
 
http://www.openoffice.org/issues/show_bug.cgi?id=37708 
msg48792 - (view) Author: Paul Boddie (pboddie) Date: 2006-08-02 22:42
Logged In: YES 
user_id=226443

I've relicensed the module and hereby withdraw it from 
consideration. 
msg140417 - (view) Author: Éric Araujo (eric.araujo) * (Python committer) Date: 2011-07-15 15:20
This was proposed anew as #3177.
History
Date User Action Args
2022-04-11 14:56:13adminsetgithub: 42408
2011-07-15 15:20:11eric.araujosetnosy: + eric.araujo
messages: + msg140417
2005-09-23 16:30:52pboddiecreate