Search code examples
djangoheroku

Django / Heroku ModuleNotFoundError: No module named 'MyProject.apps'


I've got a django app that works fine when I run it locally with "python manage.py runserver". However, Heroku is struggling to get the site up and running.

I commit changes to git, which triggers an automatic build on Heroku. The build succeeds, but then fails when trying to start the process with the gunicorn command. I've pasted the full Heroku log below, but the relevant bit seems to be "ModuleNotFoundError: No module named 'FromThePath.apps'", which seems to be referring to the INSTALLED_APPS in settings.py.

I've tried changing the INSTALLED_APPS to be prefixed with an extra "FromThePath." (which is what resolved an error in wsgi.py), but that causes a failure during build at the collectstatic command with "ModuleNotFoundError: No module named 'FromThePath.FromThePath'"

Not sure where to go from here. My Google-fu is clearly inadequate. Thanks in advance for your help!

Full heroku log:

2021-03-09T17:01:30.000000+00:00 app[api]: Build succeeded
2021-03-09T17:01:40.327614+00:00 heroku[web.1]: Starting process with command `gunicorn FromThePath.FromThePath.wsgi`
2021-03-09T17:01:44.495636+00:00 app[web.1]: [2021-03-09 17:01:44 +0000] [4] [INFO] Starting gunicorn 20.0.4
2021-03-09T17:01:44.497096+00:00 app[web.1]: [2021-03-09 17:01:44 +0000] [4] [INFO] Listening at: http://0.0.0.0:49607 (4)
2021-03-09T17:01:44.497258+00:00 app[web.1]: [2021-03-09 17:01:44 +0000] [4] [INFO] Using worker: sync
2021-03-09T17:01:44.510099+00:00 app[web.1]: [2021-03-09 17:01:44 +0000] [9] [INFO] Booting worker with pid: 9
2021-03-09T17:01:44.547692+00:00 app[web.1]: [2021-03-09 17:01:44 +0000] [10] [INFO] Booting worker with pid: 10
2021-03-09T17:01:45.165418+00:00 heroku[web.1]: State changed from starting to up
2021-03-09T17:01:45.478113+00:00 app[web.1]: [2021-03-09 11:01:45 -0600] [9] [ERROR] Exception in worker process
2021-03-09T17:01:45.478159+00:00 app[web.1]: Traceback (most recent call last):
2021-03-09T17:01:45.478161+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/gunicorn/arbiter.py", line 583, in spawn_worker
2021-03-09T17:01:45.478162+00:00 app[web.1]: worker.init_process()
2021-03-09T17:01:45.478163+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/gunicorn/workers/base.py", line 119, in init_process
2021-03-09T17:01:45.478163+00:00 app[web.1]: self.load_wsgi()
2021-03-09T17:01:45.478164+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/gunicorn/workers/base.py", line 144, in load_wsgi
2021-03-09T17:01:45.478164+00:00 app[web.1]: self.wsgi = self.app.wsgi()
2021-03-09T17:01:45.478165+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/gunicorn/app/base.py", line 67, in wsgi
2021-03-09T17:01:45.478165+00:00 app[web.1]: self.callable = self.load()
2021-03-09T17:01:45.478166+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/gunicorn/app/wsgiapp.py", line 49, in load
2021-03-09T17:01:45.478166+00:00 app[web.1]: return self.load_wsgiapp()
2021-03-09T17:01:45.478167+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/gunicorn/app/wsgiapp.py", line 39, in load_wsgiapp
2021-03-09T17:01:45.478167+00:00 app[web.1]: return util.import_app(self.app_uri)
2021-03-09T17:01:45.478167+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/gunicorn/util.py", line 358, in import_app
2021-03-09T17:01:45.478168+00:00 app[web.1]: mod = importlib.import_module(module)
2021-03-09T17:01:45.478168+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/importlib/__init__.py", line 126, in import_module
2021-03-09T17:01:45.478169+00:00 app[web.1]: return _bootstrap._gcd_import(name[level:], package, level)
2021-03-09T17:01:45.478170+00:00 app[web.1]: File "<frozen importlib._bootstrap>", line 994, in _gcd_import
2021-03-09T17:01:45.478170+00:00 app[web.1]: File "<frozen importlib._bootstrap>", line 971, in _find_and_load
2021-03-09T17:01:45.478170+00:00 app[web.1]: File "<frozen importlib._bootstrap>", line 955, in _find_and_load_unlocked
2021-03-09T17:01:45.478171+00:00 app[web.1]: File "<frozen importlib._bootstrap>", line 665, in _load_unlocked
2021-03-09T17:01:45.478171+00:00 app[web.1]: File "<frozen importlib._bootstrap_external>", line 678, in exec_module
2021-03-09T17:01:45.478172+00:00 app[web.1]: File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
2021-03-09T17:01:45.478173+00:00 app[web.1]: File "/app/FromThePath/FromThePath/wsgi.py", line 16, in <module>
2021-03-09T17:01:45.478173+00:00 app[web.1]: application = get_wsgi_application()
2021-03-09T17:01:45.478173+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/django/core/wsgi.py", line 12, in get_wsgi_application
2021-03-09T17:01:45.478174+00:00 app[web.1]: django.setup(set_prefix=False)
2021-03-09T17:01:45.478174+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/django/__init__.py", line 24, in setup
2021-03-09T17:01:45.478174+00:00 app[web.1]: apps.populate(settings.INSTALLED_APPS)
2021-03-09T17:01:45.478175+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/django/apps/registry.py", line 91, in populate
2021-03-09T17:01:45.478175+00:00 app[web.1]: app_config = AppConfig.create(entry)
2021-03-09T17:01:45.478175+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/django/apps/config.py", line 116, in create
2021-03-09T17:01:45.478176+00:00 app[web.1]: mod = import_module(mod_path)
2021-03-09T17:01:45.478176+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/importlib/__init__.py", line 126, in import_module
2021-03-09T17:01:45.478176+00:00 app[web.1]: return _bootstrap._gcd_import(name[level:], package, level)
2021-03-09T17:01:45.478177+00:00 app[web.1]: File "<frozen importlib._bootstrap>", line 994, in _gcd_import
2021-03-09T17:01:45.478177+00:00 app[web.1]: File "<frozen importlib._bootstrap>", line 971, in _find_and_load
2021-03-09T17:01:45.478177+00:00 app[web.1]: File "<frozen importlib._bootstrap>", line 953, in _find_and_load_unlocked
2021-03-09T17:01:45.478186+00:00 app[web.1]: ModuleNotFoundError: No module named 'FromThePath.apps'
2021-03-09T17:01:45.478671+00:00 app[web.1]: [2021-03-09 11:01:45 -0600] [9] [INFO] Worker exiting (pid: 9)
2021-03-09T17:01:45.542581+00:00 app[web.1]: [2021-03-09 11:01:45 -0600] [10] [ERROR] Exception in worker process
2021-03-09T17:01:45.542583+00:00 app[web.1]: Traceback (most recent call last):
2021-03-09T17:01:45.542584+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/gunicorn/arbiter.py", line 583, in spawn_worker
2021-03-09T17:01:45.542585+00:00 app[web.1]: worker.init_process()
2021-03-09T17:01:45.542585+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/gunicorn/workers/base.py", line 119, in init_process
2021-03-09T17:01:45.542585+00:00 app[web.1]: self.load_wsgi()
2021-03-09T17:01:45.542586+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/gunicorn/workers/base.py", line 144, in load_wsgi
2021-03-09T17:01:45.542586+00:00 app[web.1]: self.wsgi = self.app.wsgi()
2021-03-09T17:01:45.542587+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/gunicorn/app/base.py", line 67, in wsgi
2021-03-09T17:01:45.542587+00:00 app[web.1]: self.callable = self.load()
2021-03-09T17:01:45.542588+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/gunicorn/app/wsgiapp.py", line 49, in load
2021-03-09T17:01:45.542588+00:00 app[web.1]: return self.load_wsgiapp()
2021-03-09T17:01:45.542588+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/gunicorn/app/wsgiapp.py", line 39, in load_wsgiapp
2021-03-09T17:01:45.542589+00:00 app[web.1]: return util.import_app(self.app_uri)
2021-03-09T17:01:45.542589+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/gunicorn/util.py", line 358, in import_app
2021-03-09T17:01:45.542589+00:00 app[web.1]: mod = importlib.import_module(module)
2021-03-09T17:01:45.542592+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/importlib/__init__.py", line 126, in import_module
2021-03-09T17:01:45.542592+00:00 app[web.1]: return _bootstrap._gcd_import(name[level:], package, level)
2021-03-09T17:01:45.542593+00:00 app[web.1]: File "<frozen importlib._bootstrap>", line 994, in _gcd_import
2021-03-09T17:01:45.542593+00:00 app[web.1]: File "<frozen importlib._bootstrap>", line 971, in _find_and_load
2021-03-09T17:01:45.542594+00:00 app[web.1]: File "<frozen importlib._bootstrap>", line 955, in _find_and_load_unlocked
2021-03-09T17:01:45.542594+00:00 app[web.1]: File "<frozen importlib._bootstrap>", line 665, in _load_unlocked
2021-03-09T17:01:45.542594+00:00 app[web.1]: File "<frozen importlib._bootstrap_external>", line 678, in exec_module
2021-03-09T17:01:45.542595+00:00 app[web.1]: File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
2021-03-09T17:01:45.542595+00:00 app[web.1]: File "/app/FromThePath/FromThePath/wsgi.py", line 16, in <module>
2021-03-09T17:01:45.542595+00:00 app[web.1]: application = get_wsgi_application()
2021-03-09T17:01:45.542596+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/django/core/wsgi.py", line 12, in get_wsgi_application
2021-03-09T17:01:45.542597+00:00 app[web.1]: django.setup(set_prefix=False)
2021-03-09T17:01:45.542598+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/django/__init__.py", line 24, in setup
2021-03-09T17:01:45.542598+00:00 app[web.1]: apps.populate(settings.INSTALLED_APPS)
2021-03-09T17:01:45.542598+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/django/apps/registry.py", line 91, in populate
2021-03-09T17:01:45.542599+00:00 app[web.1]: app_config = AppConfig.create(entry)
2021-03-09T17:01:45.542599+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/django/apps/config.py", line 116, in create
2021-03-09T17:01:45.542600+00:00 app[web.1]: mod = import_module(mod_path)
2021-03-09T17:01:45.542600+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/importlib/__init__.py", line 126, in import_module
2021-03-09T17:01:45.542600+00:00 app[web.1]: return _bootstrap._gcd_import(name[level:], package, level)
2021-03-09T17:01:45.542601+00:00 app[web.1]: File "<frozen importlib._bootstrap>", line 994, in _gcd_import
2021-03-09T17:01:45.542601+00:00 app[web.1]: File "<frozen importlib._bootstrap>", line 971, in _find_and_load
2021-03-09T17:01:45.542602+00:00 app[web.1]: File "<frozen importlib._bootstrap>", line 953, in _find_and_load_unlocked
2021-03-09T17:01:45.542608+00:00 app[web.1]: ModuleNotFoundError: No module named 'FromThePath.apps'
2021-03-09T17:01:45.543290+00:00 app[web.1]: [2021-03-09 11:01:45 -0600] [10] [INFO] Worker exiting (pid: 10)
2021-03-09T17:01:45.752608+00:00 app[web.1]: [2021-03-09 17:01:45 +0000] [4] [INFO] Shutting down: Master
2021-03-09T17:01:45.752780+00:00 app[web.1]: [2021-03-09 17:01:45 +0000] [4] [INFO] Reason: Worker failed to boot.
2021-03-09T17:01:45.912133+00:00 heroku[web.1]: Process exited with status 3
2021-03-09T17:01:46.066521+00:00 heroku[web.1]: State changed from up to crashed

