Django: settings for tests of a reusable app? - django

I created a small app in Django and runserver and admin works fine.
I wrote some tests which can call with python manage.py test and the tests pass.
Now I would like to call one particular test via PyCharm.
This fails like this:
/home/guettli/x/venv/bin/python
/snap/pycharm-community/179/plugins/python-ce/helpers/pycharm/_jb_pytest_runner.py
--path /home/guettli/x/xyz/tests.py
Launching pytest with arguments /home/guettli/x/xyz/tests.py in /home/guettli/x
============================= test session starts ==============================
platform linux -- Python 3.6.9, pytest-5.4.1, py-1.8.1, pluggy-0.13.1 --
cachedir: .pytest_cache
rootdir: /home/guettli/x
collecting ...
xyz/tests.py:None (xyz/tests.py)
xyz/tests.py:6: in <module>
from . import views
xyz/views.py:5: in <module>
from xyz.models import Term, SearchLog, GlobalConfig
xyz/models.py:1: in <module>
from django.contrib.auth.models import User
venv/lib/python3.6/site-packages/django/contrib/auth/models.py:2: in <module>
from django.contrib.auth.base_user import AbstractBaseUser, BaseUserManager
venv/lib/python3.6/site-packages/django/contrib/auth/base_user.py:47: in <module>
class AbstractBaseUser(models.Model):
venv/lib/python3.6/site-packages/django/db/models/base.py:107: in __new__
app_config = apps.get_containing_app_config(module)
venv/lib/python3.6/site-packages/django/apps/registry.py:252: in get_containing_app_config
self.check_apps_ready()
venv/lib/python3.6/site-packages/django/apps/registry.py:134: in check_apps_ready
settings.INSTALLED_APPS
venv/lib/python3.6/site-packages/django/conf/__init__.py:76: in __getattr__
self._setup(name)
venv/lib/python3.6/site-packages/django/conf/__init__.py:61: in _setup
% (desc, ENVIRONMENT_VARIABLE))
E django.core.exceptions.ImproperlyConfigured: Requested setting INSTALLED_APPS,
but settings are not configured. You must either define the environment variable
DJANGO_SETTINGS_MODULE or call settings.configure() before accessing settings.
Assertion failed
collected 0 items / 1 error
I understand the background: My app xyz is reusable. It does not contain any settings.
The app does not know (and should not know) my project. But the settings are in my project.
How to solve this?
I read the great django docs, but could not find a solution.
How to set DJANGO_SETTINGS_MODULE if you execute one particular test directly from PyCharm with "Run" (ctrl-shift-F10)?

You can add DJANGO_SETTINGS_MODULE as an environmental variable:
In the menu: Run -> Edit Configurations -> Templates -> Python Tests -> Unittests
And delete old "Unittests for tests...." entries.

You can specify the settings in your test command
Assuming your in the xyz directory, and the structure is
/xyz
- manage.py
- xyz/
- settings.py
The following command should work
python manage.py test --settings=xyz.settings

Edited: For this method to work django support should me enabled in pycharm. I guess it should be possible to setup the equivalent template in the community edition version of pycharm.
Method with django support enabled:
I find that the most convenient way that also allow you to directly click on a particular test case and run it directly within pycharm without having to set the settings every time is to do the following:
->Edit configuration (Run/Debug configurations)
->Templates and select "Django Tests"
->Tick "Custom settings" and then browse to the settings you want use.
Then when you launch tests directly within pycharm it will use it as a template.
If you test with any other supported method by pycharm, you can pick testing framework in pycharm: Choose testing framework
and then create a template for it.

If you use django and pytest, then I recommend the plugin pytest-django
It provides a simple way to set DJANGO_SETTINGS_MODULE via configuration.
See configuring django
[pytest]
DJANGO_SETTINGS_MODULE = test_settings

Related

PyCharm doesn't resolve Django apps but the project works

This is the project structure generated from having run django-admin startproject school and python manage.py startapp quiz:
In INSTALLED_APPS I've added:
"quiz.apps.QuizConfig",
In order for this project to execute correctly, in school/quiz/views.py I have to import e.g. models from quiz.models instead of the commonly seen school.quiz.models. Otherwise the project fails to run:
As you can see above, PyCharm doesn't recognize quiz. It wants me to use school.quiz instead, but when I do that the project doesn't run:
File "/.../Code/breather/school/school/urls.py", line 19, in <module>
from quiz.views import QuestionView
File "/.../Code/breather/school/quiz/views.py", line 6, in <module>
from school.quiz.models import Question
ModuleNotFoundError: No module named 'school.quiz'
I'd really prefer to use school.quiz, but I can live with using quiz if needed. I just want PyCharm and runserver to reconcile on one way so that I can get on with my project.
These are my Django settings in PyCharm:
You can use "from .models import Question"

How to create a django package without setting DJANGO_SETTINGS_MODULE as environment variable?

