Update to latest version of django-selectable
authorMagnus Hagander <magnus@hagander.net>
Wed, 1 Apr 2020 19:21:11 +0000 (21:21 +0200)
committerMagnus Hagander <magnus@hagander.net>
Wed, 1 Apr 2020 19:33:29 +0000 (21:33 +0200)
32 files changed:
dep/django-selectable/AUTHORS.txt
dep/django-selectable/LICENSE.txt
dep/django-selectable/PKG-INFO [deleted file]
dep/django-selectable/README.rst
dep/django-selectable/docs/admin.rst
dep/django-selectable/docs/lookups.rst
dep/django-selectable/docs/releases.rst
dep/django-selectable/grunt.js [deleted file]
dep/django-selectable/runtests.py [changed mode: 0644->0755]
dep/django-selectable/selectable/__init__.py
dep/django-selectable/selectable/base.py
dep/django-selectable/selectable/compat.py
dep/django-selectable/selectable/decorators.py
dep/django-selectable/selectable/forms/fields.py
dep/django-selectable/selectable/forms/widgets.py
dep/django-selectable/selectable/static/selectable/js/jquery.dj.selectable.js
dep/django-selectable/selectable/tests/__init__.py
dep/django-selectable/selectable/tests/base.py
dep/django-selectable/selectable/tests/decorators.py [deleted file]
dep/django-selectable/selectable/tests/fields.py [deleted file]
dep/django-selectable/selectable/tests/forms.py [deleted file]
dep/django-selectable/selectable/tests/functests.py [deleted file]
dep/django-selectable/selectable/tests/templatetags.py [deleted file]
dep/django-selectable/selectable/tests/test_base.py
dep/django-selectable/selectable/tests/test_decorators.py
dep/django-selectable/selectable/tests/test_functional.py
dep/django-selectable/selectable/tests/test_views.py
dep/django-selectable/selectable/tests/test_widgets.py
dep/django-selectable/selectable/tests/views.py
dep/django-selectable/selectable/tests/widgets.py [deleted file]
dep/django-selectable/setup.py [changed mode: 0644->0755]
dep/django-selectable/tox.ini

index 965073b01e25521463d1ed65df674b1deb92e271..ef1920f3c94e4ff2eeec5af830e95c7b4ad49527 100644 (file)
@@ -28,5 +28,6 @@ Raphael Merx
 Josh Addington
 Tobias Zanke
 Petr Dlouhy
+Vinod Kurup
 
 Thanks for all of your work!
index b06f6132e1b23491b096cb8515f34030d8fe04a5..41cda46e304d90f594998586cd358a0c234ade82 100644 (file)
@@ -1,4 +1,4 @@
-Copyright (c) 2010-2018, Mark Lavin
+Copyright (c) 2010-201999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999, Mark Lavin
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
diff --git a/dep/django-selectable/PKG-INFO b/dep/django-selectable/PKG-INFO
deleted file mode 100644 (file)
index 4a7072d..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
-Metadata-Version: 1.1
-Name: django-selectable
-Version: 0.9.0
-Summary: Auto-complete selection widgets using Django and jQuery UI.
-Home-page: https://github.com/mlavin/django-selectable
-Author: Mark Lavin
-Author-email: markdlavin@gmail.com
-License: BSD
-Description: django-selectable
-        ===================
-        
-        Tools and widgets for using/creating auto-complete selection widgets using Django and jQuery UI.
-        
-        .. image:: https://travis-ci.org/mlavin/django-selectable.svg?branch=master
-            :target: https://travis-ci.org/mlavin/django-selectable
-        
-        
-        Features
-        -----------------------------------
-        
-        - Works with the latest jQuery UI Autocomplete library
-        - Auto-discovery/registration pattern for defining lookups
-        
-        
-        Installation Requirements
-        -----------------------------------
-        
-        - Python 2.6-2.7, 3.2+
-        - `Django <http://www.djangoproject.com/>`_ >= 1.5
-        - `jQuery <http://jquery.com/>`_ >= 1.7
-        - `jQuery UI <http://jqueryui.com/>`_ >= 1.8
-        
-        To install::
-        
-            pip install django-selectable
-        
-        Next add `selectable` to your `INSTALLED_APPS` to include the related css/js::
-        
-            INSTALLED_APPS = (
-                'contrib.staticfiles',
-                # Other apps here
-                'selectable',
-            )
-        
-        The jQuery and jQuery UI libraries are not included in the distribution but must be included
-        in your templates. See the example project for an example using these libraries from the
-        Google CDN.
-        
-        Once installed you should add the urls to your root url patterns::
-        
-            urlpatterns = patterns('',
-                # Other patterns go here
-                (r'^selectable/', include('selectable.urls')),
-            )
-        
-        
-        Documentation
-        -----------------------------------
-        
-        Documentation for django-selectable is available on `Read The Docs <http://readthedocs.org/docs/django-selectable>`_.
-        
-        
-        Additional Help/Support
-        -----------------------------------
-        
-        You can find additional help or support on the mailing list: http://groups.google.com/group/django-selectable
-        
-        
-        Contributing
-        --------------------------------------
-        
-        If you think you've found a bug or are interested in contributing to this project
-        check out our `contributing guide <http://readthedocs.org/docs/django-selectable/en/latest/contribute.html>`_.
-        
-        If you are interested in translating django-selectable into your native language
-        you can join the `Transifex project <https://www.transifex.com/projects/p/django-selectable/>`_.
-        
-        
-Platform: UNKNOWN
-Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
-Classifier: Intended Audience :: Developers
-Classifier: License :: OSI Approved :: BSD License
-Classifier: Programming Language :: Python
-Classifier: Programming Language :: Python :: 2.6
-Classifier: Programming Language :: Python :: 2.7
-Classifier: Programming Language :: Python :: 3
-Classifier: Programming Language :: Python :: 3.2
-Classifier: Programming Language :: Python :: 3.3
-Classifier: Programming Language :: Python :: 3.4
-Classifier: Framework :: Django
-Classifier: Development Status :: 5 - Production/Stable
-Classifier: Operating System :: OS Independent
index 86f8aa086dde154ec640b5829c166454fc89a168..8a06eb3800769fe0cfae33fbf89b916dd24157f9 100644 (file)
@@ -33,10 +33,10 @@ Features
 Installation Requirements
 -----------------------------------
 
-- Python 2.7, 3.3+
-- `Django <http://www.djangoproject.com/>`_ >= 1.7, <= 1.11
+- Python 2.7, 3.4+
+- `Django <http://www.djangoproject.com/>`_ >= 1.11, <= 3.0
 - `jQuery <http://jquery.com/>`_ >= 1.9, < 3.0
-- `jQuery UI <http://jqueryui.com/>`_ >= 1.10, < 1.12
+- `jQuery UI <http://jqueryui.com/>`_ >= 1.10
 
 To install::
 
index e0c02fa3d741db81c2bda9d4f696e599a2a3f4ea..df64701a93f0391673df0bfb267a1810c63beb81 100644 (file)
@@ -77,7 +77,7 @@ a many to many relation to our ``Fruit`` model.
         @python_2_unicode_compatible
         class Farm(models.Model):
             name = models.CharField(max_length=200)
-            owner = models.ForeignKey('auth.User', related_name='farms')
+            owner = models.ForeignKey('auth.User', related_name='farms', on_delete=models.CASCADE)
             fruit = models.ManyToManyField(Fruit)
 
             def __str__(self):
@@ -171,4 +171,3 @@ We can even make use of the same ``FarmAdminForm``.
         admin.site.register(User, NewUserAdmin)
 
 The auto-complete functions will be bound as new forms are added dynamically.
-
index 5bb7cda5ecb2980418cca26094ab714fa545afaf..00edbae427c149fe10e992f06cb0504f30a54bf4 100644 (file)
@@ -63,6 +63,15 @@ Lookup API
     :param item: An item from the search results.
     :return: A string representation of the item to be returned by the field/widget.
 
+
+.. py:method:: LookupBase.split_term(term)
+
+     Split searching term into array of subterms that will be searched separately.
+     You can override this function to achieve different splitting of the term.
+
+    :param term: The search term.
+    :return: Array with subterms
+
 .. py:method:: LookupBase.get_item_value(item)
 
     This is last of three formatting methods. The value is shown in the
index 6acd244b7ca700cc8a704ebc87af2187d714f76f..c48cedb12ff2312ace9274057eefa6fea63e9472 100644 (file)
@@ -2,6 +2,28 @@ Release Notes
 ==================
 
 
+v1.2.1 (Released 2019-02-02)
+--------------------------------------
+
+Fixed compatibility issue with jQuery UI 1.12. Thanks to Christian Klus (kluchrj) for the fix.
+
+
+v1.2.0 (Released 2018-10-13)
+--------------------------------------
+
+Primarily a Django support related release. This version adds support for Django 2.0 and 2.1 while
+dropping support for Django versions below 1.11. A number of deprecation warnings for future Django
+versions have also been addressed.
+
+Added the ability to search on multiple terms split by whitespace.
+
+
+Backwards Incompatible Changes
+________________________________
+
+- Dropped support for Django versions below 1.11
+
+
 v1.1.0 (Released 2018-01-12)
 --------------------------------------
 
diff --git a/dep/django-selectable/grunt.js b/dep/django-selectable/grunt.js
deleted file mode 100644 (file)
index e2065b7..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-/*global module:false*/
-module.exports = function(grunt) {
-
-  // Project configuration.
-  grunt.initConfig({
-    qunit: {
-      urls: [
-        'http://localhost:<%= server.port %>/selectable/tests/qunit/index.html?jquery=1.10.1&ui=1.10.3',
-        'http://localhost:<%= server.port %>/selectable/tests/qunit/index.html?jquery=1.9.1&ui=1.10.3',
-        'http://localhost:<%= server.port %>/selectable/tests/qunit/index.html?jquery=1.8.3&ui=1.9.2',
-        'http://localhost:<%= server.port %>/selectable/tests/qunit/index.html?jquery=1.7.2&ui=1.8.24',
-        'http://localhost:<%= server.port %>/selectable/tests/qunit/index.html?jquery=1.6.4&ui=1.8.24'
-      ]
-    },
-    lint: {
-      files: ['selectable/static/selectable/js/*.js']
-    },
-    watch: {
-      files: '<config:lint.files>',
-      tasks: 'lint qunit'
-    },
-    jshint: {
-      options: {
-        curly: true,
-        eqeqeq: true,
-        immed: true,
-        latedef: true,
-        newcap: true,
-        noarg: true,
-        sub: true,
-        undef: true,
-        boss: true,
-        eqnull: true,
-        browser: true,
-        undef: true,
-        trailing: true,
-        indent: 4
-      },
-      globals: {
-        jQuery: true,
-        // Django admin globals
-        django: true,
-        dismissAddAnotherPopup: true,
-        windowname_to_id: true,
-        html_unescape: true,
-        // Optional globals
-        djselectableAdminPatch: true,
-        djselectableAutoLoad: true,
-        // Grappelli namespace
-        grp: true
-      }
-    },
-    server: {
-      port: 8085
-    },
-  });
-
-  // Default task.
-  grunt.registerTask('default', 'server lint qunit');
-
-};
old mode 100644 (file)
new mode 100755 (executable)
index 82dc159..a06c445
@@ -13,11 +13,10 @@ if not settings.configured:
                 'NAME': ':memory:',
             }
         },
-        MIDDLEWARE_CLASSES=(),
+        MIDDLEWARE=(),
         INSTALLED_APPS=(
             'selectable',
         ),
