9

My project contains three Python applications. Application 1 is a web app. Applications 2 and 3 contain scripts downloading some data.

All three apps need to use a module Common containing a "model" (classes that are saved to database) and common settings.

I have no clue how to structure this project. I could create three directories, one for each application, and copy Common three times into their directories (doesn't seem right).

Another idea that comes to mind is; create a main directory and put there all files from Common, including __init__.py. Then, crete three subdirectories (submodules), one for each application.

Another way would be installing Common using pip, but that means I would have to reinstall every time I change something in that module.

In previous projects I used .NET - the equivalent in that world would be a Solution with four projects, one of them being Common.

Any suggestions?

user44
  • 682
  • 7
  • 20

4 Answers4

9

I have a similar project that is set up like this

project_root/
    App1/
        __init__.py
    FlaskControlPanel/
        app.py
        static/
        templates/
    models/
        __init__.py
        mymodels.py

Then, I run everything from project_root. I have a small script (either batch or shell depending on my environment) that sets PYTHONPATH=. so that imports work correctly. This is done because I usually develop using PyCharm, where the imports "just work", but when I deploy the final product the path doesn't match what it did in my IDE.

Once the PYTHONPATH is set to include everything from your project root, you can do standard imports.

For example, from my FlaskControlPanel app.py, I have this line:

from models.mymodels import Model1, Model2, Model3

From the App1 __init__.py I have the exact same import statement:

from models.mymodels import Model1, Model2, Model3

I can start the Flask application by running this from my command line (in Windows) while I am in the project_root directory:

setlocal
SET PYTHONPATH=.
python FlaskControlPanel\app.py

The setlocal is used to ensure the PYTHONPATH is only modified for this session.

Andy
  • 49,085
  • 60
  • 166
  • 233
2

I like this approach

projects/
  __init__.py
  project1/
    __init__.py
  project2/
    __init__.py
  lib1/
    __init__.py
    libfile.py
  lib2/
    __init__.py

So, I need to cd into the projects folder. To start a projects use

python -m project_name

This allows me to easily import from any external lib like

from lib1.libfile import [imoprt what you want]

or

from lib1 import libfile
Nodari Lipartiya
  • 1,148
  • 3
  • 14
  • 24
2

Make standard Python modules from your apps. I recommend structure like this:

apps/
    common/
        setup.py
        common/
            __init__.py
            models.py
    app1/
        setup.py
        app1/
            __init__.py
            models.py
project/
requirements.txt

Basic setup.py for app common:

#!/usr/bin/env python

from setuptools import setup, find_packages

setup(
    name='common',
    version='1.0.0',
    packages=find_packages(),
    zip_safe=False,
)

Make similar setup.py for other apps.

Set editable "-e" option for your apps in requirements.txt:

-e apps/common
-e apps/app1

Install requirements with pip:

$ pip install -r requirements.txt

Editable option means that source files will be linked into Python enviroment. Any change in source files of your apps will have immediate effect without reinstalling them.

Now you can import models from your common app (or any other app) anywhere (in other apps, project files, ...).

0

I would create a structure like this:

project_root/
    app1/
        __init__.py
        script.py
    common/
        __init__.py
        models.py (all "common" models)

app1/script.py

import os, sys

# add parent directory to pythonpath
basepath = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..')
if basepath not in sys.path:
    sys.path.append(basepath)

from common.models VeryCommonModel
print VeryCommonModel

If you don't want to set the python path at runtime, set the python path before running the script:

$ export PYTHONPATH=$PYTHONPATH:/path/to/project_root

And then you can do:

python app1/script.py
Louis
  • 644
  • 5
  • 18
  • so let's say I run file **app1.py** located in **project_root/app1**; the file starts with `import models.py`; but **models.py** imports **common.models** which is not in module search path (`ImportError: No module named common.models`) – user44 Aug 31 '14 at 10:53
  • Updated my answer, maybe that is what you were going for? – Louis Sep 16 '14 at 23:34
  • yes, this should work if you are ok with modifying path at runtime – user44 Sep 19 '14 at 15:22
  • 1
    I guess you can also set the PYTHONPATH before running the script to make sure "project_root" is in the python path. run: "export PYTHONPATH=$PYTHONPATH:/path/to/project_root" – Louis Sep 22 '14 at 19:14