I am creating a package that itself uses Django and I will be using it within other Django applications. The main issue I am facing is that I need to use to settings for various reasons such as logging and other extensive requirements. Since, this package does not have any views/urls, we are writing tests and using pytest to run them. The tests will not run without the settings configured. So initially I put the following snippet in the __init__ file in the root app.
import os
import django
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "my_package.settings")
django.setup()
Now, the test ran properly and the package as standalone app was working. But the moment I installed it in the main project, it overrides the enviroment variable with it's own settings and you can imagine the kind of havoc it would ensue.
This is the first time I am packaging a django app. So I am not well-versed with best practices and the docs are a little convoluted. I read the structure and code of various packages that use settings in their package but I am still not able to understand how to ensure the package accesses the intended settings and the project's settings is not affected at the same time.
While going throught the docs, I came accross this alternative to setting DJANGO_SETTINGS_MODULE, like this:
from django.conf import settings
settings.configure(DEBUG=True)
As shown here: https://docs.djangoproject.com/en/2.2/topics/settings/#using-settings-without-setting-django-settings-module
But where exactly am I supposed to add this? To every file where the settings are imported or will it work in the __init__ (Tried this but something isn't right, shows Apps aren't loaded )
I tried this as well where I imported my settings as defaults and called configure using them as defaults and called django.setup() as well but didn't do the trick:
# my_package/__init__.py
from django.conf import settings
from my_package import settings as default
if not settings.configured:
settings.configure(default_settings=default, DEBUG=True)
import django
django.setup()
Also, I need settings mainly because I have few parameters that can be overridden in the project that is using the package. When the package is installed, the overridden variables is what I should be able to access in the package during runtime.
If someone can guide on how to tackle this or have a better process of creating packages that need django settings, please do share.
So I ended up finding a way to work without setting the settings module as an environement variable. This enables me to use the specified settings by importing all the overridden settings as well as the default settings from:
Create a apps file for configuring your package as an app.
# my_package/apps.py
from django.apps import AppConfig
class MyPackageConfig(AppConfig):
name = 'my_package'
verbose_name = 'My package'
And, in your package's root. The following snippet in your __init__.py will only set the overridden settings:
# my_package/__init__.py
from django.conf import settings
import django
from my_package import settings as overridden_settings
from django.conf import settings
default_app_config = 'my_package.apps.MyPackageConfig'
if not settings.configured:
# Get the list of attributes the module has
attributes = dir(overridden_settings)
conf = {}
for attribute in attributes:
# If the attribute is upper-cased i.e. a settings variable, then copy it into conf
if attribute.isupper():
conf[attribute] = getattr(overridden_settings, attribute)
# Configure settings using the settings
settings.configure(**conf)
# This is needed since it is a standalone django package
django.setup()
Reference for what django.setup() will do:
https://docs.djangoproject.com/en/2.2/topics/settings/#calling-django-setup-is-required-for-standalone-django-usage
Points to keep in mind:
Since it is in the __init__, this will make sure if you import something from the package, the settings are configured.
As mentioned in the documentation above, you have to make sure that the settings is configured only once and similarly the setup method is called once or it will raise an Exception.
Let me know if this helps or you are able to come up with a better solution to this.

How to write a stand-alone Python script working with Django modules?

In PyCharm, I created a blank new Django app. Having created some models and issued manage.py makemigrations and manage.py migrate, I tried to write a standalone script that would populate the database with initial data. In its imports I wrote:
from MyApp.models import Model1, Model2, …
Sadly, running this script in PyCharm throws an exception: django.core.exceptions.ImproperlyConfigured: Requested setting DEFAULT_TABLESPACE, but settings are not configured. You must either define the environment variable DJANGO_SETTINGS_MODULE or call settings.configure() before accessing settings.
I Googled this exception, and found an answer in SO https://stackoverflow.com/a/27455703/4385532 advising to put this in the top of my script:
import os
os.environ['DJANGO_SETTINGS_MODULE'] = 'mysite.settings'
So I did. Sadly, this didn’t fix the issue. Now I am greeted with another exception:
django.core.exceptions.AppRegistryNotReady: Models aren't loaded yet.
What should I do?
Make sure you also do:
import django
django.setup()
To load your models.
Documentation: https://docs.djangoproject.com/en/1.10/topics/settings/#calling-django-setup-is-required-for-standalone-django-usage

django celery unit tests with pycharm 'No module named celery'

