Context:

  • I created a Django application using Python 3.7.
  • I am (attempting) to use the 2nd generation Google App Engine standard environment.

My application performs flawlessly when I run it via python manage.py runserver. Yet it comes to a sudden halt when I attempt to deploy it to Google App Engine.

Traceback (most recent call last):
  File "/tmp/tmphgUsp3/lib/python3.7/site-packages/gunicorn/arbiter.py", line 583, in spawn_worker
    worker.init_process()
  File "/tmp/tmphgUsp3/lib/python3.7/site-packages/gunicorn/workers/base.py", line 129, in init_process
    self.load_wsgi()
  File "/tmp/tmphgUsp3/lib/python3.7/site-packages/gunicorn/workers/base.py", line 138, in load_wsgi
    self.wsgi = self.app.wsgi()
  File "/tmp/tmphgUsp3/lib/python3.7/site-packages/gunicorn/app/base.py", line 67, in wsgi
    self.callable = self.load()
  File "/tmp/tmphgUsp3/lib/python3.7/site-packages/gunicorn/app/wsgiapp.py", line 52, in load
    return self.load_wsgiapp()
  File "/tmp/tmphgUsp3/lib/python3.7/site-packages/gunicorn/app/wsgiapp.py", line 41, in load_wsgiapp
    return util.import_app(self.app_uri)
  File "/tmp/tmphgUsp3/lib/python3.7/site-packages/gunicorn/util.py", line 350, in import_app
    __import__(module)
ModuleNotFoundError: No module named 'main'

I've gone through numerous threads and I cannot find the problem. (For reference the dev_appserver.py emulator produces the same problem, which is a good thing).

Following is my app.yaml

runtime: python37
env: standard

handlers:
- url: /static
  static_dir: static/
- url: .*
  script: demosite.wsgi.main

My wsgi.py file is located in the following path: demosite/wsgi.py and it's contents look like this:

import os

from django.core.wsgi import get_wsgi_application

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

main = get_wsgi_application()

My settings.py file:

import os

class AppSettings(object):
    GoogleCloudProject = os.getenv('GOOGLE_CLOUD_PROJECT')

BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

SECRET_KEY = 'say what?'

DEBUG = True

ALLOWED_HOSTS = [
    '*'
]


INSTALLED_APPS = [
    'anchor.apps.AnchorConfig',
    'crispy_forms',
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

ROOT_URLCONF = 'demosite.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [],
        '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',
            ],
        },
    },
]

WSGI_APPLICATION = 'demosite.wsgi.main'

try:
    import MySQLdb
except ImportError:
    import pymysql
    pymysql.install_as_MySQLdb()


if os.getenv('SERVER_SOFTWARE', '').startswith('Google App Engine'):
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.mysql',
            'NAME': 'webapp',
            'USER': 'aasdeytst',
            'PASSWORD': 'asdasygetasfasdfasd.',
            'HOST': 'asdgiuasfivaasd',
            'PORT': '3306'
        }
    }
else:
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.mysql',
            'NAME': 'webapp',
            'USER': 'awthdsfhfdhdf',
            'PASSWORD': 'asdasdasdagwdatwt',
            'HOST': 'localhost',
            'PORT': '3306'
        }
    }

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',
    },
]

ANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_L10N = True

USE_TZ = True

STATIC_ROOT = 'static'
STATIC_URL = '/static/'

CRISPY_TEMPLATE_PACK = 'bootstrap4'

LOGIN_REDIRECT_URL = 'index'
LOGIN_URL = 'login'

SESSION_EXPIRE_AT_BROWSER_CLOSE = False
SESSION_COOKIE_AGE = 1800

What am I missing, what am I doing wrong? I've spent close on 4 hours trying to figure this problem out to no avail.

score:35

Accepted answer

By default, App Engine looks for an app variable in a file called main.py. You have two options: put your WSGI app where App Engine expects it to be, or define a custom entrypoint:

Put your WSGI app where App Engine expects it to be:

You can create a file called main.py that has an app variable which is simply imported and aliased from the correct location:

from demosite.wsgi import main as app

Adding a custom entrypoint:

From https://cloud.google.com/appengine/docs/standard/python3/config/appref:

entrypoint: Optional. The command that is executed when your app starts. For your app to receive HTTP requests, entrypoint should contain a command which starts a web server that listens on the port specified by the PORT environment variable. If you do not specify an entrypoint, App Engine will configure and start the Gunicorn webserver.

By default it's this:

entrypoint: gunicorn -b :$PORT main:app

You would need something like:

entrypoint: gunicorn -b :$PORT demosite.wsgi:main

See here for more details about application startup: https://cloud.google.com/appengine/docs/standard/python3/runtime#application_startup

Similar question

score:0

As Farzad has said, just rename 'app.py' or 'application.py' or whatever name you have saved the application file to 'main.py'. If you can't change then create another project with the same code but this time with application file names as 'main.py'

score:2

Simply rename your main python app (for me it was app.py) to main.py. Google Cloud requires main.py to begin the process.

score:6

Adding:

The main.py have to be in root of your application, where app.yaml is.

And the content, can to be, as well:

   from mysite.wsgi import application

   # App Engine by default looks for a main.py file at the root of the app
   # directory with a WSGI-compatible object called app.
   # This file imports the WSGI-compatible object of your Django app,
   # application from mysite/wsgi.py and renames it app so it is discoverable by
   # App Engine without additional configuration.
   # Alternatively, you can add a custom entrypoint field in your app.yaml:
   # entrypoint: gunicorn -b :$PORT mysite.wsgi
   app = application

Related Query