My folder structure:

FromThePath  // root folder
³   .gitignore
³   .slugignore
³   package.json
³   Procfile
³   requirements.txt
³   ToThePath.bat
³   tree.txt
³   
.idea        // in .gitignore
FromThePath  // it's not clear from the formatting, but this is a subfolder of the FromThePath root folder
³   ³   .coverage
³   ³   .coveragerc
³   ³   db.postgresql
³   ³   db.sqlite3
³   ³   manage.py
³   ³   
³   cooking
³   ³   ³   admin.py
³   ³   ³   apps.py
³   ³   ³   forms.py
³   ³   ³   models.py
³   ³   ³   tests.py
³   ³   ³   urls.py
³   ³   ³   views.py
³   ³   ³   __init__.py
³   ³   ³   
³   ³   {other presumably irrelevant folders}
³   ³           
³   DevNotes
³   ³   {same as cooking}
³   ³           
³   FromThePath
³   ³   ³   apps.py
³   ³   ³   asgi.py
³   ³   ³   forms.py
³   ³   ³   settings.py
³   ³   ³   urls.py
³   ³   ³   views.py
³   ³   ³   wsgi.py
³   ³   ³   __init__.py
³   ³   ³   
³   ³   static
³   ³   ³   FromThePath
³   ³   ³       ...
³   ³   ³               
³   ³   templates
³   ³   ³   FromThePath
³   ³   ³           *.html files
³   ³   ³           
³   ³   templatetags
³   ³   ³   ³   general_filters.py
³   ³   ³   ³   __init__.py
³   ³   ³   ³   
³   ³           
³   journal
³   ³   {same as cooking}
³   ³           
³   polls
³   ³   {same as cooking}
³   ³           
³   staticfiles
³   templates
³   ³   admin
³   ³   ³       base_site.html
³   ³   ³       
³   ³   registration
³   ³           logged_out.html
³   ³           login.html
³   ³           password_reset_complete.html
³   ³           password_reset_confirm.html
³   ³           password_reset_done.html
³   ³           password_reset_email.html
³   ³           password_reset_form.html
³   ³           
venv (in .gitignore)