my tests work fine when my target is a single function (see 'Target' field in the image):
questionator.test_mturk_views.TestReport.submit
However, when I specify my target to include all tests within my questionator app:
questionator
I get this error:
Error ImportError: Failed to import test module:
src.questionator.test_mturk_views Traceback (most recent call last):
File "C:\Python27\Lib\unittest\loader.py", line 254, in _find_tests
module = self._get_module_from_name(name) File "C:\Python27\Lib\unittest\loader.py", line 232, in
_get_module_from_name
import(name) File "C:\Users\Andy\questionator_app\src__init__.py", line 5, in
from .celery import app as celery_app # noqa ImportError: No module named celery
Note that my tests include my settings via 'Environment variables' (see this in the pic too):
DJANGO_SETTINGS_MODULE=questionator_app.settings.development;PYTHONUNBUFFERED=1
The celery documentation mentions a "Using a custom test runner to test with celery" but this is in the now defunct djcelery package. I did though copy/paste/tweak this mentioned test runner and used it as described, but I get the same error.
Unfortunately using CELERY_ALWAYS_EAGER also does not work http://docs.celeryproject.org/en/latest/configuration.html#celery-always-eager
I would appreciate some guidance. With best wishes,
Andy.
with-the-same-problem (most likely me),
I had followed the official tutorial for getting celery working in my project. They advised the below:
Just making the last import explicit solved my problem:
from taskapp.celery import app as celery_app # noqa
I'll see if I can nudge Celery's creators to update their tutorial (pull request).

Module 'main' has no attribute application -- Google App Engine Python with Django

I have been running into this problem for a short while now and simply can't find a solution anywhere. I am using Google App Engine to run a default Python 2.7 app with Django 1.5 (via GAE SDK) created through PyCharm. I can upload the app successfully, but upon visiting the actual page, I get a Server Error. Then, checking the logs in Google App Engine, I see this:
ImportError: <module 'main' from '/base/data/home/apps/s~eloquent-ratio-109701/1.388053784931450315/main.pyc'> has no attribute application
After searching the internet for a while, I was able to find a few posts which address this issue, but attempting them never seemed to solve my problem. For example: This problem was solved by replacing "application" with "app" in the following lines:
application = django.core.handlers.wsgi.WSGIHandler()
util.run_wsgi_app(application)
In fact, I had run into this same issue before and this solution provided a fix for me in the past, however at that time I was running a separate app and it was not through the GAE.
I checked the Django documentation for version 1.5 here, but the code and suggestions there don't seem to conflict with what I currently have in my project.
I read a bit more about this type of problem, and saw another post that suggested checking the app's wsgi.py file to ensure that it is named 'application' or 'app' respectively, so that one could then use that same name throughout the rest of the application. However, upon checking those settings I saw that 'application' was used there too:
from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()
There's even a line in settings.py which uses the same nomenclature to declare the WSGI application:
WSGI_APPLICATION = 'Chimera.wsgi.application'
I'm really having trouble debugging this. I get the feeling it's really dumb and I just can't see it, but unfortunately I'm not particularly good at this kind of stuff -- I'm still a bit of a novice in this field.
Does anyone have any idea what I could try in an attempt to fix this issue?
UPDATE: I started making line by line changes and testing things, and eventually I found that the GAE log changes depending on the input for the "script" under app.yaml. So if I change the script under "handlers" between "main.app" and "main.application", it adjusts the log output to refer to "app" or "application" respectively. So that line in the app.yaml file tells the app what to look for, but I'm still not seeing why it can't be found. Not sure what else I could change to test it out. I wish I knew a bit more about the actual inner workings so that I could figure out why the app is confused about the attribute. Is it trying to run before it even gets instantiated or something?
Source code below:
main.py
import os, sys
os.environ['DJANGO_SETTINGS_MODULE'] = 'Chimera.settings'
from google.appengine.ext.webapp import util
from django.conf import settings
settings._target = None
import django.core.handlers.wsgi
import django.core.signals
import django.db
import django.dispatch.dispatcher
def main():
application = django.core.handlers.wsgi.WSGIHandler()
util.run_wsgi_app(application)
if __name__ == '__main__':
main()
app.yaml
application: eloquent-ratio-109701
version: 1
runtime: python27
api_version: 1
threadsafe: true
handlers:
- url: /.*
script: main.application
libraries:
- name: django
version: 1.5
wsgi.py
import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "Chimera.settings")
from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()
Full log from GAE:
Traceback (most recent call last):
File "/base/data/home/runtimes/python27/python27_lib/versions/1/google/appengine/runtime/wsgi.py", line 240, in Handle
handler = _config_handle.add_wsgi_middleware(self._LoadHandler())
File "/base/data/home/runtimes/python27/python27_lib/versions/1/google/appengine/runtime/wsgi.py", line 302, in _LoadHandler
raise err
ImportError: <module 'main' from '/base/data/home/apps/s~eloquent-ratio-109701/1.388053784931450315/main.pyc'> has no attribute application
Thanks for helping me out.
In your main.py file (i.e. the main module) application is a variable inside the main() function, not an attribute of the main module. Basically you don't need a main() function.
GAE has some specific support for using Django, I'd strongly suggest going through the Django Support documentation and the Django App example.
Based on the comment made by #DanielRoseman I discovered that declaring the app inside of the main() function caused an issue because the app attribute was then only accessible at the main() function level, as it was a member variable of main() as opposed to a global variable. Although the default application files were structured this way by PyCharm, it seems that it was incorrect. I'm not sure if this is a compatibility issue, but regardless, moving the app declaration outside of the main() function adjusts the scope in a way which allows for other parts of the project to access it, solving my problem.
Thank you #DanielRoseman for the comment.