Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clean up, update for Django 5, and fix tests #148

Merged
merged 4 commits into from
May 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading