Skip to content

Commit

Permalink
fix #491 pytest django Fix #491 pytest and django (#646)
Browse files Browse the repository at this point in the history
  • Loading branch information
rochacbruno committed Aug 20, 2021
1 parent 243a14e commit d71c02e
Show file tree
Hide file tree
Showing 52 changed files with 851 additions and 2 deletions.
1 change: 1 addition & 0 deletions Makefile
Expand Up @@ -49,6 +49,7 @@ test_examples:
cd example/jenkins_secrets_file;pwd;python app.py
cd example/specific_settings_files;pwd;python app.py
cd example/django_example/;pwd;python manage.py test polls -v 2
cd example/django_pytest/;pwd;pip install pytest-django;DJANGO_SETTINGS_MODULE=project.settings DJANGO_ENVIRONMENT=default pytest;pip uninstall -y pytest-django
cd example/django_example_compat/;pwd;python manage.py test polls -v 2
cd example/django_example/;pwd;PYTHONPATH=. DJANGO_SETTINGS_MODULE=foo.settings django-admin test polls -v 2
cd example/project_root/;pwd;rm -rf /tmp/dynaconf_project_root_test/settings.py;mkdir -p /tmp/dynaconf_project_root_test/;echo "MESSAGE = 'Hello from tmp'" > /tmp/dynaconf_project_root_test/settings.py;python app.py;rm -rf /tmp/dynaconf_project_root_test/
Expand Down
19 changes: 19 additions & 0 deletions docs/django.md
Expand Up @@ -209,6 +209,8 @@ print(settings.get('DATABASES'))

Django testing must work out of the box!

## Mocking envvars with django

But in some cases when you `mock` stuff and need to add `environment variables` to `os.environ` on demand for test cases it may be needed to `reload` the `dynaconf`.

To do that write up on your test case setup part:
Expand All @@ -227,6 +229,23 @@ class TestCase(...):
self.assertEqual(settings.FOO, 'BAR')
```

## Using pytest and django

Install `pip install pytest-django`

Add to your conftest.py

`project/tests/conftest.py`
```py
import pytest

@pytest.fixture(scope="session", autouse=True)
def set_test_settings():
# https://github.com/rochacbruno/dynaconf/issues/491#issuecomment-745391955
from django.conf import settings
settings.setenv('testing') # force the environment to be whatever you want
```

## Explicit mode

Some users have the preference to explicitly load each setting variable inside the `settings.py` and then let django manage it in the common way, it is possible.
Expand Down
2 changes: 2 additions & 0 deletions example/django_pytest/.env
@@ -0,0 +1,2 @@
DJANGO_SETTINGS_MODULE=project.settings
DJANGO_ENVIRONMENT=default
6 changes: 6 additions & 0 deletions example/django_pytest/.gitignore
@@ -0,0 +1,6 @@
.idea
/venv
/static
__pycache__
.cache
db.sqlite3
113 changes: 113 additions & 0 deletions example/django_pytest/README.md
@@ -0,0 +1,113 @@
# Reproduce pytest + dynaconf error

setup project
```
./setup.sh
```

run tests
```
./tests.sh
```

result
```python
=================================================================================================================================================== test session starts ====================================================================================================================================================
platform linux -- Python 3.6.9, pytest-5.4.3, py-1.10.0, pluggy-0.13.1
django: settings: project.settings (from ini)
rootdir: /home/alex/dje/django-pytest-dynaconf, inifile: pytest.ini
plugins: django-4.1.0
collected 1 item

app/tests/test_app.py E [100%]

========================================================================================================================================================== ERRORS ==========================================================================================================================================================
____________________________________________________________________________________________________________________________________________ ERROR at setup of test_admin_user _____________________________________________________________________________________________________________________________________________

request = <SubRequest '_django_db_marker' for <Function test_admin_user>>

