diff --git a/.travis.yml b/.travis.yml index 1ea6172..d94555d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,31 +1,21 @@ sudo: false language: python +cache: + directories: + - $HOME/.cache/pip install: - pip install tox env: - - TOXENV=py26-django-14 - - TOXENV=py27-django-14 - - TOXENV=py26-django-15 - - TOXENV=py26-django-16 - - TOXENV=py27-django-15 - - TOXENV=py27-django-16 - - TOXENV=py32-django-15 - - TOXENV=py32-django-16 - - TOXENV=py33-django-15 - - TOXENV=py33-django-16 - - TOXENV=py34-django-15 - - TOXENV=py34-django-16 - - TOXENV=pypy-django-15 - - TOXENV=pypy-django-16 - TOXENV=py27-django-17 - - TOXENV=py27-django-master - - TOXENV=py32-django-17 - - TOXENV=py32-django-master + - TOXENV=py27-django-18 - TOXENV=py33-django-17 - - TOXENV=py33-django-master + - TOXENV=py33-django-18 - TOXENV=py34-django-17 - - TOXENV=py34-django-master + - TOXENV=py34-django-18 - TOXENV=pypy-django-17 + - TOXENV=pypy-django-18 + - TOXENV=py27-django-master + - TOXENV=py34-django-master - TOXENV=pypy-django-master script: - tox diff --git a/AUTHORS b/AUTHORS index d69ee00..5e065dd 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1,7 +1,39 @@ -Jiri Barton -Vojtech Jasny -Roman Krejcik -Jan Vesely Ales Zoulek -Jannis Leidel +Alexander frenzel Bouke Haarsma +Camilo Nova +Charlie Hornsby +Curtis Maloney +Dan Poirier +David Burke +Florian Apolloner +Igor Támara +Jake Merdich +Jannis Leidel +Janusz Harkot +Jiri Barton +Jonas +Kuba Zarzycki +Leandra Finger +Les Orchard +Lin Xianyi +Marcin Baran +Mario Orlandi +Mario Rosa +Mattia Larentis +Merijn Bertels +Omer Katz +Petr Knap +Philip Neustrom +Pierre-Olivier Marec +Roman Krejcik +Silvan Spross +Sławek Ehlert +Vojtech Jasny +Yin Jifeng +illumin-us-r3v0lution +mega +saw2th +trbs +vl <1844144@gmail.com> +vl diff --git a/LICENSE b/LICENSE index f1915ae..16e64b9 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2009-2014, Comoga and individual contributors +Copyright (c) 2009-2015, Comoga and individual contributors All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/constance/__init__.py b/constance/__init__.py index db2511f..c4b9842 100644 --- a/constance/__init__.py +++ b/constance/__init__.py @@ -1,6 +1,6 @@ from django.utils.functional import LazyObject -__version__ = '1.0.1' +__version__ = '1.1.1' default_app_config = 'constance.apps.ConstanceConfig' diff --git a/constance/admin.py b/constance/admin.py index cbae4fc..32bc15a 100644 --- a/constance/admin.py +++ b/constance/admin.py @@ -3,30 +3,21 @@ from decimal import Decimal import hashlib from operator import itemgetter -from django import forms +from django import forms, VERSION +from django.conf.urls import url from django.contrib import admin, messages from django.contrib.admin import widgets from django.contrib.admin.options import csrf_protect_m from django.core.exceptions import PermissionDenied, ImproperlyConfigured from django.forms import fields from django.http import HttpResponseRedirect -from django.shortcuts import render_to_response -from django.template.context import RequestContext +from django.template.response import TemplateResponse from django.utils import six +from django.utils.encoding import smart_bytes from django.utils.formats import localize from django.utils.translation import ugettext_lazy as _ import django -try: - from django.utils.encoding import smart_bytes -except ImportError: - from django.utils.encoding import smart_str as smart_bytes - -try: - from django.conf.urls import patterns, url -except ImportError: # Django < 1.4 - from django.conf.urls.defaults import patterns, url - from . import LazyConfig, settings @@ -111,17 +102,18 @@ class ConstanceForm(forms.Form): class ConstanceAdmin(admin.ModelAdmin): + change_list_template = 'admin/constance/change_list.html' def get_urls(self): info = self.model._meta.app_label, self.model._meta.module_name - return patterns('', + return [ url(r'^$', self.admin_site.admin_view(self.changelist_view), name='%s_%s_changelist' % info), url(r'^$', self.admin_site.admin_view(self.changelist_view), name='%s_%s_add' % info), - ) + ] @csrf_protect_m def changelist_view(self, request, extra_context=None): @@ -146,7 +138,7 @@ class ConstanceAdmin(admin.ModelAdmin): ) return HttpResponseRedirect('.') context = { - 'config': [], + 'config_values': [], 'title': _('Constance config'), 'app_label': 'constance', 'opts': Config._meta, @@ -160,7 +152,7 @@ class ConstanceAdmin(admin.ModelAdmin): # Then if the returned value is None, get the default if value is None: value = getattr(config, name) - context['config'].append({ + context['config_values'].append({ 'name': name, 'default': localize(default), 'help_text': _(help_text), @@ -168,11 +160,12 @@ class ConstanceAdmin(admin.ModelAdmin): 'modified': value != default, 'form_field': form[name], }) - context['config'].sort(key=itemgetter('name')) - context_instance = RequestContext(request, - current_app=self.admin_site.name) - return render_to_response('admin/constance/change_list.html', - context, context_instance=context_instance) + context['config_values'].sort(key=itemgetter('name')) + request.current_app = self.admin_site.name + # compatibility to be removed when 1.7 is deprecated + extra = {'current_app': self.admin_site.name} if VERSION < (1, 8) else {} + return TemplateResponse(request, self.change_list_template, context, + **extra) def has_add_permission(self, *args, **kwargs): return False @@ -192,10 +185,12 @@ class Config(object): object_name = 'Config' model_name = module_name = 'config' verbose_name_plural = _('config') - get_ordered_objects = lambda x: False abstract = False swapped = False + def get_ordered_objects(self): + return False + def get_change_permission(self): return 'change_%s' % self.model_name diff --git a/constance/apps.py b/constance/apps.py index 77226f7..bd8a894 100644 --- a/constance/apps.py +++ b/constance/apps.py @@ -1,3 +1,5 @@ +from django.db.models import signals +from django import VERSION from django.apps import AppConfig from django.utils.translation import ugettext_lazy as _ @@ -5,3 +7,28 @@ from django.utils.translation import ugettext_lazy as _ class ConstanceConfig(AppConfig): name = 'constance' verbose_name = _('Constance') + + def ready(self): + super(ConstanceConfig, self).ready() + signals.post_migrate.connect(self.create_perm, + dispatch_uid='constance.create_perm') + + def create_perm(self, *args, **kwargs): + """ + Creates a fake content type and permission + to be able to check for permissions + """ + from django.contrib.auth.models import Permission + from django.contrib.contenttypes.models import ContentType + + if ContentType._meta.installed and Permission._meta.installed: + extra = {} if VERSION >= (1, 8) else {'name': 'config'} + content_type, created = ContentType.objects.get_or_create( + app_label='constance', + model='config', + **extra) + + permission, created = Permission.objects.get_or_create( + name='Can change config', + content_type=content_type, + codename='change_config') diff --git a/constance/backends/database/__init__.py b/constance/backends/database/__init__.py index aa1ceaa..59882d8 100644 --- a/constance/backends/database/__init__.py +++ b/constance/backends/database/__init__.py @@ -1,11 +1,7 @@ +from django.core.cache import caches +from django.core.cache.backends.locmem import LocMemCache from django.core.exceptions import ImproperlyConfigured from django.db.models.signals import post_save -from django.core.cache import get_cache - -try: - from django.core.cache.backends.locmem import LocMemCache -except ImportError: - from django.core.cache.backends.locmem import CacheClass as LocMemCache from .. import Backend from ... import settings @@ -25,7 +21,7 @@ class DatabaseBackend(Backend): "correctly. Make sure it's in your INSTALLED_APPS setting.") if settings.DATABASE_CACHE_BACKEND: - self._cache = get_cache(settings.DATABASE_CACHE_BACKEND) + self._cache = caches[settings.DATABASE_CACHE_BACKEND] if isinstance(self._cache, LocMemCache): raise ImproperlyConfigured( "The CONSTANCE_DATABASE_CACHE_BACKEND setting refers to a " diff --git a/constance/locale/zh_CN/LC_MESSAGES/django.mo b/constance/locale/zh_CN/LC_MESSAGES/django.mo index 92c32d1..d9efd21 100644 Binary files a/constance/locale/zh_CN/LC_MESSAGES/django.mo and b/constance/locale/zh_CN/LC_MESSAGES/django.mo differ diff --git a/constance/locale/zh_CN/LC_MESSAGES/django.po b/constance/locale/zh_CN/LC_MESSAGES/django.po index c469e1e..dbad41c 100644 --- a/constance/locale/zh_CN/LC_MESSAGES/django.po +++ b/constance/locale/zh_CN/LC_MESSAGES/django.po @@ -3,14 +3,15 @@ # This file is distributed under the same license as the PACKAGE package. # # Translators: +# Yifu Yu , 2015 msgid "" msgstr "" "Project-Id-Version: django-constance\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2014-11-27 19:05+0100\n" -"PO-Revision-Date: 2014-11-27 18:13+0000\n" -"Last-Translator: Jannis Leidel \n" -"Language-Team: Chinese (China) (http://www.transifex.com/projects/p/django-constance/language/zh_CN/)\n" +"PO-Revision-Date: 2015-03-15 18:40+0000\n" +"Last-Translator: Yifu Yu \n" +"Language-Team: Chinese (China) (http://www.transifex.com/jezdez/django-constance/language/zh_CN/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" @@ -22,13 +23,13 @@ msgstr "" msgid "" "Constance doesn't support config values of the type %(config_type)s. Please " "fix the value of '%(name)s'." -msgstr "" +msgstr "Constance不支持保存类型为%(config_type)s的值,请修正%(name)s的值。" #: admin.py:91 msgid "" "The settings have been modified by someone else. Please reload the form and " "resubmit your changes." -msgstr "" +msgstr "设置已经被他人修改过,请刷新页面并重新提交您的更改。" #: admin.py:129 msgid "Live settings updated successfully." @@ -36,7 +37,7 @@ msgstr "成功更新实时配置" #: admin.py:134 msgid "Constance config" -msgstr "常量配置" +msgstr "Constance 配置页面" #: admin.py:177 msgid "config" @@ -44,15 +45,15 @@ msgstr "配置" #: apps.py:9 msgid "Constance" -msgstr "" +msgstr "Constance模块" #: backends/database/models.py:19 msgid "constance" -msgstr "常量" +msgstr "Constance模块" #: backends/database/models.py:20 msgid "constances" -msgstr "常量" +msgstr "Constance模块" #: templates/admin/constance/change_list.html:50 msgid "Name" @@ -68,7 +69,7 @@ msgstr "值" #: templates/admin/constance/change_list.html:53 msgid "Is modified" -msgstr "是否修改" +msgstr "是否修改过" #: templates/admin/constance/change_list.html:79 msgid "Save" diff --git a/constance/models.py b/constance/models.py deleted file mode 100644 index e341795..0000000 --- a/constance/models.py +++ /dev/null @@ -1,24 +0,0 @@ -from django.db.models import signals - - -def create_perm(app, created_models, verbosity, db, **kwargs): - """ - Creates a fake content type and permission - to be able to check for permissions - """ - from django.contrib.auth.models import Permission - from django.contrib.contenttypes.models import ContentType - - if ContentType._meta.installed and Permission._meta.installed: - content_type, created = ContentType.objects.get_or_create( - name='config', - app_label='constance', - model='config') - - permission, created = Permission.objects.get_or_create( - name='Can change config', - content_type=content_type, - codename='change_config') - - -signals.post_syncdb.connect(create_perm, dispatch_uid="constance.create_perm") diff --git a/constance/templates/admin/constance/change_list.html b/constance/templates/admin/constance/change_list.html index 27e792c..746e263 100644 --- a/constance/templates/admin/constance/change_list.html +++ b/constance/templates/admin/constance/change_list.html @@ -1,6 +1,5 @@ {% extends "admin/base_site.html" %} {% load admin_static admin_list i18n %} -{% load url from future %} {% block extrastyle %} @@ -61,10 +60,10 @@
{% trans "Is modified" %}
- {% for item in config %} + {% for item in config_values %} {{ item.name }} -
{{ item.help_text }}
+
{{ item.help_text|linebreaksbr }}
{{ item.default }} diff --git a/constance/test/__init__.py b/constance/test/__init__.py new file mode 100644 index 0000000..0fb5524 --- /dev/null +++ b/constance/test/__init__.py @@ -0,0 +1 @@ +from .utils import override_config diff --git a/constance/test/utils.py b/constance/test/utils.py new file mode 100644 index 0000000..5f692f9 --- /dev/null +++ b/constance/test/utils.py @@ -0,0 +1,85 @@ +from functools import wraps + +from django.test import SimpleTestCase +from django.test.utils import override_settings + +from .. import config + +__all__ = ('override_config',) + + +class override_config(override_settings): + """ + Decorator to modify constance setting for TestCase. + + Based on django.test.utils.override_settings. + """ + def __init__(self, **kwargs): + super(override_config, self).__init__(**kwargs) + self.original_values = {} + + def __call__(self, test_func): + """ + Modify the decorated function to override config values. + """ + if isinstance(test_func, type): + if not issubclass(test_func, SimpleTestCase): + raise Exception( + "Only subclasses of Django SimpleTestCase can be " + "decorated with override_config") + return self.modify_test_case(test_func) + else: + @wraps(test_func) + def inner(*args, **kwargs): + with self: + return test_func(*args, **kwargs) + return inner + + def modify_test_case(self, test_case): + """ + Override the config by modifying TestCase methods. + + This method follows the Django <= 1.6 method of overriding the + _pre_setup and _post_teardown hooks rather than modifying the TestCase + itself. + """ + original_pre_setup = test_case._pre_setup + original_post_teardown = test_case._post_teardown + + def _pre_setup(inner_self): + self.enable() + original_pre_setup(inner_self) + + def _post_teardown(inner_self): + original_post_teardown(inner_self) + self.disable() + + test_case._pre_setup = _pre_setup + test_case._post_teardown = _post_teardown + + return test_case + + def enable(self): + """ + Store original config values and set overridden values. + """ + # Store the original values to an instance variable + for config_key in self.options.keys(): + self.original_values[config_key] = getattr(config, config_key) + + # Update config with the overriden values + self.unpack_values(self.options) + + def disable(self): + """ + Set original values to the config. + """ + self.unpack_values(self.original_values) + + @staticmethod + def unpack_values(options): + """ + Unpack values from the given dict to config. + """ + for name, value in options.items(): + setattr(config, name, value) diff --git a/constance/utils.py b/constance/utils.py index 96fc572..8d8d341 100644 --- a/constance/utils.py +++ b/constance/utils.py @@ -1,4 +1,4 @@ -from django.utils.importlib import import_module +from importlib import import_module def import_module_attr(path): diff --git a/docs/changes.rst b/docs/changes.rst index 20da8a6..fedbe64 100644 --- a/docs/changes.rst +++ b/docs/changes.rst @@ -1,6 +1,33 @@ Changelog --------- +v1.1.1 (2015/10/01) +~~~~~~~~~~~~~~~~~~~ + +* Fixed a regression in the 1.1 release that prevented the rendering of the + admin view with constance values when using the context processor at the + same time. + +v1.1 (2015/09/24) +~~~~~~~~~~~~~~~~~ + +* **BACKWARD INCOMPATIBLE** Dropped support for Python 2.6 + The supported versions are 2.7, 3.3 (on Django < 1.9) and 3.4. + +* **BACKWARD INCOMPATIBLE** Dropped support for Django 1.4, 1.5 and 1.6 + The supported versions are 1.7, 1.8 and the upcoming 1.9 release + +* Added compatibility to Django 1.8 and 1.9. + +* Added Spanish and Chinese (``zh_CN``) translations. + +* Added :class:`override_config` decorator/context manager for easy + :doc:`testing `. + +* Added the ability to use linebreaks in config value help texts. + +* Various testing fixes. + v1.0.1 (2015/01/07) ~~~~~~~~~~~~~~~~~~~ diff --git a/docs/conf.py b/docs/conf.py index 2134a66..e2b4bff 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -46,7 +46,7 @@ master_doc = 'index' # General information about the project. project = u'django-constance' -copyright = u'2014, Comoga and individual contributors' +copyright = u'2015, Comoga and individual contributors' # The short X.Y version. try: @@ -101,7 +101,7 @@ pygments_style = 'sphinx' # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. -html_theme = 'default' +html_theme = 'sphinx_rtd_theme' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the diff --git a/docs/index.rst b/docs/index.rst index feea83a..9aae1b7 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -160,6 +160,7 @@ More documentation :maxdepth: 2 backends + testing changes Indices and tables diff --git a/docs/testing.rst b/docs/testing.rst new file mode 100644 index 0000000..8d092f1 --- /dev/null +++ b/docs/testing.rst @@ -0,0 +1,40 @@ +Testing +======= + +Testing how your app behaves with different config values is achieved with the +:class:`override_config` class. This intentionally mirrors the use of Django's +:class:`~django.test.override_setting`. + +.. py:class:: override_config(**kwargs) + + Replaces key-value pairs in the config. + Use as decorator or context manager. + +Usage +~~~~~ + +It can be used as a decorator at the :class:`~django.test.TestCase` level, the +method level and also as a +`context manager `_. + +.. code-block:: python + + from constance import config + from constance.test import override_config + + from django.test import TestCase + + + @override_config(YOUR_NAME="Arthur of Camelot") + class ExampleTestCase(TestCase): + + def test_what_is_your_name(self): + self.assertEqual(config.YOUR_NAME, "Arthur of Camelot") + + @override_config(YOUR_QUEST="To find the Holy Grail") + def test_what_is_your_quest(self): + self.assertEqual(config.YOUR_QUEST, "To find the Holy Grail") + + def test_what_is_your_favourite_color(self): + with override_config(YOUR_FAVOURITE_COLOR="Blue?"): + self.assertEqual(config.YOUR_FAVOURITE_COLOR, "Blue?") diff --git a/example/cheeseshop/settings.py b/example/cheeseshop/settings.py index 049c3d9..9ad2ffc 100644 --- a/example/cheeseshop/settings.py +++ b/example/cheeseshop/settings.py @@ -72,6 +72,22 @@ TEMPLATE_LOADERS = ( # 'django.template.loaders.eggs.Loader', ) +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [], + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + ], + }, + }, +] + MIDDLEWARE_CLASSES = ( 'django.middleware.common.CommonMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', diff --git a/tests/settings.py b/tests/settings.py index d7678e2..361a1b9 100644 --- a/tests/settings.py +++ b/tests/settings.py @@ -72,6 +72,7 @@ CONSTANCE_CONFIG = { 'DATE_VALUE': (date(2010, 12, 24), 'Merry Chrismas'), 'TIME_VALUE': (time(23, 59, 59), 'And happy New Year'), 'CHOICE_VALUE': ('yes', 'select yes or no', 'yes_no_null_select'), + 'LINEBREAK_VALUE': ('Spam spam', 'eggs\neggs'), } DEBUG = True @@ -79,3 +80,32 @@ DEBUG = True STATIC_ROOT = './static/' STATIC_URL = '/static/' + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [], + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + 'constance.context_processors.config', + ], + }, + }, +] + +TEMPLATE_CONTEXT_PROCESSORS = ( + 'django.contrib.auth.context_processors.auth', + 'django.core.context_processors.debug', + 'django.core.context_processors.i18n', + 'django.core.context_processors.media', + 'django.core.context_processors.static', + 'django.core.context_processors.tz', + 'django.core.context_processors.request', + 'django.contrib.messages.context_processors.messages', + 'constance.context_processors.config', +) diff --git a/tests/test_admin.py b/tests/test_admin.py index 5ac9521..5ad5806 100644 --- a/tests/test_admin.py +++ b/tests/test_admin.py @@ -1,7 +1,9 @@ from django.contrib import admin from django.contrib.auth.models import User, Permission +from django.contrib.contenttypes.models import ContentType from django.core.exceptions import PermissionDenied from django.test import TestCase, RequestFactory +from django.utils import six from constance.admin import settings, Config @@ -44,3 +46,15 @@ class TestAdmin(TestCase): response = self.options.changelist_view(request, {}) self.assertEqual(response.status_code, 200) + + def test_str(self): + ct = ContentType.objects.get(app_label='constance', model='config') + self.assertEqual(six.text_type(ct), 'config') + + def test_linebreaks(self): + self.client.login(username='admin', password='nimda') + request = self.rf.get('/admin/constance/config/') + request.user = self.superuser + response = self.options.changelist_view(request, {}) + self.assertContains(response, 'LINEBREAK_VALUE') + self.assertContains(response, 'eggs
eggs') diff --git a/tests/test_test_utils.py b/tests/test_test_utils.py new file mode 100644 index 0000000..313246d --- /dev/null +++ b/tests/test_test_utils.py @@ -0,0 +1,34 @@ +from django.test import TestCase + +from constance import config +from constance.test import override_config + + +class OverrideConfigFunctionDecoratorTestCase(TestCase): + """Test that the override_config decorator works correctly. + + Test usage of override_config on test method and as context manager. + """ + def test_default_value_is_true(self): + """Assert that the default value of config.BOOL_VALUE is True.""" + self.assertTrue(config.BOOL_VALUE) + + @override_config(BOOL_VALUE=False) + def test_override_config_on_method_changes_config_value(self): + """Assert that the method decorator changes config.BOOL_VALUE.""" + self.assertFalse(config.BOOL_VALUE) + + def test_override_config_as_context_manager_changes_config_value(self): + """Assert that the context manager changes config.BOOL_VALUE.""" + with override_config(BOOL_VALUE=False): + self.assertFalse(config.BOOL_VALUE) + + self.assertTrue(config.BOOL_VALUE) + + +@override_config(BOOL_VALUE=False) +class OverrideConfigClassDecoratorTestCase(TestCase): + """Test that the override_config decorator works on classes.""" + def test_override_config_on_class_changes_config_value(self): + """Asser that the class decorator changes config.BOOL_VALUE.""" + self.assertFalse(config.BOOL_VALUE) diff --git a/tests/urls.py b/tests/urls.py index 6927e0e..12fe50c 100644 --- a/tests/urls.py +++ b/tests/urls.py @@ -1,11 +1,8 @@ from django.contrib import admin -try: - from django.conf.urls import patterns, include -except ImportError: - from django.conf.urls.defaults import patterns, include +from django.conf.urls import url, include -urlpatterns = patterns('', - (r'^admin/', include(admin.site.urls)), -) +urlpatterns = [ + url(r'^admin/', include(admin.site.urls)), +] diff --git a/tox.ini b/tox.ini index 12fb035..4449e06 100644 --- a/tox.ini +++ b/tox.ini @@ -1,30 +1,26 @@ [tox] envlist = - py26-django-14, - py27-django-14, - {py26,py27,py32,py33,py34,pypy}-django-{15,16}, - {py27,py32,py33,py34,pypy}-django-{17,master} + {py27,py33,py34,pypy}-django-{17,18}, + {py27,py34,pypy}-django-master [testenv] basepython = - py26: python2.6 py27: python2.7 - py32: python3.2 py33: python3.3 py34: python3.4 + py35: python3.5 pypy: pypy deps = redis coverage django-picklefield - py26: unittest2 - django-{14,15}: django-discover-runner - django-14: Django>=1.4,<1.5 - django-15: Django>=1.5,<1.6 - django-16: Django>=1.6,<1.7 django-17: Django>=1.7,<1.8 - django-master: https://github.com/django/django/archive/master.zip + django-18: Django>=1.8,<1.9 + django-master: https://github.com/django/django/archive/master.tar.gz usedevelop = true commands = - coverage run {envbindir}/django-admin.py test --settings=tests.settings -v2 + coverage run {envbindir}/django-admin.py test -v2 coverage report +setenv = + PYTHONDONTWRITEBYTECODE=1 + DJANGO_SETTINGS_MODULE=tests.settings