Skip to content

Commit

Permalink
Merge pull request #148 from blag/cleanup
Browse files Browse the repository at this point in the history
Clean up, update for Django 5, and fix tests
  • Loading branch information
blag authored May 21, 2024
2 parents 0da5d31 + 8094d36 commit 395d0b2
Show file tree
Hide file tree
Showing 7 changed files with 143 additions and 227 deletions.
141 changes: 72 additions & 69 deletions example/app/test_msf.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,6 @@
# You should have received a copy of the GNU Lesser General Public License
# along with this software. If not, see <http://www.gnu.org/licenses/>.

import sys

from django import VERSION
from django.core.exceptions import ValidationError
from django.forms.models import modelform_factory
from django.test import TestCase
Expand All @@ -25,36 +22,11 @@

from .models import Book, PROVINCES, STATES, PROVINCES_AND_STATES, ONE, TWO

if sys.version_info < (3,):
u = unicode # noqa: F821
else:
u = str


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):

fixtures = ['app_data.json']
maxDiff = 4000

def assertListEqual(self, left, right, msg=None):
if sys.version_info >= (3, 2):
# Added in Python 3.2
self.assertCountEqual(left, right, msg=msg)
else:
# Manually check list equality
self.assertEqual(len(left), len(right), msg=msg)
for i, tag_list in enumerate(left):
for j, tag in enumerate(tag_list):
self.assertEqual(tag, right[i][j], msg=msg)

def assertStringEqual(self, left, right, msg=None):
_msg = "Chars in position %%d differ: %%s != %%s. %s" % msg

Expand All @@ -70,18 +42,10 @@ def test_values_list(self):
tag_list_list = Book.objects.all().values_list('tags', flat=True)
categories_list_list = Book.objects.all().values_list('categories', flat=True)

# Workaround for Django bug #9619
# https://code.djangoproject.com/ticket/9619
# For Django 1.6 and 1.7, calling values() or values_list() doesn't
# call Field.from_db_field, it simply returns a Python representation
# of the data in the database (which in our case is a string of
# comma-separated values). The bug was fixed in Django 1.8+.
if VERSION >= (1, 6) and VERSION < (1, 8):
self.assertStringEqual(tag_list_list, [u('sex,work,happy')])
self.assertStringEqual(categories_list_list, [u('1,3,5')])
else:
self.assertListEqual(tag_list_list, [['sex', 'work', 'happy']])
self.assertListEqual(categories_list_list, [['1', '3', '5']])
# assertCountEqual also ensures that the elements are the same (ignoring list order)
# https://docs.python.org/3.2/library/unittest.html#unittest.TestCase.assertCountEqual
self.assertCountEqual(tag_list_list, [['sex', 'work', 'happy']])
self.assertCountEqual(categories_list_list, [['1', '3', '5']])

def test_form(self):
form_class = modelform_factory(Book, fields=('title', 'tags', 'categories'))
Expand Down Expand Up @@ -124,63 +88,102 @@ def test_object(self):

def test_validate(self):
book = Book.objects.get(id=1)
get_field(Book, 'tags').clean(['sex', 'work'], book)
Book._meta.get_field('tags').clean(['sex', 'work'], book)
try:
get_field(Book, 'tags').clean(['sex1', 'work'], book)
Book._meta.get_field('tags').clean(['sex1', 'work'], book)
raise AssertionError()
except ValidationError:
pass

get_field(Book, 'categories').clean(['1', '2', '3'], book)
Book._meta.get_field('categories').clean(['1', '2', '3'], book)
try:
get_field(Book, 'categories').clean(['1', '2', '3', '4'], book)
Book._meta.get_field('categories').clean(['1', '2', '3', '4'], book)
raise AssertionError()
except ValidationError:
pass
try:
get_field(Book, 'categories').clean(['11', '12', '13'], book)
Book._meta.get_field('categories').clean(['11', '12', '13'], book)
raise AssertionError()
except ValidationError:
pass

def test_serializer(self):
book = Book.objects.get(id=1)
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')
self.assertEqual(Book._meta.get_field('tags').value_to_string(book), 'sex,work,happy')
self.assertEqual(Book._meta.get_field('categories').value_to_string(book), '1,3,5')

def test_flatchoices(self):
self.assertEqual(get_field(Book, 'published_in').flatchoices, list(PROVINCES + STATES))
self.assertEqual(Book._meta.get_field('published_in').flatchoices, list(PROVINCES + STATES))

