Giter Club home page Giter Club logo

django-environ's Introduction

django-environ

Latest version released on PyPi Coverage Status CI Status Sponsors on Open Collective Backers on Open Collective Say Thanks! Package license

django-environ is the Python package that allows you to use Twelve-factor methodology to configure your Django application with environment variables.

For that, it gives you an easy way to configure Django application using environment variables obtained from an environment file and provided by the OS:

import environ
import os

env = environ.Env(
    # set casting, default value
    DEBUG=(bool, False)
)

# Set the project base directory
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

# Take environment variables from .env file
environ.Env.read_env(os.path.join(BASE_DIR, '.env'))

# False if not in os.environ because of casting above
DEBUG = env('DEBUG')

# Raises Django's ImproperlyConfigured
# exception if SECRET_KEY not in os.environ
SECRET_KEY = env('SECRET_KEY')

# Parse database connection url strings
# like psql://user:[email protected]:8458/db
DATABASES = {
    # read os.environ['DATABASE_URL'] and raises
    # ImproperlyConfigured exception if not found
    #
    # The db() method is an alias for db_url().
    'default': env.db(),

    # read os.environ['SQLITE_URL']
    'extra': env.db_url(
        'SQLITE_URL',
        default='sqlite:////tmp/my-tmp-sqlite.db'
    )
}

CACHES = {
    # Read os.environ['CACHE_URL'] and raises
    # ImproperlyConfigured exception if not found.
    #
    # The cache() method is an alias for cache_url().
    'default': env.cache(),

    # read os.environ['REDIS_URL']
    'redis': env.cache_url('REDIS_URL')
}

The idea of this package is to unify a lot of packages that make the same stuff: Take a string from os.environ, parse and cast it to some of useful python typed variables. To do that and to use the 12factor approach, some connection strings are expressed as url, so this package can parse it and return a urllib.parse.ParseResult. These strings from os.environ are loaded from a .env file and filled in os.environ with setdefault method, to avoid to overwrite the real environ. A similar approach is used in Two Scoops of Django book and explained in 12factor-django article.

Using django-environ you can stop to make a lot of unversioned settings_*.py to configure your app. See cookiecutter-django for a concrete example on using with a django project.

Feature Support

  • Fast and easy multi environment for deploy
  • Fill os.environ with .env file variables
  • Variables casting
  • Url variables exploded to django specific package settings
  • Optional support for Docker-style file based config variables (use environ.FileAwareEnv instead of environ.Env)

Project Information

django-environ is released under the MIT / X11 License, its documentation lives at Read the Docs, the code on GitHub, and the latest release on PyPI.

It’s rigorously tested on Python 3.6+, and officially supports Django 1.11, 2.2, 3.0, 3.1, 3.2, 4.0, 4.1 and 4.2.

If you'd like to contribute to django-environ you're most welcome!

Support

Should you have any question, any remark, or if you find a bug, or if there is something you can't do with the django-environ, please open an issue.

django-environ's People

Contributors

ad-m avatar adamkal avatar browniebroke avatar burhan avatar cmheisel avatar dependabot[bot] avatar ei-grad avatar fdemmer avatar flipperpa avatar imomaliev avatar jnm avatar joehybird avatar joke2k avatar kylekaniecki avatar lanterno avatar legau avatar ljagged avatar lvanderree avatar max-arnold avatar maygrass avatar mcoconnor avatar mehdy avatar mjrimrie avatar mrodal avatar normic avatar rasulkireev avatar sergeyklay avatar simkimsia avatar smileychris avatar wongcht avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

django-environ's Issues

Python 2 broken by Python 3 compatibility commit

[ ei-grad@yoga ~/repos/django-environ ‹4325313*› ]
→ git diff
diff --git a/environ/test_env.txt b/environ/test_env.txt
index edb5ac5..ad75c12 100644
--- a/environ/test_env.txt
+++ b/environ/test_env.txt
@@ -20,3 +20,4 @@ INT_VAR=42
 STR_LIST_WITH_SPACES= foo,  bar
 STR_VAR=bar
 INT_LIST=42,33
+CYRILLIC_VAR=фуубар
[ ei-grad@yoga ~/repos/django-environ ‹4325313*› ]
→ git stash
Saved working directory and index state WIP on (no branch): 4325313 add support for python 3
HEAD is now at 4325313 add support for python 3
[ ei-grad@yoga ~/repos/django-environ ‹4325313› ]
→ nosetests2   
........................................
----------------------------------------------------------------------
Ran 40 tests in 0.033s

OK
[ ei-grad@yoga ~/repos/django-environ ‹4325313› ]
→ git stash pop
HEAD detached at 4325313
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   environ/test_env.txt

