Testing reusable Django apps with Django testrunner - django

I want to test a small reusable app which comes with its own settings module. Global (project) settings are accessed inside app's settings to support variables' overriding, e.g.
# in <my_app>/settings.py
from django.conf import settings
MY_SETTING_VAR = getattr(settings, 'MY_OVERRIDDEN_VAR', False)
When I run tests with manage.py test myapp I get the following:
ImportError: Settings cannot be imported, because environment
variable DJANGO_SETTINGS_MODULE is undefined.
What is the right way to run tests in this case?

I'm not sure, i tested exactly what you posted and it works for me:
<<< 12:18.25 Fri Feb 24 2012!~/testproject
<<< jpic#germaine!10019 env
>>> ./manage.py test testapp
Creating test database for alias 'default'...
Destroying old test database 'default'...
.
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK
Destroying test database for alias 'default'...
<<< 12:18.27 Fri Feb 24 2012!~/testproject
<<< jpic#germaine!10020 env
>>> cat testapp/tests.py
from django.test import TestCase
from .settings import *
class SomeTestCase(TestCase):
def testSomething(self):
self.assertEqual(MY_SETTING_VAR, 'default')
<<< 12:18.30 Fri Feb 24 2012!~/testproject
<<< jpic#germaine!10021 env
>>> cat testapp/settings.py
from django.conf import settings
MY_SETTING_VAR = getattr(settings, 'MY_OVERRIDDEN_VAR', 'default')
You want to make sure your actual code matches this working code.
It's better for an app to include a dummy project that demonstrates the app or at least allows testing. For example:
<<< 12:42.56 Fri Feb 24 2012!~/testproject/testapp
<<< jpic#germaine!10034 E:1 env
>>> pip install -e git+git#github.com:subsume/django-subscription.git#egg=sub
Obtaining sub from git+git#github.com:subsume/django-subscription.git#egg=sub
Cloning git#github.com:subsume/django-subscription.git to /home/jpic/env/src/sub
Running setup.py egg_info for package sub
Installing collected packages: sub
Running setup.py develop for sub
Creating /home/jpic/env/lib/python2.7/site-packages/django-subscription.egg-link (link to .)
Removing django-subscription 0.0 from easy-install.pth file
Adding django-subscription 0.1 to easy-install.pth file
Installed /home/jpic/env/src/sub
Successfully installed sub
Cleaning up...
<<< 12:43.08 Fri Feb 24 2012!~/testproject/testapp
<<< jpic#germaine!10035 env
<<< 12:43.11 Fri Feb 24 2012!~/testproject/testapp
<<< jpic#germaine!10035 env
>>> cd ../../env/src/sub
<<< 12:43.15 Fri Feb 24 2012!~/env/src/sub
<<< jpic#germaine!10036 G:master env
>>> ls
django_subscription.egg-info docs README setup.py subscription subscription_test_project
<<< 12:43.16 Fri Feb 24 2012!~/env/src/sub
<<< jpic#germaine!10037 G:master env
>>> cd subscription_test_project
<<< 12:43.20 Fri Feb 24 2012!~/env/src/sub/subscription_test_project
<<< jpic#germaine!10038 G:master env
>>> ./manage.py test subscription
Creating test database for alias 'default'...
........
----------------------------------------------------------------------
Ran 8 tests in 0.012s
OK
Destroying test database for alias 'default'...

ImportError: Settings cannot be imported, because environment variable DJANGO_SETTINGS_MODULE is undefined.
You get this because DJANGO_SETTINGS_MODULE is not in your python environment variables... To solve your problem you must define it as
import os
os.environ['DJANGO_SETTINGS_MODULE'] = '<django_application_root>.settings'
You can add it to your root __init__.py file...

Related

Test not found in github actions

I am trying to do an automated test.
There should be 21 tests, but github-actions can't find them for some reason.
https://github.com/duri0214/portfolio/actions/runs/4215160033/jobs/7316095166#step:3:6
manage.py is under mysite directory, so...
(Below is when I run it on my local PC)
(venv) PS D:\OneDrive\dev\portfolio\mysite> python manage.py test
Found 21 test(s).
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
:
self.client.post(reverse('vnm:likes', kwargs={'user_id': 1, 'article_id': 99}), follow=True)
AssertionError: ObjectDoesNotExist not raised
======================================================================
FAIL: test_post_click_good_button
(vietnam_research.tests.test_views.TestView)
----------------------------------------------------------------------
OK
Anyone know a solution?
thanks

