Skip to content

Commit

Permalink
Merge b349d54 into 315a33c
Browse files Browse the repository at this point in the history
  • Loading branch information
doismellburning committed Mar 2, 2015
2 parents 315a33c + b349d54 commit e6985f5
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -4,6 +4,7 @@

* Python 3.2 and 3.4 support
* Improved test suite - 100% coverage + flake8
* Multiple database support - `TEST_DATABASE_URL` will create `settings.DATABASES['test']`

## 1.2

Expand Down
4 changes: 4 additions & 0 deletions README.rst
Expand Up @@ -132,6 +132,10 @@ Uses
`dj-database-url <https://github.com/kennethreitz/dj-database-url>`__ -
parses ``DATABASE_URL`` if it exists, otherwise falls back to in-memory sqlite.

Anything of the form ``FOO_DATABASE_URL`` will be parsed as
``DATABASES['foo']``, allowing you to configure multiple databases via the
environment.

``ALLOWED_HOSTS``
~~~~~~~~~~~~~~~~~

Expand Down
30 changes: 30 additions & 0 deletions django12factor/__init__.py
Expand Up @@ -11,6 +11,7 @@
import dj_email_url
import os
import logging
import six
import sys

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -73,6 +74,35 @@ def factorise(custom_settings=None):
'default': dj_database_url.config(default='sqlite://:memory:')
}

for (key, value) in six.iteritems(os.environ):
_SUFFIX = "_DATABASE_URL"
_OFFSET = len(_SUFFIX)

if key.endswith(_SUFFIX):
prefix = key[:-_OFFSET]

if prefix != prefix.upper():
# i.e. it was not already all upper-cased
logger.warn(
"Not parsing %s as a database url because the "
"prefix (%s) was not all upper-case - django12factor "
"will convert prefixes to lower-case for use as database "
"names" % (key, prefix))
continue

dbname = key[:-_OFFSET].lower()

if dbname == "default" and 'DATABASE_URL' in os.environ:
logger.warn(
"You have set the environment variables DATABASE_URL "
"_and_ {key}, both of which would configure "
"`DATABASES['default']`. {key} is being "
"ignored.".format(key=key))
continue

db = dj_database_url.parse(os.environ[key])
settings['DATABASES'][dbname] = db

settings['DEBUG'] = getenv_bool('DEBUG')
if 'TEMPLATE_DEBUG' in os.environ:
settings['TEMPLATE_DEBUG'] = getenv_bool('TEMPLATE_DEBUG')
Expand Down
1 change: 1 addition & 0 deletions setup.py
Expand Up @@ -30,6 +30,7 @@
"dj-database-url==0.3.0",
"dj-email-url==0.0.2",
"django-cache-url==0.8.0",
"six",
),

tests_require=(
Expand Down
59 changes: 59 additions & 0 deletions tests/test_d12f.py
Expand Up @@ -65,3 +65,62 @@ def test_missing_custom_keys(self):
settings = d12f(['PRESENT', 'MISSING'])
self.assertEquals(present, settings['PRESENT'])
self.assertIsNone(settings['MISSING'])

def test_multiple_db_support(self):
DBNAME = "test"
DB_URL_NAME = "%s_DATABASE_URL" % DBNAME.upper()
e = {DB_URL_NAME: "postgres://username:password@host:1234/dbname"}

with debugenv(**e):
dbs = d12f()['DATABASES']
self.assertIn(
'sqlite',
dbs['default']['ENGINE'],
"Failed to load default DATABASE"
)
self.assertIn(
DBNAME,
dbs,
"Failed to parse a database called '%s' from the environment "
"variable %s" % (DBNAME, DB_URL_NAME)
)
self.assertIn('postgres', dbs[DBNAME]['ENGINE'])

def test_multiple_default_databases(self):
"""
Ensure if DEFAULT_DATABASE_URL and DATABASE_URL are set, latter wins.
"""

IGNORED_DB_NAME = "should_be_ignored"
DATABASE_URL = "postgres://username:password@host:1234/dbname"
IGNORED = "postgres://username:password@host:1234/%s" % IGNORED_DB_NAME

with debugenv(DATABASE_URL=DATABASE_URL, DEFAULT_DATABASE_URL=IGNORED):
default_db = d12f()['DATABASES']['default']
self.assertNotEquals(
default_db['NAME'],
IGNORED_DB_NAME,
"Parsed the contents of DEFAULT_DATABASE_URL instead of "
"ignoring it in favour of DATABASE_URL"
)

def test_non_capitalised_database_ignored(self):
"""
Ensure "malformed" X_DATABASE_URLs aren't parsed.
"""

e = {
'invalid_DATABASE_URL': "",
'AlsoInValid_DATABASE_URL': "",
'ALMOST_CORRECt_DATABASE_URL': "",
}

with debugenv(**e):
dbs = d12f()['DATABASES']

self.assertEquals(
len(dbs),
1,
"Loaded %d databases instead of just 1 (default) - got %s "
"from environment %s" % (len(dbs), dbs.keys(), e)
)

0 comments on commit e6985f5

Please sign in to comment.