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
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.