jazzband / django-configurations

A helper for organizing Django project settings by relying on well established programming patterns.
https://django-configurations.readthedocs.io/
BSD 3-Clause "New" or "Revised" License
1.1k stars 143 forks source link

Can't run any command #27

Closed yunmanger1 closed 11 years ago

yunmanger1 commented 11 years ago

Django 1.5.1 django-configurations 0.2.1

When I run any command it says:

ImproperlyConfigured: The SECRET_KEY setting must not be empty.

But SECRET_KEY is set in Base configuration.

Looks like somehow it does not pick up class-based configs: when I run ./manage.py, only django commands are listed.

jezdez commented 11 years ago

Could you paste your settings so I can try reproducing it?

yunmanger1 commented 11 years ago

manage.py

#!/usr/bin/env python
import os
import sys

if __name__ == "__main__":
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "hedgehog.settings")
    os.environ.setdefault('DJANGO_CONFIGURATION', 'DevSettings')

    from configurations.management import execute_from_command_line

    execute_from_command_line(sys.argv)

settings.py

# -*- coding: utf-8 -*-
# Django settings for hedgehog project.
import os
import sys
import imp
from configurations import Settings
from configurations.utils import uppercase_attributes
import mongoengine

import djcelery
djcelery.setup_loader()

def rel(*x):
    return os.path.join(os.path.abspath(os.path.dirname(__file__)), *x)

# left this here, because when testing with django-nose
# settings could not be picked up from classes
# NOTE: this was true for django-configurations==0.1
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': rel('..', 'hedgehog.db'),
    }
}

sys.path.insert(0, rel('apps'))

def FileSettings(path):
    path = os.path.expanduser(path)

    class Holder(object):

        def __init__(self, *args, **kwargs):
            mod = imp.new_module('hedgehog.local')
            mod.__file__ = path

            try:
                execfile(path, mod.__dict__)
            except IOError, e:
                print("Notice: Unable to load configuration file %s (%s), "
                      "using default settings\n\n" % (path, e.strerror))
                return Holder

            for name, value in uppercase_attributes(mod).items():
                setattr(self, name, value)

    return Holder