@pytest.fixture(autouse=True)
def _django_db_marker(request):
"""Implement the django_db marker, internal to pytest-django.
This will dynamically request the ``db``, ``transactional_db`` or
``django_db_reset_sequences`` fixtures as required by the django_db marker.
"""
marker = request.node.get_closest_marker("django_db")
if marker:
transaction, reset_sequences = validate_django_db(marker)
if reset_sequences:
request.getfixturevalue("django_db_reset_sequences")
elif transaction:
request.getfixturevalue("transactional_db")
else:
> request.getfixturevalue("db")

venv/lib/python3.6/site-packages/pytest_django/plugin.py:436:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
venv/lib/python3.6/site-packages/pytest_django/fixtures.py:108: in django_db_setup
**setup_databases_args
venv/lib/python3.6/site-packages/django/test/utils.py:174: in setup_databases
serialize=connection.settings_dict.get('TEST', {}).get('SERIALIZE', True),
venv/lib/python3.6/site-packages/django/db/backends/base/creation.py:68: in create_test_db
run_syncdb=True,
venv/lib/python3.6/site-packages/django/core/management/__init__.py:110: in call_command
command = load_command_class(app_name, command_name)
venv/lib/python3.6/site-packages/django/core/management/__init__.py:36: in load_command_class
module = import_module('%s.management.commands.%s' % (app_name, name))
/usr/lib/python3.6/importlib/__init__.py:126: in import_module
return _bootstrap._gcd_import(name[level:], package, level)
venv/lib/python3.6/site-packages/django/core/management/commands/migrate.py:14: in <module>
from django.db.migrations.autodetector import MigrationAutodetector
venv/lib/python3.6/site-packages/django/db/migrations/autodetector.py:11: in <module>
from django.db.migrations.questioner import MigrationQuestioner
venv/lib/python3.6/site-packages/django/db/migrations/questioner.py:9: in <module>
from .loader import MigrationLoader
venv/lib/python3.6/site-packages/django/db/migrations/loader.py:8: in <module>
from django.db.migrations.recorder import MigrationRecorder
venv/lib/python3.6/site-packages/django/db/migrations/recorder.py:9: in <module>
class MigrationRecorder:
venv/lib/python3.6/site-packages/django/db/migrations/recorder.py:22: in MigrationRecorder
class Migration(models.Model):
venv/lib/python3.6/site-packages/django/db/models/base.py:101: in __new__
new_class.add_to_class('_meta', Options(meta, app_label))
venv/lib/python3.6/site-packages/django/db/models/options.py:101: in __init__
self.db_tablespace = settings.DEFAULT_TABLESPACE
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <dynaconf.base.LazySettings object at 0x7f251735c208>, name = 'DEFAULT_TABLESPACE'

def __getattr__(self, name):
"""Allow getting keys from self.store using dot notation"""
if self._wrapped is empty:
self._setup()
if name in self._wrapped._deleted: # noqa
raise AttributeError(
f"Attribute {name} was deleted, " "or belongs to different env"
)

if name not in RESERVED_ATTRS:
lowercase_mode = self._kwargs.get(
"LOWERCASE_READ_FOR_DYNACONF",
default_settings.LOWERCASE_READ_FOR_DYNACONF,
)
if lowercase_mode is True:
name = name.upper()

if (
name.isupper()
and (
self._wrapped._fresh
or name in self._wrapped.FRESH_VARS_FOR_DYNACONF
)
and name not in dir(default_settings)
):
return self._wrapped.get_fresh(name)
> value = getattr(self._wrapped, name)
E AttributeError: 'Settings' object has no attribute 'DEFAULT_TABLESPACE'

