[Distutils] Improving distutils' script and GUI app handling

Phillip J. Eby pje at telecommunity.com
Thu Sep 15 17:19:05 CEST 2005

Every so often, there's a perennial debate on the distutils-sig about 
script filenames.  Should they have .py extensions or not?  What about .pyw 
apps on Windows?  What about Mac OS?  and so on.

It occurred to me this morning that we now have a new tool for resolving 
this issue in setuptools' "entry points" feature.  For various reasons, 
it's common practice to write scripts as Python modules with a "main" 
function of some kind.  These modules are then run directly with '-m', or 
use "if __name__=='__main__'", or have a short script that imports the main 
function and runs it.

So, if these "main" functions were simply declared as entry points in the 
project's setup script, then EasyInstall could automatically generate stub 
scripts for them, in a platform-appropriate fashion, with no need for '-m', 
"__name__=='__main__'", or fiddling with file extensions.  For example, 
if  PyUnit were distributed as an egg, with the following entry points:

     unittest = unittest:main

Then EasyInstall could create a 'unittest' script with a #! line on 
Unix-like OSes, and a 'unittest.py', 'unittest.bat', or 'unittest.exe' on 
Windows.  In each case, the generated program would simply load and run the 
entry point with no arguments.  Similarly, there could be a 
"distutils.gui_apps" entry point group, which could be handled differently 
according to the target platform.  (For example, by creating desktop or 
menu shortcuts on Windows.)  And, tools that create standalone applications 
or installers could use this information to create other kinds of wrappers 
around the same entry points.

In order for this to work well, there are obviously some details to be 
worked out.  Unix-like OSes are pretty obvious: #! line and no extension 
should work fine for all app types' executables.  But adding desktop icons 
or menu items for GUI apps is very platform-specific (e.g. Gnome vs. 
KDE).  So, whatever mechanism is used needs to be extensible and 
configurable.  Ideally, it should be possible for the platform's Python 
installation to provide the necessary hooks to do this, because I 
personally don't want to have to write and maintain all that code.  :)

As for Mac OS, I have almost no experience with it, so I'm not sure what 
GUI applications there need.  Does everything need py2app?  If you have a 
wx-based app, would you just make a #! script?  Bob Ippolito previously 
mentioned that you don't "install" applications there, that people just 
drag applications wherever they want them rather than using shortcuts, so 
at least that part isn't a problem.  :)

On Windows, I'd say that applications are pretty much always better as 
.exe's, whether console or GUI.  The .py/.pyw form is dependent on a single 
global consistent version of Python, but it's possible and reasonable to 
have multiple Python versions installed.  An .exe also has a lot more 
control over how Python is initialized, and that can be particularly 
important for applications.  On the other hand, in the short run I can also 
see using .bat or .cmd files for console apps, and .pyw for GUI apps, just 
to have something that works and wait for the path management use cases for 
various .exe options to work themselves out.

Anyway, my idea here is that when using setuptools, you would define entry 
points instead of creating scripts and listing them in setup().  Then, 
using either EasyInstall or "setup.py install" would automatically create 
platform-appropriate scripts.

Some of the open questions:

* What groups (if any) should exist besides "console_apps" and "gui_apps"?

* How can we allow easy control of installation options on the target 
system?  (e.g., I only want Windows Programs Menu items, you only want 
desktop shortcuts for KDE, etc., but we can't have six billion command line 
options, and all of this stuff can't go into setuptools anyway)

* Should launchers hardcode their sys.path?  This would prevent breakage 
caused by installing new and incompatible versions of their dependencies, 
but require an explicit upgrade action to update them, and make the 
installation process more complex.

Thoughts, anyone?

More information about the Distutils-SIG mailing list