-        SITE_ID=1,
         SECRET_KEY='super-secret',
         ROOT_URLCONF='selectable.tests.urls',
         TEMPLATES=[{
index 0412b9b014780ec7a1489412036ae9e449c0a997..a93d9cccc1afd2de6d58cd57019be090263c2035 100644 (file)
@@ -1,6 +1,6 @@
 "Auto-complete selection widgets using Django and jQuery UI."
 
 
-__version__ = '1.1.0'
+__version__ = '1.2.1'
 
 default_app_config = 'selectable.apps.SelectableConfig'
index bc74204ce5190fa50e495003e272194d39a19b6e..9570a19454695dfc7ee5a556ace3a93031448dc3 100644 (file)
@@ -7,15 +7,14 @@ from functools import reduce
 
 from django.conf import settings
 from django.core.paginator import Paginator, InvalidPage, EmptyPage
-from django.core.urlresolvers import reverse
 from django.http import JsonResponse
 from django.db.models import Q, Model
+from django.urls import reverse
 from django.utils.encoding import smart_text
 from django.utils.html import conditional_escape
 from django.utils.translation import ugettext as _
 
-from selectable.forms import BaseLookupForm
-
+from .forms import BaseLookupForm
 
 __all__ = (
     'LookupBase',
@@ -36,6 +35,13 @@ class LookupBase(object):
         return name
     name = classmethod(_name)
 
+    def split_term(self, term):
+        """
+        Split searching term into array of subterms
+        that will be searched separately.
+        """
+        return term.split()
+
     def _url(cls):
         return reverse('selectable-lookup', args=[cls.name()])
     url = classmethod(_url)
@@ -123,11 +129,12 @@ class ModelLookup(LookupBase):
     def get_query(self, request, term):
         qs = self.get_queryset()
         if term:
-            search_filters = []
             if self.search_fields:
-                for field in self.search_fields:
-                    search_filters.append(Q(**{field: term}))
-            qs = qs.filter(reduce(operator.or_, search_filters))
+                for t in self.split_term(term):
+                    search_filters = []
+                    for field in self.search_fields:
+                        search_filters.append(Q(**{field: t}))
+                    qs = qs.filter(reduce(operator.or_, search_filters))
         return qs
 
     def get_queryset(self):
index 448a798232611de72021347c0d2b8aead4110b20..c438c8506c468ccbf9ad8dd1a0fbf0c6054633d2 100644 (file)
@@ -1,6 +1,7 @@
-"Compatibility utilites for Python/Django versions."
+"Compatibility utilites for Python versions."
 
 try:
     from urllib.parse import urlparse
 except ImportError:
+    # This can be removed when Python 2.7 support is dropped
     from urlparse import urlparse
index a831a007dc421be88be8d35a420a04cc30322ad9..3245383ebb64f035c8a2c1c067caeae79249cef1 100644 (file)
@@ -40,7 +40,7 @@ def results_decorator(func):
 
 
 @results_decorator
-def ajax_required(request):    
+def ajax_required(request):
     "Lookup decorator to require AJAX calls to the lookup view."
     if not request.is_ajax():
         return HttpResponseBadRequest()
@@ -50,7 +50,7 @@ def ajax_required(request):
 def login_required(request):
     "Lookup decorator to require the user to be authenticated."
     user = getattr(request, 'user', None)
-    if user is None or not user.is_authenticated():
+    if user is None or not user.is_authenticated:
         return HttpResponse(status=401) # Unauthorized
 
 
@@ -58,7 +58,7 @@ def login_required(request):
 def staff_member_required(request):
     "Lookup decorator to require the user is a staff member."
     user = getattr(request, 'user', None)
-    if user is None or not user.is_authenticated():
+    if user is None or not user.is_authenticated:
         return HttpResponse(status=401) # Unauthorized
     elif not user.is_staff:
         return HttpResponseForbidden()
index 6336cb12bc10caed0bb24c7832f9e2ec7fd03234..45e7da167b8c653c0bce7e36f75e9ad25a7c5abf 100644 (file)
@@ -1,6 +1,6 @@
 from __future__ import unicode_literals
 
-from django import forms, VERSION as DJANGO_VERSION
+from django import forms
 from django.core.exceptions import ValidationError
 from django.core.validators import EMPTY_VALUES
 from django.utils.translation import ugettext_lazy as _
@@ -41,10 +41,6 @@ class BaseAutoCompleteField(forms.Field):
         else:
             return data != initial
 
-    if DJANGO_VERSION < (1, 8):
-        def _has_changed(self, initial, data):
-            return self.has_changed(initial, data)
-
 
 class AutoCompleteSelectField(BaseAutoCompleteField):
     widget = AutoCompleteSelectWidget
@@ -62,8 +58,6 @@ class AutoCompleteSelectField(BaseAutoCompleteField):
             kwargs['widget'] = widget(lookup_class, allow_new=self.allow_new, limit=self.limit)
         super(AutoCompleteSelectField, self).__init__(*args, **kwargs)
 
-
-
     def to_python(self, value):
         if value in EMPTY_VALUES:
             return None
index 5edc0c7d0bda686d304ec4c3e4ef46d6a02d752c..bdc8b01cff0f01d2030c0e111f4da2be96d0c9c3 100644 (file)
@@ -1,14 +1,11 @@
 from __future__ import unicode_literals
 
-import inspect
 import json
 
 from django import forms
 from django.conf import settings
-from django.forms.utils import flatatt
 from django.utils.encoding import force_text
 from django.utils.http import urlencode
-from django.utils.safestring import mark_safe
 
 from selectable import __version__
 from selectable.forms.base import import_lookup_class
@@ -35,59 +32,7 @@ class SelectableMediaMixin(object):
         js = ('%sjs/jquery.dj.selectable.js?v=%s' % (STATIC_PREFIX, __version__),)
 
 
-new_style_build_attrs = (
-    'base_attrs' in
-    inspect.getargs(forms.widgets.Widget.build_attrs.__code__).args)
-
-
-class BuildAttrsCompat(object):
-    """
-    Mixin to provide compatibility between old and new function
-    signatures for Widget.build_attrs, and a hook for adding our
-    own attributes.
-    """
-    # These are build_attrs definitions that make it easier for
-    # us to override, without having to worry about the signature,
-    # by adding a standard hook, `build_attrs_extra`.
-    # It has a different signature when we are running different Django
-    # versions.
-    if new_style_build_attrs:
-        def build_attrs(self, base_attrs, extra_attrs=None):
-            attrs = super(BuildAttrsCompat, self).build_attrs(
-                base_attrs, extra_attrs=extra_attrs)
-            return self.build_attrs_extra(attrs)
-    else:
-        def build_attrs(self, extra_attrs=None, **kwargs):
-            attrs = super(BuildAttrsCompat, self).build_attrs(
-                extra_attrs=extra_attrs, **kwargs)
-            return self.build_attrs_extra(attrs)
-
-    def build_attrs_extra(self, attrs):
-        # Default implementation, does nothing
-        return attrs
-
-    # These provide a standard interface for when we want to call build_attrs
-    # in our own `render` methods. In both cases it is the same as the Django
-    # 1.11 signature, but has a different implementation for different Django
-    # versions.
-    if new_style_build_attrs:
-        def build_attrs_compat(self, base_attrs, extra_attrs=None):
-            return self.build_attrs(base_attrs, extra_attrs=extra_attrs)
-
-    else:
-        def build_attrs_compat(self, base_attrs, extra_attrs=None):
-            # Implementation copied from Django 1.11, plus include our
-            # hook `build_attrs_extra`
-            attrs = base_attrs.copy()
-            if extra_attrs is not None:
-                attrs.update(extra_attrs)
-            return self.build_attrs_extra(attrs)
-
-
-CompatMixin = BuildAttrsCompat
-
-
-class AutoCompleteWidget(CompatMixin, forms.TextInput, SelectableMediaMixin):
+class AutoCompleteWidget(forms.TextInput, SelectableMediaMixin):
 
     def __init__(self, lookup_class, *args, **kwargs):
         self.lookup_class = import_lookup_class(lookup_class)
@@ -99,8 +44,8 @@ class AutoCompleteWidget(CompatMixin, forms.TextInput, SelectableMediaMixin):
     def update_query_parameters(self, qs_dict):
         self.qs.update(qs_dict)
 
-    def build_attrs_extra(self, attrs):
-        attrs = super(AutoCompleteWidget, self).build_attrs_extra(attrs)
+    def build_attrs(self, base_attrs, extra_attrs=None):
+        attrs = super(AutoCompleteWidget, self).build_attrs(base_attrs, extra_attrs)
         url = self.lookup_class.url()
         if self.limit and 'limit' not in self.qs:
             self.qs['limit'] = self.limit
@@ -114,7 +59,7 @@ class AutoCompleteWidget(CompatMixin, forms.TextInput, SelectableMediaMixin):
         return attrs
 
 
-class SelectableMultiWidget(CompatMixin, forms.MultiWidget):
+class SelectableMultiWidget(forms.MultiWidget):
 
     def update_query_parameters(self, qs_dict):
         self.widgets[0].update_query_parameters(qs_dict)
@@ -189,8 +134,8 @@ class AutoCompleteSelectWidget(_BaseSingleSelectWidget):
 
 class AutoComboboxWidget(AutoCompleteWidget, SelectableMediaMixin):
 
-    def build_attrs_extra(self, attrs):
-        attrs = super(AutoComboboxWidget, self).build_attrs_extra(attrs)
+    def build_attrs(self, base_attrs, extra_attrs=None):
+        attrs = super(AutoComboboxWidget, self).build_attrs(base_attrs, extra_attrs)
         attrs['data-selectable-type'] = 'combobox'
         return attrs
 
@@ -200,13 +145,12 @@ class AutoComboboxSelectWidget(_BaseSingleSelectWidget):
     primary_widget = AutoComboboxWidget
 
 
-class LookupMultipleHiddenInput(CompatMixin, forms.MultipleHiddenInput):
+class LookupMultipleHiddenInput(forms.MultipleHiddenInput):
 
     def __init__(self, lookup_class, *args, **kwargs):
         self.lookup_class = import_lookup_class(lookup_class)
         super(LookupMultipleHiddenInput, self).__init__(*args, **kwargs)
 
-    # This supports Django 1.11 and later
     def get_context(self, name, value, attrs):
         lookup = self.lookup_class()
         values = self._normalize_value(value)
@@ -223,32 +167,8 @@ class LookupMultipleHiddenInput(CompatMixin, forms.MultipleHiddenInput):
                 widget_ctx['attrs']['title'] = title
         return context
 
-    # This supports Django 1.10 and earlier
-    def render(self, name, value, attrs=None, choices=()):
-        lookup = self.lookup_class()
-        value = self._normalize_value(value)
-
-        base_attrs = dict(self.attrs, type=self.input_type, name=name)
-        combined_attrs = self.build_attrs_compat(base_attrs, attrs)
-        id_ = combined_attrs.get('id', None)
-        inputs = []
-        for i, v in enumerate(value):
-            input_attrs = combined_attrs.copy()
-            v_, title = self._lookup_value_and_title(lookup, v)
-            input_attrs.update(
-                value=v_,
-                title=title,
-            )
-            if id_:
-                # An ID attribute was given. Add a numeric index as a suffix
-                # so that the inputs don't all have the same ID attribute.
-                input_attrs['id'] = '%s_%s' % (id_, i)
-            inputs.append('<input%s />' % flatatt(input_attrs))
-        return mark_safe('\n'.join(inputs))
-
-    # These are used by both paths
-    def build_attrs_extra(self, attrs):
-        attrs = super(LookupMultipleHiddenInput, self).build_attrs_extra(attrs)
+    def build_attrs(self, base_attrs, extra_attrs=None):
+        attrs = super(LookupMultipleHiddenInput, self).build_attrs(base_attrs, extra_attrs)
         attrs['data-selectable-type'] = 'hidden-multiple'
         return attrs
 
@@ -305,17 +225,17 @@ class _BaseMultipleSelectWidget(SelectableMultiWidget, SelectableMediaMixin):
             value = self.get_compatible_postdata(data, name)
         return value
 
-    def build_attrs_extra(self, attrs):
-        attrs = super(_BaseMultipleSelectWidget, self).build_attrs_extra(attrs)
+    def build_attrs(self, base_attrs, extra_attrs=None):
+        attrs = super(_BaseMultipleSelectWidget, self).build_attrs(base_attrs, extra_attrs)
         if 'required' in attrs:
             attrs.pop('required')
         return attrs
 
-    def render(self, name, value, attrs=None):
+    def render(self, name, value, attrs=None, renderer=None):
         if value and not hasattr(value, '__iter__'):
             value = [value]
         value = ['', value]
-        return super(_BaseMultipleSelectWidget, self).render(name, value, attrs)
+        return super(_BaseMultipleSelectWidget, self).render(name, value, attrs, renderer)
 
 
 class AutoCompleteSelectMultipleWidget(_BaseMultipleSelectWidget):
index c16cc64d43ddbbcdbba3b6a242fbbeca2baf0c66..7555a417503bfe9c4387f054822a6fe10098451b 100644 (file)
                 ul.empty();
             }
             $input.data('page', null);
-            ul.zIndex($input.zIndex() + 1);
+            ul.css("zIndex", $input.css("zIndex") + 1);
             this._renderMenu(ul, items);
             // jQuery UI menu does not define deactivate
             if (this.menu.deactivate) {
index 3227bb50e2eab126a97507c3946317113b085bc7..b529c3c64f53765be63b37fc84d67d04f69fbb63 100644 (file)
@@ -20,7 +20,7 @@ class Thing(models.Model):
 @python_2_unicode_compatible
 class OtherThing(models.Model):
     name = models.CharField(max_length=100)
-    thing = models.ForeignKey(Thing)
+    thing = models.ForeignKey(Thing, on_delete=models.CASCADE)
 
     def __str__(self):
         return self.name
index c77c96100ee855cb16737792e68f13344def6617..c7e729eef02260e8dc1559993b57d9503df0c5c3 100644 (file)
@@ -3,26 +3,21 @@ from __future__ import unicode_literals
 import random
 import string
 from collections import defaultdict
-from xml.dom.minidom import parseString
 
 
 from django.test import TestCase, override_settings
+from django.test.html import parse_html
 
 from . import Thing
 from ..base import ModelLookup
 
 
-def as_xml(html):
-    "Convert HTML portion to minidom node."
-    return parseString('<root>%s</root>' % html)
-
-
 def parsed_inputs(html):
     "Returns a dictionary mapping name --> node of inputs found in the HTML."
-    node = as_xml(html)
+    node = parse_html(html)
     inputs = {}
-    for field in node.getElementsByTagName('input'):
-        name = dict(field.attributes.items())['name']
+    for field in [c for c in node.children if c.name == 'input']:
+        name = dict(field.attributes)['name']
         current = inputs.get(name, [])
         current.append(field)
         inputs[name] = current
@@ -66,14 +61,14 @@ def parsed_widget_attributes(widget):
 
 class AttrMap(object):
     def __init__(self, html):
-        dom = as_xml(html)
+        dom = parse_html(html)
         self._attrs = defaultdict(set)
         self._build_attr_map(dom)
 
     def _build_attr_map(self, dom):
         for node in _walk_nodes(dom):
             if node.attributes is not None:
-                for k, v in node.attributes.items():
+                for (k, v) in node.attributes:
                     self._attrs[k].add(v)
 
     def __contains__(self, key):
@@ -92,6 +87,6 @@ class AttrMap(object):
 
 def _walk_nodes(dom):
     yield dom
-    for child in dom.childNodes:
+    for child in dom.children:
         for item in _walk_nodes(child):
             yield item
diff --git a/dep/django-selectable/selectable/tests/decorators.py b/dep/django-selectable/selectable/tests/decorators.py
deleted file mode 100644 (file)
index 25bb4eb..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-from mock import Mock
-
-from selectable.decorators import ajax_required, login_required, staff_member_required
-from selectable.tests.base import BaseSelectableTestCase, SimpleModelLookup
-
-
-__all__ = (
-    'AjaxRequiredLookupTestCase',
-    'LoginRequiredLookupTestCase',
-    'StaffRequiredLookupTestCase',
-)
-
-
-class AjaxRequiredLookupTestCase(BaseSelectableTestCase):
-
-    def setUp(self):
-        self.lookup = ajax_required(SimpleModelLookup)()
-
-    def test_ajax_call(self):
-        "Ajax call should yield a successful response."
-        request = Mock()
-        request.is_ajax = lambda: True
-        response = self.lookup.results(request)
-        self.assertTrue(response.status_code, 200)
-
-    def test_non_ajax_call(self):
-        "Non-Ajax call should yield a bad request response."
-        request = Mock()
-        request.is_ajax = lambda: False
-        response = self.lookup.results(request)
-        self.assertEqual(response.status_code, 400)
-
-
-class LoginRequiredLookupTestCase(BaseSelectableTestCase):
-
-    def setUp(self):
-        self.lookup = login_required(SimpleModelLookup)()
-    
-    def test_authenicated_call(self):
-        "Authenicated call should yield a successful response."
-        request = Mock()
-        user = Mock()
-        user.is_authenticated = lambda: True
-        request.user = user
-        response = self.lookup.results(request)
-        self.assertTrue(response.status_code, 200)
-
-    def test_non_authenicated_call(self):
-        "Non-Authenicated call should yield an unauthorized response."
-        request = Mock()
-        user = Mock()
-        user.is_authenticated = lambda: False
-        request.user = user
-        response = self.lookup.results(request)
-        self.assertEqual(response.status_code, 401)
-
-
-class StaffRequiredLookupTestCase(BaseSelectableTestCase):
-
-    def setUp(self):
-        self.lookup = staff_member_required(SimpleModelLookup)()
-
-    def test_staff_member_call(self):
-        "Staff member call should yield a successful response."
-        request = Mock()
-        user = Mock()
-        user.is_authenticated = lambda: True
-        user.is_staff = True
-        request.user = user
-        response = self.lookup.results(request)
-        self.assertTrue(response.status_code, 200)
-
-    def test_authenicated_but_not_staff(self):
-        "Authenicated but non staff call should yield a forbidden response."
-        request = Mock()
-        user = Mock()
-        user.is_authenticated = lambda: True
-        user.is_staff = False
-        request.user = user
-        response = self.lookup.results(request)
-        self.assertTrue(response.status_code, 403)
-
-    def test_non_authenicated_call(self):
-        "Non-Authenicated call should yield an unauthorized response."
-        request = Mock()
-        user = Mock()
-        user.is_authenticated = lambda: False
-        user.is_staff = False
-        request.user = user
-        response = self.lookup.results(request)
-        self.assertEqual(response.status_code, 401)
diff --git a/dep/django-selectable/selectable/tests/fields.py b/dep/django-selectable/selectable/tests/fields.py
deleted file mode 100644 (file)
index 6c28c66..0000000
+++ /dev/null
@@ -1,134 +0,0 @@
-from django import forms
-
-from selectable.forms import fields, widgets
-from selectable.tests import ThingLookup
-from selectable.tests.base import BaseSelectableTestCase
-
-
-__all__ = (
-    'AutoCompleteSelectFieldTestCase',
-    'AutoCompleteSelectMultipleFieldTestCase',
-)
-
-class BaseFieldTestCase(BaseSelectableTestCase):
-    field_cls = None
-    lookup_cls = None
-
-    def get_field_instance(self, allow_new=False, limit=None, widget=None):
-        return self.field_cls(self.lookup_cls, allow_new=allow_new, limit=limit, widget=widget)
-
-    def test_init(self):
-        field = self.get_field_instance()
-        self.assertEqual(field.lookup_class, self.lookup_cls)
-
-    def test_init_with_limit(self):
-        field = self.get_field_instance(limit=10)
-        self.assertEqual(field.limit, 10)
-        self.assertEqual(field.widget.limit, 10)
-
-    def test_clean(self):
-        self.fail('This test has not yet been written')
-
-    def test_dotted_path(self):
-        """
-        Ensure lookup_class can be imported from a dotted path.
-        """
-        dotted_path = '.'.join([self.lookup_cls.__module__, self.lookup_cls.__name__])
-        field = self.field_cls(dotted_path)
-        self.assertEqual(field.lookup_class, self.lookup_cls)
-
-    def test_invalid_dotted_path(self):
-        """
-        An invalid lookup_class dotted path should raise an ImportError.
-        """
-        with self.assertRaises(ImportError):
-            self.field_cls('this.is.an.invalid.path')
-
-    def test_dotted_path_wrong_type(self):
-        """
-        lookup_class must be a subclass of LookupBase.
-        """
-        dotted_path = 'selectable.forms.fields.AutoCompleteSelectField'
-        with self.assertRaises(TypeError):
-            self.field_cls(dotted_path)
-
-class AutoCompleteSelectFieldTestCase(BaseFieldTestCase):
-    field_cls = fields.AutoCompleteSelectField
-    lookup_cls = ThingLookup
-
-    def test_clean(self):
-        thing = self.create_thing()
-        field = self.get_field_instance()
-        value = field.clean([thing.name, thing.id])
-        self.assertEqual(thing, value)
-
-    def test_new_not_allowed(self):
-        field = self.get_field_instance()
-        value = self.get_random_string()
-        self.assertRaises(forms.ValidationError, field.clean, [value, ''])
-
-    def test_new_allowed(self):
-        field = self.get_field_instance(allow_new=True)
-        value = self.get_random_string()
-        value = field.clean([value, ''])
-        self.assertTrue(isinstance(value, ThingLookup.model))
-
-    def test_default_widget(self):
-        field = self.get_field_instance()
-        self.assertTrue(isinstance(field.widget, widgets.AutoCompleteSelectWidget))
-
-    def test_alternate_widget(self):
-        widget_cls = widgets.AutoComboboxWidget
-        field = self.get_field_instance(widget=widget_cls)
-        self.assertTrue(isinstance(field.widget, widget_cls))
-
-    def test_alternate_widget_instance(self):
-        widget = widgets.AutoComboboxWidget(self.lookup_cls)
-        field = self.get_field_instance(widget=widget)
-        self.assertTrue(isinstance(field.widget, widgets.AutoComboboxWidget))
-
-    def test_invalid_pk(self):
-        field = self.get_field_instance()
-        value = self.get_random_string()
-        self.assertRaises(forms.ValidationError, field.clean, [value, 'XXX'])
-
-
-class AutoCompleteSelectMultipleFieldTestCase(BaseFieldTestCase):
-    field_cls = fields.AutoCompleteSelectMultipleField
-    lookup_cls = ThingLookup
-
-    def get_field_instance(self, limit=None, widget=None):
-        return self.field_cls(self.lookup_cls, limit=limit, widget=widget)
-
-    def test_clean(self):
-        thing = self.create_thing()
-        field = self.get_field_instance()
-        value = field.clean([thing.id])
-        self.assertEqual([thing], value)
-
-    def test_clean_multiple(self):
-        thing = self.create_thing()
-        other_thing = self.create_thing()
-        field = self.get_field_instance()
-        ids = [thing.id, other_thing.id]
-        value = field.clean(ids)
-        self.assertEqual([thing, other_thing], value)
-
-    def test_default_widget(self):
-        field = self.get_field_instance()
-        self.assertTrue(isinstance(field.widget, widgets.AutoCompleteSelectMultipleWidget))
-
-    def test_alternate_widget(self):
-        widget_cls = widgets.AutoComboboxSelectMultipleWidget
-        field = self.get_field_instance(widget=widget_cls)
-        self.assertTrue(isinstance(field.widget, widget_cls))
-
-    def test_alternate_widget_instance(self):
-        widget = widgets.AutoComboboxSelectMultipleWidget(self.lookup_cls)
-        field = self.get_field_instance(widget=widget)
-        self.assertTrue(isinstance(field.widget, widgets.AutoComboboxSelectMultipleWidget))
-
-    def test_invalid_pk(self):
-        field = self.get_field_instance()
-        value = self.get_random_string()
-        self.assertRaises(forms.ValidationError, field.clean, ['XXX', ])
diff --git a/dep/django-selectable/selectable/tests/forms.py b/dep/django-selectable/selectable/tests/forms.py
deleted file mode 100644 (file)
index c01343b..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-from django.conf import settings
-
-from selectable.forms import BaseLookupForm
-from selectable.tests.base import BaseSelectableTestCase, PatchSettingsMixin
-
-
-__all__ = (
-    'BaseLookupFormTestCase',
-)
-
-
-class BaseLookupFormTestCase(PatchSettingsMixin, BaseSelectableTestCase):
-
-    def get_valid_data(self):
-        data = {
-            'term': 'foo',
-            'limit': 10,
-        }
-        return data
-
-    def test_valid_data(self):
-        data = self.get_valid_data()
-        form = BaseLookupForm(data)
-        self.assertTrue(form.is_valid(), "%s" % form.errors)
-
-    def test_invalid_limit(self):
-        """
-        Test giving the form an invalid limit.
-        """
-
-        data = self.get_valid_data()
-        data['limit'] = 'bar'
-        form = BaseLookupForm(data)
-        self.assertFalse(form.is_valid())
-
-    def test_no_limit(self):
-        """
-        If SELECTABLE_MAX_LIMIT is set and limit is not given then
-        the form will return SELECTABLE_MAX_LIMIT.
-        """
-
-        data = self.get_valid_data()
-        if 'limit' in data:
-            del data['limit']
-        form = BaseLookupForm(data)
-        self.assertTrue(form.is_valid(), "%s" % form.errors)
-        self.assertEqual(form.cleaned_data['limit'], settings.SELECTABLE_MAX_LIMIT)
-
-    def test_no_max_set(self):
-        """
-        If SELECTABLE_MAX_LIMIT is not set but given then the form
-        will return the given limit.
-        """
-
-        settings.SELECTABLE_MAX_LIMIT = None
-        data = self.get_valid_data()
-        form = BaseLookupForm(data)
-        self.assertTrue(form.is_valid(), "%s" % form.errors)
-        if 'limit' in data:
-            self.assertTrue(form.cleaned_data['limit'], data['limit'])
-
-    def test_no_max_set_not_given(self):
-        """
-        If SELECTABLE_MAX_LIMIT is not set and not given then the form
-        will return no limit.
-        """
-
-        settings.SELECTABLE_MAX_LIMIT = None
-        data = self.get_valid_data()
-        if 'limit' in data:
-            del data['limit']
-        form = BaseLookupForm(data)
-        self.assertTrue(form.is_valid(), "%s" % form.errors)
-        self.assertFalse(form.cleaned_data.get('limit'))
-
-    def test_over_limit(self):
-        """
-        If SELECTABLE_MAX_LIMIT is set and limit given is greater then
-        the form will return SELECTABLE_MAX_LIMIT.
-        """
-
-        data = self.get_valid_data()
-        data['limit'] = settings.SELECTABLE_MAX_LIMIT + 100
-        form = BaseLookupForm(data)
-        self.assertTrue(form.is_valid(), "%s" % form.errors)
-        self.assertEqual(form.cleaned_data['limit'], settings.SELECTABLE_MAX_LIMIT)
diff --git a/dep/django-selectable/selectable/tests/functests.py b/dep/django-selectable/selectable/tests/functests.py
deleted file mode 100644 (file)
index 493e580..0000000
+++ /dev/null
@@ -1,502 +0,0 @@
-"""
-Larger functional tests for fields and widgets.
-"""
-from __future__ import unicode_literals
-
-from django import forms
-
-from selectable.forms import AutoCompleteSelectField, AutoCompleteSelectMultipleField
-from selectable.forms import AutoCompleteSelectWidget, AutoComboboxSelectWidget
-from selectable.tests import ManyThing, OtherThing, ThingLookup
-from selectable.tests.base import BaseSelectableTestCase, parsed_inputs
-
-
-__all__ = (
-    'FuncAutoCompleteSelectTestCase',
-    'FuncSelectModelChoiceTestCase',
-    'FuncComboboxModelChoiceTestCase',
-    'FuncManytoManyMultipleSelectTestCase',
-    'FuncFormTestCase',
-)
-
-
-class OtherThingForm(forms.ModelForm):
-
-    thing = AutoCompleteSelectField(lookup_class=ThingLookup)
-
-    class Meta(object):
-        model = OtherThing
-
-
-class FuncAutoCompleteSelectTestCase(BaseSelectableTestCase):
-
-    def setUp(self):
-        self.test_thing = self.create_thing()
-
-    def test_valid_form(self):
-        "Valid form using an AutoCompleteSelectField."
-        data = {
-            'name': self.get_random_string(),
-            'thing_0': self.test_thing.name, # Text input
-            'thing_1': self.test_thing.pk, # Hidden input
-        }
-        form = OtherThingForm(data=data)
-        self.assertTrue(form.is_valid(), str(form.errors))
-
-    def test_invalid_form_missing_selected_pk(self):
-        "Invalid form using an AutoCompleteSelectField."
-        data = {
-            'name': self.get_random_string(),
-            'thing_0': self.test_thing.name, # Text input
-            'thing_1': '', # Hidden input
-        }
-        form = OtherThingForm(data=data)
-        self.assertFalse(form.is_valid(), 'Form should not be valid')
-        self.assertFalse('name' in form.errors)
-        self.assertTrue('thing' in form.errors)
-
-    def test_invalid_form_missing_name(self):
-        "Invalid form using an AutoCompleteSelectField."
-        data = {
-            'name': '',
-            'thing_0': self.test_thing.name, # Text input
-            'thing_1': self.test_thing.pk, # Hidden input
-        }
-        form = OtherThingForm(data=data)
-        self.assertFalse(form.is_valid(), 'Form should not be valid')
-        self.assertTrue('name' in form.errors)
-        self.assertFalse('thing' in form.errors)
-
-    def test_invalid_but_still_selected(self):
-        "Invalid form should keep selected item."
-        data = {
-            'name': '',
-            'thing_0': self.test_thing.name, # Text input
-            'thing_1': self.test_thing.pk, # Hidden input
-        }
-        form = OtherThingForm(data=data)
-        self.assertFalse(form.is_valid(), 'Form should not be valid')
-        rendered_form = form.as_p()
-        inputs = parsed_inputs(rendered_form)
-        # Selected text should be populated
-        thing_0 = inputs['thing_0'][0]
-        self.assertEqual(thing_0.attributes['value'].value, self.test_thing.name)
-        # Selected pk should be populated
-        thing_1 = inputs['thing_1'][0]
-        self.assertEqual(int(thing_1.attributes['value'].value), self.test_thing.pk)
-
-    def test_populate_from_model(self):
-        "Populate from existing model."
-        other_thing = OtherThing.objects.create(thing=self.test_thing, name='a')
-        form = OtherThingForm(instance=other_thing)
-        rendered_form = form.as_p()
-        inputs = parsed_inputs(rendered_form)
-        # Selected text should be populated
-        thing_0 = inputs['thing_0'][0]
-        self.assertEqual(thing_0.attributes['value'].value, self.test_thing.name)
-        # Selected pk should be populated
-        thing_1 = inputs['thing_1'][0]
-        self.assertEqual(int(thing_1.attributes['value'].value), self.test_thing.pk)
-
-
-class SelectWidgetForm(forms.ModelForm):
-
-    class Meta(object):
-        model = OtherThing
-        widgets = {
-            'thing': AutoCompleteSelectWidget(lookup_class=ThingLookup)
-        }
-
-
-class FuncSelectModelChoiceTestCase(BaseSelectableTestCase):
-    """
-    Functional tests for AutoCompleteSelectWidget compatibility
-    with a ModelChoiceField.
-    """
-
-    def setUp(self):
-        self.test_thing = self.create_thing()
-
-    def test_valid_form(self):
-        "Valid form using an AutoCompleteSelectWidget."
-        data = {
-            'name': self.get_random_string(),
-            'thing_0': self.test_thing.name, # Text input
-            'thing_1': self.test_thing.pk, # Hidden input
-        }
-        form = SelectWidgetForm(data=data)
-        self.assertTrue(form.is_valid(), str(form.errors))
-
-    def test_missing_pk(self):
-        "Invalid form (missing required pk) using an AutoCompleteSelectWidget."
-        data = {
-            'name': self.get_random_string(),
-            'thing_0': self.test_thing.name, # Text input
-            'thing_1': '', # Hidden input missing
-        }
-        form = SelectWidgetForm(data=data)
-        self.assertFalse(form.is_valid())
-        self.assertTrue('thing' in form.errors)
-
-    def test_invalid_pk(self):
-        "Invalid form (invalid pk value) using an AutoCompleteSelectWidget."
-        data = {
-            'name': self.get_random_string(),
-            'thing_0': self.test_thing.name, # Text input
-            'thing_1': 'XXX', # Hidden input doesn't match a PK
-        }
-        form = SelectWidgetForm(data=data)
-        self.assertFalse(form.is_valid())
-        self.assertTrue('thing' in form.errors)
-
-
-class ComboboxSelectWidgetForm(forms.ModelForm):
-
-    class Meta(object):
-        model = OtherThing
-        widgets = {
-            'thing': AutoComboboxSelectWidget(lookup_class=ThingLookup)
-        }
-
-
-class FuncComboboxModelChoiceTestCase(BaseSelectableTestCase):
-    """
-    Functional tests for AutoComboboxSelectWidget compatibility
-    with a ModelChoiceField.
-    """
-
-    def setUp(self):
-        self.test_thing = self.create_thing()
-
-    def test_valid_form(self):
-        "Valid form using an AutoComboboxSelectWidget."
-        data = {
-            'name': self.get_random_string(),
-            'thing_0': self.test_thing.name, # Text input
-            'thing_1': self.test_thing.pk, # Hidden input
-        }
-        form = ComboboxSelectWidgetForm(data=data)
-        self.assertTrue(form.is_valid(), str(form.errors))
-
-    def test_missing_pk(self):
-        "Invalid form (missing required pk) using an AutoComboboxSelectWidget."
-        data = {
-            'name': self.get_random_string(),
-            'thing_0': self.test_thing.name, # Text input
-            'thing_1': '', # Hidden input missing
-        }
-        form = SelectWidgetForm(data=data)
-        self.assertFalse(form.is_valid())
-        self.assertTrue('thing' in form.errors)
-
-    def test_invalid_pk(self):
-        "Invalid form (invalid pk value) using an AutoComboboxSelectWidget."
-        data = {
-            'name': self.get_random_string(),
-            'thing_0': self.test_thing.name, # Text input
-            'thing_1': 'XXX', # Hidden input doesn't match a PK
-        }
-        form = SelectWidgetForm(data=data)
-        self.assertFalse(form.is_valid())
-        self.assertTrue('thing' in form.errors)
-
-
-class ManyThingForm(forms.ModelForm):
-
-    things = AutoCompleteSelectMultipleField(lookup_class=ThingLookup)
-
-    class Meta(object):
-        model = ManyThing
-
-
-class FuncManytoManyMultipleSelectTestCase(BaseSelectableTestCase):
-    """
-    Functional tests for AutoCompleteSelectMultipleField compatibility
-    with a ManyToManyField.
-    """
-
-    def setUp(self):
-        self.test_thing = self.create_thing()
-
-    def test_valid_form(self):
-        "Valid form using an AutoCompleteSelectMultipleField."
-        data = {
-            'name': self.get_random_string(),
-            'things_0': '', # Text input
-            'things_1': [self.test_thing.pk, ], # Hidden inputs
-        }
-        form = ManyThingForm(data=data)
-        self.assertTrue(form.is_valid(), str(form.errors))
-
-    def test_valid_save(self):
-        "Saving data from a valid form."
-        data = {
-            'name': self.get_random_string(),
-            'things_0': '', # Text input
-            'things_1': [self.test_thing.pk, ], # Hidden inputs
-        }
-        form = ManyThingForm(data=data)
-        manything = form.save()
-        self.assertEqual(manything.name, data['name'])
-        things = manything.things.all()
-        self.assertEqual(things.count(), 1)
-        self.assertTrue(self.test_thing in things)
-
-    def test_not_required(self):
-        "Valid form where many to many is not required."
-        data = {
-            'name': self.get_random_string(),
-            'things_0': '', # Text input
-            'things_1': [], # Hidden inputs
-        }
-        form = ManyThingForm(data=data)
-        form.fields['things'].required = False
-        self.assertTrue(form.is_valid(), str(form.errors))
-
-    def test_not_required_save(self):
-        "Saving data when many to many is not required."
-        data = {
-            'name': self.get_random_string(),
-            'things_0': '', # Text input
-            'things_1': [], # Hidden inputs
-        }
-        form = ManyThingForm(data=data)
-        form.fields['things'].required = False
-        manything = form.save()
-        self.assertEqual(manything.name, data['name'])
-        things = manything.things.all()
-        self.assertEqual(things.count(), 0)
-
-    def test_has_changed(self):
-        "Populate intial data from a model."
-        manything = ManyThing.objects.create(name='Foo')
-        thing_1 = self.create_thing()
-        manything.things.add(thing_1)
-        data = {
-            'name': manything.name,
-            'things_0': '', # Text input
-            'things_1': [thing_1.pk], # Hidden inputs
-        }
-        form = ManyThingForm(data=data, instance=manything)
-        self.assertFalse(form.has_changed(), str(form.changed_data))
-
-
-class SimpleForm(forms.Form):
-    "Non-model form usage."
-    thing = AutoCompleteSelectField(lookup_class=ThingLookup)
-    new_thing = AutoCompleteSelectField(lookup_class=ThingLookup, allow_new=True)
-    things = AutoCompleteSelectMultipleField(lookup_class=ThingLookup)
-
-
-class FuncFormTestCase(BaseSelectableTestCase):
-    """
-    Functional tests for using AutoCompleteSelectField
-    and AutoCompleteSelectMultipleField outside the context
-    of a ModelForm.
-    """
-
-    def setUp(self):
-        self.test_thing = self.create_thing()
-
-    def test_blank_new_item(self):
-        "Regression test for #91. new_thing is required but both are blank."
-        data = {
-            'thing_0': self.test_thing.name,
-            'thing_1': self.test_thing.pk,
-            'new_thing_0': '',
-            'new_thing_1': '',
-            'things_0': '',
-            'things_1': [self.test_thing.pk, ]
-        }
-        form = SimpleForm(data=data)
-        self.assertFalse(form.is_valid())
-        self.assertTrue('new_thing' in form.errors)
-
-    def test_has_changed_with_empty_permitted(self):
-        """
-        Regression test for #92. has_changed fails when there is no initial and
-        allow_new=False.
-        """
-        data = {
-            'thing_0': '',
-            'thing_1': self.test_thing.pk,
-            'new_thing_0': self.test_thing.name,
-            'new_thing_1': self.test_thing.pk,
-            'things_0': '',
-            'things_1': [self.test_thing.pk, ]
-        }
-        form = SimpleForm(data=data, empty_permitted=True)
-        self.assertTrue(form.has_changed())
-        self.assertTrue(form.is_valid(), str(form.errors))
-
-    def test_not_changed(self):
-        """
-        Regression test for #92. has_changed fails when there is no initial and
-        allow_new=False.
-        """
-        data = {
-            'thing_0': self.test_thing.name,
-            'thing_1': self.test_thing.pk,
-            'new_thing_0': self.test_thing.name,
-            'new_thing_1': self.test_thing.pk,
-            'things_0': '',
-            'things_1': [self.test_thing.pk, ]
-        }
-        initial = {
-            'thing': self.test_thing.pk,
-            'new_thing': self.test_thing.pk,
-            'things': [self.test_thing.pk, ]
-        }
-        form = SimpleForm(data=data, initial=initial)
-        self.assertFalse(form.has_changed())
-        self.assertTrue(form.is_valid(), str(form.errors))
-
-    def test_not_changed_with_empty_permitted(self):
-        """
-        Regression test for #92. has_changed fails when there is no initial and
-        allow_new=False.
-        """
-        data = {
-            'thing_0': '',
-            'thing_1': '',
-            'new_thing_0': '',
-            'new_thing_1': '',
-            'things_0': '',
-            'things_1': '',
-        }
-        initial = {
-            'thing': '',
-            'new_thing': '',
-            'things': '',
-        }
-        form = SimpleForm(data=data, initial=initial, empty_permitted=True)
-        self.assertFalse(form.has_changed(), str(form.changed_data))
-        self.assertTrue(form.is_valid(), str(form.errors))
-
-    def test_no_initial_with_empty_permitted(self):
-        """
-        If empty data is submitted and allowed with no initial then
-        the form should not be seen as changed.
-        """
-        data = {
-            'thing_0': '',
-            'thing_1': '',
-            'new_thing_0': '',
-            'new_thing_1': '',
-            'things_0': '',
-            'things_1': '',
-        }
-        form = SimpleForm(data=data, empty_permitted=True)
-        self.assertFalse(form.has_changed(), str(form.changed_data))
-        self.assertTrue(form.is_valid(), str(form.errors))
-
-    def test_no_data_with_empty_permitted(self):
-        """
-        If no data is submitted and allowed with no initial then
-        the form should not be seen as changed.
-        """
-        form = SimpleForm(data={}, empty_permitted=True)
-        self.assertFalse(form.has_changed(), str(form.changed_data))
-        self.assertTrue(form.is_valid(), str(form.errors))
-
-    def test_select_multiple_changed(self):
-        """
-        Detect changes for a multiple select input with and without
-        initial data.
-        """
-        data = {
-            'thing_0': '',
-            'thing_1': '',
-            'new_thing_0': '',
-            'new_thing_1': '',
-            'things_0': '',
-            'things_1': [self.test_thing.pk, ]
-        }
-        form = SimpleForm(data=data)
-        self.assertTrue(form.has_changed())
-        self.assertTrue('things' in form.changed_data)
-
-        initial = {
-            'thing': '',
-            'new_thing': '',
-            'things': [self.test_thing.pk, ],
-        }
-        form = SimpleForm(data=data, initial=initial)
-        self.assertFalse(form.has_changed(), str(form.changed_data))
-
-        initial = {
-            'thing': '',
-            'new_thing': '',
-            'things': [],
-        }
-        form = SimpleForm(data=data, initial=initial)
-        self.assertTrue(form.has_changed())
-        self.assertTrue('things' in form.changed_data)
-
-    def test_single_select_changed(self):
-        """
-        Detect changes for a single select input with and without
-        initial data.
-        """
-        data = {
-            'thing_0': '',
-            'thing_1': self.test_thing.pk,
-            'new_thing_0': '',
-            'new_thing_1': '',
-            'things_0': '',
-            'things_1': ''
-        }
-        form = SimpleForm(data=data)
-        self.assertTrue(form.has_changed())
-        self.assertTrue('thing' in form.changed_data)
-
-        initial = {
-            'thing': self.test_thing.pk,
-            'new_thing': '',
-            'things': '',
-        }
-        form = SimpleForm(data=data, initial=initial)
-        self.assertFalse(form.has_changed(), str(form.changed_data))
-
-        initial = {
-            'thing': '',
-            'new_thing': '',
-            'things': '',
-        }
-        form = SimpleForm(data=data, initial=initial)
-        self.assertTrue(form.has_changed())
-        self.assertTrue('thing' in form.changed_data)
-
-    def test_new_select_changed(self):
-        """
-        Detect changes for a single select input which allows new items
-        with and without initial data.
-        """
-        data = {
-            'thing_0': '',
-            'thing_1': '',
-            'new_thing_0': 'Foo',
-            'new_thing_1': '',
-            'things_0': '',
-            'things_1': ''
-        }
-        form = SimpleForm(data=data)
-        self.assertTrue(form.has_changed())
-        self.assertTrue('new_thing' in form.changed_data)
-
-        initial = {
-            'thing': '',
-            'new_thing': ['Foo', None],
-            'things': '',
-        }
-        form = SimpleForm(data=data, initial=initial)
-        self.assertFalse(form.has_changed(), str(form.changed_data))
-
-        initial = {
-            'thing': '',
-            'new_thing': '',
-            'things': '',
-        }
-        form = SimpleForm(data=data, initial=initial)
-        self.assertTrue(form.has_changed())
-        self.assertTrue('new_thing' in form.changed_data)
\ No newline at end of file
diff --git a/dep/django-selectable/selectable/tests/templatetags.py b/dep/django-selectable/selectable/tests/templatetags.py
deleted file mode 100644 (file)
index 5e50d8e..0000000
+++ /dev/null
@@ -1,115 +0,0 @@
-from django.template import Template, Context
-
-from selectable.tests.base import BaseSelectableTestCase
-
-__all__ = (
-    'JqueryTagTestCase',
-    'ThemeTagTestCase',
-)
-
-
-class JqueryTagTestCase(BaseSelectableTestCase):
-
-    def assertJQueryVersion(self, result, version):
-        expected = "//ajax.googleapis.com/ajax/libs/jquery/%s/jquery.min.js" % version
-        self.assertTrue(expected in result)
-
-    def assertUIVersion(self, result, version):
-        expected = "//ajax.googleapis.com/ajax/libs/jqueryui/%s/jquery-ui.js" % version
-        self.assertTrue(expected in result)
-
-    def test_render(self):
-        "Render template tag with default versions."
-        template = Template("{% load selectable_tags %}{% include_jquery_libs %}")
-        context = Context({})
-        result = template.render(context)
-        self.assertJQueryVersion(result, '1.7.2')
-        self.assertUIVersion(result, '1.8.23')
-
-    def test_render_jquery_version(self):
-        "Render template tag with specified jQuery version."
-        template = Template("{% load selectable_tags %}{% include_jquery_libs '1.4.3' %}")
-        context = Context({})
-        result = template.render(context)
-        self.assertJQueryVersion(result, '1.4.3')
-
-    def test_render_variable_jquery_version(self):
-        "Render using jQuery version from the template context."
-        version = '1.4.3'
-        template = Template("{% load selectable_tags %}{% include_jquery_libs version %}")
-        context = Context({'version': version})
-        result = template.render(context)
-        self.assertJQueryVersion(result, '1.4.3')
-
-    def test_render_jquery_ui_version(self):
-        "Render template tag with specified jQuery UI version."
-        template = Template("{% load selectable_tags %}{% include_jquery_libs '1.4.3' '1.8.13' %}")
-        context = Context({})
-        result = template.render(context)
-        self.assertUIVersion(result, '1.8.13')
-
-    def test_render_variable_jquery_ui_version(self):
-        "Render using jQuery UI version from the template context."
-        version = '1.8.13'
-        template = Template("{% load selectable_tags %}{% include_jquery_libs '1.4.3' version %}")
-        context = Context({'version': version})
-        result = template.render(context)
-        self.assertUIVersion(result, '1.8.13')
-
-    def test_render_no_jquery(self):
-        "Render template tag without jQuery."
-        template = Template("{% load selectable_tags %}{% include_jquery_libs '' %}")
-        context = Context({})
-        result = template.render(context)
-        self.assertTrue('jquery.min.js' not in result)
-
-    def test_render_no_jquery_ui(self):
-        "Render template tag without jQuery UI."
-        template = Template("{% load selectable_tags %}{% include_jquery_libs '1.7.2' '' %}")
-        context = Context({})
-        result = template.render(context)
-        self.assertTrue('jquery-ui.js' not in result)
-
-
-class ThemeTagTestCase(BaseSelectableTestCase):
-
-    def assertUICSS(self, result, theme, version):
-        expected = "//ajax.googleapis.com/ajax/libs/jqueryui/%s/themes/%s/jquery-ui.css" % (version, theme)
-        self.assertTrue(expected in result)
-
-    def test_render(self):
-        "Render template tag with default settings."
-        template = Template("{% load selectable_tags %}{% include_ui_theme %}")
-        context = Context({})
-        result = template.render(context)
-        self.assertUICSS(result, 'base', '1.8.23')
-
-    def test_render_version(self):
-        "Render template tag with alternate version."
-        template = Template("{% load selectable_tags %}{% include_ui_theme 'base' '1.8.13' %}")
-        context = Context({})
-        result = template.render(context)
-        self.assertUICSS(result, 'base', '1.8.13')
-        
-    def test_variable_version(self):
-        "Render using version from content variable."
-        version = '1.8.13'
-        template = Template("{% load selectable_tags %}{% include_ui_theme 'base' version %}")
-        context = Context({'version': version})
-        result = template.render(context)
-        self.assertUICSS(result, 'base', version)
-
-    def test_render_theme(self):
-        "Render template tag with alternate theme."
-        template = Template("{% load selectable_tags %}{% include_ui_theme 'ui-lightness' %}")
-        context = Context({})
-        result = template.render(context)
-        self.assertUICSS(result, 'ui-lightness', '1.8.23')
-        
-    def test_variable_theme(self):
-        "Render using theme from content variable."
-        theme = 'ui-lightness'
-        template = Template("{% load selectable_tags %}{% include_ui_theme theme %}")
-        context = Context({'theme': theme})
-        result = template.render(context)
-        self.assertUICSS(result, theme, '1.8.23')
index 2b1581f85cca9ef8eb1db6a86eb34b9b26f8b195..b6b2bb9eabaa598c4b3a53ad9b0f48b15b4143f6 100644 (file)
@@ -1,6 +1,6 @@
 from __future__ import unicode_literals
 
-from django.core.urlresolvers import reverse
+from django.urls import reverse
 from django.utils.html import escape
 from django.utils.safestring import SafeData, mark_safe
 
index a9f569f26a9341aca05a0a64add10f4868a0ca3f..2a7ef0eda0454ab657f952cd6a4e41bfa54218c4 100644 (file)
@@ -38,12 +38,12 @@ class LoginRequiredLookupTestCase(BaseSelectableTestCase):
 
     def setUp(self):
         self.lookup = login_required(SimpleModelLookup)()
-    
+
     def test_authenicated_call(self):
         "Authenicated call should yield a successful response."
         request = Mock()
         user = Mock()
-        user.is_authenticated = lambda: True
+        user.is_authenticated = True
         request.user = user
         response = self.lookup.results(request)
         self.assertTrue(response.status_code, 200)
@@ -52,7 +52,7 @@ class LoginRequiredLookupTestCase(BaseSelectableTestCase):
         "Non-Authenicated call should yield an unauthorized response."
         request = Mock()
         user = Mock()
-        user.is_authenticated = lambda: False
+        user.is_authenticated = False
         request.user = user
         response = self.lookup.results(request)
         self.assertEqual(response.status_code, 401)
@@ -67,7 +67,7 @@ class StaffRequiredLookupTestCase(BaseSelectableTestCase):
         "Staff member call should yield a successful response."
         request = Mock()
         user = Mock()
-        user.is_authenticated = lambda: True
+        user.is_authenticated = True
         user.is_staff = True
         request.user = user
         response = self.lookup.results(request)
@@ -77,7 +77,7 @@ class StaffRequiredLookupTestCase(BaseSelectableTestCase):
         "Authenicated but non staff call should yield a forbidden response."
         request = Mock()
         user = Mock()
-        user.is_authenticated = lambda: True
+        user.is_authenticated = True
         user.is_staff = False
         request.user = user
         response = self.lookup.results(request)
@@ -87,7 +87,7 @@ class StaffRequiredLookupTestCase(BaseSelectableTestCase):
         "Non-Authenicated call should yield an unauthorized response."
         request = Mock()
         user = Mock()
-        user.is_authenticated = lambda: False
+        user.is_authenticated = False
         user.is_staff = False
         request.user = user
         response = self.lookup.results(request)
index ef3933480b4f8d845616e0fa4051d8b3b9ca5b82..082927fdab4db572b7542d05b31c45e800cae8af 100644 (file)
@@ -38,8 +38,8 @@ class FuncAutoCompleteSelectTestCase(BaseSelectableTestCase):
         "Valid form using an AutoCompleteSelectField."
         data = {
             'name': self.get_random_string(),
-            'thing_0': self.test_thing.name, # Text input
-            'thing_1': self.test_thing.pk, # Hidden input
+            'thing_0': self.test_thing.name,  # Text input
+            'thing_1': self.test_thing.pk,  # Hidden input
         }
         form = OtherThingForm(data=data)
         self.assertTrue(form.is_valid(), str(form.errors))
@@ -48,8 +48,8 @@ class FuncAutoCompleteSelectTestCase(BaseSelectableTestCase):
         "Invalid form using an AutoCompleteSelectField."
         data = {
             'name': self.get_random_string(),
-            'thing_0': self.test_thing.name, # Text input
-            'thing_1': '', # Hidden input
+            'thing_0': self.test_thing.name,  # Text input
+            'thing_1': '',  # Hidden input
         }
         form = OtherThingForm(data=data)
         self.assertFalse(form.is_valid(), 'Form should not be valid')
@@ -60,8 +60,8 @@ class FuncAutoCompleteSelectTestCase(BaseSelectableTestCase):
         "Invalid form using an AutoCompleteSelectField."
         data = {
             'name': '',
-            'thing_0': self.test_thing.name, # Text input
-            'thing_1': self.test_thing.pk, # Hidden input
+            'thing_0': self.test_thing.name,  # Text input
+            'thing_1': self.test_thing.pk,  # Hidden input
         }
         form = OtherThingForm(data=data)
         self.assertFalse(form.is_valid(), 'Form should not be valid')
@@ -72,8 +72,8 @@ class FuncAutoCompleteSelectTestCase(BaseSelectableTestCase):
         "Invalid form should keep selected item."
         data = {
             'name': '',
-            'thing_0': self.test_thing.name, # Text input
-            'thing_1': self.test_thing.pk, # Hidden input
+            'thing_0': self.test_thing.name,  # Text input
+            'thing_1': self.test_thing.pk,  # Hidden input
         }
         form = OtherThingForm(data=data)
         self.assertFalse(form.is_valid(), 'Form should not be valid')
@@ -147,8 +147,8 @@ class FuncSelectModelChoiceTestCase(BaseSelectableTestCase):
         "Valid form using an AutoCompleteSelectWidget."
         data = {
             'name': self.get_random_string(),
-            'thing_0': self.test_thing.name, # Text input
-            'thing_1': self.test_thing.pk, # Hidden input
+            'thing_0': self.test_thing.name,  # Text input
+            'thing_1': self.test_thing.pk,  # Hidden input
         }
         form = SelectWidgetForm(data=data)
         self.assertTrue(form.is_valid(), str(form.errors))
@@ -157,8 +157,8 @@ class FuncSelectModelChoiceTestCase(BaseSelectableTestCase):
         "Invalid form (missing required pk) using an AutoCompleteSelectWidget."
         data = {
             'name': self.get_random_string(),
-            'thing_0': self.test_thing.name, # Text input
-            'thing_1': '', # Hidden input missing
+            'thing_0': self.test_thing.name,  # Text input
+            'thing_1': '',  # Hidden input missing
         }
         form = SelectWidgetForm(data=data)
         self.assertFalse(form.is_valid())
@@ -168,8 +168,8 @@ class FuncSelectModelChoiceTestCase(BaseSelectableTestCase):
         "Invalid form (invalid pk value) using an AutoCompleteSelectWidget."
         data = {
             'name': self.get_random_string(),
-            'thing_0': self.test_thing.name, # Text input
-            'thing_1': 'XXX', # Hidden input doesn't match a PK
+            'thing_0': self.test_thing.name,  # Text input
+            'thing_1': 'XXX',  # Hidden input doesn't match a PK
         }
         form = SelectWidgetForm(data=data)
         self.assertFalse(form.is_valid())
@@ -211,8 +211,8 @@ class FuncComboboxModelChoiceTestCase(BaseSelectableTestCase):
         "Valid form using an AutoComboboxSelectWidget."
         data = {
             'name': self.get_random_string(),
-            'thing_0': self.test_thing.name, # Text input
-            'thing_1': self.test_thing.pk, # Hidden input
+            'thing_0': self.test_thing.name,  # Text input
+            'thing_1': self.test_thing.pk,  # Hidden input
         }
         form = ComboboxSelectWidgetForm(data=data)
         self.assertTrue(form.is_valid(), str(form.errors))
@@ -221,8 +221,8 @@ class FuncComboboxModelChoiceTestCase(BaseSelectableTestCase):
         "Invalid form (missing required pk) using an AutoComboboxSelectWidget."
         data = {
             'name': self.get_random_string(),
-            'thing_0': self.test_thing.name, # Text input
-            'thing_1': '', # Hidden input missing
+            'thing_0': self.test_thing.name,  # Text input
+            'thing_1': '',  # Hidden input missing
         }
         form = ComboboxSelectWidgetForm(data=data)
         self.assertFalse(form.is_valid())
@@ -232,8 +232,8 @@ class FuncComboboxModelChoiceTestCase(BaseSelectableTestCase):
         "Invalid form (invalid pk value) using an AutoComboboxSelectWidget."
         data = {
             'name': self.get_random_string(),
-            'thing_0': self.test_thing.name, # Text input
-            'thing_1': 'XXX', # Hidden input doesn't match a PK
+            'thing_0': self.test_thing.name,  # Text input
+            'thing_1': 'XXX',  # Hidden input doesn't match a PK
         }
         form = ComboboxSelectWidgetForm(data=data)
         self.assertFalse(form.is_valid())
@@ -274,8 +274,8 @@ class FuncManytoManyMultipleSelectTestCase(BaseSelectableTestCase):
         "Valid form using an AutoCompleteSelectMultipleField."
         data = {
             'name': self.get_random_string(),
-            'things_0': '', # Text input
-            'things_1': [self.test_thing.pk, ], # Hidden inputs
+            'things_0': '',  # Text input
+            'things_1': [self.test_thing.pk, ],  # Hidden inputs
         }
         form = ManyThingForm(data=data)
         self.assertTrue(form.is_valid(), str(form.errors))
@@ -284,8 +284,8 @@ class FuncManytoManyMultipleSelectTestCase(BaseSelectableTestCase):
         "Saving data from a valid form."
         data = {
             'name': self.get_random_string(),
-            'things_0': '', # Text input
-            'things_1': [self.test_thing.pk, ], # Hidden inputs
+            'things_0': '',  # Text input
+            'things_1': [self.test_thing.pk, ],  # Hidden inputs
         }
         form = ManyThingForm(data=data)
         manything = form.save()
@@ -298,8 +298,8 @@ class FuncManytoManyMultipleSelectTestCase(BaseSelectableTestCase):
         "Valid form where many to many is not required."
         data = {
             'name': self.get_random_string(),
-            'things_0': '', # Text input
-            'things_1': [], # Hidden inputs
+            'things_0': '',  # Text input
+            'things_1': [],  # Hidden inputs
         }
         form = ManyThingForm(data=data)
         form.fields['things'].required = False
@@ -309,8 +309,8 @@ class FuncManytoManyMultipleSelectTestCase(BaseSelectableTestCase):
         "Saving data when many to many is not required."
         data = {
             'name': self.get_random_string(),
-            'things_0': '', # Text input
-            'things_1': [], # Hidden inputs
+            'things_0': '',  # Text input
+            'things_1': [],  # Hidden inputs
         }
         form = ManyThingForm(data=data)
         form.fields['things'].required = False
@@ -326,8 +326,8 @@ class FuncManytoManyMultipleSelectTestCase(BaseSelectableTestCase):
         manything.things.add(thing_1)
         data = {
             'name': manything.name,
-            'things_0': '', # Text input
-            'things_1': [thing_1.pk], # Hidden inputs
+            'things_0': '',  # Text input
+            'things_1': [thing_1.pk],  # Hidden inputs
         }
         form = ManyThingForm(data=data, instance=manything)
         self.assertFalse(form.has_changed(), str(form.changed_data))
@@ -398,7 +398,7 @@ class FuncFormTestCase(BaseSelectableTestCase):
             'things_0': '',
             'things_1': [self.test_thing.pk, ]
         }
-        form = SimpleForm(data=data, empty_permitted=True)
+        form = SimpleForm(data=data, empty_permitted=True, use_required_attribute=False)
         self.assertTrue(form.has_changed())
         self.assertTrue(form.is_valid(), str(form.errors))
 
@@ -442,7 +442,7 @@ class FuncFormTestCase(BaseSelectableTestCase):
             'new_thing': '',
             'things': '',
         }
-        form = SimpleForm(data=data, initial=initial, empty_permitted=True)
+        form = SimpleForm(data=data, initial=initial, empty_permitted=True, use_required_attribute=False)
         self.assertFalse(form.has_changed(), str(form.changed_data))
         self.assertTrue(form.is_valid(), str(form.errors))
 
@@ -459,7 +459,7 @@ class FuncFormTestCase(BaseSelectableTestCase):
             'things_0': '',
             'things_1': '',
         }