venv/lib/python3.6/site-packages/dynaconf/base.py:164: AttributeError
================================================================================================================================================= short test summary info ==================================================================================================================================================
ERROR app/tests/test_app.py::test_admin_user - AttributeError: 'Settings' object has no attribute 'DEFAULT_TABLESPACE'
===================================================================================================================================================== 1 error in 0.25s =====================================================================================================================================================
```
Empty file.
3 changes: 3 additions & 0 deletions example/django_pytest/app/admin.py
@@ -0,0 +1,3 @@
from django.contrib import admin

# Register your models here.
5 changes: 5 additions & 0 deletions example/django_pytest/app/apps.py
@@ -0,0 +1,5 @@
from django.apps import AppConfig


class AppConfig(AppConfig):
name = "app"
Empty file.
3 changes: 3 additions & 0 deletions example/django_pytest/app/models.py
@@ -0,0 +1,3 @@
from django.db import models

# Create your models here.
18 changes: 18 additions & 0 deletions example/django_pytest/app/templates/hello.html
@@ -0,0 +1,18 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>{{ title }}</title>
<style type="text/css" media="screen">
body {
font-family: sans-serif;
}
</style>
</head>
<body>
<p>{{ message }}</p>
<script type="text/javascript">
console.log('{{ message }}');
</script>
</body>
</html>
Empty file.
16 changes: 16 additions & 0 deletions example/django_pytest/app/tests/conftest.py
@@ -0,0 +1,16 @@
import pytest
from django.core.management import call_command


@pytest.fixture(scope="session", autouse=True)
def set_test_settings():
# https://github.com/rochacbruno/dynaconf/issues/491#issuecomment-745391955
from django.conf import settings

settings.setenv("pytest")


@pytest.fixture(scope="session")
def django_db_setup(django_db_setup, django_db_blocker):
with django_db_blocker.unblock():
call_command("loaddata", "project/fixtures/admin.json")
16 changes: 16 additions & 0 deletions example/django_pytest/app/tests/test_app.py
@@ -0,0 +1,16 @@
import django

django.setup() # noqa

import pytest

from django.contrib.auth import get_user_model
from django.conf import settings


@pytest.mark.django_db
def test_admin_user():
User = get_user_model()

assert User.objects.filter(username="admin").exists()
assert settings.FOO == "foo-test"
10 changes: 10 additions & 0 deletions example/django_pytest/app/urls.py
@@ -0,0 +1,10 @@
from app import views
from django.urls import include
from django.urls import path

# namespacing
app_name = "app"

urlpatterns = [
path(r"", views.HelloView.as_view(), name="hello"),
]
11 changes: 11 additions & 0 deletions example/django_pytest/app/views.py
@@ -0,0 +1,11 @@
from django.views.generic import TemplateView


class HelloView(TemplateView):
template_name = "hello.html"

def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["title"] = "Hello!"
context["message"] = "Hello world!"
return context
22 changes: 22 additions & 0 deletions example/django_pytest/manage.py
@@ -0,0 +1,22 @@
#!/usr/bin/env python
import os
import sys

if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "project.settings")
try:
from django.core.management import execute_from_command_line
except ImportError:
# The above import may fail for some other reason. Ensure that the
# issue is really that Django is missing to avoid masking other
# exceptions on Python 2.
try:
import django
except ImportError:
raise ImportError(
"Couldn't import Django. Are you sure it's installed and "
"available on your PYTHONPATH environment variable? Did you "
"forget to activate a virtual environment?"
)
raise
execute_from_command_line(sys.argv)
Empty file.
20 changes: 20 additions & 0 deletions example/django_pytest/project/fixtures/admin.json
@@ -0,0 +1,20 @@
[
{
"model": "auth.user",
"pk": 1,
"fields": {
"password": "pbkdf2_sha256$120000$hzEDlLe2T6O2$YVDIso96yOXVq6+IcD0Iy1K6He/x9lzM5IFQU64UeKg=",
"last_login": null,
"is_superuser": true,
"username": "admin",
"first_name": "",
"last_name": "",
"email": "",
"is_staff": true,
"is_active": true,
"date_joined": "2020-12-15T08:31:26.387Z",
"groups": [],
"user_permissions": []
}
}
]

0 comments on commit d71c02e

Please sign in to comment.