settings.py

import os
import django_heroku

# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))


# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/3.0/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = '[redacted]'

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

ALLOWED_HOSTS = []


# Application definition

INSTALLED_APPS = [

    'django.contrib.admin',
    'django.contrib.auth',  # Core authentication framework and its default models.
    'django.contrib.contenttypes',  # Django content type system (allows permissions to be associated with models).
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    'FromThePath.apps.FromThePathConfig',
    'cooking.apps.CookingConfig',
    'journal.apps.JournalConfig',
    'DevNotes.apps.DevnotesConfig',
    'polls.apps.PollsConfig',

    # # Build fails on "python FromThePath/manage.py collectstatic --noinput" step
    # #  relevant part of error: ModuleNotFoundError: No module named 'FromThePath.FromThePath'
    # 'FromThePath.FromThePath.apps.FromThePathConfig',
    # 'FromThePath.cooking.apps.CookingConfig',
    # 'FromThePath.journal.apps.JournalConfig',
    # 'FromThePath.DevNotes.apps.DevnotesConfig',
    # 'FromThePath.polls.apps.PollsConfig',

]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',  # Manages sessions across requests
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',  # Associates users with requests using sessions.
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

ROOT_URLCONF = 'FromThePath.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates')],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
                'FromThePath.DevNotes.context_processors.dev_note_form_context_processor',
            ],
            'libraries':{
                'general_filters': 'FromThePath.templatetags.general_filters',
            }
        },
    },
]

