Merge remote-tracking branch 'joke2k/dot-env'

Signed-off-by: Jannis Leidel <jannis@leidel.info>

Conflicts:
	.gitignore
This commit is contained in:
Jannis Leidel 2015-01-06 21:42:36 +01:00
commit 01e3f5837f
7 changed files with 76 additions and 17 deletions

2
.gitignore vendored
View file

@ -7,4 +7,4 @@ build/
.tox/
htmlcov/
*.pyc
dist/
dist/

View file

@ -1,3 +1,5 @@
import os
import re
import warnings
from django.utils import six
@ -66,9 +68,53 @@ class Configuration(six.with_metaclass(ConfigurationBase)):
to the name of the class.
"""
DOTENV_LOADED = None
@classmethod
def load_dotenv(cls):
"""
Pulled from Honcho code with minor updates, reads local default
environment variables from a .env file located in the project root
or provided directory.
http://www.wellfireinteractive.com/blog/easier-12-factor-django/
https://gist.github.com/bennylope/2999704
"""
# check if the class has DOTENV set wether with a path or None
dotenv = getattr(cls, 'DOTENV', None)
# if DOTENV is falsy we want to disable it
if not dotenv:
return
# now check if we can access the file since we know we really want to
try:
with open(dotenv, 'r') as f:
content = f.read()
except IOError as e:
raise ImproperlyConfigured("Couldn't read .env file "
"with the path {}. Error: "
"{}".format(dotenv, e))
else:
for line in content.splitlines():
m1 = re.match(r'\A([A-Za-z_0-9]+)=(.*)\Z', line)
if not m1:
continue
key, val = m1.group(1), m1.group(2)
m2 = re.match(r"\A'(.*)'\Z", val)
if m2:
val = m2.group(1)
m3 = re.match(r'\A"(.*)"\Z', val)
if m3:
val = re.sub(r'\\(.)', r'\1', m3.group(1))
os.environ.setdefault(key, val)
cls.DOTENV_LOADED = dotenv
@classmethod
def pre_setup(cls):
pass
if cls.DOTENV_LOADED is None:
cls.load_dotenv()
@classmethod
def post_setup(cls):
@ -88,4 +134,4 @@ class Settings(Configuration):
# make sure to remove the handling of the Settings class above when deprecating
warnings.warn("configurations.Settings was renamed to "
"settings.Configuration and will be "
"removed in 1.0", PendingDeprecationWarning)
"removed in 1.0", DeprecationWarning)

1
test_project/.env Normal file
View file

@ -0,0 +1 @@
DJANGO_DOTENV_VALUE='is set'

View file

@ -160,20 +160,6 @@ class Base(Configuration):
}
}
INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.messages',
'django.contrib.staticfiles',
# Uncomment the next line to enable the admin:
# 'django.contrib.admin',
# Uncomment the next line to enable admin documentation:
# 'django.contrib.admindocs',
'configurations',
)
class Debug(Base):
YEAH = True

View file

@ -0,0 +1,8 @@
from configurations import Configuration, values
class DotEnvConfiguration(Configuration):
DOTENV = 'test_project/.env'
DOTENV_VALUE = values.Value()

View file

@ -3,9 +3,13 @@ import uuid
import django
from configurations import Configuration, pristinemethod
from configurations.values import BooleanValue
class Test(Configuration):
ENV_LOADED = BooleanValue(False)
DEBUG = True
SITE_ID = 1

14
tests/test_env.py Normal file
View file

@ -0,0 +1,14 @@
import os
from django.test import TestCase
from mock import patch
class DotEnvLoadingTests(TestCase):
@patch.dict(os.environ, clear=True,
DJANGO_CONFIGURATION='DotEnvConfiguration',
DJANGO_SETTINGS_MODULE='tests.settings.dot_env')
def test_env_loaded(self):
from tests.settings import dot_env
self.assertEqual(dot_env.DOTENV_VALUE, 'is set')
self.assertEqual(dot_env.DOTENV_LOADED, dot_env.DOTENV)