skwidbreth
skwidbreth

Reputation: 8454

Python/Flask - suddenly getting "ImportError: No module named..." error

I'm running into what I believe is a fairly common problem in Python apps - ImportError: No module named lib.handle_data - but I'm not experienced enough with the Python/Flask ecosystem to really understand why this is happening, especially since my code was working until I made a small adjustment and reinstalled some dependencies. Ok here's how it went down...

I'm working on a Flask app and, up until a little while ago, it was running fine. I realized that I hadn't included semantic versioning for the dependencies in my setup.py file. Originally, the file looked like this:

from setuptools import setup

setup(
    name='my_app',
    packages=['my_app'],
    include_package_data=True,
    python_requires='>3.6.4',
    install_requires=[
        'flask',
        'gtfs-realtime-bindings',
        'gunicorn',
    ],
)

which I changed to look like:

from setuptools import setup

setup(
    name='my_app',
    packages=['my_app'],
    include_package_data=True,
    python_requires='>3.6.4',
    install_requires=[
        'flask==0.12.2',
        'gtfs-realtime-bindings==0.0.5',
        'gunicorn==19.7.1',
    ],
)

and then just to make sure all was well, I ran python setup.py install and everything seemed to go ok - none of the versions changed, as these were what had already been installed.

However, when I ran flask run, the server wouldn't start and I was left with the error:

import my_app.lib.handle_data as HandleData
ImportError: No module named lib.handle_data

and trying to start the server with gunicorn via

gunicorn my_app.my_app:app -b 0.0.0.0:8000

yields the same error (no surprise, I'm sure, just being comprehensive).

Here's the file structure:

setup.py
my_app/
   |
   - __pycache__/
   - __init__.py
   - my_app.py
   - lib/
      |
      - __pycache__/
      - __init__.py
      - handle_data.py
      - request.py

The contents of my_app/__init__.py are:

from .my_app import app

and my_app/lib/__init__.py is empty.

How did I break my app, and how can I fix this?

Python version is 3.6.4, running this on macOS Mojave, 10.14. And if I didn't make this clear, my app was running just fine before I made this change/reinstalled deps.

Upvotes: 1

Views: 395

Answers (1)

a_guest
a_guest

Reputation: 36329

You should add "my_app.lib" to packages because otherwise the corresponding sub-package and the my_app.lib.* modules won't be installed. You can check the existing installation by

>>> import my_app
>>> my_app.__file__
'/path/to/virtualenv/lib/python3.6/site-packages/my_app/__init__.py'

Now inspecting the corresponding directory will reveal that lib is missing. If you add "my_app.lib" to packages then the lib directory (package) will be installed as well.

As to why it worked before while you didn't change anything about the package setup / structure I can only speculate. There is however one thing about the installation process itself that can have an effect. If you had installed the package in --editable (-e) mode (or python setup.py develop)1 before then your environment would contain a my-app.egg-link pointing to the package's source directory instead of a copy of the relevant files. This way the my_app.lib is of course not missing (as it's contained in the source directory). According to your description you did a "normal" installation after applying the changes and this requires the full structure as specified in packages to be complete (also using --upgrade would remove the link).


1. --editable / -e is the pip option to place a link to the source directory rather than to copy the relevant files; using setup.py directly the corresponding mode is develop, i.e. python setup.py develop.

Upvotes: 2

Related Questions