We're beginning to write unit tests for our API (created with the Django Rest Framework). We decided to start off simple and use the built in unittest and django.test.client classes. I've got the stub of a test written and it runs just fine:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import absolute_import
import unittest
# from django.test.client import Client
class TestGrowth(unittest.TestCase):
def setUp(self):
# self.client = Client()
pass
def test_numbers_3_4(self):
self.assertEqual(4, 4, True)
def test_strings_a_3(self):
self.assertEqual('andy', 'andy', True)
def suite():
suite = unittest.TestSuite()
# Add test cases to suite
suite.addTests(unittest.makeSuite(TestGrowth))
return suite
if __name__ == '__main__':
# Run test suite
unittest.TextTestRunner(verbosity=2).run(suite())
However as soon as I uncomment the line reading from django.test.client import Client I get an error:
Traceback (most recent call last):
File "./AccountGrowth.py", line 8, in <module>
from django.test.client import Client
File "/home/vagrant/.virtualenvs/emmasocial/lib/python2.7/site-packages/django/test/__init__.py", line 5, in <module>
from django.test.client import Client, RequestFactory
File "/home/vagrant/.virtualenvs/emmasocial/lib/python2.7/site-packages/django/test/client.py", line 21, in <module>
from django.db import close_connection
File "/home/vagrant/.virtualenvs/emmasocial/lib/python2.7/site-packages/django/db/__init__.py", line 11, in <module>
if settings.DATABASES and DEFAULT_DB_ALIAS not in settings.DATABASES:
File "/home/vagrant/.virtualenvs/emmasocial/lib/python2.7/site-packages/django/conf/__init__.py", line 53, in __getattr__
self._setup(name)
File "/home/vagrant/.virtualenvs/emmasocial/lib/python2.7/site-packages/django/conf/__init__.py", line 46, in _setup
% (desc, ENVIRONMENT_VARIABLE))
django.core.exceptions.ImproperlyConfigured: Requested setting DATABASES, but settings are not configured.
You must either define the environment variable DJANGO_SETTINGS_MODULE or call settings.configure() before accessing settings.
We are defining DATABASES in settings.py as follows:
if "DATABASE_URL" in os.environ:
# Parse database configuration from $DATABASE_URL
DATABASES = {
'default': dj_database_url.config()
}
else:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
'NAME': 'emmasocial', # Or path to database file if using sqlite3.
'USER': 'root', # Not used with sqlite3.
'PASSWORD': '', # Not used with sqlite3.
'HOST': '', # Set to empty string for localhost. Not used with sqlite3.
'PORT': '', # Set to empty string for default. Not used with sqlite3.
}
}
I'm running the tests from within the vagrant shell inside <app>/api/tests with the following command python ./AccountGrowth.py.
Can anyone shed some light on why this is happening?
You're not running the tests via Django's test runner, which sets all that up for you. You don't need that if __name__ == '__main__' block or its explicit call to run(), and you should run your tests via ./manage.py test.
Related
I have finished a flask app. When I run it by python run.py, the app can work perfectly.
But when I want to open flask shell by flask shell or even just flask, it tell me:
Traceback (most recent call last):
File "f:\programs\anaconda\envs\web\lib\site-packages\flask\cli.py", line 556, in list_commands
rv.update(info.load_app().cli.list_commands(ctx))
File "f:\programs\anaconda\envs\web\lib\site-packages\flask\cli.py", line 388, in load_app
app = locate_app(self, import_name, name)
File "f:\programs\anaconda\envs\web\lib\site-packages\flask\cli.py", line 257, in locate_app
return find_best_app(script_info, module)
File "f:\programs\anaconda\envs\web\lib\site-packages\flask\cli.py", line 83, in find_best_app
app = call_factory(script_info, app_factory)
File "f:\programs\anaconda\envs\web\lib\site-packages\flask\cli.py", line 117, in call_factory
return app_factory(script_info)
File "C:\Users\zkhp\Desktop\flask-bigger-master\backend\startup.py", line 41, in create_app
app.config['SECRET_KEY'] = config.get('secret', '!secret!')
AttributeError: 'ScriptInfo' object has no attribute 'get'
The last sentence is here:
def create_app(config):
app = Flask(
__name__,
template_folder=template_folder,
static_folder=static_folder
)
app.config['SECRET_KEY'] = config.get('secret', '!secret!')
The config is a dictionary, which is given by:
def start_server(run_cfg=None, is_deploy=False):
config = {
'use_cdn': False,
'debug': run_cfg.get('debug', False),
'secret': md5('!secret!'),
'url_prefix': None,
'debugtoolbar': True
}
app = create_app(config)
I am confused with how the dictionary config is transformed to be a ScriptInfo?
And what should I do to solve the problem?
seeing that you've already resolved your initial query, i wanted to suggest a better structured config write up for your future flask apps that would also make it easier to add more config variables in the case your app becomes bigger.
Consider having the configs in a module of their own, preferably in a folder name instance in the app's root folder. Here's a sample.
"""
This module sets the configurations for the application
"""
import os
class Config(object):
"""Parent configuration class."""
DEBUG = False
CSRF_ENABLED = True
SECRET_KEY = os.getenv("SECRET_KEY")
DATABASE_URL = os.getenv("DATABASE_URL")
BUNDLE_ERRORS = True
class DevelopmentConfig(Config):
"""Development phase configurations"""
DEBUG = True
class TestingConfig(Config):
"""Testing Configurations."""
TESTING = True
DEBUG = True
DATABASE_URL = os.getenv("DATABASE_TEST_URL")
class ReleaseConfig(Config):
"""Release Configurations."""
DEBUG = False
TESTING = False
app_config = {
'development': DevelopmentConfig,
'testing': TestingConfig,
'release': ReleaseConfig,
}
Now I solve the problem.
I have a file manage.py to deal all shell command lines. So the right operation is input:
python manage.py shell
And now it works normally. (OK, I still don't know why……)
I'm trying to write a test using the django testing framework, the test spawns a new background process that has access the test datebase. The test looks like this,
temp_project/temp_app/tests.py
import subprocess
from django.test import TestCase
from temp_app.models import TempModel
# Create your tests here.
class TempTest(TestCase):
def setUp(self):
TempModel.objects.create()
def test_main(self):
self.assertEqual(str(TempModel.objects.all()) + '\n',
subprocess.check_output(['python', 'manage.py', 'temp_command']))
The subprocess simply prints out the contents of the database, temp_project/temp_app/management/commands/temp_command.py
from temp_app.models import TempModel
from django.core.management.base import BaseCommand
class Command(BaseCommand):
def handle(self, *args, **kwargs):
print TempModel.objects.all()
The model is an empty placeholder, temp_project/temp_app/models.py
from django.db import models
# Create your models here.
class TempModel(models.Model):
pass
However the output from the test looks like,
> python manage.py test
Creating test database for alias 'default'...
F
======================================================================
FAIL: test_main (temp_app.tests.TempTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/dvoong/projects/opentrv/ors/source/temp/temp_project/temp_app/tests.py", line 15, in test_main
subprocess.check_output(['python', 'manage.py', 'temp_command']))
AssertionError: '[<TempModel: TempModel object>]\n' != '[]\n'
----------------------------------------------------------------------
Ran 1 test in 0.285s
FAILED (failures=1)
Destroying test database for alias 'default'...
So it seems the subprocess is accessing the production database instead of the test one. Any ideas? The database settings are, the default values,
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
The subprocess not using the test database is to be expected since you the subprocess isn't running a test command anyway. The solution would be to create a new settings file and pass it as a parameter to your subprocess using the --settings parameter. Naturally this new settings file should point to the test database.
I'm trying to test how to integrate Flask with Spark model according to this tutorial https://www.codementor.io/spark/tutorial/building-a-web-service-with-apache-spark-flask-example-app-part2#/ . Here CherryPy is used for wsgi. Trouble is that when we are launching app via spark-submit, it shows such stack trace:
Traceback (most recent call last):
File "/home/roman/dev/python/flask-spark/cherrypy.py", line 43, in <module>
run_server(app)
File "/home/roman/dev/python/flask-spark/cherrypy.py", line 21, in run_server
cherrypy.tree.graft(app_logged, '/')
AttributeError: 'module' object has no attribute 'tree'
I have no idea where the trouble is. I think that it because of new/old version or something like that, but I'm not sure. I have used also python 3 instead of python 2, but it didn't help. Here is wsgi config:
import time, sys, cherrypy, os
from paste.translogger import TransLogger
from webapp import create_app
from pyspark import SparkContext, SparkConf
def init_spark_context():
# load spark context
conf = SparkConf().setAppName("movie_recommendation-server")
# IMPORTANT: pass aditional Python modules to each worker
sc = SparkContext(conf=conf, pyFiles=['test.py', 'webapp.py'])
return sc
def run_server(app):
# Enable WSGI access logging via Paste
app_logged = TransLogger(app)
# Mount the WSGI callable object (app) on the root directory
cherrypy.tree.graft(app_logged, '/')
# Set the configuration of the web server
cherrypy.config.update({
'engine.autoreload.on': True,
'log.screen': True,
'server.socket_port': 5432,
'server.socket_host': '0.0.0.0'
})
# Start the CherryPy WSGI web server
cherrypy.engine.start()
cherrypy.engine.block()
if __name__ == "__main__":
# Init spark context and load libraries
sc = init_spark_context()
dataset_path = os.path.join('datasets', 'ml-latest-small')
app = create_app(sc, dataset_path)
# start web server
run_server(app)
Traceback you've provided clearly shows that your app is trying to use a local module called cherrypy (/home/roman/dev/python/flask-spark/cherrypy.py) not the actual cherrypy library (which should be something like /path/to/your/python/lib/python-version/siteX.Y/cherrypy).
To solve this problem you can simply rename the local module to avoid conflicts.
As a beginner in Python i must understand this code:
from settings import PROJECT_ROOT
--> I am trying in the Python Shell to type this but Python gives me a Traceback even though i have such a module
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
'NAME': '', # Or path to database file if using sqlite3.
'USER': '', # Not used with sqlite3.
'PASSWORD': '', # Not used with sqlite3.
'HOST': '', # Set to empty string for localhost. Not used with sqlite3.
'PORT': '', # Set to empty string for default. Not used with sqlite3.
}
}
--> I want to use sqlite the db that is built into Python but i really can't understand what i must do
Pardon me for the basicness of the question but i feel overwhelmed by the task i have in Python these days.
For reasons of completness this is all the code in the module which is called settings.py:
from settings import PROJECT_ROOT
DEBUG = True
TEMPLATE_DEBUG = DEBUG
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
'NAME': '', # Or path to database file if using sqlite3.
'USER': '', # Not used with sqlite3.
'PASSWORD': '', # Not used with sqlite3.
'HOST': '', # Set to empty string for localhost. Not used with sqlite3.
'PORT': '', # Set to empty string for default. Not used with sqlite3.
}
}
# Make this unique, and don't share it with anybody.
SECRET_KEY = ''
# Python dotted path to the WSGI application used by Django's runserver; added in v1.4
WSGI_APPLICATION = 'wsgi.application'
############### PYSEC specific variables
# assumes this directory exists
DATA_DIR = "%s/pysec/data/" % PROJECT_ROOT
UPDATE
I dont want to stress your already overstressed patience but why does it keep telling me the SECRET_KEY value is empty? I put
# Make this unique, and don't share it with anybody.
SECRET_KEY = 'sdfgtardyure34654356435'
and it gives me ths in text
raise ImproperlyConfigured("The SECRET_KEY setting must not be empty.")
Here it is in a pic in the cmd
Try using python manage.py shell to open the python shell.
Usually the settings.py file reside inside the project root directory, so in order to import the PROJECT_ROOT variable, you can use from project_name.settings import PROJECT_ROOT
[EDIT]
To use the sqlite engine, change the DATABASES dictionary to:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(PROJECT_ROOT, '/project_database/db_name.sqlite3'),
}
}
2[EDIT]
There's no stress. Like a tip, see this Adding Python Path on Windows 7 question to add the python files to the win path variable, this help you to avoid to put your projects inside c:PythonXX, and use another directory instead.
I've take a look at the linked github project, and it seems to explain inside the README file that you must add a SECRET_KEY and a DATA_DIR variables.
Here's a workaround I've done to get work that project:
$ git clone https://github.com/lukerosiak/pysec.git
$ cd pysec
$ ls # the dir command when on Windows
README.md
TODO.md
local_settings-example.py
manage.py*
pysec/
requirements.txt
settings.py*
$ cp local_settings-example.py local_settings.py
Edit the local_settings.py file and modify the SECRET_KEY and DATA_DIR variables:
SECRET_KEY = '#r65u-33v3vu-e^h-%u4kg=g9y5z'
DATA_DIR = '/home/slacker/pysec/project_database' # or something like: C:\\users\tosh\pysec\
project_database
Run:
$ python manage.py syncdb
I hope it can help!
I've got python installed and sqlite is included with it... but where is the sqlite db file path that was created with manage.py syncdb? I'm on a mac.
In the settings.py file, there is a variable called DATABASES. It is a dict, and one of its keys is default, which maps to another dict. This sub-dict has a key, NAME, which has the path of the SQLite database.
This is an example of a project of mine:
CURRENT_DIR= '/Users/brandizzi/Documents/software/netunong'
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': CURRENT_DIR+ '/database.db', # <- The path
'USER': '',
'PASSWORD': '',
'HOST': '',
'PORT': '',
}
}
You can easily retrieve this value using the Django shell that is accessible running the command python manage.py shell. Just follow the steps below:
>>> import settings
>>> settings.DATABASES['default']['NAME']
'/Users/brandizzi/Documents/software/netunong/database.db'
If the returned value is some relative path, just use os.path.abspath to find the absolute one:
>>> import os.path
>>> os.path.abspath(settings.DATABASES['default']['NAME'])
'/Users/brandizzi/Documents/software/netunong/database.db'
if settings not available then this could embedded in your packageName/base Directory:
try:
import packageName
import os.path.abspath
In [3]: os.path.abspath(packageName.DATABASES['default']['NAME'])`
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-3-ca6dcbd75c6d> in <module>()
----> 1 os.path.abspath(settings.DATABASES['default']['NAME'])
>>> NameError: name 'settings' is not defined
>>> os.path.abspath(packageName.settings.DATABASES['default']['NAME'])`
>>> '/Users/brandizzi/Documents/software/netunong/database.db'