no changes added to commit (use "git add" and/or "git commit -a")
Dropped refs/stash@{0} (17f7d685907c5d156e2a0de7fba4401673a4cf9c)
[ ei-grad@yoga ~/repos/django-environ ‹4325313*› ]
→ nosetests2   
..................EEEEEEEEEEEEEEEEEE....
======================================================================
ERROR: test_bool_false (environ.test.FileEnvTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/ei-grad/repos/django-environ/environ/test.py", line 173, in setUp
    self.env.read_env(file_path, PATH_VAR=Path(__file__, is_file=True).__root__)
  File "/home/ei-grad/repos/django-environ/environ/environ.py", line 297, in read_env
    os.environ.setdefault(key, text_type(val))
UnicodeDecodeError: 'ascii' codec can't decode byte 0xd1 in position 0: ordinal not in range(128)
-------------------- >> begin captured logging << --------------------
/home/ei-grad/repos/django-environ/environ/environ.pyc: DEBUG: Read environment variables from file: /home/ei-grad/repos/django-environ/environ/test_env.txt
--------------------- >> end captured logging << ---------------------

<...>

----------------------------------------------------------------------
Ran 40 tests in 0.033s

FAILED (errors=18)
[ ei-grad@yoga ~/repos/django-environ ‹4325313*› ]
→ git stash && git co HEAD^ && git stash pop                                                              1 ↵
Saved working directory and index state WIP on (no branch): 4325313 add support for python 3
HEAD is now at 4325313 add support for python 3
Previous HEAD position was 4325313... add support for python 3
HEAD is now at cda8e72... fix travis script
HEAD detached at cda8e72
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   environ/test_env.txt

no changes added to commit (use "git add" and/or "git commit -a")
Dropped refs/stash@{0} (177a60be37f051761f4fe557122c198d8769b078)
[ ei-grad@yoga ~/repos/django-environ ‹cda8e72*› ]
→ nosetests2                                
........................................
----------------------------------------------------------------------
Ran 40 tests in 0.035s

OK

Improve documentation for read_env()

The readme briefly mentions read_env(), however it wasn't until reading the source that the following became apparent:

  • that the values read in from the .env file are overridden by any that already existed in the environment (I think this is handy, but isn't immediately obvious)
  • that read_env() also takes an overrides list
  • that read_env() updates os.environ directly, rather than just that particular Env instance (someone not realising this was intentional is what caused #66 to be filed)

It would be great to mention the above in the readme. If I get a chance to open a PR I will, but it may not be soon, so if anyone wants to do so in the meantime, go ahead :-)

Initialize .env with generated secret key

It would be great if django-environ could initialize .env file with secret key automatically generated.

I imagine, this could look like this:

import environ

environ.init(SECRET_KEY=environ.genpass())

environ.init would check if .env exists and if it is missing, then it would create new one with specified values. In this case, SECRET_KEY would be set with a random value. After initializing, environment variables would be read with read_env.

Add documentation for proxied values

With django-environ it's possible to have one environment variable refer to another, using this syntax:

CLOUDAMQP_URL=amqp://.....
BROKER_URL='$CLOUDAMQP_URL'

(Heroku escapes the environment variables, and so they are not expanded in os.environ, so this support from django-environ is very handy)

It would be good to document this feature in the readme :-)

filter/override query urls for db_url_config database "OPTIONS"

I'm trying to use django-environ in my project that will run in a PaaS offering (Cloud Foundry)
The DATABASE_URL is automatically populated with something similar to this:
mysql://123456:[email protected]:3306/ad_123456?reconnect=true

django-environ does take the query string reconnect=true and populates database OPTIONS with reconnect=true.
My problem is, that this option is not supported by mysqlclient and let to an exception:
reconnect=true is an invalid keyword argument for this function django databases

Anyway to filter/override unsupported database OPTIONS?
As a workaround I currently fallback to use dj-database-url which does not evaluate the query strings.

https://github.com/joke2k/django-environ/blob/develop/environ/environ.py#L374

if url.query:
    config_options = {}
    for k, v in urlparse.parse_qs(url.query).items():
        if k.upper() in cls._DB_BASE_OPTIONS:
            config.update({k.upper(): _cast_int(v[0])})
        else:
            config_options.update({k: _cast_int(v[0])})
    config['OPTIONS'] = config_options

Cache url for redis provide wrong LOCATION params.

I have following env var.
CACHE_URL=rediscache://broker:6379
Which is expanded by environ to following:
{'default': {'BACKEND': 'django_redis.cache.RedisCache',
'LOCATION': 'broker:6379'}}

But its incorrect.
django redis will give following error with this:
ConnectionError: Error 111 connecting to None:6379. Connection refused.

And if we look into django redis docks we will see following:
http://niwinz.github.io/django-redis/latest/

This is a examples of url format
redis://[:password]@localhost:6379/0
rediss://[:password]@localhost:6379/0
unix://[:password]@/path/to/socket.sock?db=0

And as you see scheme is needed. But environ dont pass scheme into location, so redis cache fails to work.

Im not sure for earlier version of django-redis, but current works like i described.

AttributeError: 'NoneType' object has no attribute 'find'

Using current PyPI django-environ release (v0.3.0):

>>> import environ
>>> env = environ.Env()
>>> env.url("FOO", default=None)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python2.7/site-packages/environ/environ.py", line 173, in url
    return self.get_value(var, cast=urlparse.urlparse, default=default, parse_default=True)
  File "/usr/lib/python2.7/site-packages/environ/environ.py", line 260, in get_value
    value = self.parse_value(value, cast)
  File "/usr/lib/python2.7/site-packages/environ/environ.py", line 308, in parse_value
    value = cast(value)
  File "/usr/lib/python2.7/urlparse.py", line 143, in urlparse
    tuple = urlsplit(url, scheme, allow_fragments)
  File "/usr/lib/python2.7/urlparse.py", line 182, in urlsplit
    i = url.find(':')
AttributeError: 'NoneType' object has no attribute 'find'

Expected:
It returns None like env("BAR", default=None) would.

EMAIL_USE_TLS and EMAIL_USE_SSL have no default value

My config broke when upgrading to version 0.4.0 because I had EMAIL_USE_TLS = email_config['EMAIL_USE_TLS'] in my settings file and that key does not exist when no tls is defined.

I think this should default to False, as wel as the EMAIL_USE_SSL entry.

Otherwise it would be a good idea to document how to use the email_url in your settings.

How to make django-environ work with uwsgi emperor?

I use this project with my django projection, deployed by uwsgi(emperor mode) + nginx, it worked well, thanks for your working, but when i touch the uwsgi config file, the env vars will not reload, for now, i can send signal 3 to the process which served my django app,, is there any good ways to make this done?

(sorry for my poor english...

Inline comments does not work

If you put

VARIABLE=SomeValue # Comment

in your .env file, the # Comment part is included in the value for VARIABLE, so its value becomes SomeValue # Comment.

does not load env variables from the .env file

I have an .env file (in same folder as manage.py) with:
DJANGO_DEBUG=False
DATABASE_URL=postgres://user:[email protected]:5432/dbname
POSTGRES_PASSWORD=pw
POSTGRES_USER=user
DJANGO_ADMIN_URL=r'^admin/'
DJANGO_SETTINGS_MODULE=config.settings.production
DJANGO_SECRET_KEY=7878078078078907890789087etc
DJANGO_ALLOWED_HOSTS=email.com
DJANGO_SERVER_EMAIL=[email protected]
DJANGO_SECURE_SSL_REDIRECT=False

But when I do:
python manage.py migrate --settings config.settings.production

I get:
django.core.exceptions.ImproperlyConfigured: Set the DJANGO_SECRET_KEY environment variable

Also env does not show any of the variables. The variables should have been loaded from my .env file right? So what's wrong?

BTW: I think the docs could be clearer on where to put the .env file and that is is loaded and when, I suppose. I looked elsewhere to find that that was indeed to be expected.

Typo doc

Hi,

In the documentation for the dict type, the prototype is this:

dict (BAR=key=val;foo=bar)

it should be this:

dict (BAR=key=val,foo=bar)

django-environ not installable under python 3.3

Running pip install django-environ in a python 3.3 (and other py3k) environment gives a syntax error:

Installing collected packages: Django, django-environ
  Running setup.py install for django-environ

      File "/home/lee/tmp/analyticshub/venv/lib/python3.3/site-packages/environ/test.py", line 237
        print "{0}={1}".format(key, value)
                      ^
    SyntaxError: invalid syntax

The print statement is now a function, ie print("{0}={1}".format(key, value))

read_env path

When running read_env without providing a filename, it looks for .env in the current directory (i.e. /project/project/.env), when providing a filename it looks in the parent directory (i.e. /project/.env/)

Shouldn't the behaviour be the same in both cases?

env file cannot have space around equals sign

I found out that I cannot do this in the .env file:

SOMEVAR = foo

but this works fine:

SOMEVAR=foo

is this by design? maybe a quick mention of this in the README because it confused me for a bit, I thought settings weren't being read, until I removed the spaces around the = sign.

MySQL strict mode

Hello,

Django 1.10 introduces:

?: (mysql.W002) MySQL Strict Mode is not set for database connection 'default'
    HINT: MySQL's Strict Mode fixes many data integrity problems in MySQL, such as data truncation upon insertion, by escalating warnings into errors. It is strongly recommended you activate it. See: https://docs.djangoproject.com/en/1.10/ref/databases/#mysql-sql-mode

It looks unsupported in django-environ unfortunately.

Greetings,

Why read_env reads everything to os.environ?

It looks quite suspicious that everything is read into global variable environ.Env.ENVIRON and even worse, environ.Env.ENVIRON points to os.eviron.

For global variables, if I will instantiate environ.Env two times, I would expect to get two independent environments, but currently, I will have two class instances operating on same global environment.

Is there a good reason for this?

support lower case options

Some backends use lowercase options. For example https://github.com/django-pylibmc/django-pylibmc

CACHES = {
    'default': {
        'BACKEND': 'django_pylibmc.memcached.PyLibMCCache',
        'LOCATION': 'localhost:11211',
        'TIMEOUT': 500,
        'BINARY': True,
        'OPTIONS': {  # Maps to pylibmc "behaviors"
            'tcp_nodelay': True,
            'ketama': True
        }
    }
}

So I create a protocol on the fly like so in settings:

environ.Env.CACHE_SCHEMES['django-pylibmc'] = 'django_pylibmc.memcached.PyLibMCCache'

and set my environment like so:

CACHE_URL=django-pylibmc://memcached:11211?tcp_nodelay=1&ketama=1

But it get's converted to uppercase like so:

opt = {k.upper(): _cast_int(v[0])}

Support section

It would be great if the file '.env' had support sections. So I would not have to keep repeating the same prefix (ZENDESK), as in:

ZENDESK_URL_COMPANY_NAME=xxx
ZENDESK_EMAIL=xxx
ZENDESK_PASSWORD=xx
ZENDESK_API_VERSION=2

Sections

[ZENDESK]
  URL_COMPANY_NAME=xxx
  EMAIL=xxx
  PASSWORD=xx
  API_VERSION=2

I did not see anything about it in the documentation, is there any solution to this ?

Documentation of Usage is Poor

It would be great for the documentation to clarify best practice usage, for example, it's unclear whether I should be importing variables from settings in a module or directly importing from Environ:

from django.conf import settings

my_var = settings.MY_VAR
...

For a tool born out of best-practices, it would be great if we could clean up the documentation with some use cases.

Cannot parse a list of tuples

Hi @joke2k ,

thanks for an awesome project!

I was looking for a way to get a list of tuples parsed e.g.
[('Bar', 'Bar'), ('Foo', 'Foo')]

This is as close as I can get:

MY_VAR='Bar,Bar;Foo,Foo'
MY_VAR = env.list('MY_VAR', default=[], cast=tuple)


('B', 'a', 'r'),
('B', 'a', 'r', ';', 'F', 'o', 'o'),
('F', 'o', 'o')]

Any tips how to deal with this?

Thanks,
Lena

Unspecified database properties default to `None` rather than the empty string

Using django-environ v0.4.0 on Python v2.7.10.

STR:

$ DATABASE_URL='mysql://root@localhost/test_db'
$ python
>>> import json
>>> import environ
>>> env = environ.Env()
>>> print(json.dumps(env.db_url('DATABASE_URL'), indent=2))

(Travis' MySQL setup has no password, hence the DATABASE_URL value above.)

Expected:

{
  "ENGINE": "django.db.backends.mysql",
  "NAME": "test_db",
  "HOST": "localhost",
  "USER": "root",
  "PASSWORD": "",
  "PORT": ""
}

...or else:

{
  "ENGINE": "django.db.backends.mysql",
  "NAME": "test_db",
  "HOST": "localhost",
  "USER": "root"
}

Django has defaults for those properties - which are the empty string: docs

Actual:

{
  "ENGINE": "django.db.backends.mysql",
  "NAME": "test_db",
  "HOST": "localhost",
  "USER": "root",
  "PASSWORD": null,
  "PORT": null
}

tests fail with Python 3.5

======================================================================
ERROR: test_bool_false (environ.test.FileEnvTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/<<PKGBUILDDIR>>/environ/test.py", line 213, in setUp
    self.env.read_env(file_path, PATH_VAR=Path(__file__, is_file=True).__root__)
  File "/<<PKGBUILDDIR>>/environ/environ.py", line 577, in read_env
    content = f.read()
  File "/usr/lib/python3.5/encodings/ascii.py", line 26, in decode
    return codecs.ascii_decode(input, self.errors)[0]
UnicodeDecodeError: 'ascii' codec can't decode byte 0xd1 in position 960: ordinal not in range(128)

======================================================================
ERROR: test_bool_true (environ.test.FileEnvTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/<<PKGBUILDDIR>>/environ/test.py", line 213, in setUp
    self.env.read_env(file_path, PATH_VAR=Path(__file__, is_file=True).__root__)
  File "/<<PKGBUILDDIR>>/environ/environ.py", line 577, in read_env
    content = f.read()
  File "/usr/lib/python3.5/encodings/ascii.py", line 26, in decode
    return codecs.ascii_decode(input, self.errors)[0]
UnicodeDecodeError: 'ascii' codec can't decode byte 0xd1 in position 960: ordinal not in range(128)

======================================================================
ERROR: test_cache_url_value (environ.test.FileEnvTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/<<PKGBUILDDIR>>/environ/test.py", line 213, in setUp
    self.env.read_env(file_path, PATH_VAR=Path(__file__, is_file=True).__root__)
  File "/<<PKGBUILDDIR>>/environ/environ.py", line 577, in read_env
    content = f.read()
  File "/usr/lib/python3.5/encodings/ascii.py", line 26, in decode
    return codecs.ascii_decode(input, self.errors)[0]
UnicodeDecodeError: 'ascii' codec can't decode byte 0xd1 in position 960: ordinal not in range(128)

======================================================================
ERROR: test_db_url_value (environ.test.FileEnvTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/<<PKGBUILDDIR>>/environ/test.py", line 213, in setUp
    self.env.read_env(file_path, PATH_VAR=Path(__file__, is_file=True).__root__)
  File "/<<PKGBUILDDIR>>/environ/environ.py", line 577, in read_env
    content = f.read()
  File "/usr/lib/python3.5/encodings/ascii.py", line 26, in decode
    return codecs.ascii_decode(input, self.errors)[0]
UnicodeDecodeError: 'ascii' codec can't decode byte 0xd1 in position 960: ordinal not in range(128)

======================================================================
ERROR: test_dict_parsing (environ.test.FileEnvTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/<<PKGBUILDDIR>>/environ/test.py", line 213, in setUp
    self.env.read_env(file_path, PATH_VAR=Path(__file__, is_file=True).__root__)
  File "/<<PKGBUILDDIR>>/environ/environ.py", line 577, in read_env
    content = f.read()
  File "/usr/lib/python3.5/encodings/ascii.py", line 26, in decode
    return codecs.ascii_decode(input, self.errors)[0]
UnicodeDecodeError: 'ascii' codec can't decode byte 0xd1 in position 960: ordinal not in range(128)

======================================================================
ERROR: test_dict_value (environ.test.FileEnvTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/<<PKGBUILDDIR>>/environ/test.py", line 213, in setUp
    self.env.read_env(file_path, PATH_VAR=Path(__file__, is_file=True).__root__)
  File "/<<PKGBUILDDIR>>/environ/environ.py", line 577, in read_env
    content = f.read()
  File "/usr/lib/python3.5/encodings/ascii.py", line 26, in decode
    return codecs.ascii_decode(input, self.errors)[0]
UnicodeDecodeError: 'ascii' codec can't decode byte 0xd1 in position 960: ordinal not in range(128)

======================================================================
ERROR: test_email_url_value (environ.test.FileEnvTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/<<PKGBUILDDIR>>/environ/test.py", line 213, in setUp
    self.env.read_env(file_path, PATH_VAR=Path(__file__, is_file=True).__root__)
  File "/<<PKGBUILDDIR>>/environ/environ.py", line 577, in read_env
    content = f.read()
  File "/usr/lib/python3.5/encodings/ascii.py", line 26, in decode
    return codecs.ascii_decode(input, self.errors)[0]
UnicodeDecodeError: 'ascii' codec can't decode byte 0xd1 in position 960: ordinal not in range(128)

======================================================================
ERROR: test_empty_list (environ.test.FileEnvTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/<<PKGBUILDDIR>>/environ/test.py", line 213, in setUp
    self.env.read_env(file_path, PATH_VAR=Path(__file__, is_file=True).__root__)
  File "/<<PKGBUILDDIR>>/environ/environ.py", line 577, in read_env
    content = f.read()
  File "/usr/lib/python3.5/encodings/ascii.py", line 26, in decode
    return codecs.ascii_decode(input, self.errors)[0]
UnicodeDecodeError: 'ascii' codec can't decode byte 0xd1 in position 960: ordinal not in range(128)

======================================================================
ERROR: test_float (environ.test.FileEnvTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/<<PKGBUILDDIR>>/environ/test.py", line 213, in setUp
    self.env.read_env(file_path, PATH_VAR=Path(__file__, is_file=True).__root__)
  File "/<<PKGBUILDDIR>>/environ/environ.py", line 577, in read_env
    content = f.read()
  File "/usr/lib/python3.5/encodings/ascii.py", line 26, in decode
    return codecs.ascii_decode(input, self.errors)[0]
UnicodeDecodeError: 'ascii' codec can't decode byte 0xd1 in position 960: ordinal not in range(128)

======================================================================
ERROR: test_int (environ.test.FileEnvTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/<<PKGBUILDDIR>>/environ/test.py", line 213, in setUp
    self.env.read_env(file_path, PATH_VAR=Path(__file__, is_file=True).__root__)
  File "/<<PKGBUILDDIR>>/environ/environ.py", line 577, in read_env
    content = f.read()
  File "/usr/lib/python3.5/encodings/ascii.py", line 26, in decode
    return codecs.ascii_decode(input, self.errors)[0]
UnicodeDecodeError: 'ascii' codec can't decode byte 0xd1 in position 960: ordinal not in range(128)

======================================================================
ERROR: test_int_list (environ.test.FileEnvTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/<<PKGBUILDDIR>>/environ/test.py", line 213, in setUp
    self.env.read_env(file_path, PATH_VAR=Path(__file__, is_file=True).__root__)
  File "/<<PKGBUILDDIR>>/environ/environ.py", line 577, in read_env
    content = f.read()
  File "/usr/lib/python3.5/encodings/ascii.py", line 26, in decode
    return codecs.ascii_decode(input, self.errors)[0]
UnicodeDecodeError: 'ascii' codec can't decode byte 0xd1 in position 960: ordinal not in range(128)

======================================================================
ERROR: test_int_tuple (environ.test.FileEnvTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/<<PKGBUILDDIR>>/environ/test.py", line 213, in setUp
    self.env.read_env(file_path, PATH_VAR=Path(__file__, is_file=True).__root__)
  File "/<<PKGBUILDDIR>>/environ/environ.py", line 577, in read_env
    content = f.read()
  File "/usr/lib/python3.5/encodings/ascii.py", line 26, in decode
    return codecs.ascii_decode(input, self.errors)[0]
UnicodeDecodeError: 'ascii' codec can't decode byte 0xd1 in position 960: ordinal not in range(128)

======================================================================
ERROR: test_int_with_none_default (environ.test.FileEnvTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/<<PKGBUILDDIR>>/environ/test.py", line 213, in setUp
    self.env.read_env(file_path, PATH_VAR=Path(__file__, is_file=True).__root__)
  File "/<<PKGBUILDDIR>>/environ/environ.py", line 577, in read_env
    content = f.read()
  File "/usr/lib/python3.5/encodings/ascii.py", line 26, in decode
    return codecs.ascii_decode(input, self.errors)[0]
UnicodeDecodeError: 'ascii' codec can't decode byte 0xd1 in position 960: ordinal not in range(128)

======================================================================
ERROR: test_json_value (environ.test.FileEnvTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/<<PKGBUILDDIR>>/environ/test.py", line 213, in setUp
    self.env.read_env(file_path, PATH_VAR=Path(__file__, is_file=True).__root__)
  File "/<<PKGBUILDDIR>>/environ/environ.py", line 577, in read_env
    content = f.read()
  File "/usr/lib/python3.5/encodings/ascii.py", line 26, in decode
    return codecs.ascii_decode(input, self.errors)[0]
UnicodeDecodeError: 'ascii' codec can't decode byte 0xd1 in position 960: ordinal not in range(128)

======================================================================
ERROR: test_not_present_with_default (environ.test.FileEnvTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/<<PKGBUILDDIR>>/environ/test.py", line 213, in setUp
    self.env.read_env(file_path, PATH_VAR=Path(__file__, is_file=True).__root__)
  File "/<<PKGBUILDDIR>>/environ/environ.py", line 577, in read_env
    content = f.read()
  File "/usr/lib/python3.5/encodings/ascii.py", line 26, in decode
    return codecs.ascii_decode(input, self.errors)[0]
UnicodeDecodeError: 'ascii' codec can't decode byte 0xd1 in position 960: ordinal not in range(128)

======================================================================
ERROR: test_not_present_without_default (environ.test.FileEnvTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/<<PKGBUILDDIR>>/environ/test.py", line 213, in setUp
    self.env.read_env(file_path, PATH_VAR=Path(__file__, is_file=True).__root__)
  File "/<<PKGBUILDDIR>>/environ/environ.py", line 577, in read_env
    content = f.read()
  File "/usr/lib/python3.5/encodings/ascii.py", line 26, in decode
    return codecs.ascii_decode(input, self.errors)[0]
UnicodeDecodeError: 'ascii' codec can't decode byte 0xd1 in position 960: ordinal not in range(128)

======================================================================
ERROR: test_path (environ.test.FileEnvTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/<<PKGBUILDDIR>>/environ/test.py", line 213, in setUp
    self.env.read_env(file_path, PATH_VAR=Path(__file__, is_file=True).__root__)
  File "/<<PKGBUILDDIR>>/environ/environ.py", line 577, in read_env
    content = f.read()
  File "/usr/lib/python3.5/encodings/ascii.py", line 26, in decode
    return codecs.ascii_decode(input, self.errors)[0]
UnicodeDecodeError: 'ascii' codec can't decode byte 0xd1 in position 960: ordinal not in range(128)

======================================================================
ERROR: test_proxied_value (environ.test.FileEnvTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/<<PKGBUILDDIR>>/environ/test.py", line 213, in setUp
    self.env.read_env(file_path, PATH_VAR=Path(__file__, is_file=True).__root__)
  File "/<<PKGBUILDDIR>>/environ/environ.py", line 577, in read_env
    content = f.read()
  File "/usr/lib/python3.5/encodings/ascii.py", line 26, in decode
    return codecs.ascii_decode(input, self.errors)[0]
UnicodeDecodeError: 'ascii' codec can't decode byte 0xd1 in position 960: ordinal not in range(128)

======================================================================
ERROR: test_str (environ.test.FileEnvTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/<<PKGBUILDDIR>>/environ/test.py", line 213, in setUp
    self.env.read_env(file_path, PATH_VAR=Path(__file__, is_file=True).__root__)
  File "/<<PKGBUILDDIR>>/environ/environ.py", line 577, in read_env
    content = f.read()
  File "/usr/lib/python3.5/encodings/ascii.py", line 26, in decode
    return codecs.ascii_decode(input, self.errors)[0]
UnicodeDecodeError: 'ascii' codec can't decode byte 0xd1 in position 960: ordinal not in range(128)

======================================================================
ERROR: test_str_list_with_spaces (environ.test.FileEnvTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/<<PKGBUILDDIR>>/environ/test.py", line 213, in setUp
    self.env.read_env(file_path, PATH_VAR=Path(__file__, is_file=True).__root__)
  File "/<<PKGBUILDDIR>>/environ/environ.py", line 577, in read_env
    content = f.read()
  File "/usr/lib/python3.5/encodings/ascii.py", line 26, in decode
    return codecs.ascii_decode(input, self.errors)[0]
UnicodeDecodeError: 'ascii' codec can't decode byte 0xd1 in position 960: ordinal not in range(128)

======================================================================
ERROR: test_url_value (environ.test.FileEnvTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/<<PKGBUILDDIR>>/environ/test.py", line 213, in setUp
    self.env.read_env(file_path, PATH_VAR=Path(__file__, is_file=True).__root__)
  File "/<<PKGBUILDDIR>>/environ/environ.py", line 577, in read_env
    content = f.read()
  File "/usr/lib/python3.5/encodings/ascii.py", line 26, in decode
    return codecs.ascii_decode(input, self.errors)[0]
UnicodeDecodeError: 'ascii' codec can't decode byte 0xd1 in position 960: ordinal not in range(128)

----------------------------------------------------------------------
Ran 76 tests in 0.019s

FAILED (errors=21)

Add external server

Hi again,

In our Django project we make ssh connections and scp to external server.

Now they are configured like this:

SERVERS = {
'asterisk': {
'HOST': 'my_host',
'PORT': '22',
'LOGIN': 'login',
'PASSWORD': 'password',
'PKEY': '/.ssh/id_rsa',
'PKEY_SECRET': ''
},
'archive': {
'HOST': 'host',
'PORT': '22',
'LOGIN': 'login',
'PASSWORD': 'password',
'PKEY': '
/.ssh/id_rsa',
'PKEY_SECRET': ''
}
}

What do you think about having something along env.db() (let's say env.server()) to manage this type of use case ?

Thanks !

Support for django-redis

In the CACHE_SCHEMES, both redis and rediscache map to redis_cache.cache.RedisCache, referring to django-redis-cache. For comparison sake, in the django-cache-url project, redis and hiredis both map to django_redis.cache.RedisCache, referring to django-redis.

Is there a reason that, in django-environ, one of these (or perhaps a new scheme) couldn't map to django_redis.cache.RedisCache?

Or is there a particularly strong reason for preferring django-redis-cache over django-redis?

db_url does not handle '#' in password?

I'm trying to configure a database password that happens to contain a #. Is that character not supported in this package's processing of the database url? When I alter the test_postgres_parsing in test.py so that the password contains that character, eg wegauwhgeuioweg --> weg#auwhgeuioweg, the test encounters this error:

ERROR: test_postgres_parsing (environ.test.DatabaseTestSuite)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "c:\projects\django-environ\environ\test.py", line 241, in test_postgres_parsing
    url = Env.db_url_config(url)
  File "c:\projects\django-environ\environ\environ.py", line 371, in db_url_config
    'PORT': _cast_int(url.port),
  File "C:\Python27\Lib\urlparse.py", line 113, in port
    port = int(port, 10)
ValueError: invalid literal for int() with base 10: 'weg'

I've found that other special chars, such as these: }{)(}|!\^><; can be embedded in the database password and not break the test. For example, when I alter the password from wegauwhgeuioweg to :wegauw}{)(}|!\^><;hgeuioweg on lines 238 and 245 of the test case in test.py, no tests fail.

My environment is python 2.7.10.

Summary: Is it true that a # included in the db password will corrupt the db url?

Add LDAP DB url

Hi,

I'm using django-ldapdb in my project, so I have to add an ldap db to my DATABASES var.

Do you think it would be possible for django-environ to support it ?

Thanks !

Is this being maintained?

Hi,

just wondering if this is still being maintained. I notice that there are some old pull requests and issues without comments.

Logger object name is the filepath rather than the module name

From https://docs.python.org/2/library/logging.html#logger-objects :

The name is potentially a period-separated hierarchical value, like foo.bar.baz (though it could also be just plain foo, for example). Loggers that are further down in the hierarchical list are children of loggers higher up in the list. For example, given a logger with a name of foo, loggers with names of foo.bar, foo.bar.baz, and foo.bam are all descendants of foo. The logger name hierarchy is analogous to the Python package hierarchy, and identical to it if you organise your loggers on a per-module basis using the recommended construction logging.getLogger(__name__). That’s because in a module, __name__ is the module’s name in the Python package namespace.

Whereas at the moment, the logger object is instantiated using:

logger = logging.getLogger(__file__)

When using logging_tree to inspect the available logging objects, this results in:

>>> import requests
>>> import environ
>>> import logging_tree
>>> logging_tree.printout()
<--""
   Level WARNING
   |
   o<--[/home/vagrant/venv/local/lib/python2]
   |   |
   |   o<--[/home/vagrant/venv/local/lib/python2.7/site-packages/environ/environ]
   |       |
   |       o<--"/home/vagrant/venv/local/lib/python2.7/site-packages/environ/environ.pyc"
   |           Level NOTSET so inherits level WARNING
   |
   o<--"requests"
       Level NOTSET so inherits level WARNING
       Handler <logging.NullHandler object at 0xb6ed5f6c>
       |
       o<--[requests.packages]
           |
           o<--"requests.packages.urllib3"
               Level NOTSET so inherits level WARNING
               Handler <logging.NullHandler object at 0xb6ed5f0c>
               |
               o<--"requests.packages.urllib3.connectionpool"
               |   Level NOTSET so inherits level WARNING
               |
               o<--"requests.packages.urllib3.poolmanager"
               |   Level NOTSET so inherits level WARNING
               |
               o<--[requests.packages.urllib3.util]
                   |
                   o<--"requests.packages.urllib3.util.retry"
                       Level NOTSET so inherits level WARNING
>>>

ie: The logger name is /home/vagrant/venv/local/lib/python2.7/site-packages/environ/environ.pyc rather than environ (and compare to what is shown for requests).

EMAIL_URL example

Hi,

It would be great to have an EMAIL_URL sample to see what syntax it accept, like for DATABASE_URL.

For example does it support username with an @ in it ?
Where do I put the smtp server + port ?

Thanks for this awesome project !

RFC -- import all DJANGO__* variables from environment

Hi! I have a new package I'm thinking of releasing, but that could also make sense to just fold into django-environ if you want it. I'd love to get your thoughts.

The basic idea is, instead of explicitly having to add DEBUG = env('DEBUG') to your settings.py file, you keep it as DEBUG = False. Then set DJANGO__bool__DEBUG=True in the environment and the setting gets picked up automatically.

This also works for sub-settings and for any data type supported by django-environ, so any of these are valid:

DJANGO__SECRET_KEY=secret
POSTGRES=postgres://uf07k1:[email protected]:5431/d8r82722
DJANGO__db__DATABASES__default=$POSTGRES
DJANGO__TEMPLATES__0__OPTIONS__context_processors__1='my.context.processor'

This works by adding a couple of lines at the bottom of your settings.py file or module:

import django_env_overrides
django_env_overrides.apply_to(globals())

Advantages are:

  • You don't have to anticipate every setting you might want to override. If you suddenly want to try setting DEBUG_PROPAGATE_EXCEPTIONS=True on production, you just do heroku config:set DJANGO__bool__DEBUG_PROPAGATE_EXCEPTIONS=True and it's done.
  • It's easy to have an app that runs in both 12-factor and non-12-factor environments. To deploy a non-12-factor app to Heroku, just add a buildpack that runs echo "import django_env_overrides; django_env_overrides.apply_to(globals())" >> settings.py

I have this ready to release here:

https://github.com/jcushman/django-env-overrides

But honestly I'd be just as happy to fold it into django-environ. Any thoughts about:

  • whether it makes sense to fold into this package, and
  • whether there's anything I should consider before releasing it as a separate package?

Thanks!

How to get HOME dir path

I want to get HOME DIR path in my settings file expanduser works but as I am using django-environ now can you tell me how to do that using the same.

When I tried : 'environ.Path('/') and environ.Path('~')' But no luck.

DATABASE_UR postgresql alias: pgsql | psql

Using psql instead of pgsql, as the postgresql alias in the DATABASE_URL::

DATABASE_URL=psql://postgres@localhost/db_name

results in the following error::

...
File "/home/virtualenvs/odl_datasets_survey/local/lib/python2.7/site-packages/south/models.py", line 2, in <module>
  from south.db import DEFAULT_DB_ALIAS
File "/home/virtualenvs/odl_datasets_survey/local/lib/python2.7/site-packages/south/db/__init__.py", line 84, in <module>
  db = dbs[DEFAULT_DB_ALIAS]
KeyError: 'default'

Environment variables starting with $ cause a recursion error

This SECRET_KEY declaration causes a maximum recursion depth exceeded error. (Note: I never used this secret key value anywhere since I was just starting the project)

SECRET_KEY = env("DJANGO_SECRET_KEY", default='$%ify^q7jg*o7(5me*g%+ae-7_1iy)gey*#eo%3c##-=1d=6mb')

Results in:

...snip...
  File "/Users/chromakey/.virtualenvs/xxxx/lib/python3.4/site-packages/environ/environ.py", line 260, in get_value
    value = self.get_value(value, cast=cast, default=default)
  File "/Users/chromakey/.virtualenvs/xxxx/lib/python3.4/site-packages/environ/environ.py", line 260, in get_value
    value = self.get_value(value, cast=cast, default=default)
  File "/Users/chromakey/.virtualenvs/xxxx/lib/python3.4/site-packages/environ/environ.py", line 249, in get_value
    value = os.environ[var]
  File "/Users/chromakey/.virtualenvs/xxxx/bin/../lib/python3.4/os.py", line 630, in __getitem__
    value = self._data[self.encodekey(key)]
RuntimeError: maximum recursion depth exceeded

This however, causes no error:

SECRET_KEY = env("DJANGO_SECRET_KEY", default='%ify^q7jg*o7(5me*g%+ae-7_1iy)gey*#eo%3c##-=1d=6mb')

Obviously not a blocker for me on anything, but thought I'd let you know. Thanks!

using default with proxied values leads to recursion

similar to #60 except I want to use a proxied value.

example:

DATABASES = {
    'default': env.db_url('DATABASE_URL', default='postgis://ubuntu@localhost/postgres'),
    'local': env.db_url('LOCAL_DATABASE_URL', default='$DATABASE_URL'),
}

I want to set local to be the same default if the environment isn't set. If I get it a default value it won't use the same one as DATABASE_URL

...
  File "/usr/local/lib/python2.7/site-packages/environ/environ.py", line 260, in get_value
    value = self.get_value(value, cast=cast, default=default)
  File "/usr/local/lib/python2.7/site-packages/environ/environ.py", line 260, in get_value
    value = self.get_value(value, cast=cast, default=default)
  File "/usr/local/lib/python2.7/site-packages/environ/environ.py", line 260, in get_value
    value = self.get_value(value, cast=cast, default=default)
  File "/usr/local/lib/python2.7/site-packages/environ/environ.py", line 260, in get_value
    value = self.get_value(value, cast=cast, default=default)
  File "/usr/local/lib/python2.7/site-packages/environ/environ.py", line 260, in get_value
    value = self.get_value(value, cast=cast, default=default)
  File "/usr/local/lib/python2.7/site-packages/environ/environ.py", line 260, in get_value
    value = self.get_value(value, cast=cast, default=default)
  File "/usr/local/lib/python2.7/site-packages/environ/environ.py", line 260, in get_value
    value = self.get_value(value, cast=cast, default=default)
  File "/usr/local/lib/python2.7/site-packages/environ/environ.py", line 260, in get_value
    value = self.get_value(value, cast=cast, default=default)
  File "/usr/local/lib/python2.7/site-packages/environ/environ.py", line 260, in get_value
    value = self.get_value(value, cast=cast, default=default)
  File "/usr/local/lib/python2.7/site-packages/environ/environ.py", line 260, in get_value
    value = self.get_value(value, cast=cast, default=default)
...

error of collectstatic for AttributeError: 'Path' object has no attribute 'startswith'

Question: Why I have to use root property of Path instance?

1. First try

# settings.py
STATIC_ROOT = root.path('collected_static/')
STATICFILES_DIRS = [
    root.path("web/static"),
    ("components", root.path("bower_components/")),
]

then, run collectstatic command print out:

Traceback (most recent call last):
  File "./manage.py", line 12, in <module>
    execute_from_command_line(sys.argv)
  File "/Users/raccoony/.pyenv/versions/3.5.0/envs/box/lib/python3.5/site-packages/django/core/management/__init__.py", line 353, in execute_from_command_line
    utility.execute()
  File "/Users/raccoony/.pyenv/versions/3.5.0/envs/box/lib/python3.5/site-packages/django/core/management/__init__.py", line 345, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/Users/raccoony/.pyenv/versions/3.5.0/envs/box/lib/python3.5/site-packages/django/core/management/__init__.py", line 195, in fetch_command
    klass = load_command_class(app_name, subcommand)
  File "/Users/raccoony/.pyenv/versions/3.5.0/envs/box/lib/python3.5/site-packages/django/core/management/__init__.py", line 40, in load_command_class
    return module.Command()
  File "/Users/raccoony/.pyenv/versions/3.5.0/envs/box/lib/python3.5/site-packages/django/contrib/staticfiles/management/commands/collectstatic.py", line 32, in __init__
    self.storage.path('')
  File "/Users/raccoony/.pyenv/versions/3.5.0/envs/box/lib/python3.5/site-packages/django/utils/functional.py", line 204, in inner
    self._setup()
  File "/Users/raccoony/.pyenv/versions/3.5.0/envs/box/lib/python3.5/site-packages/django/contrib/staticfiles/storage.py", line 394, in _setup
    self._wrapped = get_storage_class(settings.STATICFILES_STORAGE)()
  File "/Users/raccoony/.pyenv/versions/3.5.0/envs/box/lib/python3.5/site-packages/django/contrib/staticfiles/storage.py", line 39, in __init__
    *args, **kwargs)
  File "/Users/raccoony/.pyenv/versions/3.5.0/envs/box/lib/python3.5/site-packages/django/core/files/storage.py", line 185, in __init__
    self.location = abspathu(self.base_location)
  File "/Users/raccoony/.pyenv/versions/3.5.0/lib/python3.5/posixpath.py", line 357, in abspath
    if not isabs(path):
  File "/Users/raccoony/.pyenv/versions/3.5.0/lib/python3.5/posixpath.py", line 64, in isabs
    return s.startswith(sep)
AttributeError: 'Path' object has no attribute 'startswith'

when I print out STATICFILES_DIRS

[<Path:/Users/raccoony/smartstudy/box/web/static>, ('components', <Path:/Users/raccoony/smartstudy/box/bower_components>)]

not path strings but Path instaces.

2. so I tried root property

# settings.py (modeified)
STATIC_ROOT = root.path('collected_static/').root
STATICFILES_DIRS = [
    root.path("web/static").root,
    ("components", root.path("bower_components/").root),
]

then, run collectstatic will be:

Traceback (most recent call last):
  File "./manage.py", line 12, in <module>
    execute_from_command_line(sys.argv)
  File "/Users/raccoony/.pyenv/versions/3.5.0/envs/box/lib/python3.5/site-packages/django/core/management/__init__.py", line 353, in execute_from_command_line
    utility.execute()
  File "/Users/raccoony/.pyenv/versions/3.5.0/envs/box/lib/python3.5/site-packages/django/core/management/__init__.py", line 345, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/Users/raccoony/.pyenv/versions/3.5.0/envs/box/lib/python3.5/site-packages/django/core/management/__init__.py", line 195, in fetch_command
    klass = load_command_class(app_name, subcommand)
  File "/Users/raccoony/.pyenv/versions/3.5.0/envs/box/lib/python3.5/site-packages/django/core/management/__init__.py", line 40, in load_command_class
    return module.Command()
  File "/Users/raccoony/.pyenv/versions/3.5.0/envs/box/lib/python3.5/site-packages/django/contrib/staticfiles/management/commands/collectstatic.py", line 32, in __init__
    self.storage.path('')
  File "/Users/raccoony/.pyenv/versions/3.5.0/envs/box/lib/python3.5/site-packages/django/utils/functional.py", line 204, in inner
    self._setup()
  File "/Users/raccoony/.pyenv/versions/3.5.0/envs/box/lib/python3.5/site-packages/django/contrib/staticfiles/storage.py", line 394, in _setup
    self._wrapped = get_storage_class(settings.STATICFILES_STORAGE)()
  File "/Users/raccoony/.pyenv/versions/3.5.0/envs/box/lib/python3.5/site-packages/django/contrib/staticfiles/storage.py", line 37, in __init__
    check_settings(base_url)
  File "/Users/raccoony/.pyenv/versions/3.5.0/envs/box/lib/python3.5/site-packages/django/contrib/staticfiles/utils.py", line 58, in check_settings
    (settings.MEDIA_ROOT == settings.STATIC_ROOT)):
  File "/Users/raccoony/.pyenv/versions/3.5.0/envs/box/lib/python3.5/site-packages/environ/environ.py", line 670, in __eq__
    return self.__root__ == other.__root__
AttributeError: 'str' object has no attribute '__root__'

3. I used root property to MEDIA_ROOT too.

# settings.py (2nd modified)
STATIC_ROOT = root.path('collected_static/').root
STATICFILES_DIRS = [
    root.path("web/static").root,
    ("components", root.path("bower_components/").root),
]

MEDIA_ROOT = root.path("media").root

then, collectstatic runs without error.

support for inheritance in env

support such that I have multiple environment files,

  • base
  • development
  • staging
  • production

base to have common variables
and the rest to have specific variables and also have all base variables and can also override base variable

Support setting the OPTIONS SSL dict via the query string for MySQL

When using django-environ with MySQL RDS, the absolute path to the certificate bundle has to be set manually like so:

env = environ.Env()
DATABASES = {
    'default': env.db_url()
}
DATABASES['default']['OPTIONS'] = {
    'ssl': {'ca': '/app/foo/bar/mysql-ssl-ca-cert.pem'}
}

...since it's not possible to specify a dict via django-environ's query string option feature.

I see two ways this could be supported:

  1. Try to json.loads() the value for each key specified in the query string.
  2. Add an alias for the ssl ca setting specifically (eg mysql://...?sslca=/app/foo/bar/mysql-ssl-ca-cert.pem) that django-environ uses to construct the ssl options dict

Would a PR for one of the above (or any other suggested approach) be accepted? :-)
(I would personally prefer the second approach)

Can't set CONN_MAX_AGE to None

When setting DATABASE_URL to something like postgres://posgres@db:5432/postgres?conn_max_age=None the end result is:

{
    'ENGINE': 'django.db.backends.postgresql_psycopg2',
    'HOST': 'db'
    'PORT': 5432,
    'USER': 'postgres',
    'PASSWORD': None,
    'NAME': 'postgres',
    'CONN_MAX_AGE': 'None',
    'OPTIONS': {},
}

Where CONN_MAX_AGE has an invalid value: it has to be set to either a float or None, but django-environ returns a str.

ImproperlyConfigured exception when running django-admin.py flush

When running the command django-admin.py flush I get the following error:

django.core.exceptions.ImproperlyConfigured: Requested setting USE_I18N, but settings are not configured. You must either define the environment variable DJANGO_SETTINGS_MODULE or call settings.configure() before accessing settings.

django.core.exceptions.ImproperlyConfigured: Requested setting DATABASES, but settings are not configured. You must either define the environment variable DJANGO_SETTINGS_MODULE or call settings.configure() before accessing settings.

In project_directory/settings.py I have:

USE_I18N = True
DATABASES = { 'default': env.db()}

In root_directory/.env I have:

DATABASE_URL=postgresql://postgres_user:postgres_password@localhost:5432/postgres_database

I can run other django-admin.py commands without any issues (e.g. django-admin.py startapp test_app), and I can also run manage.py commands without any issues (e.g. python manage.py createsuperuser). It seems to be only the django-admin.py flush command that doesn't work.

Here is the full stacktrace:

Traceback (most recent call last):
  File "/dev/django-project/venv/lib/python3.5/site-packages/django/core/management/base.py", line 348, in run_from_argv
    self.execute(*args, **cmd_options)
  File "/dev/django-project/venv/lib/python3.5/site-packages/django/core/management/base.py", line 391, in execute
    saved_locale = translation.get_language()
  File "/dev/django-project/venv/lib/python3.5/site-packages/django/utils/translation/__init__.py", line 176, in get_language
    return _trans.get_language()
  File "/dev/django-project/venv/lib/python3.5/site-packages/django/utils/translation/__init__.py", line 57, in __getattr__
    if settings.USE_I18N:
  File "/dev/django-project/venv/lib/python3.5/site-packages/django/conf/__init__.py", line 55, in __getattr__
    self._setup(name)
  File "/dev/django-project/venv/lib/python3.5/site-packages/django/conf/__init__.py", line 41, in _setup
    % (desc, ENVIRONMENT_VARIABLE))
django.core.exceptions.ImproperlyConfigured: Requested setting USE_I18N, but settings are not configured. You must either define the environment variable DJANGO_SETTINGS_MODULE or call settings.configure() before accessing settings.

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/dev/django-project/venv/bin/django-admin.py", line 5, in <module>
    management.execute_from_command_line()
  File "/dev/django-project/venv/lib/python3.5/site-packages/django/core/management/__init__.py", line 353, in execute_from_command_line
    utility.execute()
  File "/dev/django-project/venv/lib/python3.5/site-packages/django/core/management/__init__.py", line 345, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/dev/django-project/venv/lib/python3.5/site-packages/django/core/management/base.py", line 360, in run_from_argv
    connections.close_all()
  File "/dev/django-project/venv/lib/python3.5/site-packages/django/db/utils.py", line 230, in close_all
    for alias in self:
  File "/dev/django-project/venv/lib/python3.5/site-packages/django/db/utils.py", line 224, in __iter__
    return iter(self.databases)
  File "/dev/django-project/venv/lib/python3.5/site-packages/django/utils/functional.py", line 33, in __get__
    res = instance.__dict__[self.name] = self.func(instance)
  File "/dev/django-project/venv/lib/python3.5/site-packages/django/db/utils.py", line 157, in databases
    self._databases = settings.DATABASES
  File "/dev/django-project/venv/lib/python3.5/site-packages/django/conf/__init__.py", line 55, in __getattr__
    self._setup(name)
  File "/dev/django-project/venv/lib/python3.5/site-packages/django/conf/__init__.py", line 41, in _setup
    % (desc, ENVIRONMENT_VARIABLE))
django.core.exceptions.ImproperlyConfigured: Requested setting DATABASES, but settings are not configured. You must either define the environment variable DJANGO_SETTINGS_MODULE or call settings.configure() before accessing settings.

In case it's relevant, here is my wsgi.py file:

import os

from django.core.wsgi import get_wsgi_application
from dj_static import Cling, MediaCling

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "project.settings")

application = Cling(MediaCling(get_wsgi_application()))

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.