def test_named_groups(self):
self.assertEqual(get_field(Book, 'published_in').choices, PROVINCES_AND_STATES)
# We can't use a single self.assertEqual here, because model subchoices may be lists or tuples
# Iterate through the parent choices
for book_choices, province_or_state_choice in zip(Book._meta.get_field('published_in').choices, PROVINCES_AND_STATES):
parent_book_choice, *book_subchoices = book_choices
parent_pors_choice, *pors_subchoices = province_or_state_choice
# Check the parent keys
self.assertEqual(parent_book_choice, parent_pors_choice)
# Iterate through all of the subchoices
for book_subchoice, pors_subchoice in zip(book_subchoices, pors_subchoices):
# The model subchoices might be tuples, so make sure to convert both to lists
self.assertEqual(list(book_subchoice), list(pors_subchoice))

def test_named_groups_form(self):
form_class = modelform_factory(Book, fields=('published_in',))
self.assertEqual(len(form_class.base_fields), 1)
form = form_class(initial={'published_in': ['BC', 'AK']})

expected_html = u("""<p><label for="id_published_in_0">Province or State:</label> <ul id="id_published_in"><li>Canada - Provinces<ul id="id_published_in_0"><li><label for="id_published_in_0_0"><input id="id_published_in_0_0" name="published_in" type="checkbox" value="AB" /> Alberta</label></li>\n"""
"""<li><label for="id_published_in_0_1"><input checked="checked" id="id_published_in_0_1" name="published_in" type="checkbox" value="BC" /> British Columbia</label></li></ul></li>\n"""
"""<li>USA - States<ul id="id_published_in_1"><li><label for="id_published_in_1_0"><input checked="checked" id="id_published_in_1_0" name="published_in" type="checkbox" value="AK" /> Alaska</label></li>\n"""
"""<li><label for="id_published_in_1_1"><input id="id_published_in_1_1" name="published_in" type="checkbox" value="AL" /> Alabama</label></li>\n"""
"""<li><label for="id_published_in_1_2"><input id="id_published_in_1_2" name="published_in" type="checkbox" value="AZ" /> Arizona</label></li></ul></li></ul></p>""")
expected_html = """
<p>
<label>
Province or State:
</label>
<div id="id_published_in">
<div>
<label>
Canada - Provinces
</label>
<div>
<label for="id_published_in_0_0">
<input id="id_published_in_0_0" name="published_in" type="checkbox" value="AB" />
Alberta
</label>
</div>
<div>
<label for="id_published_in_0_1">
<input checked id="id_published_in_0_1" name="published_in" type="checkbox" value="BC" />
British Columbia
</label>
</div>
</div>
<div>
<label>
USA - States
</label>
<div>
<label for="id_published_in_1_0">
<input checked id="id_published_in_1_0" name="published_in" type="checkbox" value="AK" />
Alaska
</label>
</div>
<div>
<label for="id_published_in_1_1">
<input id="id_published_in_1_1" name="published_in" type="checkbox" value="AL" />
Alabama
</label>
</div>
<div>
<label for="id_published_in_1_2">
<input id="id_published_in_1_2" name="published_in" type="checkbox" value="AZ" />
Arizona
</label>
</div>
</div>
</div>
</p>
"""

actual_html = form.as_p()
if (1, 11) <= VERSION:
# Django 1.11+ does not assign 'for' attributes on labels if they
# are group labels
expected_html = expected_html.replace('label for="id_published_in_0"', 'label')

if VERSION < (1, 6):
# Django 1.6 renders the Python repr() for each group (eg: tuples
# with HTML entities), so we skip the test for that version
self.assertEqual(expected_html.replace('\n', ''), actual_html.replace('\n', ''))

if VERSION >= (2, 0):
expected_html = expected_html.replace('input checked="checked"', 'input checked')

if VERSION >= (1, 7):
self.assertHTMLEqual(expected_html, actual_html)
self.assertHTMLEqual(expected_html, actual_html)


Expand Down
34 changes: 5 additions & 29 deletions example/app/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,35 +14,11 @@
# You should have received a copy of the GNU Lesser General Public License
# along with this software. If not, see <http://www.gnu.org/licenses/>.

from django import VERSION
try:
from django.conf.urls import url

# Compatibility for Django > 1.8
def patterns(prefix, *args):
if VERSION < (1, 9):
from django.conf.urls import patterns as django_patterns
return django_patterns(prefix, *args)
elif prefix != '':
raise NotImplementedError("You need to update your URLConf for "
"Django 1.10, or tweak it to remove the "
"prefix parameter")
else:
return list(args)
except ImportError: # Django < 1.4
if VERSION < (4, 0):
from django.conf.urls.defaults import patterns, url
else:
from django.urls import re_path as url
from django.urls import path