class Base(Settings):

    DEBUG = True
    TEMPLATE_DEBUG = DEBUG

    # direct to another sys path
    PROJECT_PATH = os.path.abspath(os.path.dirname(__file__))

    ACCOUNTANT_EMAILS = (
    )
    ADMINS = (
    )
    MANAGERS = ()

    CACHES = {
        'default': {
            'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
            'LOCATION': '127.0.0.1:11211',

        }
    }
    SESSION_ENGINE = 'django.contrib.sessions.backends.cache'
    AUTHENTICATION_BACKENDS = (
        'django_extensions.backends.auth_backend.AuthBackend',
    )
    LOGIN_REDIRECT_URL = '/'
    LOGIN_URL = '/login/'
    LOGOUT_URL = '/logout/'
    MANAGERS = ADMINS

    REGISTRATION_OPEN = True
    FREE_PERIOD = 15

    # mailing
    EMAIL_HOST_USER = ''
    EMAIL_HOST_PASSWORD = ''
    EMAIL_SUBJECT_PREFIX = '[hedgehog.com] '
    SERVER_EMAIL = u''
    DEFAULT_FROM_EMAIL = u''

    EMAIL_BACKEND = 'django_ses.SESBackend'
    AWS_ACCESS_KEY_ID = ''
    AWS_SECRET_ACCESS_KEY = ''

    # Local time zone for this installation. Choices can be found here:
    # http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
    # although not all choices may be available on all operating systems.
    # In a Windows environment this must be set to your system time zone.
    TIME_ZONE = 'UTC'

    # Language code for this installation. All choices can be found here:
    # http://www.i18nguy.com/unicode/language-identifiers.html

    LANGUAGE_CODE = 'ru'
    ugettext = lambda s: s
    LANGUAGES = (
        ('kk', ugettext('Kazakh')),
        ('ru', ugettext('Russian')),
    )
    LANGUAGE_COOKIE_NAME = 'lang'
    LOCALE_PATHS = (
        rel('locale'),
    )

    SITE_ID = 1

    # If you set this to False, Django will make some optimizations so as not
    # to load the internationalization machinery.
    USE_I18N = True

    # If you set this to False, Django will not format dates, numbers and
    # calendars according to the current locale.
    USE_L10N = True

    # If you set this to False, Django will not use timezone-aware datetimes.
    USE_TZ = False

    # Absolute filesystem path to the directory
    # that will hold user-uploaded files.
    # Example: "/home/media/media.lawrence.com/media/"
    MEDIA_ROOT = rel('..', 'media')
    IMAGES_ROOT = rel('..', 'media', 'images')
    # URL that handles the media served from MEDIA_ROOT. Make sure to use a
    # trailing slash.
    # Examples: "http://media.lawrence.com/media/", "http://example.com/media/"
    MEDIA_URL = '/media/'
    IMAGES_URL = '/media/images/'

    FILE_UPLOAD_TEMP_DIR = rel('temp')
    # Absolute path to the directory static files should be collected to.
    # Don't put anything in this directory yourself; store your static files
    # in apps' "static/" subdirectories and in STATICFILES_DIRS.
    # Example: "/home/media/media.lawrence.com/static/"
    STATIC_ROOT = rel('..', 'static')
    # URL prefix for static files.
    # Example: "http://media.lawrence.com/static/"
    STATIC_URL = '/static/'
    GALLERY_URL = '/static/gallery/'
    # Additional locations of static files
    STATICFILES_DIRS = (
        rel('static'),
        # Put strings here, like "/home/html/static" or "C:/www/django/static".
        # Always use forward slashes, even on Windows.
        # Don't forget to use absolute paths, not relative paths.
    )

    # List of finder classes that know how to find static files in
    # various locations.
    STATICFILES_FINDERS = (
        'django.contrib.staticfiles.finders.FileSystemFinder',
        'django.contrib.staticfiles.finders.AppDirectoriesFinder',
        # 'django.contrib.staticfiles.finders.DefaultStorageFinder',
    )

    # Hosts/domain names that are valid for this site; required if DEBUG is
    # False
    # See https://docs.djangoproject.com/en/1.5/ref/settings/#allowed-hosts
    ALLOWED_HOSTS = []

    # Make this unique, and don't share it with anybody.
    SECRET_KEY = 'this is a secret'

    # List of callables that know how to import templates from various sources.
    TEMPLATE_LOADERS = (
        'django.template.loaders.filesystem.Loader',
        'django.template.loaders.app_directories.Loader',
        # 'django.template.loaders.eggs.Loader',
    )

    MIDDLEWARE_CLASSES = (
        'django.middleware.common.CommonMiddleware',
        'subdomains.middleware.SubdomainURLRoutingMiddleware',
        'django.contrib.sessions.middleware.SessionMiddleware',
        'django.middleware.csrf.CsrfViewMiddleware',
        'django.contrib.auth.middleware.AuthenticationMiddleware',
        'django.contrib.messages.middleware.MessageMiddleware',
        'django.middleware.locale.LocaleMiddleware',
    )

    ROOT_URLCONF = 'hedgehog.saas_urls'

    # subdomin configuration
    SUBDOMAIN_URLCONFS = {
        None: 'hedgehog.urls',
        'api': 'hedgehog.api_urls',
    }

    RESERVED_SUBDOMAINS = (
    )
    # Python dotted path to the WSGI application used by Django's runserver.
    WSGI_APPLICATION = 'hedgehog.wsgi.application'

    TEMPLATE_DIRS = (
        rel('templates')
        # Put strings here, like "/home/html/django_templates" or
        # "C:/www/django/templates".
        # Always use forward slashes, even on Windows.
        # Don't forget to use absolute paths, not relative paths.
    )

    BROKER_URL = 'amqp://guest:guest@localhost:5672/'
    CELERY_IGNORE_RESULT = True
    CELERY_TIMEZONE = 'UTC'
    TEMPLATE_CONTEXT_PROCESSORS = (
        'django.contrib.auth.context_processors.auth',
        'django.core.context_processors.debug',
        'django.core.context_processors.i18n',
        'django.core.context_processors.media',
        'django.core.context_processors.static',
        'django.core.context_processors.tz',
        'django.core.context_processors.request',
        'django.contrib.messages.context_processors.messages',
    )

    INSTALLED_APPS = (
        # only for admin static
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.sites',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'djcelery',
        'rosetta',
        'subdomains',
        'captcha',
        'django_nose',
        'logical_rules',
        # only for admin static
        'django.contrib.admin',
        'django.contrib.humanize',
        'mailviews',
        'django_ses',
    )
    # A sample logging configuration. The only tangible logging
    # performed by this configuration is to send an email to
    # the site admins on every HTTP 500 error when DEBUG=False.
    # See http://docs.djangoproject.com/en/dev/topics/logging for
    # more details on how to customize your logging configuration.
    LOGGING = {
        'version': 1,
        'disable_existing_loggers': False,
        'filters': {
            'require_debug_false': {
                '()': 'django.utils.log.RequireDebugFalse'
            }
        },
        'handlers': {
            'mail_admins': {
                'level': 'ERROR',
                'filters': ['require_debug_false'],
                'class': 'django.utils.log.AdminEmailHandler'
            }
        },
        'loggers': {
            'django.request': {
                'handlers': ['mail_admins'],
                'level': 'ERROR',
                'propagate': True,
            },
        }
    }
    ROSETTA_WSGI_AUTO_RELOAD = True
    ROSETTA_UWSGI_AUTO_RELOAD = True
    ROSETTA_REQUIRES_AUTH = False
    REGISTRATION_OPEN = True

    USE_X_FORWARDED_HOST = True

    # re
    SUBDOMAIN_REGEX = r'^(\w+)([\W]\w+)?$'
    TEST_RUNNER = 'django_nose.NoseTestSuiteRunner'