-        form = SimpleForm(data=data, empty_permitted=True)
+        form = SimpleForm(data=data, empty_permitted=True, use_required_attribute=False)
         self.assertFalse(form.has_changed(), str(form.changed_data))
         self.assertTrue(form.is_valid(), str(form.errors))
 
@@ -468,7 +468,7 @@ class FuncFormTestCase(BaseSelectableTestCase):
         If no data is submitted and allowed with no initial then
         the form should not be seen as changed.
         """
-        form = SimpleForm(data={}, empty_permitted=True)
+        form = SimpleForm(data={}, empty_permitted=True, use_required_attribute=False)
         self.assertFalse(form.has_changed(), str(form.changed_data))
         self.assertTrue(form.is_valid(), str(form.errors))
 
index 0bb65597c097405441f2e41298d4d36396f68489..c29ca09d2f17234e04edc9c6678ea7d4b0011ac5 100644 (file)
@@ -3,7 +3,7 @@ from __future__ import division
 import json
 
 from django.conf import settings
-from django.core.urlresolvers import reverse
+from django.urls import reverse
 from django.test import override_settings
 
 from . import ThingLookup
index 08e802468434b8b7f7ad9038758d03400841b91a..5209717a3a6c1ea445be8f7c3b65f00c98bb89c3 100644 (file)
@@ -292,9 +292,10 @@ class AutoCompleteSelectMultipleWidgetTestCase(BaseSelectableTestCase, WidgetTes
         rendered_value = widget.render('field_name', val)
         inputs = parsed_inputs(rendered_value)
         field = inputs['field_name_1'][0]
-        self.assertEqual(field.attributes['data-selectable-type'].value, 'hidden-multiple')
-        self.assertEqual(field.attributes['type'].value, 'hidden')
-        self.assertEqual(int(field.attributes['value'].value), val)
+        attributes = dict(field.attributes)
+        self.assertEqual(attributes['data-selectable-type'], 'hidden-multiple')
+        self.assertEqual(attributes['type'], 'hidden')
+        self.assertEqual(int(attributes['value']), val)
 
     def test_render_list(self):
         widget = self.get_widget_instance()
@@ -303,9 +304,10 @@ class AutoCompleteSelectMultipleWidgetTestCase(BaseSelectableTestCase, WidgetTes
         inputs = parsed_inputs(rendered_value)
         found_values = []
         for field in inputs['field_name_1']:
-            self.assertEqual(field.attributes['data-selectable-type'].value, 'hidden-multiple')
-            self.assertEqual(field.attributes['type'].value, 'hidden')
-            found_values.append(int(field.attributes['value'].value))
+            attributes = dict(field.attributes)
+            self.assertEqual(attributes['data-selectable-type'], 'hidden-multiple')
+            self.assertEqual(attributes['type'], 'hidden')
+            found_values.append(int(attributes['value']))
         self.assertListEqual(found_values, list_val)
 
     def test_render_qs(self):
@@ -318,10 +320,11 @@ class AutoCompleteSelectMultipleWidgetTestCase(BaseSelectableTestCase, WidgetTes
         found_values = []
         found_titles = []
         for field in inputs['field_name_1']:
-            self.assertEqual(field.attributes['data-selectable-type'].value, 'hidden-multiple')
-            self.assertEqual(field.attributes['type'].value, 'hidden')
-            found_titles.append(field.attributes['title'].value)
-            found_values.append(field.attributes['value'].value)
+            attributes = dict(field.attributes)
+            self.assertEqual(attributes['data-selectable-type'], 'hidden-multiple')
+            self.assertEqual(attributes['type'], 'hidden')
+            found_titles.append(attributes['title'])
+            found_values.append(attributes['value'])
         self.assertListEqual(found_values, [str(t1.pk), str(t2.pk)])
         self.assertListEqual(found_titles, [t1.name, t2.name])
 
@@ -391,9 +394,10 @@ class AutoComboboxSelectMultipleWidgetTestCase(BaseSelectableTestCase, WidgetTes
         rendered_value = widget.render('field_name', val)
         inputs = parsed_inputs(rendered_value)
         field = inputs['field_name_1'][0]
-        self.assertEqual(field.attributes['data-selectable-type'].value, 'hidden-multiple')
-        self.assertEqual(field.attributes['type'].value, 'hidden')
-        self.assertEqual(field.attributes['value'].value, str(val))
+        attributes = dict(field.attributes)
+        self.assertEqual(attributes['data-selectable-type'], 'hidden-multiple')
+        self.assertEqual(attributes['type'], 'hidden')
+        self.assertEqual(attributes['value'], str(val))
 
     def test_render_list(self):
         widget = self.get_widget_instance()
@@ -402,9 +406,10 @@ class AutoComboboxSelectMultipleWidgetTestCase(BaseSelectableTestCase, WidgetTes
         inputs = parsed_inputs(rendered_value)
         found_values = []
         for field in inputs['field_name_1']:
-            self.assertEqual(field.attributes['data-selectable-type'].value, 'hidden-multiple')
-            self.assertEqual(field.attributes['type'].value, 'hidden')
-            found_values.append(int(field.attributes['value'].value))
+            attributes = dict(field.attributes)
+            self.assertEqual(attributes['data-selectable-type'], 'hidden-multiple')
+            self.assertEqual(attributes['type'], 'hidden')
+            found_values.append(int(attributes['value']))
         self.assertListEqual(found_values, list_val)
 
     def test_render_qs(self):
@@ -416,9 +421,10 @@ class AutoComboboxSelectMultipleWidgetTestCase(BaseSelectableTestCase, WidgetTes
         inputs = parsed_inputs(rendered_value)
         found_values = []
         for field in inputs['field_name_1']:
-            self.assertEqual(field.attributes['data-selectable-type'].value, 'hidden-multiple')
-            self.assertEqual(field.attributes['type'].value, 'hidden')
-            found_values.append(int(field.attributes['value'].value))
+            attributes = dict(field.attributes)
+            self.assertEqual(attributes['data-selectable-type'], 'hidden-multiple')
+            self.assertEqual(attributes['type'], 'hidden')
+            found_values.append(int(attributes['value']))
         self.assertListEqual(found_values, [t1.pk, t2.pk])
 
     def test_update_query_parameters(self):
index aa18f3e3a294edce057e010786239fde2ab90e7f..83a71d1a594be5c19f7e8af602e228524e4a6fd0 100644 (file)
@@ -1,9 +1,9 @@
 from django.http import HttpResponseNotFound, HttpResponseServerError
 
 
-def test_404(request):
+def test_404(request, *args, **kwargs):
     return HttpResponseNotFound()
 
 
-def test_500(request):
+def test_500(request, *args, **kwargs):
     return HttpResponseServerError()
diff --git a/dep/django-selectable/selectable/tests/widgets.py b/dep/django-selectable/selectable/tests/widgets.py
deleted file mode 100644 (file)
index 052a839..0000000
+++ /dev/null
@@ -1,470 +0,0 @@
-import json
-
-from django import forms
-from django.utils.http import urlencode
-
-from selectable.compat import urlparse
-from selectable.forms import widgets
-from selectable.tests import Thing, ThingLookup
-from selectable.tests.base import BaseSelectableTestCase, parsed_inputs
-
-
-__all__ = (
-    'AutoCompleteWidgetTestCase',
-    'AutoCompleteSelectWidgetTestCase',
-    'AutoComboboxWidgetTestCase',
-    'AutoComboboxSelectWidgetTestCase',
-    'AutoCompleteSelectMultipleWidgetTestCase',
-    'AutoComboboxSelectMultipleWidgetTestCase',
-)
-
-
-class BaseWidgetTestCase(BaseSelectableTestCase):
-    widget_cls = None
-    lookup_cls = None
-
-    def get_widget_instance(self, **kwargs):
-        return self.__class__.widget_cls(self.__class__.lookup_cls, **kwargs)
-
-    def test_init(self):
-        widget = self.get_widget_instance()
-        self.assertEqual(widget.lookup_class, self.__class__.lookup_cls)
-
-    def test_dotted_path(self):
-        """
-        Ensure lookup_class can be imported from a dotted path.
-        """
-        dotted_path = '.'.join([self.__class__.lookup_cls.__module__, self.__class__.lookup_cls.__name__])
-        widget = self.__class__.widget_cls(dotted_path)
-        self.assertEqual(widget.lookup_class, self.__class__.lookup_cls)
-
-    def test_invalid_dotted_path(self):
-        """
-        An invalid lookup_class dotted path should raise an ImportError.
-        """
-        with self.assertRaises(ImportError):
-            self.__class__.widget_cls('this.is.an.invalid.path')
-
-    def test_dotted_path_wrong_type(self):
-        """
-        lookup_class must be a subclass of LookupBase.
-        """
-        dotted_path = 'selectable.forms.widgets.AutoCompleteWidget'
-        with self.assertRaises(TypeError):
-            self.__class__.widget_cls(dotted_path)
-
-
-class AutoCompleteWidgetTestCase(BaseWidgetTestCase):
-    widget_cls = widgets.AutoCompleteWidget
-    lookup_cls = ThingLookup
-
-    def test_build_attrs(self):
-        widget = self.get_widget_instance()
-        attrs = widget.build_attrs()
-        self.assertTrue('data-selectable-url' in attrs)
-        self.assertTrue('data-selectable-type' in attrs)
-        self.assertTrue('data-selectable-allow-new' in attrs)
-
-    def test_update_query_parameters(self):
-        params = {'active': 1}
-        widget = self.get_widget_instance()
-        widget.update_query_parameters(params)
-        attrs = widget.build_attrs()
-        url = attrs['data-selectable-url']
-        parse = urlparse(url)
-        query = parse.query
-        self.assertEqual(query, urlencode(params))
-
-    def test_limit_paramter(self):
-        widget = self.get_widget_instance(limit=10)
-        attrs = widget.build_attrs()
-        url = attrs['data-selectable-url']
-        parse = urlparse(url)
-        query = parse.query
-        self.assertTrue('limit=10' in query)
-
-    def test_initial_query_parameters(self):
-        params = {'active': 1}
-        widget = self.get_widget_instance(query_params=params)
-        attrs = widget.build_attrs()
-        url = attrs['data-selectable-url']
-        parse = urlparse(url)
-        query = parse.query
-        self.assertEqual(query, urlencode(params))
-
-    def test_build_selectable_options(self):
-        "Serialize selectable options as json in data attribute."
-        options = {'autoFocus': True}
-        widget = self.get_widget_instance(attrs={'data-selectable-options': options})
-        attrs = widget.build_attrs()
-        self.assertTrue('data-selectable-options' in attrs)
-        self.assertEqual(attrs['data-selectable-options'], json.dumps(options))
-
-
-class AutoCompleteSelectWidgetTestCase(BaseWidgetTestCase):
-    widget_cls = widgets.AutoCompleteSelectWidget
-    lookup_cls = ThingLookup
-
-    def test_has_complete_widget(self):
-        widget = self.get_widget_instance()
-        self.assertEqual(widget.widgets[0].__class__, widgets.AutoCompleteWidget)
-
-    def test_has_hidden_widget(self):
-        widget = self.get_widget_instance()
-        self.assertEqual(widget.widgets[1].__class__, forms.HiddenInput)
-
-    def test_hidden_type(self):
-        widget = self.get_widget_instance()
-        sub_widget = widget.widgets[1]
-        attrs = sub_widget.build_attrs()
-        self.assertTrue('data-selectable-type' in attrs)
-        self.assertEqual(attrs['data-selectable-type'], 'hidden')
-
-    def test_update_query_parameters(self):
-        params = {'active': 1}
-        widget = self.get_widget_instance()
-        widget.update_query_parameters(params)
-        sub_widget = widget.widgets[0]
-        attrs = sub_widget.build_attrs()
-        url = attrs['data-selectable-url']
-        parse = urlparse(url)
-        query = parse.query
-        self.assertEqual(query, urlencode(params))
-
-    def test_limit_paramter(self):
-        widget = self.get_widget_instance(limit=10)
-        sub_widget = widget.widgets[0]
-        attrs = sub_widget.build_attrs()
-        url = attrs['data-selectable-url']
-        parse = urlparse(url)
-        query = parse.query
-        self.assertTrue('limit=10' in query)
-
-    def test_initial_query_parameters(self):
-        params = {'active': 1}
-        widget = self.get_widget_instance(query_params=params)
-        sub_widget = widget.widgets[0]
-        attrs = sub_widget.build_attrs()
-        url = attrs['data-selectable-url']
-        parse = urlparse(url)
-        query = parse.query
-        self.assertEqual(query, urlencode(params))
-
-    def test_build_selectable_options(self):
-        "Serialize selectable options as json in data attribute."
-        options = {'autoFocus': True}
-        widget = self.get_widget_instance(attrs={'data-selectable-options': options})
-        sub_widget = widget.widgets[0]
-        attrs = sub_widget.build_attrs()
-        self.assertTrue('data-selectable-options' in attrs)
-        self.assertEqual(attrs['data-selectable-options'], json.dumps(options))
-
-
-class AutoComboboxWidgetTestCase(BaseWidgetTestCase):
-    widget_cls = widgets.AutoComboboxWidget
-    lookup_cls = ThingLookup
-
-    def test_build_attrs(self):
-        widget = self.get_widget_instance()
-        attrs = widget.build_attrs()
-        self.assertTrue('data-selectable-url' in attrs)
-        self.assertTrue('data-selectable-type' in attrs)
-        self.assertTrue('data-selectable-allow-new' in attrs)
-
-    def test_update_query_parameters(self):
-        params = {'active': 1}
-        widget = self.get_widget_instance()
-        widget.update_query_parameters(params)
-        attrs = widget.build_attrs()
-        url = attrs['data-selectable-url']
-        parse = urlparse(url)
-        query = parse.query
-        self.assertEqual(query, urlencode(params))
-
-    def test_limit_paramter(self):
-        widget = self.get_widget_instance(limit=10)
-        attrs = widget.build_attrs()
-        url = attrs['data-selectable-url']
-        parse = urlparse(url)
-        query = parse.query
-        self.assertTrue('limit=10' in query)
-
-    def test_initial_query_parameters(self):
-        params = {'active': 1}
-        widget = self.get_widget_instance(query_params=params)
-        attrs = widget.build_attrs()
-        url = attrs['data-selectable-url']
-        parse = urlparse(url)
-        query = parse.query
-        self.assertEqual(query, urlencode(params))
-
-    def test_build_selectable_options(self):
-        "Serialize selectable options as json in data attribute."
-        options = {'autoFocus': True}
-        widget = self.get_widget_instance(attrs={'data-selectable-options': options})
-        attrs = widget.build_attrs()
-        self.assertTrue('data-selectable-options' in attrs)
-        self.assertEqual(attrs['data-selectable-options'], json.dumps(options))
-
-
-class AutoComboboxSelectWidgetTestCase(BaseWidgetTestCase):
-    widget_cls = widgets.AutoComboboxSelectWidget
-    lookup_cls = ThingLookup
-
-    def test_has_complete_widget(self):
-        widget = self.get_widget_instance()
-        self.assertEqual(widget.widgets[0].__class__, widgets.AutoComboboxWidget)
-
-    def test_has_hidden_widget(self):
-        widget = self.get_widget_instance()
-        self.assertEqual(widget.widgets[1].__class__, forms.HiddenInput)
-
-    def test_hidden_type(self):
-        widget = self.get_widget_instance()
-        sub_widget = widget.widgets[1]
-        attrs = sub_widget.build_attrs()
-        self.assertTrue('data-selectable-type' in attrs)
-        self.assertEqual(attrs['data-selectable-type'], 'hidden')
-
-    def test_update_query_parameters(self):
-        params = {'active': 1}
-        widget = self.get_widget_instance()
-        widget.update_query_parameters(params)
-        sub_widget = widget.widgets[0]
-        attrs = sub_widget.build_attrs()
-        url = attrs['data-selectable-url']
-        parse = urlparse(url)
-        query = parse.query
-        self.assertEqual(query, urlencode(params))
-
-    def test_limit_paramter(self):
-        widget = self.get_widget_instance(limit=10)
-        sub_widget = widget.widgets[0]
-        attrs = sub_widget.build_attrs()
-        url = attrs['data-selectable-url']
-        parse = urlparse(url)
-        query = parse.query
-        self.assertTrue('limit=10' in query)
-
-    def test_initial_query_parameters(self):
-        params = {'active': 1}
-        widget = self.get_widget_instance(query_params=params)
-        sub_widget = widget.widgets[0]
-        attrs = sub_widget.build_attrs()
-        url = attrs['data-selectable-url']
-        parse = urlparse(url)
-        query = parse.query
-        self.assertEqual(query, urlencode(params))
-
-    def test_build_selectable_options(self):
-        "Serialize selectable options as json in data attribute."
-        options = {'autoFocus': True}
-        widget = self.get_widget_instance(attrs={'data-selectable-options': options})
-        sub_widget = widget.widgets[0]
-        attrs = sub_widget.build_attrs()
-        self.assertTrue('data-selectable-options' in attrs)
-        self.assertEqual(attrs['data-selectable-options'], json.dumps(options))
-
-
-class AutoCompleteSelectMultipleWidgetTestCase(BaseWidgetTestCase):
-    widget_cls = widgets.AutoCompleteSelectMultipleWidget
-    lookup_cls = ThingLookup
-
-    def test_has_complete_widget(self):
-        widget = self.get_widget_instance()
-        self.assertEqual(widget.widgets[0].__class__, widgets.AutoCompleteWidget)
-
-    def test_multiple_attr(self):
-        widget = self.get_widget_instance()
-        sub_widget = widget.widgets[0]
-        attrs = sub_widget.build_attrs()
-        self.assertTrue('data-selectable-multiple' in attrs)
-        self.assertEqual(attrs['data-selectable-multiple'], 'true')
-
-    def test_has_hidden_widget(self):
-        widget = self.get_widget_instance()
-        self.assertEqual(widget.widgets[1].__class__, widgets.LookupMultipleHiddenInput)
-
-    def test_hidden_type(self):
-        widget = self.get_widget_instance()
-        sub_widget = widget.widgets[1]
-        attrs = sub_widget.build_attrs()
-        self.assertTrue('data-selectable-type' in attrs)
-        self.assertEqual(attrs['data-selectable-type'], 'hidden-multiple')
-
-    def test_render_single(self):
-        widget = self.get_widget_instance()
-        val = 4
-        rendered_value = widget.render('field_name', val)
-        inputs = parsed_inputs(rendered_value)
-        field = inputs['field_name_1'][0]
-        self.assertEqual(field.attributes['data-selectable-type'].value, 'hidden-multiple')
-        self.assertEqual(field.attributes['type'].value, 'hidden')
-        self.assertEqual(int(field.attributes['value'].value), val)
-
-    def test_render_list(self):
-        widget = self.get_widget_instance()
-        list_val = [8, 5]
-        rendered_value = widget.render('field_name', list_val)
-        inputs = parsed_inputs(rendered_value)
-        found_values = []
-        for field in inputs['field_name_1']:
-            self.assertEqual(field.attributes['data-selectable-type'].value, 'hidden-multiple')
-            self.assertEqual(field.attributes['type'].value, 'hidden')
-            found_values.append(int(field.attributes['value'].value))
-        self.assertListEqual(found_values, list_val)
-
-    def test_render_qs(self):
-        widget = self.get_widget_instance()
-        t1 = self.create_thing()
-        t2 = self.create_thing()
-        qs_val = Thing.objects.filter(pk__in=[t1.pk, t2.pk]).values_list('pk', flat=True)
-        rendered_value = widget.render('field_name', qs_val)
-        inputs = parsed_inputs(rendered_value)
-        found_values = []
-        for field in inputs['field_name_1']:
-            self.assertEqual(field.attributes['data-selectable-type'].value, 'hidden-multiple')
-            self.assertEqual(field.attributes['type'].value, 'hidden')
-            found_values.append(int(field.attributes['value'].value))
-        self.assertListEqual(found_values, [t1.pk, t2.pk])
-
-    def test_update_query_parameters(self):
-        params = {'active': 1}
-        widget = self.get_widget_instance()
-        widget.update_query_parameters(params)
-        sub_widget = widget.widgets[0]
-        attrs = sub_widget.build_attrs()
-        url = attrs['data-selectable-url']
-        parse = urlparse(url)
-        query = parse.query
-        self.assertEqual(query, urlencode(params))
-
-    def test_limit_paramter(self):
-        widget = self.get_widget_instance(limit=10)
-        sub_widget = widget.widgets[0]
-        attrs = sub_widget.build_attrs()
-        url = attrs['data-selectable-url']
-        parse = urlparse(url)
-        query = parse.query
-        self.assertTrue('limit=10' in query)
-
-    def test_initial_query_parameters(self):
-        params = {'active': 1}
-        widget = self.get_widget_instance(query_params=params)
-        sub_widget = widget.widgets[0]
-        attrs = sub_widget.build_attrs()
-        url = attrs['data-selectable-url']
-        parse = urlparse(url)
-        query = parse.query
-        self.assertEqual(query, urlencode(params))
-
-    def test_build_selectable_options(self):
-        "Serialize selectable options as json in data attribute."
-        options = {'autoFocus': True}
-        widget = self.get_widget_instance(attrs={'data-selectable-options': options})
-        sub_widget = widget.widgets[0]
-        attrs = sub_widget.build_attrs()
-        self.assertTrue('data-selectable-options' in attrs)
-        self.assertEqual(attrs['data-selectable-options'], json.dumps(options))
-
-
-class AutoComboboxSelectMultipleWidgetTestCase(BaseWidgetTestCase):
-    widget_cls = widgets.AutoComboboxSelectMultipleWidget
-    lookup_cls = ThingLookup
-
-    def test_has_complete_widget(self):
-        widget = self.get_widget_instance()
-        self.assertEqual(widget.widgets[0].__class__, widgets.AutoComboboxWidget)
-
-    def test_multiple_attr(self):
-        widget = self.get_widget_instance()
-        sub_widget = widget.widgets[0]
-        attrs = sub_widget.build_attrs()
-        self.assertTrue('data-selectable-multiple' in attrs)
-        self.assertEqual(attrs['data-selectable-multiple'], 'true')
-
-    def test_has_hidden_widget(self):
-        widget = self.get_widget_instance()
-        self.assertEqual(widget.widgets[1].__class__, widgets.LookupMultipleHiddenInput)
-
-    def test_hidden_type(self):
-        widget = self.get_widget_instance()
-        sub_widget = widget.widgets[1]
-        attrs = sub_widget.build_attrs()
-        self.assertTrue('data-selectable-type' in attrs)
-        self.assertEqual(attrs['data-selectable-type'], 'hidden-multiple')
-
-    def test_render_single(self):
-        widget = self.get_widget_instance()
-        val = 4
-        rendered_value = widget.render('field_name', val)
-        inputs = parsed_inputs(rendered_value)
-        field = inputs['field_name_1'][0]
-        self.assertEqual(field.attributes['data-selectable-type'].value, 'hidden-multiple')
-        self.assertEqual(field.attributes['type'].value, 'hidden')
-        self.assertEqual(field.attributes['value'].value, str(val))
-
-    def test_render_list(self):
-        widget = self.get_widget_instance()
-        list_val = [8, 5]
-        rendered_value = widget.render('field_name', list_val)
-        inputs = parsed_inputs(rendered_value)
-        found_values = []
-        for field in inputs['field_name_1']:
-            self.assertEqual(field.attributes['data-selectable-type'].value, 'hidden-multiple')
-            self.assertEqual(field.attributes['type'].value, 'hidden')
-            found_values.append(int(field.attributes['value'].value))
-        self.assertListEqual(found_values, list_val)
-
-    def test_render_qs(self):
-        widget = self.get_widget_instance()
-        t1 = self.create_thing()
-        t2 = self.create_thing()
-        qs_val = Thing.objects.filter(pk__in=[t1.pk, t2.pk]).values_list('pk', flat=True)
-        rendered_value = widget.render('field_name', qs_val)
-        inputs = parsed_inputs(rendered_value)
-        found_values = []
-        for field in inputs['field_name_1']:
-            self.assertEqual(field.attributes['data-selectable-type'].value, 'hidden-multiple')
-            self.assertEqual(field.attributes['type'].value, 'hidden')
-            found_values.append(int(field.attributes['value'].value))
-        self.assertListEqual(found_values, [t1.pk, t2.pk])
-
-    def test_update_query_parameters(self):
-        params = {'active': 1}
-        widget = self.get_widget_instance()
-        widget.update_query_parameters(params)
-        sub_widget = widget.widgets[0]
-        attrs = sub_widget.build_attrs()
-        url = attrs['data-selectable-url']
-        parse = urlparse(url)
-        query = parse.query
-        self.assertEqual(query, urlencode(params))
-
-    def test_limit_paramter(self):
-        widget = self.get_widget_instance(limit=10)
-        sub_widget = widget.widgets[0]
-        attrs = sub_widget.build_attrs()
-        url = attrs['data-selectable-url']
-        parse = urlparse(url)
-        query = parse.query
-        self.assertTrue('limit=10' in query)
-
-    def test_initial_query_parameters(self):
-        params = {'active': 1}
-        widget = self.get_widget_instance(query_params=params)
-        sub_widget = widget.widgets[0]
-        attrs = sub_widget.build_attrs()
-        url = attrs['data-selectable-url']
-        parse = urlparse(url)
-        query = parse.query
-        self.assertEqual(query, urlencode(params))
-
-    def test_build_selectable_options(self):
-        "Serialize selectable options as json in data attribute."
-        options = {'autoFocus': True}
-        widget = self.get_widget_instance(attrs={'data-selectable-options': options})
-        sub_widget = widget.widgets[0]
-        attrs = sub_widget.build_attrs()
-        self.assertTrue('data-selectable-options' in attrs)
-        self.assertEqual(attrs['data-selectable-options'], json.dumps(options))
old mode 100644 (file)
new mode 100755 (executable)
index fc2aa04..40b9ab0
@@ -27,14 +27,17 @@ setup(
         'Development Status :: 5 - Production/Stable',
         'Intended Audience :: Developers',
         'Framework :: Django',
+        'Framework :: Django :: 1.11',
+        'Framework :: Django :: 2.0',
+        'Framework :: Django :: 2.1',
         'License :: OSI Approved :: BSD License',
         'Operating System :: OS Independent',
         'Programming Language :: Python',
         'Programming Language :: Python :: 2.7',
         'Programming Language :: Python :: 3',
-        'Programming Language :: Python :: 3.3',
         'Programming Language :: Python :: 3.4',
         'Programming Language :: Python :: 3.5',
+        'Programming Language :: Python :: 3.6',
         'Topic :: Internet :: WWW/HTTP :: Dynamic Content',
     ],
     long_description=read_file('README.rst'),
index 7e21929e8b602ca84b2654b9e2be2efe2ffb8401..c6c4e96e1f5d7af0c09b6e510e902c1b016a403c 100644 (file)
@@ -1,19 +1,17 @@
 [tox]
-envlist = py{27,33}-django{17,18},py{27,34,35}-django{19,110,111},py35-django_master,docs
+envlist = py{27,34,35,36}-django{111},py{34,35,36}-django{20,21},py35-django_master,docs
 
 [testenv]
 basepython =
     py27: python2.7
-    py33: python3.3
     py34: python3.4
     py35: python3.5
+    py36: python3.6
 deps =
     coverage>=4.0,<4.1
-    django17: Django>=1.7,<1.8
-    django18: Django>=1.8,<1.9
-    django19: Django>=1.9,<1.10
-    django110: Django>=1.10,<1.11
     django111: Django>=1.11,<2.0
+    django20: Django>=2.0,<2.1
+    django21: Django>=2.1,<2.2
     django_master: https://github.com/django/django/archive/master.tar.gz
     py27: mock
 commands = coverage run runtests.py