WSGI_APPLICATION = 'FromThePath.wsgi.application'


# Database
# https://docs.djangoproject.com/en/3.0/ref/settings/#databases

DATABASES = {
    'default': {
        [redacted]
    }
}


# Password validation
# https://docs.djangoproject.com/en/3.0/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]


# Internationalization
# https://docs.djangoproject.com/en/3.0/topics/i18n/

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'America/Chicago'

USE_I18N = True

USE_L10N = True

USE_TZ = True


# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.0/howto/static-files/

STATIC_URL = '/static/'

# Redirect to home URL after login (Default redirects to /accounts/profile/)
LOGIN_REDIRECT_URL = '/'

# Site isn't capable of email yet. This makes it so that the stuff that would be emailed is logged to the Django Console
#   starting point to actually implement: https://docs.djangoproject.com/en/3.1/topics/email/
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'

django_heroku.settings(locals())

Procfile

web: gunicorn FromThePath.FromThePath.wsgi

wsgi.py

import os

from django.core.wsgi import get_wsgi_application

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'FromThePath.FromThePath.settings')

application = get_wsgi_application()

.gitignore

*.pyc
venv/*
.idea/*
FromThePath/htmlcov

Solution

  • Got it working by changing the Procfile so that it was running in the same directory as manage.py. You can do this using gunicorn's chrdir or pythonpath options

    web: gunicorn --chdir FromThePath FromThePath.wsgi
    

    or

    web: gunicorn --pythonpath FromThePath FromThePath.wsgi
    

    I also had to remove the project name from a few places (wsgi.py and a context processor in settings.py)