1

I am trying to make a stand-alone application in Python and there are some problems related to imports and the project's directory structure that I do not how to solve.

This is how the project is structured:

root/
  app/
    __init__.py 
    main.py
    foo.py     
  tests/
    __init__.py
    main_tests.py
    foo_tests.py

These are the two conflicting requirements which I don't know how to solve:

  • The tests are written using the Nose framework. When I run nosetests from the root directory, it requires all imports to be relative to the app package.

    # app/main.py
    import app.foo  # `import foo` will not work
    
  • On the other hand, if I want to run the application from root (with a command like python app/main.py), another problem occurs. It will rightly complain that it cannot find the app package.

How can I fix these problems? Is there anything I need to change in how I organized my project?

Paul Manta
  • 30,618
  • 31
  • 128
  • 208
  • I would expect imports in `tests` to have to be absolute, but not `app`. It sounds like this is a problem of properly setting up the python path used by the testing framework. – aruisdante Feb 19 '15 at 18:44
  • @aruisdante All I did was to run `pip3 install nose`. I didn't do any configuration of any sort. Is there something I should have done first? – Paul Manta Feb 19 '15 at 18:48
  • Reading the docs, it doesn't look like it. This may be a more general case of importing one package from another package when they aren't both sub-packages of a common package. Try adding a line in `test.__init__.py` that adds `app` to the python path, ex: `sys.path.append('path_to_app_dir')` and see if that fixes the problem. In the more general case, see discussions here: http://stackoverflow.com/questions/1893598/pythonpath-vs-sys-path and various other questions about similar. – aruisdante Feb 19 '15 at 18:51
  • Changing `sys.path` does the job. It feel hacky, though... – Paul Manta Feb 19 '15 at 18:57
  • It is hacky. The proper way to do it is to actually install packages as per Antti's answer below so that they're already on your python path. I just wanted a test to confirm that was the problem. This can serve as a short-term fix while you're doing very early stage development so you don't have to write a `setup.py` script. – aruisdante Feb 19 '15 at 18:59
  • You might also want to see the [other question](http://stackoverflow.com/questions/28613439/do-i-need-an-init-py-if-i-want-to-build-a-standalone-program-and-not-a-packa/) that I just answered ;) – Antti Haapala -- Слава Україні Feb 19 '15 at 19:02

1 Answers1

1

You should have a setup.py; in the setup.py you should have:

setup(
    ...
    scripts = ['bin/run_my_app']
    ...
)

and bin/run_my_app then a script with content:

#!/usr/bin/env python

from app.main import main
main()

Now when you run python setup.py develop or python setup.py install, the setuptools/distribute will install the command line script run_my_app into your path. The python setup.py develop makes it possible to not need to reinstall the package to virtualenv after each change to the source code; you need to rerun setup.py develop only after changes to the setup.py itself, or any of the possible C language extension modules in your package.

Alternatively run your main module with

python -m app.main

Especially do not try to run an application from within the package with python app/main, as it never was supposed to work like that.


For developing the code, you'd have a virtualenv, then you can use python setup.py develop to link the code into the virtualenv; a special link is installed into the site-packages that points to the source code of your application, thus you can develop it in place, but it behaves as if it was installed into the site-packages.