Reputation: 8454
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
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