How to fix ‘ No such file or directory’ error in execute console-script by setup.py?

I wrote a static blog generator built using Django. Some problems occurred when I packaged it with setup.py and created the corresponding executable.
When I use pip install maltose to install it and run maltose-cli migrate, everything is normal so far.
But when I run maltose-cli runserver, I get a error that c:\software\python\python.exe: can't open file 'C:\Software\Python\Scripts\maltose-cli': [Errno 2] No such file or directory.
And then, I try maltose-cli.py runserver, everything is OK.
This is my setup.py
setup(
name=NAME,
version=about['__version__'],
description=DESCRIPTION,
long_description=long_description,
long_description_content_type='text/markdown',
author=AUTHOR,
author_email=EMAIL,
python_requires=REQUIRES_PYTHON,
url=URL,
packages=find_packages(include=["maltose", 'maltose.*']),
scripts=['maltose-cli.py'],
entry_points={
'console_scripts': ['maltose-cli=maltose:execute'],
},
install_requires=REQUIRED,
extras_require=EXTRAS,
include_package_data=True,
license='MIT',
classifiers=[
# Trove classifiers
# Full list: https://pypi.python.org/pypi?%3Aaction=list_classifiers
'License :: OSI Approved :: MIT License',
'Programming Language :: Python :: 3.6',
],
# $ setup.py publish support.
cmdclass={
'upload': UploadCommand,
},
)
Dir
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 2019/4/20 18:41 maltose
-a---- 2019/4/20 18:47 90 maltose-cli.py
-a---- 2019/4/20 18:47 4047 setup.py
In maltose/__init__.py
import os
import sys
def execute():
os.environ.setdefault('DJANGO_DEBUG', 'True')
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'maltose.maltose.settings')
try:
from django.core.management import execute_from_command_line
except ImportError as exc:
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?"
) from exc
execute_from_command_line()
If you need, all the code is at https://github.com/MaltoseEditor/maltose
How can I solve it? I hope that it will work fine when I run maltose-cli runserver.
This error is related with the auto-reload functionality when the project's source code changes.
As a workaround, use the --noreload flag to disable this feature.
maltose-cli runserver --noreload
Side note: this also applies to Bottle.py

How do I use flask-migrate on pythonanywhere?

