Django Unit Tests Failing on Travis CI Builds - django

I have a very basic Django app (Python 3.6.4) and I've written a unit test which passes locally. An in memory SQLite DB is created (by default) for the tests. When my Travis CI build runs the same tests the tests pass but the test command fails with the following error:
File "/home/travis/virtualenv/python3.6.5/lib/python3.6/site-packages/django/db/backends/sqlite3/base.py", line 301, in execute
return Database.Cursor.execute(self, query)
django.db.utils.OperationalError: near "SCHEMA": syntax error
The command "python manage.py test --settings=myapp.dev_settings" exited with 1.
One strange thing I notice is that when the tests are run on Travis, it's says it's reusing an existing DB and never destroys it after the tests are run:
$ python manage.py test --settings=myapp.dev_settings
Using existing test database for alias 'default'...
I don't really get that, because it should be an in memory DB and when I run it locally, a new database is created each time:
Creating test database for alias 'default'...
. . .
Destroying test database for alias 'default'...
My dev_settings.py file has a sqlite db on the filesystem, but that is only used for running the local development server:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
Travis installs all the dependencies and they match my local environment (I'm fairly sure).
Any help would be great, I'm definitely missing something obvious here!!!

This is because the Django-Heroku package sets its own Test Runner that does extra stuff with the database if it detects a CI environment, presumably to cater to their Heroku CI offering:
# Enable test runner if found in CI environment.
if 'CI' in os.environ:
config['TEST_RUNNER'] = 'django_heroku.HerokuDiscoverRunner'
The test runner does the following which does not work for SQLite:
with connection.cursor() as cursor:
cursor.execute(
"""
DROP SCHEMA public CASCADE;
CREATE SCHEMA public;
GRANT ALL ON SCHEMA public TO postgres;
GRANT ALL ON SCHEMA public TO public;
COMMENT ON SCHEMA public IS 'standard public schema';
"""
)
Unfortunately this check also detects non-Heroku CI environments such as Travis or GitLab CI and attempts to use the above configuration.
You can solve this problem by disabling the Heroku test runner like so in your settings.py:
# Configure Django App for Heroku.
django_heroku.settings(locals(), test_runner=False)

#LaSmell is correct (I had the same problem). It's because you're trying to access Heroku dependencies in your build.
BUT I can still show you how to implement a solution.
You need to do 3 things to solve this problem.
1 - Specify a new requirements doc without django-heroku
I personally made another file called requirements-build.txt and it has all the same dependencies except django-heroku==0.3.1
I just delete it out.
2 - Specify the new requirements file in .travis.yml
In your .travis.yml file just replace
install:
- pip install -r requirements.txt
with
install:
- pip install -r requirements-build.txt
3 - Account for these changes in your settings.py file
To make sure you don't import heroku-django if it's not installed, check if it can be imported first. I did:
# Try to import django-heroku depending on Travis or Heroku
try:
# Configure Django App for Heroku.
import django_heroku
django_heroku.settings(locals())
except ImportError:
found = False
This way it will only use django-heroku if it has been installed. Since Heroku uses requirements.txt by default this patch works perfectly fine.
Hope this helps! It took me a while to get it myself.

In the stack trace of the travis build I noticed an unexpected package being executed:
File "/home/travis/virtualenv/python3.6.5/lib/python3.6/site-packages/django_heroku/core.py", line 41, in teardown_databases
self._wipe_tables(connection)
The problem was I was executing my tests with a settings.py file that included Heroku (deployment) specific code:
import django_heroku
import dj_database_url
# Parse database configuration from Heroku's $DATABASE_URL (Postgres)
DATABASES = {
'default': dj_database_url.config(conn_max_age=500, ssl_require=True)
}
# Activate Django-Heroku (DATABASE_URL and all that).
django_heroku.settings(locals())
And dependencies in my requirements.txt file:
django-heroku==0.3.1
Once I remove all the Heroku config from the Travis build config, the build passes!
Still unsure how I didn't see this fail locally.

Related

Running into a booting worker issue with Django application when deploying to heroku [duplicate]

I built a Django 1.9 project locally with sqlite3 as my default database. I have an application named Download which defines the DownloadedSongs table in models.py:
models.py
from __future__ import unicode_literals
from django.db import models
class DownloadedSongs(models.Model):
song_name = models.CharField(max_length = 255)
song_artist = models.CharField(max_length = 255)
def __str__(self):
return self.song_name + ' - ' + self.song_artist
Now, in order to deploy my local project to Heroku, I added the following lines at the bottom of my settings.py file:
import dj_database_url
DATABASES['default'] = dj_database_url.config()
My application has a form with a couple of text fields, and on submitting that form, the data gets inserted into the DownloadedSongs table. Now, when I deployed my project on Heroku and tried submitting this form, I got the following error:
Exception Type: ProgrammingError at /download/
Exception Value: relation "Download_downloadedsongs" does not exist
LINE 1: INSERT INTO "Download_downloadedsongs" ("song_name", "song_a...
This is how my requirements.txt file looks like:
beautifulsoup4==4.4.1
cssselect==0.9.1
dj-database-url==0.4.1
dj-static==0.0.6
Django==1.9
django-toolbelt==0.0.1
gunicorn==19.6.0
lxml==3.6.0
psycopg2==2.6.1
requests==2.10.0
static3==0.7.0
Also, I did try to run the following commands as well:
heroku run python manage.py makemigrations
heroku run python manage.py migrate
However, the issue still persists. What seems to be wrong here?
Make sure your local migration folder and content is under git version control.
If not, add, commit & push them as follows (assuming you have a migrations folder under <myapp>, and your git remote is called 'heroku'):
git add <myapp>/migrations/*
git commit -m "Fix Heroku deployment"
git push heroku
Wait until the push is successful and you get the local prompt back.
Then log in to heroku and there execute migrate.
To do this in one execution environment, do not launch these as individual heroku commands, but launch a bash shell and execute both commands in there: (do not type the '~$', this represents the Heroku prompt)
heroku run bash
~$ ./manage.py migrate
~$ exit
You must not run makemigrations via heroku run. You must run it locally, and commit the result to git. Then you can deploy that code and run those generated migrations via heroku run python manage.py migrate.
The reason is that heroku run spins up a new dyno each time, with a new filesystem, so any migrations generated in the first command are lost by the time the second command runs. But in any case, migrations are part of your code, and must be in version control.
As Heroku's dynos don't have a filesystem that persists across deploys, a file-based database like SQLite3 isn't going to be suitable. It's a great DB for development/quick prototypes, though. https://stackoverflow.com/a/31395988/784648
So between deploys your entire SQLite database is going to be wiped, you should move onto a dedicated database when you deploy to heroku I think. I know heroku has a free tier for postgres databases which I'd recommend if you just want to test deployment to heroku.
python manage.py makemigrations
python manage.py migrate
python manage.py migrate --run-syncdb
this worked for me.
I know this is old, but I had this issue and found this thread useful.
To sum up, the error can also appear when executing the migrations (which is supposed to create the needed relations in the DB), because recent versions of Django check your urls.py before doing the migrations. In my case - and in many others' it seems, loading urls.py meant loading the views, and some views were class-based and had an attribute defined through get_object_or_404:
class CustomView(ParentCustomView):
phase = get_object_or_404(Phase, code='C')
This is what was evaluated before the migrations actually ran, and caused the error. I fixed it by turning my view's attribute as a property:
class CustomView(ParentCustomView):
#property
def phase(self):
return get_object_or_404(Phase, code='C')
You'll know quite easily if this is the problem you are encountering, as the Traceback will point you towards the problematic view.
Also this problem might not appear in development because you have migrated before creating the view.

Packaging Flask-Script and Flask-Migrate utilties with Flask application

I have an application design using flask with flask-sqlalchemy. In order to control database migrations as the models change I am using flask-migrate to wrap alembic and use within the flask-script management context.
I am trying to decide how to split the package distribution to achieve the following goals
Minimal set of dependencies for the main application package
Allow distribution of management scripts and test data for migrations and deployments perhaps using a secondary package depending on the main application module
The project structure is as follows
/
tests/ #test data
migrations/ #alembic root include env.py and alembic.ini
myapp/ # application package
setup.py
manage.py
wsgi.py
My manage.py looks like a lot the following. This is how I avoid any alembic or flask-migrate dependencies in the main application package, by attaching the Migrate object to the app in manage.py. This also allows me to control migration configurations in the same config file as the general flask/app configurations (as the config context is pushed by the manager and with Migrate.init_app)
from myapp import db, create_app
from myapp.database import database_manager #sub manager for creating/dropping db
from flask_migrate import Migrate, MigrateCommand
def _create_app(*args, **kwargs):
app = create_app(*args, **kwargs)
if migration is not None:
migration.init_app(app)
return app
manager = Manager(_create_app)
migration = Migrate(db = db)
manager.add_command('database', database_manager)
manager.add_command('migration', MigrateCommand)
if __name__ == "__main__":
manager.run()
The application submanager myapp.database.database_manager enables such commands as python manage.py database create/drop/test_data which uses sqlalchemy to create tables and populate the table with test_data from tests/ directory, but does not hook in any migration scripts, and allows me to use python manage.py migration init/revision/migrate/... to execute flask-migrate/alembic commands using the application configuration context.
I am trying to distribute this application to deploy on our internal servers. There are two distribution use cases as they are currently being used
Install new server
Install source distribution
Create new config file to reflect DB host etc.
Use manage.py -c /path/to/config to create database tables with database create
Point HTTP Server to wsgi.py
Update existing server
Update source distribution
Use manage.py -c /path/to/server/config migration upgrade to pull up the databases using the current app context
Server continues to point to wsgi.py
I would like to move this distribution to wheels/packages so that I can automate deployment on our corp intranet, So what I'm seeing here is that I would like to split my package into the main package myapp with only Flask framework dependencies and wsgi entrypoint and myapp-manage which includes the manage.py , tests, and migrationsdirectory.
So in the perfect world, the application will be installed on the system with global configuration files, and a specific management user will have access to the management package to perform upgrades.
Right now I am angling towards splitting the distribution with setup-app.py and setup-manage.py to create two seperate packages from the same source distribution. Is there a more appropriate way to package migrations and management scripts with a flask application? I have dug through the docs and while its clear how to package a flask application, distribution strategies for management scripts and migrations is less clear.

Getting error with postgis Geodjango on Heroku

Postgis extension is installed:
:DATABASE=> SELECT postgis_version();
postgis_version
2.2 USE_GEOS=1 USE_PROJ=1 USE_STATS=1
I have the following buildpacks:
https://github.com/cyberdelia/heroku-geo-buildpack.git
https://github.com/heroku/heroku-buildpack-python.git
When I run manage.py migrate I get:
AttributeError: 'DatabaseOperations' object has no attribute 'geo_db_type'
I am using the hobby deb postgres which now supports postgis
https://devcenter.heroku.com/changelog-items/792
Do I need to install a different build pack or add some additional configuration? Everything works locally using postgis.
I finally had some time to go back and look at this. It turns out the issue was Heroku was not importing my settings correctly. I was using cookiecutter-django settings scheme that imports common settings into production and for some reason Heroku was not working as expected.
My common settings contained:
DATABASES['default']['ATOMIC_REQUESTS'] = True
DATABASES['default']['ENGINE'] = "django.contrib.gis.db.backends.postgis"
And my production contained:
DATABASES['default'] = env.db("DATABASE_URL")
Heroku did not import those common settings. When I checked in the django shell in heroku the production settings had
'ENGINE': 'django.db.backends.postgresql_psycopg2', 'ATOMIC_REQUESTS': False
After adding DATABASES['default']['ENGINE'] = "django.contrib.gis.db.backends.postgis" to production settings everything is working.
Does anybody know what could be going wrong with importing settings correctly from common.py? It seems to import the rest of the settings correctly, just not the database ones.

deploying Django - Dreamhost

I am neewbie with django and I am stuck trying to deploy my project on the server ( a shared Dreamhost server). I have followed the tutorials I found but it doesnt work. My project structure is:
/usr/mydomain.com
- public
* media
* static
- project
* __init__.py
* manage.py
* settings.py
* urls.py
* views.py
- tmp
- django-setup.py
- manage.py
- passenger_wsgi.py
- passenger_wsgi.pyc
It only works on my domain.com/admin, but I have a simple 'hello world' view to try but it isnt showing. I get only an HTTP 404 when I access my domain...
EDIT
I have installed Python 2.7 and Django 1.5 . Now I get a 500 Internal Server Error.
This is how I do it, with Django 1.5, on DreamHost:
A virtualenv dedicated to my project is in ~/virtualenv/myproject
My Django project is in ~/projects/myproject, with setup:
The database file is in the project root, named sqlite3.db
STATIC_ROOT is set to os.path.join(os.path.abspath(os.path.dirname(__file__)), '..', 'static'), that is, the static directory in the project root.
When the static files are updated in the project, I have to run python manage.py collectstatic
I have per-environment settings in ~/projects/myproject/myproject, named prod_settings.py, beta_settings.py, and so on.
My site is in ~/sites/www.myproject.com, the layout inside:
myproject -- symlink to the Django project
sqlite3.db -- symlink to the database file in the Django project
public/static -- symlink to the STATIC_ROOT defined in the Django project
tmp/restart.txt -- touch this file to have Passenger reload the site settings
passenger_wsgi.py -- the Passenger configuration
Create passenger_wsgi.py like this:
projectname = 'myproject'
virtualenv_root = '/home/jack/virtualenv/' + projectname
import sys
import os
INTERP = os.path.join(virtualenv_root, 'bin', 'python')
if sys.executable != INTERP:
os.execl(INTERP, INTERP, *sys.argv)
sys.path.append(os.path.join(os.getcwd(), projectname))
os.environ['DJANGO_SETTINGS_MODULE'] = projectname + '.prod_settings'
import django.core.handlers.wsgi
application = django.core.handlers.wsgi.WSGIHandler()
Create prod_settings.py like this:
from myproject.settings import *
DEBUG = False
TEMPLATE_DEBUG = DEBUG
ADMINS = (('My Project', 'info#myproject.com'), )
MANAGERS = ADMINS
DATABASES = {} # Appropriately for your production environment
SECRET_KEY = "..." # Your secret key
ALLOWED_HOSTS = ["myproject.com", "www.myproject.com"]
For Django 1.4 or earlier, you need to make some minor modifications, but the same idea works. I've been using variations of this setup since Django 1.2.
I setup virtualenv like this:
# install pip and virtualenv in my home directory
easy_install --user pip
pip install --user virtualenv
# create a virtualenv dedicated to my django project
mkdir ~/virtualenv
virtualenv --distribute ~/virtualenv/myproject
# activate the virtualenv, install django and all project dependencies
. ~/virtualenv/myproject/bin/activate
cd ~/projects/myproject
pip install -r requirements.txt
Notice that after activating the virtualenv, you don't need the --user flag anymore when you install packages with pip. When a virtualenv is active, all packages are installed in that virtualenv.
About requirements.txt:
Create it in your development like this: pip freeze > requirements.txt
Edit it, leave only the packages that your project really really needs. It's better to remove too much and add back later as needed.
Note that virtualenv is not necessary, but recommended. You can do without by setting INTERP in your passenger_wsgi.py to /usr/bin/python. virtualenv is useful to have multiple Django sites with different dependencies on the same account. It is also useful when you want to upgrade Django for your site, so that you can test the upgrade on beta.myproject.com without disrupting traffic on your main site.
Finally, if you are using shared hosting, DreamHost support encourages using different user accounts for each website, but I don't know what difference that makes. Be careful with heavy operations, for example large data imports, because if the process uses much memory, it can get killed by DreamHost. The memory ceiling is unspecified, but it's quite low. So if your site needs to do some heavy operations, you need to make such operations fault tolerant, in order to resume after killed.

how to use manage.py syncdb outside of Django project, such as in Tornado?

I was looking through http://lincolnloop.com/blog/2009/sep/15/using-django-inside-tornado-web-server/ and I thought it was interesting and useful to use parts of Django if we need it in Tornado.
Based on the setup in http://lincolnloop.com/blog/2009/sep/15/using-django-inside-tornado-web-server/ how can we use manage.py syncdb ?
Here's what i have tried so far:
I've tried shifting manage.py to the same folder as the tornado project, and ran manage.py syncdb but it returns saying that settings.py is not found.
than i tried to move setting.py to the same folder and ran manage.py again. It tells me that no fixtures found. This time round, I have no idea how to configure settings.py since this is not a Django project.
Any advice or thoughts?
=================updates======================
Hi all,
continuing from the above an using advice provided by Agos,
i've tried running python manage.py syncdb --settings=dj_tornado and it returns
`"Error: Can't find the file 'settings.py'` in the directory containing 'manage.py'`. It appears you've customized things.
You'll have to run django-admin.py, passing it your settings module.
(If the file settings.py does indeed exist, it's causing an ImportError somehow.)"
So what i did is to run django-admin.py syncdb --settings=dj_tornado and it returns "django.core.exceptions.ImproperlyConfigured: You haven't set the database ENGINE setting yet."
But the weird thing is that the database engine has been set. How would I go about fixing this? i'm using django 1.2.3 and Tornado 0.2 by the way.
=================updates again======================
Hi all,
i've applied the advice provided by Agos, with a settings.py file in teh same folder as manage.py, and ran the command django-admin.py syncdb --settings=dj_tornado.
I still received the error:
django.core.exceptions.ImproperlyConfigured: You haven't set the database ENGINE setting yet.
But i have already configured the database based engine as follows:
in dj_tornado.py:
from django.conf import settings
settings.configure(
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': 'dev.db',
}
}
)
I'm kind of at my wits end. How do i use syncdb outside of Django project?
Best.
If I got it correctly, you can just use the --settings switch to point manage.py to the dj_tornado.py, which is your settings file after all
Update 1
from the help, available at python manage.py help:
Options:
--settings=SETTINGS The Python path to a settings module, e.g.
"myproject.settings.main". If this isn't provided, the
DJANGO_SETTINGS_MODULE environment variable will be
used.
So I would try this:
python manage.py syncdb --settings=dj_tornado
Update 2
Another error, another update to the answer!
First of all, consider that that blog post is quite old (september 2009). Django's DATABASES setting has been updated since 1.2.
The syntax in the blog post was:
settings.configure(DATABASE_ENGINE='sqlite3', DATABASE_NAME='dev.db')
With Django 1.2.X this is surely not correct. This would be the equivalent version:
settings.configure(DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': 'dev.db'
}
})
(sorry for the horrible formatting of the code).
If this still won't work, I'd consider creating a “standard” Django settings file to import. But my bet is on the db settings syntax.
Last update, I swear
Have you tried using django-admin.py again with the new syntax? If so, and still didn't work, a minimal settings.py would be just this:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': 'dev.db'
}
}
You can also keep the original configuration inside dj_tornado.py and use settings.py just to do syncdb.