Search code examples
pythondistributionconventionsdistutils

General convention for python libraries that also have an interface module?


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.


Solution

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