Does anyone have an example of successfully using flask-migrate on pythonanywhere? Does anyone have a simple example of what an app.py using migration should look like? Something along the lines of:
from flask import Flask, request, render_template
from flask.ext.sqlalchemy import SQLAlchemy
from flask.ext.migrate import Migrate, MigrateCommand
from flask.ext.script import Manager
app = Flask(__name__ )
app.secret_key = 'This is really unique and secret'
app.config['SQLALCHEMY_DATABASE_URI'] = '<whatever>'
db = SQLAlchemy(app)
db.create_all()
manager = Manager( app )
migrate = Migrate( app, db )
manager.add_command('db', MigrateCommand )
I find that when I try to run
python app.py db init
it fails to generate the migration repository. Could this be a file permission issue on pythonanywhere?
Author of Flask-Migrate here.
The idea is that you generate your db repository in your development environment. You have to commit your repository along with your source files to source control.
Then when you install the application on your hosting service all you need to do is run the upgrade command to get your db created and migrated to the latest revision.
Update: base on your comments below, you want to develop an application from scratch. I just tested this myself, and was able to create a db repository, create a migration, and apply it. What I did is start the pythonanywhere bash console. Here is a copy of my complete session:
17:39 ~ $ mkdir dbtest
17:39 ~ $ cd dbtest
17:39 ~/dbtest $ virtualenv venv
New python executable in venv/bin/python2.7
Also creating executable in venv/bin/python
Installing setuptools............done.
Installing pip...............done.
17:39 ~/dbtest $ . venv/bin/activate
(venv)17:39 ~/dbtest $ pip install flask flask-migrate
...
(venv)17:42 ~/dbtest $ vi dbtest.py
... (entered flask-migrate example code, see below)
(venv)17:47 ~/dbtest $ python dbtest.py
usage: dbtest.py [-?] {shell,db,runserver} ...
positional arguments:
{shell,db,runserver}
shell Runs a Python shell inside Flask application context.
db Perform database migrations
runserver Runs the Flask development server i.e. app.run()
optional arguments:
-?, --help show this help message and exit
(venv)17:47 ~/dbtest $ python dbtest.py db init
Creating directory /home/miguelgrinberg/dbtest/migrations ... done
Creating directory /home/miguelgrinberg/dbtest/migrations/versions ... done
Generating /home/miguelgrinberg/dbtest/migrations/README ... done
Generating /home/miguelgrinberg/dbtest/migrations/alembic.ini ... done
Generating /home/miguelgrinberg/dbtest/migrations/env.py ... done
Generating /home/miguelgrinberg/dbtest/migrations/script.py.mako ... done
Generating /home/miguelgrinberg/dbtest/migrations/env.pyc ... done
Please edit configuration/connection/logging settings in '/home/miguelgrinberg/dbtest/migrations/alembic.ini' before proceeding.
(venv)17:54 ~/dbtest $ python dbtest.py db migrate
INFO [alembic.migration] Context impl SQLiteImpl.
INFO [alembic.migration] Will assume non-transactional DDL.
INFO [alembic.autogenerate.compare] Detected added table 'user'
Generating /home/miguelgrinberg/dbtest/migrations/versions/1c4aa671e23a_.py ... done
(venv)17:54 ~/dbtest $ python dbtest.py db upgrade
INFO [alembic.migration] Context impl SQLiteImpl.
INFO [alembic.migration] Will assume non-transactional DDL.
INFO [alembic.migration] Running upgrade None -> 1c4aa671e23a, empty message
(venv)17:55 ~/dbtest $ ls -l
total 8
-rw-r--r-- 1 miguelgrinberg registered_users 3072 Sep 28 2014 app.db
-rwxrwxr-x 1 miguelgrinberg registered_users 511 Sep 28 17:48 dbtest.py
drwxrwxr-x 3 miguelgrinberg registered_users 100 Sep 28 17:55 migrations
drwxrwxr-x 6 miguelgrinberg registered_users 52 Sep 28 17:41 venv
The example application that I used to test this is below:
from flask import Flask
from flask.ext.sqlalchemy import SQLAlchemy
from flask.ext.script import Manager
from flask.ext.migrate import Migrate, MigrateCommand
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///app.db'
db = SQLAlchemy(app)
migrate = Migrate(app, db)
manager = Manager(app)
manager.add_command('db', MigrateCommand)
class User(db.Model):
id = db.Column(db.Integer, primary_key = True)
name = db.Column(db.String(128))
if __name__ == '__main__':
manager.run()
Any chance you already have a migration repository created? Or a database?

uwsgi: no app loaded. going in full dynamic mode