class DummySite(object):
    def __init__(self, domain):
        self.domain = domain

class DevSettings(FileSettings('~/.hedgehog/hedgehog.conf.py'), Base):

    def __init__(self, *a, **kw):
        mongoengine.connect('hedgehog')
        from django.contrib.sites.models import SITE_CACHE
        SITE_CACHE[Base.SITE_ID] = DummySite(self.SITE_DOMAIN)
        super(DevSettings, self).__init__(*a, **kw)

    SITE_DOMAIN = 'hedgehog.io:8000'
    SESSION_COOKIE_DOMAIN = ".hedgehog.io"
    DOMAIN_PREFIX = 'http://' + SITE_DOMAIN
    BILL_CRON = {
        'minute': '*'
    }
jezdez commented 11 years ago

Okay, the last thing that would be useful is the traceback of the ImproperlyConfigured.

I think it may be related to the djcelery.setup_loader() on top, since that may force the settings to be loaded. Could you try moving that to the end of the file?

yunmanger1 commented 11 years ago

Did not help!

jezdez commented 11 years ago

And the traceback?

yunmanger1 commented 11 years ago

Ooops! It's the same

ImproperlyConfigured: The SECRET_KEY setting must not be empty.
jezdez commented 11 years ago

Okay, but is there an actual stacktrace, more than just the last line of the error?

yunmanger1 commented 11 years ago

No traceback. Only this message in red color. On weekend I will dig a little bit and find out what is the issue.

jezdez commented 11 years ago

Try running the script with --traceback

jezdez commented 11 years ago

E.g. python manage.py shell --traceback

yunmanger1 commented 11 years ago
Traceback (most recent call last):
  File "/home/german/work/python/v3na/venv/local/lib/python2.7/site-packages/django/core/management/base.py", line 222, in run_from_argv
    self.execute(*args, **options.__dict__)
  File "/home/german/work/python/v3na/venv/local/lib/python2.7/site-packages/django/core/management/base.py", line 249, in execute
    saved_lang = translation.get_language()
  File "/home/german/work/python/v3na/venv/local/lib/python2.7/site-packages/django/utils/translation/__init__.py", line 114, in get_language
    return _trans.get_language()
  File "/home/german/work/python/v3na/venv/local/lib/python2.7/site-packages/django/utils/translation/__init__.py", line 47, in __getattr__
    if settings.USE_I18N:
  File "/home/german/work/python/v3na/venv/local/lib/python2.7/site-packages/django/conf/__init__.py", line 53, in __getattr__
    self._setup(name)
  File "/home/german/work/python/v3na/venv/local/lib/python2.7/site-packages/django/conf/__init__.py", line 48, in _setup
    self._wrapped = Settings(settings_module)
  File "/home/german/work/python/v3na/venv/local/lib/python2.7/site-packages/django/conf/__init__.py", line 152, in __init__
    raise ImproperlyConfigured("The SECRET_KEY setting must not be empty.")
ImproperlyConfigured: The SECRET_KEY setting must not be empty.
jezdez commented 11 years ago

Okay, I was able to reproduce the problem. Here is what I discovered:

First: importing the mongoengine library hid an error with the FileSettings helper function if the passed ~/.hedgehog/hedgehog.conf.py file doesn't exist. I created that file then.

Second: it seems like the culprit is what you do in the overridden __init__, something that triggers code that requires a fully loaded settings enviroment to exist (e.g. from django.contrib.sites.models import SITE_CACHE). Commenting that out made the whole thing work.

So all in all this is a problem since the __init__ is indeed required for the correct loading of the settings classes. So I would suggest to add a new hook that is called after the whole settings are setup, e.g. post_load or something that you could override and add your custom hooks into?

yunmanger1 commented 11 years ago

Thank you! Something like post_load would be nice. To prevent people from making the same mistake, maybe we should make __init__ non-overridable, if it is possible.

jezdez commented 11 years ago

@yunmanger1 Feel free to use the new post_setup method to do anything that requires Django models. See https://django-configurations.readthedocs.org/en/latest/#setup-methods for more information.

yunmanger1 commented 11 years ago

Cool. Thank you!