from .views import app_index

if VERSION < (1, 11):
urlpatterns = patterns(
'',
url(r'^$', app_index, name='app_index'),
)
else:
urlpatterns = [
url(r'^$', app_index, name='app_index'),
]

urlpatterns = [
path('', app_index, name='app_index'),
]
95 changes: 33 additions & 62 deletions example/example/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@
import os
from os import path

from django import VERSION

DEBUG = True

BASE_DIR = path.dirname(path.abspath(__file__))
Expand All @@ -42,6 +40,8 @@
}
}

DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'

# Hosts/domain names that are valid for this site; required if DEBUG is False
# See https://docs.djangoproject.com/en/1.5/ref/settings/#allowed-hosts
ALLOWED_HOSTS = ['localhost']
Expand Down Expand Up @@ -121,57 +121,30 @@
# Python dotted path to the WSGI application used by Django's runserver.
WSGI_APPLICATION = 'example.wsgi.application'

if VERSION < (1, 8):
TEMPLATE_DEBUG = DEBUG

# List of callables that know how to import templates from various sources.
TEMPLATE_LOADERS = (
'django.template.loaders.filesystem.Loader',
'django.template.loaders.app_directories.Loader',
# 'django.template.loaders.eggs.Loader',
)

TEMPLATE_DIRS = (
# Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
# Always use forward slashes, even on Windows.
# Don't forget to use absolute paths, not relative paths.
)

TEMPLATE_CONTEXT_PROCESSORS = (
'django.contrib.auth.context_processors.auth',
'django.core.context_processors.debug',
'django.core.context_processors.i18n',
'django.core.context_processors.media',
'django.core.context_processors.request',
'django.core.context_processors.tz',
'django.core.context_processors.static',
'django.contrib.messages.context_processors.messages',
)
else:
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'OPTIONS': {
'context_processors': [
'django.contrib.auth.context_processors.auth',
'django.template.context_processors.debug',
'django.template.context_processors.i18n',
'django.template.context_processors.media',
'django.template.context_processors.request',
'django.template.context_processors.static',
'django.template.context_processors.tz',
'django.contrib.messages.context_processors.messages',
],
'debug': DEBUG,
'loaders': [
# List of callables that know how to import templates from
# various sources.
'django.template.loaders.filesystem.Loader',
'django.template.loaders.app_directories.Loader',
]
},
}
]
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'OPTIONS': {
'context_processors': [
'django.contrib.auth.context_processors.auth',
'django.template.context_processors.debug',
'django.template.context_processors.i18n',
'django.template.context_processors.media',
'django.template.context_processors.request',
'django.template.context_processors.static',
'django.template.context_processors.tz',
'django.contrib.messages.context_processors.messages',
],
'debug': DEBUG,
'loaders': [
# List of callables that know how to import templates from
# various sources.
'django.template.loaders.filesystem.Loader',
'django.template.loaders.app_directories.Loader',
]
},
}
]

INSTALLED_APPS = (
'django.contrib.auth',
Expand Down Expand Up @@ -227,13 +200,11 @@
}
}

if VERSION >= (1, 4):
LOGGING['filters'] = {
'require_debug_false': {
'()': 'django.utils.log.RequireDebugFalse',
},
}
LOGGING['handlers']['mail_admins']['filters'] = ['require_debug_false']
LOGGING['filters'] = {
'require_debug_false': {
'()': 'django.utils.log.RequireDebugFalse',
},
}
LOGGING['handlers']['mail_admins']['filters'] = ['require_debug_false']

if VERSION >= (1, 6):
TEST_RUNNER = 'django.test.runner.DiscoverRunner'
TEST_RUNNER = 'django.test.runner.DiscoverRunner'
7 changes: 1 addition & 6 deletions example/run_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
import os
import sys

import django
from django.conf import ENVIRONMENT_VARIABLE
from django.core import management
from django.core.wsgi import get_wsgi_application
Expand All @@ -30,10 +29,6 @@
else:
os.environ[ENVIRONMENT_VARIABLE] = sys.argv[1]

if django.VERSION[0] == 1 and django.VERSION[1] >= 7:
from django.core.wsgi import get_wsgi_application as get_wsgi_application_v1
application = get_wsgi_application_v1()
else:
application = get_wsgi_application()
application = get_wsgi_application()

management.call_command('test', 'app')
Loading

0 comments on commit 395d0b2

Please sign in to comment.