In my uwsgi config, I have these options:
[uwsgi]
chmod-socket = 777
socket = 127.0.0.1:9031
plugins = python
pythonpath = /adminserver/
callable = app
master = True
processes = 4
reload-mercy = 8
cpu-affinity = 1
max-requests = 2000
limit-as = 512
reload-on-as = 256
reload-on-rss = 192
no-orphans
vacuum
My app structure looks like this:
/adminserver
app.py
...
My app.py has these bits of code:
app = Flask(__name__)
...
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5003, debug=True)
The result is that when I try to curl my server, I get this error:
Wed Sep 11 23:28:56 2013 - added /adminserver/ to pythonpath.
Wed Sep 11 23:28:56 2013 - *** no app loaded. going in full dynamic mode ***
Wed Sep 11 23:28:56 2013 - *** uWSGI is running in multiple interpreter mode ***
What do the module and callable options do? The docs say:
module, wsgi Argument: string
Load a WSGI module as the application. The module (sans .py) must be
importable, ie. be in PYTHONPATH.
This option may be set with -w from the command line.
callable Argument: string Default: application
Set default WSGI callable name.
Module
A module in Python maps to a file on disk - when you have a directory like this:
/some-dir
module1.py
module2.py
If you start up a python interpreter while the current working directory is /some-dir you will be able to import each of the modules:
some-dir$ python
>>> import module1, module2
# Module1 and Module2 are now imported
Python searches sys.path (and a few other things, see the docs on import for more information) for a file that matches the name you are trying to import. uwsgi uses Python's import process under the covers to load the module that contains your WSGI application.
Callable
The WSGI PEPs (333 and 3333) specify that a WSGI application is a callable that takes two arguments and returns an iterable that yields bytestrings:
# simple_wsgi.py
# The simplest WSGI application
HELLO_WORLD = b"Hello world!\n"
def simple_app(environ, start_response):
"""Simplest possible application object"""
status = '200 OK'
response_headers = [('Content-type', 'text/plain')]
start_response(status, response_headers)
return [HELLO_WORLD]
uwsgi needs to know the name of a symbol inside of your module that maps to the WSGI application callable, so it can pass in the environment and the start_response callable - essentially, it needs to be able to do the following:
wsgi_app = getattr(simple_wsgi, 'simple_app')
TL;PC (Too Long; Prefer Code)
A simple parallel of what uwsgi is doing:
# Use `module` to know *what* to import
import simple_wsgi
# construct request environment from user input
# create a callable to pass for start_response
# and then ...
# use `callable` to know what to call
wsgi_app = getattr(simple_wsgi, 'simple_app')
# and then call it to respond to the user
response = wsgi_app(environ, start_response)
For anyone else having this problem, if you are sure your configuration is correct, you should check your uWSGI version.
Ubuntu 12.04 LTS provides 1.0.3. Removing that and using pip to install 2.0.4 resolved my issues.
First, check your configuration whether is correct.
my uwsgi.ini configuration:
[uwsgi]
chdir=/home/air/repo/Qiy
uid=nobody
gid=nobody
module=Qiy.wsgi:application
socket=/home/air/repo/Qiy/uwsgi.sock
master=true
workers=5
pidfile=/home/air/repo/Qiy/uwsgi.pid
vacuum=true
thunder-lock=true
enable-threads=true
harakiri=30
post-buffering=4096
daemonize=/home/air/repo/Qiy/uwsgi.log
then use uwsgi --ini uwsgi.ini to run uwsgi.
if not work, you rm -rf the venv directory, and re-initial the venv, and re-try my step.
I re-initial the venv solved my issue, seems the problem is when I pip3 install some packages of requirements.txt, and upgrade the pip, then install uwsgi package. so, I delete the venv, and re-initial my virtual environment.

how to use django mailer without PINAX

I want to use django-mailer without PINAX. When I run ./manager.py send_mail
it prints:
Unknown command: 'send_mail'
Type 'manage.py help' for usage.
How do I fix this?
Python 2.5.1 (r251:54863, Sep 22 2007, 01:43:31)
[GCC 4.2.1 (SUSE Linux)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from django.conf import settings
>>> 'mailer' in settings.INSTALLED_APPS
True
>>>
$./manage.py send_mail
Unknown command: 'send_mail'
Type 'manage.py help' for usage.
and I used easy_install django-mailer to install the mailer, and the django version
is
VERSION = (1, 1, 1, 'final', 0)
and mailer version is 0.1.0
A few things to double check:
Did you install django-mailer?
Is mailer in your PYTHONPATH? When you import mailer, are you getting the expected module (version and expected path)?
Is mailer listed in your INSTALLED_APPS?
$ ./manage.py shell
>>> import mailer
>>> mailer.get_version()
'0.1.0'
>>> mailer.__file__
/PATH/TO/YOUR/PYTHON/LIBS/mailer/__init__.py
>>> # did it import? did you get the expected version? expected path?
>>> # good, django-mailer is in your PYTHONPATH. now verify project settings.
>>> from django.conf import settings
>>> 'mailer' in settings.INSTALLED_APPS
True
At this point you should see send_mail in the list of available manage.py subcommands.
$ ./manage.py --help
Usage: manage.py subcommand [options] [args]
[...]
runserver
send_mail
shell
[...]
$
After than you will also want to make sure that you are running ./manage.py send_mail via a cron job.
* * * * * (cd $YOUR_PROJECT; /usr/bin/python manage.py send_mail >> cron_mail.log 2>&1)
0,20,40 * * * * (cd $YOUR_PROJECT; /usr/bin/python manage.py retry_deferred >> cron_mail_deferred.log 2>&1)
There is no need to actually set these two cronjobs up during development, just look for your messages via the admin.
The django-mailer module has usage instructions but this should get you up and running.
Can't you just download it from django-mailer and install it separately?