Search code examples
pythonmodulepackagevirtualenvflask-restful

Python can't import module from package


I have a flask restful project with the following layout (file names changed for convenience)

myproject/
    __init__.py
    app.py
    common/
        __init__.py
        util.py
    foo/
        __init__.py
        main.py
        utilities.py

foo/ is just a folder containing code for one of the API endpoints, I'm planning to add others in the future, for this reason I have common/util.py file which contains reusable functions that I will use with other API endpoints.

foo/main.py

from flask_restful import Resource, request

from utilities import Analysis

class Foo(Resource):
    def get(self):      
        pass

in foo/utilities.py I have classes with methods that get some data, I import those classes to foo/main.py to return JSON response

classes in foo/utilities.py also uses some functions from common/util.py but when I try to import something from common/util.py to foo/utilities.py I get import common.util ModuleNotFoundError: No module named 'common'

What could be causing this? I tried importing various ways: from common.util import my_func from .common.util import my_func from myproject.common.util import my_func

but none worked.

This is myproject/app.py in case it matters:

from flask import Flask
from flask_restful import Api

from foo.main import Foo

app = Flask(__name__)
api = Api(app)

api.add_resource(Foo, '/Foo')

if __name__ == "__main__":
    app.run()

I'm doing all of this in activated virtualenv if it matters


Solution

  • from common.util import my_func

    In Python 3 this is an absolute import, that is, the directory with common/ subdirectory must be in sys.path. In your situation it's certainly a wrong approach.

    from .common.util import my_func

    This import expects common to be a subdirectory of foo which is also not the case.

    from myproject.common.util import my_func

    This is finally the best approach but for it to work the parent directory of myproject/ subdirectory must be in sys.path. Either you install the entire myproject or add the parent directory to $PYTHONPATH environment variable or add the directory to sys.path in foo/main.py. Something like:

    PYTHONPATH=/home/to/parentdir /home/to/parentdir/myproject/foo/main.py
    

    or

    import sys
    sys.path.insert(0, '/home/to/parentdir')
    

    /home/to/parentdir is the directory where myproject/ is.

    After installing myproject or adding its parent directory to sys.path you can also use relative import. You need to remember that common is a sibling package comparing to foo so the import must be not from .common but from ..common:

    from ..common.util import my_func