views:

52

answers:

2

Right now I've got a project that has the following layout:

foo/
  __init__.py
  __main__.py
  foo.py

In this case, foo.py is actually the main api file, so developers are meant to do "from foo import foo", but I also wanted to make it so that end users could just run ~$ foo and get an interface.

which, when I do a distutils install, creates /usr/bin/__main__.py because (a) I don't know how to use distutils, [less important] and (b) I am not sure about what is generally considered to be the Right Thing.

As far as I can tell I have three options:

  1. Make distutils smarter, so that setup.py install creates the symlink /usr/bin/foo -> $PYTHONLIB/foo/__main__.py. This is my immediate intuition, and I could probably figure out how to do it, although the things that I'm thinking of doing all feel like hacks and I haven't found anybody talking about this.

  2. Rename __main__.py to just foo before distribution, and modify the call to distutils' setup to be setup(scripts=['foo'], ...). This is pretty similar to (1), except for when it happens, I think.

  3. Just don't include an interface with a library package. I feel like this depends mostly on the size of the library/interface as to whether it makes sense.

I haven't seen very many packages that include a __main__.py, if any, so I'm not sure if people just don't use them or I haven't been using the right packages. The fact that I couldn't find any blog posts or articles dealing with __main__.py and distutils suggests to me that it's not a particularly popular combination, though.

+3  A: 

Calling a module __main__.py is a bad idea, since that name has a special meaning. Instead use a main sentinel in __init__.py and create a script that does exec python -m foo.

Ignacio Vazquez-Abrams
my understanding of this is that if my foo/__init__.py has `if __name__ == "__main__":\n print 'success.'`, and I do `python -m foo`, I should see "success." Instead I get: "foo is a package and cannot be directly executed". Same thing happens if I stick the command in a script.
quodlibetor
Well that's silly. Try `foo.__init__` instead.
Ignacio Vazquez-Abrams
Also, I thought I was relying on the special characteristics of `__main__.py`? Unless there are other ones, I thought all it did was to make a directory executable as a script.
quodlibetor
There are no special characteristics for `__main__.py`. It's just another (valid, yet strange) module name.
Ignacio Vazquez-Abrams
ah. It's `exec python -m foo/__init__`. Thanks! What is the etiquette for requesting a correction in an answer to accept it?
quodlibetor
Oh, you're actually wrong about `__main__.py`. If you have `foo/__main__.py` and you do `python foo` it will run the code in `__main__`. Or at least it does for me.
quodlibetor
I see, it's new with Python 3. The problem is that Python 3 still doesn't have a lot of popularity.
Ignacio Vazquez-Abrams
According to http://docs.python.org/release/2.6.2/using/cmdline.html (down below the <script> section) it was changed in 2.5. So, you know, a new thing for you to use?
quodlibetor
Ah, I get it now. Python 3 changed it so that it *also* works with `-m`.
Ignacio Vazquez-Abrams
+1  A: 

Combining Ignacio Vazquez-Abrams' answer with some googling that resulted in me finding this article about using _main_.py, I think I'm probably going to go with a layout along the lines of:

foo/
    foo/
        __main__.py
        ...
    scripts/
        foo

where scripts/foo is just

#!/bin/sh
exec python foo "$@"

This seems like it will install cleanly, and let people use my module without installing, just by doing python path/to/foo.

quodlibetor