diff --git a/.gitignore b/.gitignore index 7f583c5..ad91cf4 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,5 @@ local_settings.py .idea build dist -*.egg-info \ No newline at end of file +*.egg-info +.coverage* \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index 6cca6a2..506375f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,11 +1,60 @@ language: python +python: + - "2.6" + - "2.7" + - "3.3" + - "3.4" + - "3.5" +env: + - DJANGO=1.4 + - DJANGO=1.5 + - DJANGO=1.6 + - DJANGO=1.7 + - DJANGO=1.8 + - DJANGO=1.9 + - DJANGO=1.10 +matrix: + exclude: + - python: "2.6" + env: DJANGO=1.7 + - python: "2.6" + env: DJANGO=1.8 + - python: "2.6" + env: DJANGO=1.9 + - python: "2.6" + env: DJANGO=1.10 + - python: "3.3" + env: DJANGO=1.4 + - python: "3.4" + env: DJANGO=1.4 + - python: "3.5" + env: DJANGO=1.4 + - python: "3.3" + env: DJANGO=1.5 + - python: "3.4" + env: DJANGO=1.5 + - python: "3.5" + env: DJANGO=1.5 + - python: "3.4" + env: DJANGO=1.6 + - python: "3.5" + env: DJANGO=1.6 + - python: "3.5" + env: DJANGO=1.7 + - python: "3.3" + env: DJANGO=1.9 + - python: "3.3" + env: DJANGO=1.10 + install: - - pip install -q --use-mirrors tox==1.6.1 coveralls==0.3 + - pip install -q Django==$DJANGO + - pip install tox coveralls script: - coverage erase - - tox + - PYTHONPATH=. coverage run -p example/run_tests.py + - PYTHONPATH=. coverage run -p example/run_tests.py example.settings_no_debug after_success: - coverage combine - coveralls @@ -13,3 +62,4 @@ after_success: notifications: email: - goinnn@gmail.com + - blag@users.noreply.github.com diff --git a/example/example/app/__init__.py b/example/app/__init__.py similarity index 100% rename from example/example/app/__init__.py rename to example/app/__init__.py diff --git a/example/example/app/admin.py b/example/app/admin.py similarity index 95% rename from example/example/app/admin.py rename to example/app/admin.py index a8f2595..ef01fc1 100644 --- a/example/example/app/admin.py +++ b/example/app/admin.py @@ -16,7 +16,7 @@ from django.contrib import admin -from example.app.models import Book +from .models import Book class BookAdmin(admin.ModelAdmin): diff --git a/example/example/app/fixtures/app_data.json b/example/app/fixtures/app_data.json similarity index 100% rename from example/example/app/fixtures/app_data.json rename to example/app/fixtures/app_data.json diff --git a/example/example/app/models.py b/example/app/models.py similarity index 100% rename from example/example/app/models.py rename to example/app/models.py diff --git a/example/example/app/tests.py b/example/app/test_msf.py similarity index 75% rename from example/example/app/tests.py rename to example/app/test_msf.py index d986f96..23e1f29 100644 --- a/example/example/app/tests.py +++ b/example/app/test_msf.py @@ -14,11 +14,20 @@ # You should have received a copy of the GNU Lesser General Public License # along with this software. If not, see . +from django import VERSION from django.core.exceptions import ValidationError from django.forms.models import modelform_factory from django.test import TestCase -from example.app.models import Book +from .models import Book + + +if VERSION < (1, 9): + def get_field(model, name): + return model._meta.get_field_by_name(name)[0] +else: + def get_field(model, name): + return model._meta.get_field(name) class MultiSelectTestCase(TestCase): @@ -30,7 +39,7 @@ class MultiSelectTestCase(TestCase): self.assertEqual(Book.objects.filter(tags__contains='boring').count(), 0) def test_form(self): - form_class = modelform_factory(Book) + form_class = modelform_factory(Book, fields='__all__') self.assertEqual(len(form_class.base_fields), 3) form = form_class({'title': 'new book', 'categories': '1,2'}) @@ -49,26 +58,26 @@ class MultiSelectTestCase(TestCase): def test_validate(self): book = Book.objects.get(id=1) - Book._meta.get_field_by_name('tags')[0].clean(['sex', 'work'], book) + get_field(Book, 'tags').clean(['sex', 'work'], book) try: - Book._meta.get_field_by_name('tags')[0].clean(['sex1', 'work'], book) + get_field(Book, 'tags').clean(['sex1', 'work'], book) raise AssertionError() except ValidationError: pass - Book._meta.get_field_by_name('categories')[0].clean(['1', '2', '3'], book) + get_field(Book, 'categories').clean(['1', '2', '3'], book) try: - Book._meta.get_field_by_name('categories')[0].clean(['1', '2', '3', '4'], book) + get_field(Book, 'categories').clean(['1', '2', '3', '4'], book) raise AssertionError() except ValidationError: pass try: - Book._meta.get_field_by_name('categories')[0].clean(['11', '12', '13'], book) + get_field(Book, 'categories').clean(['11', '12', '13'], book) raise AssertionError() except ValidationError: pass def test_serializer(self): book = Book.objects.get(id=1) - self.assertEqual(Book._meta.get_field_by_name('tags')[0].value_to_string(book), 'sex,work,happy') - self.assertEqual(Book._meta.get_field_by_name('categories')[0].value_to_string(book), '1,3,5') + self.assertEqual(get_field(Book, 'tags').value_to_string(book), 'sex,work,happy') + self.assertEqual(get_field(Book, 'categories').value_to_string(book), '1,3,5') diff --git a/example/example/app/urls.py b/example/app/urls.py similarity index 95% rename from example/example/app/urls.py rename to example/app/urls.py index d2b8e28..f7d22c0 100644 --- a/example/example/app/urls.py +++ b/example/app/urls.py @@ -20,6 +20,6 @@ except ImportError: # Django < 1.4 from django.conf.urls.defaults import include, patterns, url -urlpatterns = patterns('example.app.views', +urlpatterns = patterns('app.views', url(r'^$', 'app_index', name='app_index'), ) diff --git a/example/example/app/views.py b/example/app/views.py similarity index 100% rename from example/example/app/views.py rename to example/app/views.py diff --git a/example/example/settings.py b/example/example/settings.py index 9e5d174..afef900 100644 --- a/example/example/settings.py +++ b/example/example/settings.py @@ -157,7 +157,7 @@ INSTALLED_APPS = ( # 'django.contrib.admindocs', 'multiselectfield', - 'example.app' + 'app' ) @@ -208,3 +208,6 @@ if django.VERSION[0] == 1 and django.VERSION[1] >= 4: }, } LOGGING['handlers']['mail_admins']['filters'] = ['require_debug_false'] + +if django.VERSION >= (1, 6): + TEST_RUNNER = 'django.test.runner.DiscoverRunner' diff --git a/example/run_tests.py b/example/run_tests.py index b91dc12..9cc12c4 100644 --- a/example/run_tests.py +++ b/example/run_tests.py @@ -34,7 +34,4 @@ if django.VERSION[0] == 1 and django.VERSION[1] >= 7: from django.core.wsgi import get_wsgi_application application = get_wsgi_application() -if django.VERSION[0] == 1 and django.VERSION[1] <= 5: - management.call_command('test', 'app') -else: - management.call_command('test', 'example.app') +management.call_command('test', 'app') diff --git a/multiselectfield/db/fields.py b/multiselectfield/db/fields.py index a9ddb6d..d23cf36 100644 --- a/multiselectfield/db/fields.py +++ b/multiselectfield/db/fields.py @@ -109,6 +109,11 @@ class MultiSelectField(models.CharField): return value if isinstance(value, list) else value.split(',') return [] + def from_db_value(self, value, expression, connection, context): + if value is None: + return value + return self.to_python(value) + def contribute_to_class(self, cls, name): super(MultiSelectField, self).contribute_to_class(cls, name) if self.choices: @@ -133,7 +138,8 @@ class MultiSelectField(models.CharField): setattr(cls, 'get_%s_list' % self.name, get_list) setattr(cls, 'get_%s_display' % self.name, get_display) -MultiSelectField = add_metaclass(models.SubfieldBase)(MultiSelectField) +if django.VERSION < (1, 8): + MultiSelectField = add_metaclass(models.SubfieldBase)(MultiSelectField) try: from south.modelsinspector import add_introspection_rules diff --git a/setup.py b/setup.py index c303ebc..f889201 100644 --- a/setup.py +++ b/setup.py @@ -35,12 +35,25 @@ setup( 'Framework :: Django', 'License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)', 'Programming Language :: Python :: 2', + 'Programming Language :: Python :: 2.6', + 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.3', + 'Programming Language :: Python :: 3.4', + 'Programming Language :: Python :: 3.5', ], license="LGPL 3", keywords="django,multiple,select,field,choices", url='https://github.com/goinnn/django-multiselectfield', packages=find_packages(), include_package_data=True, + tests_require=[ + 'django>=1.4', + 'tox', + 'coverage', + ], + install_requires=[ + 'django>=1.4', + ], zip_safe=False, ) diff --git a/tox.ini b/tox.ini index 2bfae2f..4258ea7 100644 --- a/tox.ini +++ b/tox.ini @@ -1,18 +1,18 @@ [tox] -envlist = py27-dj17,py27-dj16,py27-dj15,py27-dj14,py34-dj17,py33-dj17,py33-dj16,py33-dj15,py26-dj16,py26-dj15,py26-dj14 +envlist = py26-dj14,py27-dj14,py26-dj15,py27-dj15,py26-dj16,py27-dj16,py33-dj16,py27-dj17,py33-dj17,py34-dj17,py27-dj18,py33-dj18,py34-dj18,py35-dj18,py27-dj19,py34-dj19,py35-dj19,py27-dj110,py34-dj110,py35-dj110 [testenv] usedevelop = True commands = - python {envbindir}/coverage run -p example/run_tests.py - python {envbindir}/coverage run -p example/run_tests.py example.settings_no_debug + PYTHONPATH=. python {envbindir}/coverage run -p example/run_tests.py + PYTHONPATH=. python {envbindir}/coverage run -p example/run_tests.py example.settings_no_debug install_command = pip install {opts} {packages} -[testenv:py26-dj16] +[testenv:py26-dj14] basepython = python2.6 deps = - django==1.6 + django==1.4.10 pillow==1.7.8 PyYAML==3.10 coveralls==0.3 @@ -25,18 +25,27 @@ deps = PyYAML==3.10 coveralls==0.3 -[testenv:py26-dj14] +[testenv:py26-dj16] basepython = python2.6 +deps = + django==1.6 + pillow==1.7.8 + PyYAML==3.10 + coveralls==0.3 + + +[testenv:py27-dj14] +basepython = python2.7 deps = django==1.4.10 pillow==1.7.8 PyYAML==3.10 coveralls==0.3 -[testenv:py27-dj17] +[testenv:py27-dj15] basepython = python2.7 deps = - django==1.7 + django==1.5.5 pillow==1.7.8 PyYAML==3.10 coveralls==0.3 @@ -49,36 +58,35 @@ deps = PyYAML==3.10 coveralls==0.3 - -[testenv:py27-dj15] +[testenv:py27-dj17] basepython = python2.7 deps = - django==1.5.5 + django==1.7 pillow==1.7.8 PyYAML==3.10 coveralls==0.3 -[testenv:py27-dj14] +[testenv:py27-dj18] basepython = python2.7 deps = - django==1.4.10 + django==1.8 pillow==1.7.8 PyYAML==3.10 coveralls==0.3 -[testenv:py34-dj17] -basepython = python3.4 +[testenv:py27-dj19] +basepython = python2.7 deps = - django==1.7 - pillow==2.1.0 + django==1.9 + pillow==1.7.8 PyYAML==3.10 coveralls==0.3 -[testenv:py33-dj17] -basepython = python3.3 +[testenv:py27-dj110] +basepython = python2.7 deps = - django==1.7 - pillow==2.1.0 + django==1.10 + pillow==1.7.8 PyYAML==3.10 coveralls==0.3 @@ -91,11 +99,76 @@ deps = PyYAML==3.10 coveralls==0.3 - -[testenv:py33-dj15] +[testenv:py33-dj17] basepython = python3.3 deps = - django==1.5.5 + django==1.7 + pillow==2.1.0 + PyYAML==3.10 + coveralls==0.3 + +[testenv:py33-dj18] +basepython = python3.3 +deps = + django==1.8 + pillow==2.1.0 + PyYAML==3.10 + coveralls==0.3 + + +[testenv:py34-dj17] +basepython = python3.4 +deps = + django==1.7 + pillow==2.1.0 + PyYAML==3.10 + coveralls==0.3 + +[testenv:py34-dj18] +basepython = python3.4 +deps = + django==1.8 + pillow==2.1.0 + PyYAML==3.10 + coveralls==0.3 + +[testenv:py34-dj19] +basepython = python3.4 +deps = + django==1.9 + pillow==2.1.0 + PyYAML==3.10 + coveralls==0.3 + +[testenv:py34-dj110] +basepython = python3.4 +deps = + django==1.10 + pillow==2.1.0 + PyYAML==3.10 + coveralls==0.3 + + +[testenv:py35-dj18] +basepython = python3.5 +deps = + django==1.8 + pillow==2.1.0 + PyYAML==3.10 + coveralls==0.3 + +[testenv:py35-dj19] +basepython = python3.5 +deps = + django==1.9 + pillow==2.1.0 + PyYAML==3.10 + coveralls==0.3 + +[testenv:py35-dj110] +basepython = python3.5 +deps = + django==1.10 pillow==2.1.0 PyYAML==3.10 coveralls==0.3