HBNetwork / python-decouple

Strict separation of config from code.
MIT License
2.79k stars 192 forks source link

Use of config() for DATABASE_URL from .env doesn't work as expected #112

Closed karlsaintlucy closed 2 years ago

karlsaintlucy commented 3 years ago

When I run config('DATABASE_URL') on the postgres:// URL from my .env, it returns the string enclosed in two nested sets of quotes. My workaround for the moment is to set DATABASE_URL = config('DATABASE_URL').replace("\'", "") before calling dj_database_url.parse() on the string in the DATABASES dict. This was unexpected, and doesn't seem to be how the functionality is spec'd out in the README.

In the Django shell:

>>> from decouple import config
>>> config('DATABASE_URL')
"'postgres://***:***@***:5432/***'"

In settings.py:

DATABASE_URL = config('DATABASE_URL').replace("\'", "")

DATABASES = {
    'default': dj_database_url.parse(DATABASE_URL, conn_max_age=600)
}

In .env:

DATABASE_URL=postgres://***:***@***:5432/***
henriquebastos commented 3 years ago

This is very strange. The testa would break with this behabior.

Which python version are you using? Can you provide a simple code that manifests this issue so I could run and reproduce the error?

karlsaintlucy commented 3 years ago

Hi yes, sure. Sorry it's taken me so long to write back.

In .env, I've got my database url configured using the string DATABASE_URL=postgres://xxx:xxx@xxx.xxx.xxx/xxx. I couldn't get it to work at all with the config sample in the documentation:

from decouple import config
from unipath import Path
from dj_database_url import parse as db_url

BASE_DIR = Path(__file__).parent

DEBUG = config('DEBUG', default=False, cast=bool)
TEMPLATE_DEBUG = DEBUG

DATABASES = {
    'default': config(
        'DATABASE_URL',
        default='sqlite:///' + BASE_DIR.child('db.sqlite3'),
        cast=db_url
    )
}

Here's the configuration I set up in settings.py:

DATABASE_URL = config('DATABASE_URL')
DATABASES = {}
DATABASES['default'] = dj_database_url.parse(DATABASE_URL, conn_max_age=600)

That produces the following traceback:

Traceback (most recent call last):
  File "manage.py", line 22, in <module>
    main()
  File "manage.py", line 18, in main
    execute_from_command_line(sys.argv)
  File "D:\xxx\xxx\venv\lib\site-packages\django\core\management\__init__.py", line 419, in execute_from_command_line
    utility.execute()
  File "D:\xxx\xxx\venv\lib\site-packages\django\core\management\__init__.py", line 363, in execute
    settings.INSTALLED_APPS
  File "D:\xxx\xxx\venv\lib\site-packages\django\conf\__init__.py", line 82, in __getattr__
    self._setup(name)
  File "D:\xxx\xxx\venv\lib\site-packages\django\conf\__init__.py", line 69, in _setup
    self._wrapped = Settings(settings_module)
  File "D:\xxx\xxx\venv\lib\site-packages\django\conf\__init__.py", line 170, in __init__
    mod = importlib.import_module(self.SETTINGS_MODULE)
  File "C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.8_3.8.2800.0_x64__qbz5n2kfra8p0\lib\importlib\__init__.py", line 127, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 1014, in _gcd_import
  File "<frozen importlib._bootstrap>", line 991, in _find_and_load
  File "<frozen importlib._bootstrap>", line 975, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 671, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 848, in exec_module
  File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
  File "D:\xxx\xxx\xxx\settings.py", line 57, in <module>
    DATABASES['default'] = dj_database_url.parse(DATABASE_URL, conn_max_age=600)
  File "D:\xxx\xxx\venv\lib\site-packages\dj_database_url.py", line 103, in parse
    engine = SCHEMES[url.scheme] if engine is None else engine
KeyError: ''

I noticed that when I ran the Django shell, I was getting the URL back as "'postgres://...'" and wondered if the interior set of quotes was maybe the issue. The following change in settings.py clears up the error:

DATABASE_URL = config('DATABASE_URL').replace('\'', '')

This is Python 3.8.10 running on Windows 10 with Django version 3.2.4 and dj-database-url version 0.5.0. I've run into this issue every time I've set up a new Django project with python-decouple on my machine, so the code you'd need to put in to reproduce the issue would be just the out-of-the-box config with the changes to the config I outlined. I haven't noticed any parsing issues with any other variables set in .env.

henriquebastos commented 2 years ago

Very strange. I couldn't reproduce the error. It's crashing on the parse function. It seems the value of you DATABASE_URL is not compatible with dj_database_url.