{% if inline_admin_form.original or inline_admin_form.show_url %}
{% if inline_admin_form.original %} {{ inline_admin_form.original }}{% endif %}
- {% if inline_admin_form.show_url %}{% trans "View on site" %}{% endif %}
+ {% if inline_admin_form.show_url %}{% trans "View on site" %}{% endif %}
{% endif %}
{% if inline_admin_form.has_auto_field %}{{ inline_admin_form.pk_field.field }}{% endif %}
{{ inline_admin_form.fk_field.field }}
diff --git a/django/contrib/admin/templates/admin/object_history.html b/django/contrib/admin/templates/admin/object_history.html
index 2c353374f6..55dd4a3b4c 100644
--- a/django/contrib/admin/templates/admin/object_history.html
+++ b/django/contrib/admin/templates/admin/object_history.html
@@ -7,7 +7,7 @@
{% trans 'Home' %}
› {{ app_label|capfirst|escape }}
› {{ module_name }}
-› {{ object|truncatewords:"18" }}
+› {{ object|truncatewords:"18" }}
› {% trans 'History' %}
{% endblock %}
diff --git a/django/contrib/admin/templatetags/admin_list.py b/django/contrib/admin/templatetags/admin_list.py
index bda8d4b4cd..1873d44989 100644
--- a/django/contrib/admin/templatetags/admin_list.py
+++ b/django/contrib/admin/templatetags/admin_list.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
import datetime
from django.contrib.admin.util import (lookup_field, display_for_field,
@@ -8,11 +10,12 @@ from django.contrib.admin.templatetags.admin_static import static
from django.core.exceptions import ObjectDoesNotExist
from django.db import models
from django.utils import formats
-from django.utils.html import escape, conditional_escape
+from django.utils.html import format_html
from django.utils.safestring import mark_safe
+from django.utils import six
from django.utils.text import capfirst
from django.utils.translation import ugettext as _
-from django.utils.encoding import smart_unicode, force_unicode
+from django.utils.encoding import smart_text, force_text
from django.template import Library
from django.template.loader import get_template
from django.template.context import Context
@@ -27,11 +30,14 @@ def paginator_number(cl,i):
Generates an individual page index link in a paginated list.
"""
if i == DOT:
- return u'... '
+ return '... '
elif i == cl.page_num:
- return mark_safe(u'%d ' % (i+1))
+ return format_html('{0} ', i+1)
else:
- return mark_safe(u'%d ' % (escape(cl.get_query_string({PAGE_VAR: i})), (i == cl.paginator.num_pages-1 and ' class="end"' or ''), i+1))
+ return format_html('{2} ',
+ cl.get_query_string({PAGE_VAR: i}),
+ mark_safe(' class="end"' if i == cl.paginator.num_pages-1 else ''),
+ i+1)
@register.inclusion_tag('admin/pagination.html')
def pagination(cl):
@@ -120,7 +126,7 @@ def result_headers(cl):
if i in ordering_field_columns:
sorted = True
order_type = ordering_field_columns.get(i).lower()
- sort_priority = ordering_field_columns.keys().index(i) + 1
+ sort_priority = list(ordering_field_columns).index(i) + 1
th_classes.append('sorted %sending' % order_type)
new_order_type = {'asc': 'desc', 'desc': 'asc'}[order_type]
@@ -157,13 +163,14 @@ def result_headers(cl):
"url_primary": cl.get_query_string({ORDER_VAR: '.'.join(o_list_primary)}),
"url_remove": cl.get_query_string({ORDER_VAR: '.'.join(o_list_remove)}),
"url_toggle": cl.get_query_string({ORDER_VAR: '.'.join(o_list_toggle)}),
- "class_attrib": mark_safe(th_classes and ' class="%s"' % ' '.join(th_classes) or '')
+ "class_attrib": format_html(' class="{0}"', ' '.join(th_classes))
+ if th_classes else '',
}
def _boolean_icon(field_val):
icon_url = static('admin/img/icon-%s.gif' %
{True: 'yes', False: 'no', None: 'unknown'}[field_val])
- return mark_safe(u'' % (icon_url, field_val))
+ return format_html('', icon_url, field_val)
def items_for_result(cl, result, form):
"""
@@ -179,8 +186,8 @@ def items_for_result(cl, result, form):
result_repr = EMPTY_CHANGELIST_VALUE
else:
if f is None:
- if field_name == u'action_checkbox':
- row_class = ' class="action-checkbox"'
+ if field_name == 'action_checkbox':
+ row_class = mark_safe(' class="action-checkbox"')
allow_tags = getattr(attr, 'allow_tags', False)
boolean = getattr(attr, 'boolean', False)
if boolean:
@@ -188,24 +195,22 @@ def items_for_result(cl, result, form):
result_repr = display_for_value(value, boolean)
# Strip HTML tags in the resulting text, except if the
# function has an "allow_tags" attribute set to True.
- if not allow_tags:
- result_repr = escape(result_repr)
- else:
+ if allow_tags:
result_repr = mark_safe(result_repr)
if isinstance(value, (datetime.date, datetime.time)):
- row_class = ' class="nowrap"'
+ row_class = mark_safe(' class="nowrap"')
else:
if isinstance(f.rel, models.ManyToOneRel):
field_val = getattr(result, f.name)
if field_val is None:
result_repr = EMPTY_CHANGELIST_VALUE
else:
- result_repr = escape(field_val)
+ result_repr = field_val
else:
result_repr = display_for_field(value, f)
if isinstance(f, (models.DateField, models.TimeField, models.ForeignKey)):
- row_class = ' class="nowrap"'
- if force_unicode(result_repr) == '':
+ row_class = mark_safe(' class="nowrap"')
+ if force_text(result_repr) == '':
result_repr = mark_safe(' ')
# If list_display_links not defined, add the link tag to the first field
if (first and not cl.list_display_links) or field_name in cl.list_display_links:
@@ -219,9 +224,15 @@ def items_for_result(cl, result, form):
else:
attr = pk
value = result.serializable_value(attr)
- result_id = repr(force_unicode(value))[1:]
- yield mark_safe(u'<%s%s>%s%s>' % \
- (table_tag, row_class, url, (cl.is_popup and ' onclick="opener.dismissRelatedLookupPopup(window, %s); return false;"' % result_id or ''), conditional_escape(result_repr), table_tag))
+ result_id = repr(force_text(value))[1:]
+ yield format_html('<{0}{1}>{4}{5}>',
+ table_tag,
+ row_class,
+ url,
+ format_html(' onclick="opener.dismissRelatedLookupPopup(window, {0}); return false;"', result_id)
+ if cl.is_popup else '',
+ result_repr,
+ table_tag)
else:
# By default the fields come from ModelAdmin.list_editable, but if we pull
# the fields out of the form instead of list_editable custom admins
@@ -230,12 +241,10 @@ def items_for_result(cl, result, form):
field_name == cl.model._meta.pk.name and
form[cl.model._meta.pk.name].is_hidden)):
bf = form[field_name]
- result_repr = mark_safe(force_unicode(bf.errors) + force_unicode(bf))
- else:
- result_repr = conditional_escape(result_repr)
- yield mark_safe(u'
',
+ ((force_text(w),) for w in self)))
class AdminRadioSelect(forms.RadioSelect):
renderer = AdminRadioFieldRenderer
class AdminFileWidget(forms.ClearableFileInput):
- template_with_initial = (u'
%s
'
+ template_with_initial = ('
%s
'
% forms.ClearableFileInput.template_with_initial)
- template_with_clear = (u'%s'
+ template_with_clear = ('%s'
% forms.ClearableFileInput.template_with_clear)
def url_params_from_lookup_dict(lookups):
@@ -113,12 +117,12 @@ def url_params_from_lookup_dict(lookups):
items = []
for k, v in lookups.items():
if isinstance(v, (tuple, list)):
- v = u','.join([str(x) for x in v])
+ v = ','.join([str(x) for x in v])
elif isinstance(v, bool):
# See django.db.fields.BooleanField.get_prep_lookup
v = ('0', '1')[v]
else:
- v = unicode(v)
+ v = six.text_type(v)
items.append((k, v))
params.update(dict(items))
return params
@@ -148,21 +152,21 @@ class ForeignKeyRawIdWidget(forms.TextInput):
params = self.url_parameters()
if params:
- url = u'?' + u'&'.join([u'%s=%s' % (k, v) for k, v in params.items()])
+ url = '?' + '&'.join(['%s=%s' % (k, v) for k, v in params.items()])
else:
- url = u''
+ url = ''
if "class" not in attrs:
attrs['class'] = 'vForeignKeyRawIdAdminField' # The JavaScript code looks for this hook.
# TODO: "lookup_id_" is hard-coded here. This should instead use
# the correct API to determine the ID dynamically.
- extra.append(u' '
+ extra.append(' '
% (related_url, url, name))
- extra.append(u''
+ extra.append(''
% (static('admin/img/selector-search.gif'), _('Lookup')))
output = [super(ForeignKeyRawIdWidget, self).render(name, value, attrs)] + extra
if value:
output.append(self.label_for_value(value))
- return mark_safe(u''.join(output))
+ return mark_safe(''.join(output))
def base_url_parameters(self):
return url_params_from_lookup_dict(self.rel.limit_choices_to)
@@ -193,7 +197,7 @@ class ManyToManyRawIdWidget(ForeignKeyRawIdWidget):
# The related object is registered with the same AdminSite
attrs['class'] = 'vManyToManyRawIdAdminField'
if value:
- value = ','.join([force_unicode(v) for v in value])
+ value = ','.join([force_text(v) for v in value])
else:
value = ''
return super(ManyToManyRawIdWidget, self).render(name, value, attrs)
@@ -217,7 +221,7 @@ class ManyToManyRawIdWidget(ForeignKeyRawIdWidget):
if len(initial) != len(data):
return True
for pk1, pk2 in zip(initial, data):
- if force_unicode(pk1) != force_unicode(pk2):
+ if force_text(pk1) != force_text(pk2):
return True
return False
@@ -261,11 +265,11 @@ class RelatedFieldWidgetWrapper(forms.Widget):
related_url = reverse('admin:%s_%s_add' % info, current_app=self.admin_site.name)
# TODO: "add_id_" is hard-coded here. This should instead use the
# correct API to determine the ID dynamically.
- output.append(u' '
+ output.append(' '
% (related_url, name))
- output.append(u''
+ output.append(''
% (static('admin/img/icon_addlink.gif'), _('Add Another')))
- return mark_safe(u''.join(output))
+ return mark_safe(''.join(output))
def build_attrs(self, extra_attrs=None, **kwargs):
"Helper function for building an attribute dictionary."
@@ -303,12 +307,17 @@ class AdminURLFieldWidget(forms.TextInput):
super(AdminURLFieldWidget, self).__init__(attrs=final_attrs)
class AdminIntegerFieldWidget(forms.TextInput):
+ class_name = 'vIntegerField'
+
def __init__(self, attrs=None):
- final_attrs = {'class': 'vIntegerField'}
+ final_attrs = {'class': self.class_name}
if attrs is not None:
final_attrs.update(attrs)
super(AdminIntegerFieldWidget, self).__init__(attrs=final_attrs)
+class AdminBigIntegerFieldWidget(AdminIntegerFieldWidget):
+ class_name = 'vBigIntegerField'
+
class AdminCommaSeparatedIntegerFieldWidget(forms.TextInput):
def __init__(self, attrs=None):
final_attrs = {'class': 'vCommaSeparatedIntegerField'}
diff --git a/django/contrib/admindocs/templates/admin_doc/bookmarklets.html b/django/contrib/admindocs/templates/admin_doc/bookmarklets.html
index cde285481d..819beea326 100644
--- a/django/contrib/admindocs/templates/admin_doc/bookmarklets.html
+++ b/django/contrib/admindocs/templates/admin_doc/bookmarklets.html
@@ -22,7 +22,7 @@ your computer is "internal").
{% endblocktrans %}
' % \
- u', '.join(['%s' % (f.name, force_unicode(capfirst(f.verbose_name))) for f in fields.values()]))
+ return ''
+ return format_html('
View by: {0}
',
+ format_html_join(', ', '{1}',
+ ((f.name, force_text(capfirst(f.verbose_name))) for f in fields.values())))
def urls(self, plugin_name, easy_instance_field):
if easy_instance_field.field in self.field_dict(easy_instance_field.model.model).values():
- field_value = smart_str(easy_instance_field.raw_value)
- return [mark_safe(u'%s%s/%s/%s/' % (
+ return ['%s%s/%s/%s/' % (
easy_instance_field.model.url(),
plugin_name, easy_instance_field.field.name,
- urllib.quote(field_value, safe='')))]
+ urlquote(easy_instance_field.raw_value, safe=''))]
def model_view(self, request, model_databrowse, url):
self.model, self.site = model_databrowse.model, model_databrowse.site
@@ -60,7 +63,7 @@ class FieldChoicePlugin(DatabrowsePlugin):
def homepage_view(self, request):
easy_model = EasyModel(self.site, self.model)
- field_list = self.fields.values()
+ field_list = list(self.fields.values())
field_list.sort(key=lambda k: k.verbose_name)
return render_to_response('databrowse/fieldchoice_homepage.html', {'root_url': self.site.root_url, 'model': easy_model, 'field_list': field_list})
diff --git a/django/contrib/databrowse/plugins/objects.py b/django/contrib/databrowse/plugins/objects.py
index 7326566655..e956f4ea67 100644
--- a/django/contrib/databrowse/plugins/objects.py
+++ b/django/contrib/databrowse/plugins/objects.py
@@ -1,14 +1,18 @@
+try:
+ from urllib.parse import urljoin
+except ImportError: # Python 2
+ from urlparse import urljoin
+
from django import http
from django.contrib.databrowse.datastructures import EasyModel
from django.contrib.databrowse.sites import DatabrowsePlugin
from django.shortcuts import render_to_response
-import urlparse
class ObjectDetailPlugin(DatabrowsePlugin):
def model_view(self, request, model_databrowse, url):
# If the object ID wasn't provided, redirect to the model page, which is one level up.
if url is None:
- return http.HttpResponseRedirect(urlparse.urljoin(request.path, '../'))
+ return http.HttpResponseRedirect(urljoin(request.path, '../'))
easy_model = EasyModel(model_databrowse.site, model_databrowse.model)
obj = easy_model.object_by_pk(url)
return render_to_response('databrowse/object_detail.html', {'object': obj, 'root_url': model_databrowse.site.root_url})
diff --git a/django/contrib/databrowse/sites.py b/django/contrib/databrowse/sites.py
index d90bb562b2..b5cb2639d6 100644
--- a/django/contrib/databrowse/sites.py
+++ b/django/contrib/databrowse/sites.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
from django import http
from django.db import models
from django.contrib.databrowse.datastructures import EasyModel
@@ -61,7 +63,7 @@ class ModelDatabrowse(object):
def main_view(self, request):
easy_model = EasyModel(self.site, self.model)
- html_snippets = mark_safe(u'\n'.join([p.model_index_html(request, self.model, self.site) for p in self.plugins.values()]))
+ html_snippets = mark_safe('\n'.join([p.model_index_html(request, self.model, self.site) for p in self.plugins.values()]))
return render_to_response('databrowse/model_detail.html', {
'model': easy_model,
'root_url': self.site.root_url,
diff --git a/django/contrib/databrowse/tests.py b/django/contrib/databrowse/tests.py
index 149383cf72..d649b4af67 100644
--- a/django/contrib/databrowse/tests.py
+++ b/django/contrib/databrowse/tests.py
@@ -1,26 +1,30 @@
from django.contrib import databrowse
from django.db import models
from django.test import TestCase
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class SomeModel(models.Model):
some_field = models.CharField(max_length=50)
- def __unicode__(self):
+ def __str__(self):
return self.some_field
+@python_2_unicode_compatible
class SomeOtherModel(models.Model):
some_other_field = models.CharField(max_length=50)
- def __unicode__(self):
+ def __str__(self):
return self.some_other_field
+@python_2_unicode_compatible
class YetAnotherModel(models.Model):
yet_another_field = models.CharField(max_length=50)
- def __unicode__(self):
+ def __str__(self):
return self.yet_another_field
diff --git a/django/contrib/flatpages/models.py b/django/contrib/flatpages/models.py
index 85873ac7b1..3a5b4d6135 100644
--- a/django/contrib/flatpages/models.py
+++ b/django/contrib/flatpages/models.py
@@ -1,8 +1,12 @@
+from __future__ import unicode_literals
+
from django.db import models
from django.contrib.sites.models import Site
from django.utils.translation import ugettext_lazy as _
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class FlatPage(models.Model):
url = models.CharField(_('URL'), max_length=100, db_index=True)
title = models.CharField(_('title'), max_length=200)
@@ -19,8 +23,8 @@ class FlatPage(models.Model):
verbose_name_plural = _('flat pages')
ordering = ('url',)
- def __unicode__(self):
- return u"%s -- %s" % (self.url, self.title)
+ def __str__(self):
+ return "%s -- %s" % (self.url, self.title)
def get_absolute_url(self):
return self.url
diff --git a/django/contrib/flatpages/tests/forms.py b/django/contrib/flatpages/tests/forms.py
index 0e54176aa2..3bdfa15dfe 100644
--- a/django/contrib/flatpages/tests/forms.py
+++ b/django/contrib/flatpages/tests/forms.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
from django.conf import settings
from django.contrib.flatpages.forms import FlatpageForm
from django.contrib.flatpages.models import FlatPage
@@ -60,7 +62,7 @@ class FlatpageAdminFormTests(TestCase):
self.assertEqual(
f.errors,
- {'__all__': [u'Flatpage with url /myflatpage1/ already exists for site example.com']})
+ {'__all__': ['Flatpage with url /myflatpage1/ already exists for site example.com']})
def test_flatpage_admin_form_edit(self):
"""
@@ -92,5 +94,5 @@ class FlatpageAdminFormTests(TestCase):
self.assertEqual(
f.errors,
- {'sites': [translation.ugettext(u'This field is required.')]})
+ {'sites': [translation.ugettext('This field is required.')]})
diff --git a/django/contrib/flatpages/views.py b/django/contrib/flatpages/views.py
index ef7fda5d5c..0b462ac5a4 100644
--- a/django/contrib/flatpages/views.py
+++ b/django/contrib/flatpages/views.py
@@ -23,7 +23,7 @@ def flatpage(request, url):
Models: `flatpages.flatpages`
Templates: Uses the template defined by the ``template_name`` field,
- or `flatpages/default.html` if template_name is not defined.
+ or :template:`flatpages/default.html` if template_name is not defined.
Context:
flatpage
`flatpages.flatpages` object
diff --git a/django/contrib/formtools/tests/__init__.py b/django/contrib/formtools/tests/__init__.py
index b5d905071f..15941332ed 100644
--- a/django/contrib/formtools/tests/__init__.py
+++ b/django/contrib/formtools/tests/__init__.py
@@ -1,4 +1,9 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+import datetime
import os
+import pickle
import re
import warnings
@@ -14,6 +19,7 @@ from django.contrib.formtools.tests.wizard import *
from django.contrib.formtools.tests.forms import *
success_string = "Done was called!"
+success_string_encoded = success_string.encode()
class TestFormPreview(preview.FormPreview):
def get_context(self, request, form):
@@ -41,7 +47,7 @@ class PreviewTests(TestCase):
self.preview = preview.FormPreview(TestForm)
input_template = ''
self.input = input_template % (self.preview.unused_name('stage'), "%d")
- self.test_data = {'field1':u'foo', 'field1_':u'asdf'}
+ self.test_data = {'field1': 'foo', 'field1_': 'asdf'}
def test_unused_name(self):
"""
@@ -76,7 +82,7 @@ class PreviewTests(TestCase):
"""
# Pass strings for form submittal and add stage variable to
# show we previously saw first stage of the form.
- self.test_data.update({'stage': 1})
+ self.test_data.update({'stage': 1, 'date1': datetime.date(2006, 10, 25)})
response = self.client.post('/preview/', self.test_data)
# Check to confirm stage is set to 2 in output form.
stage = self.input % 2
@@ -94,13 +100,13 @@ class PreviewTests(TestCase):
"""
# Pass strings for form submittal and add stage variable to
# show we previously saw first stage of the form.
- self.test_data.update({'stage':2})
+ self.test_data.update({'stage': 2, 'date1': datetime.date(2006, 10, 25)})
response = self.client.post('/preview/', self.test_data)
- self.assertNotEqual(response.content, success_string)
+ self.assertNotEqual(response.content, success_string_encoded)
hash = self.preview.security_hash(None, TestForm(self.test_data))
self.test_data.update({'hash': hash})
response = self.client.post('/preview/', self.test_data)
- self.assertEqual(response.content, success_string)
+ self.assertEqual(response.content, success_string_encoded)
def test_bool_submit(self):
"""
@@ -117,10 +123,10 @@ class PreviewTests(TestCase):
"""
self.test_data.update({'stage':2})
hash = self.preview.security_hash(None, TestForm(self.test_data))
- self.test_data.update({'hash':hash, 'bool1':u'False'})
+ self.test_data.update({'hash': hash, 'bool1': 'False'})
with warnings.catch_warnings(record=True):
response = self.client.post('/preview/', self.test_data)
- self.assertEqual(response.content, success_string)
+ self.assertEqual(response.content, success_string_encoded)
def test_form_submit_good_hash(self):
"""
@@ -131,11 +137,11 @@ class PreviewTests(TestCase):
# show we previously saw first stage of the form.
self.test_data.update({'stage':2})
response = self.client.post('/preview/', self.test_data)
- self.assertNotEqual(response.content, success_string)
+ self.assertNotEqual(response.content, success_string_encoded)
hash = utils.form_hmac(TestForm(self.test_data))
self.test_data.update({'hash': hash})
response = self.client.post('/preview/', self.test_data)
- self.assertEqual(response.content, success_string)
+ self.assertEqual(response.content, success_string_encoded)
def test_form_submit_bad_hash(self):
@@ -148,11 +154,11 @@ class PreviewTests(TestCase):
self.test_data.update({'stage':2})
response = self.client.post('/preview/', self.test_data)
self.assertEqual(response.status_code, 200)
- self.assertNotEqual(response.content, success_string)
+ self.assertNotEqual(response.content, success_string_encoded)
hash = utils.form_hmac(TestForm(self.test_data)) + "bad"
self.test_data.update({'hash': hash})
response = self.client.post('/previewpreview/', self.test_data)
- self.assertNotEqual(response.content, success_string)
+ self.assertNotEqual(response.content, success_string_encoded)
class FormHmacTests(unittest.TestCase):
@@ -163,8 +169,8 @@ class FormHmacTests(unittest.TestCase):
leading/trailing whitespace so as to be friendly to broken browsers that
submit it (usually in textareas).
"""
- f1 = HashTestForm({'name': u'joe', 'bio': u'Nothing notable.'})
- f2 = HashTestForm({'name': u' joe', 'bio': u'Nothing notable. '})
+ f1 = HashTestForm({'name': 'joe', 'bio': 'Speaking español.'})
+ f2 = HashTestForm({'name': ' joe', 'bio': 'Speaking español. '})
hash1 = utils.form_hmac(f1)
hash2 = utils.form_hmac(f2)
self.assertEqual(hash1, hash2)
@@ -266,10 +272,13 @@ class WizardTests(TestCase):
Form should advance if the hash is present and good, as calculated using
current method.
"""
- data = {"0-field": u"test",
- "1-field": u"test2",
- "hash_0": u"cd13b1db3e8f55174bc5745a1b1a53408d4fd1ca",
- "wizard_step": u"1"}
+ data = {"0-field": "test",
+ "1-field": "test2",
+ "hash_0": {
+ 2: "cd13b1db3e8f55174bc5745a1b1a53408d4fd1ca",
+ 3: "9355d5dff22d49dbad58e46189982cec649f9f5b",
+ }[pickle.HIGHEST_PROTOCOL],
+ "wizard_step": "1"}
response = self.client.post('/wizard1/', data)
self.assertEqual(2, response.context['step0'])
@@ -291,18 +300,27 @@ class WizardTests(TestCase):
reached[0] = True
wizard = WizardWithProcessStep([WizardPageOneForm])
- data = {"0-field": u"test",
- "1-field": u"test2",
- "hash_0": u"cd13b1db3e8f55174bc5745a1b1a53408d4fd1ca",
- "wizard_step": u"1"}
+ data = {"0-field": "test",
+ "1-field": "test2",
+ "hash_0": {
+ 2: "cd13b1db3e8f55174bc5745a1b1a53408d4fd1ca",
+ 3: "9355d5dff22d49dbad58e46189982cec649f9f5b",
+ }[pickle.HIGHEST_PROTOCOL],
+ "wizard_step": "1"}
wizard(DummyRequest(POST=data))
self.assertTrue(reached[0])
- data = {"0-field": u"test",
- "1-field": u"test2",
- "hash_0": "cd13b1db3e8f55174bc5745a1b1a53408d4fd1ca",
- "hash_1": u"1e6f6315da42e62f33a30640ec7e007ad3fbf1a1",
- "wizard_step": u"2"}
+ data = {"0-field": "test",
+ "1-field": "test2",
+ "hash_0": {
+ 2: "cd13b1db3e8f55174bc5745a1b1a53408d4fd1ca",
+ 3: "9355d5dff22d49dbad58e46189982cec649f9f5b",
+ }[pickle.HIGHEST_PROTOCOL],
+ "hash_1": {
+ 2: "1e6f6315da42e62f33a30640ec7e007ad3fbf1a1",
+ 3: "c33142ef9d01b1beae238adf22c3c6c57328f51a",
+ }[pickle.HIGHEST_PROTOCOL],
+ "wizard_step": "2"}
self.assertRaises(http.Http404, wizard, DummyRequest(POST=data))
def test_14498(self):
@@ -315,16 +333,19 @@ class WizardTests(TestCase):
class WizardWithProcessStep(TestWizardClass):
def process_step(self, request, form, step):
- that.assertTrue(hasattr(form, 'cleaned_data'))
+ that.assertTrue(form.is_valid())
reached[0] = True
wizard = WizardWithProcessStep([WizardPageOneForm,
WizardPageTwoForm,
WizardPageThreeForm])
- data = {"0-field": u"test",
- "1-field": u"test2",
- "hash_0": u"cd13b1db3e8f55174bc5745a1b1a53408d4fd1ca",
- "wizard_step": u"1"}
+ data = {"0-field": "test",
+ "1-field": "test2",
+ "hash_0": {
+ 2: "cd13b1db3e8f55174bc5745a1b1a53408d4fd1ca",
+ 3: "9355d5dff22d49dbad58e46189982cec649f9f5b",
+ }[pickle.HIGHEST_PROTOCOL],
+ "wizard_step": "1"}
wizard(DummyRequest(POST=data))
self.assertTrue(reached[0])
@@ -345,10 +366,13 @@ class WizardTests(TestCase):
wizard = Wizard([WizardPageOneForm,
WizardPageTwoForm])
- data = {"0-field": u"test",
- "1-field": u"test2",
- "hash_0": u"cd13b1db3e8f55174bc5745a1b1a53408d4fd1ca",
- "wizard_step": u"1"}
+ data = {"0-field": "test",
+ "1-field": "test2",
+ "hash_0": {
+ 2: "cd13b1db3e8f55174bc5745a1b1a53408d4fd1ca",
+ 3: "9355d5dff22d49dbad58e46189982cec649f9f5b",
+ }[pickle.HIGHEST_PROTOCOL],
+ "wizard_step": "1"}
wizard(DummyRequest(POST=data))
self.assertTrue(reached[0])
@@ -371,10 +395,13 @@ class WizardTests(TestCase):
wizard = WizardWithProcessStep([WizardPageOneForm,
WizardPageTwoForm,
WizardPageThreeForm])
- data = {"0-field": u"test",
- "1-field": u"test2",
- "hash_0": u"cd13b1db3e8f55174bc5745a1b1a53408d4fd1ca",
- "wizard_step": u"1"}
+ data = {"0-field": "test",
+ "1-field": "test2",
+ "hash_0": {
+ 2: "cd13b1db3e8f55174bc5745a1b1a53408d4fd1ca",
+ 3: "9355d5dff22d49dbad58e46189982cec649f9f5b",
+ }[pickle.HIGHEST_PROTOCOL],
+ "wizard_step": "1"}
wizard(DummyRequest(POST=data))
self.assertTrue(reached[0])
diff --git a/django/contrib/formtools/tests/forms.py b/django/contrib/formtools/tests/forms.py
index 9f6f596d3c..1ed2ab48bb 100644
--- a/django/contrib/formtools/tests/forms.py
+++ b/django/contrib/formtools/tests/forms.py
@@ -21,6 +21,7 @@ class TestForm(forms.Form):
field1 = forms.CharField()
field1_ = forms.CharField()
bool1 = forms.BooleanField(required=False)
+ date1 = forms.DateField(required=False)
class HashTestForm(forms.Form):
name = forms.CharField()
diff --git a/django/contrib/formtools/tests/wizard/forms.py b/django/contrib/formtools/tests/wizard/forms.py
index 8afbd30721..51cfaa661b 100644
--- a/django/contrib/formtools/tests/wizard/forms.py
+++ b/django/contrib/formtools/tests/wizard/forms.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
from django import forms, http
from django.conf import settings
from django.test import TestCase
@@ -64,22 +66,22 @@ class TestWizard(WizardView):
class FormTests(TestCase):
def test_form_init(self):
testform = TestWizard.get_initkwargs([Step1, Step2])
- self.assertEqual(testform['form_list'], {u'0': Step1, u'1': Step2})
+ self.assertEqual(testform['form_list'], {'0': Step1, '1': Step2})
testform = TestWizard.get_initkwargs([('start', Step1), ('step2', Step2)])
self.assertEqual(
- testform['form_list'], {u'start': Step1, u'step2': Step2})
+ testform['form_list'], {'start': Step1, 'step2': Step2})
testform = TestWizard.get_initkwargs([Step1, Step2, ('finish', Step3)])
self.assertEqual(
- testform['form_list'], {u'0': Step1, u'1': Step2, u'finish': Step3})
+ testform['form_list'], {'0': Step1, '1': Step2, 'finish': Step3})
def test_first_step(self):
request = get_request()
testform = TestWizard.as_view([Step1, Step2])
response, instance = testform(request)
- self.assertEqual(instance.steps.current, u'0')
+ self.assertEqual(instance.steps.current, '0')
testform = TestWizard.as_view([('start', Step1), ('step2', Step2)])
response, instance = testform(request)
diff --git a/django/contrib/formtools/tests/wizard/namedwizardtests/tests.py b/django/contrib/formtools/tests/wizard/namedwizardtests/tests.py
index 37913fa078..7529d89a2c 100644
--- a/django/contrib/formtools/tests/wizard/namedwizardtests/tests.py
+++ b/django/contrib/formtools/tests/wizard/namedwizardtests/tests.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
from django.core.urlresolvers import reverse
from django.http import QueryDict
from django.test import TestCase
@@ -51,8 +53,8 @@ class NamedWizardTests(object):
self.assertEqual(response.status_code, 200)
self.assertEqual(response.context['wizard']['steps'].current, 'form1')
self.assertEqual(response.context['wizard']['form'].errors,
- {'name': [u'This field is required.'],
- 'user': [u'This field is required.']})
+ {'name': ['This field is required.'],
+ 'user': ['This field is required.']})
def test_form_post_success(self):
response = self.client.post(
@@ -120,6 +122,7 @@ class NamedWizardTests(object):
self.assertEqual(response.context['wizard']['steps'].current, 'form2')
post_data = self.wizard_step_data[1]
+ post_data['form2-file1'].close()
post_data['form2-file1'] = open(__file__, 'rb')
response = self.client.post(
reverse(self.wizard_urlname,
@@ -147,13 +150,15 @@ class NamedWizardTests(object):
self.assertEqual(response.status_code, 200)
all_data = response.context['form_list']
- self.assertEqual(all_data[1]['file1'].read(), open(__file__, 'rb').read())
+ with open(__file__, 'rb') as f:
+ self.assertEqual(all_data[1]['file1'].read(), f.read())
+ all_data[1]['file1'].close()
del all_data[1]['file1']
self.assertEqual(all_data, [
- {'name': u'Pony', 'thirsty': True, 'user': self.testuser},
- {'address1': u'123 Main St', 'address2': u'Djangoland'},
- {'random_crap': u'blah blah'},
- [{'random_crap': u'blah blah'}, {'random_crap': u'blah blah'}]])
+ {'name': 'Pony', 'thirsty': True, 'user': self.testuser},
+ {'address1': '123 Main St', 'address2': 'Djangoland'},
+ {'random_crap': 'blah blah'},
+ [{'random_crap': 'blah blah'}, {'random_crap': 'blah blah'}]])
def test_cleaned_data(self):
response = self.client.get(
@@ -180,9 +185,10 @@ class NamedWizardTests(object):
response = self.client.get(step2_url)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.context['wizard']['steps'].current, 'form2')
- self.assertEqual(
- response.context['wizard']['form'].files['form2-file1'].read(),
- open(__file__, 'rb').read())
+ with open(__file__, 'rb') as f:
+ self.assertEqual(
+ response.context['wizard']['form'].files['form2-file1'].read(),
+ f.read())
response = self.client.post(
reverse(self.wizard_urlname,
@@ -199,15 +205,17 @@ class NamedWizardTests(object):
self.assertEqual(response.status_code, 200)
all_data = response.context['all_cleaned_data']
- self.assertEqual(all_data['file1'].read(), open(__file__, 'rb').read())
+ with open(__file__, 'rb') as f:
+ self.assertEqual(all_data['file1'].read(), f.read())
+ all_data['file1'].close()
del all_data['file1']
self.assertEqual(
all_data,
- {'name': u'Pony', 'thirsty': True, 'user': self.testuser,
- 'address1': u'123 Main St', 'address2': u'Djangoland',
- 'random_crap': u'blah blah', 'formset-form4': [
- {'random_crap': u'blah blah'},
- {'random_crap': u'blah blah'}
+ {'name': 'Pony', 'thirsty': True, 'user': self.testuser,
+ 'address1': '123 Main St', 'address2': 'Djangoland',
+ 'random_crap': 'blah blah', 'formset-form4': [
+ {'random_crap': 'blah blah'},
+ {'random_crap': 'blah blah'}
]})
def test_manipulated_data(self):
@@ -223,6 +231,7 @@ class NamedWizardTests(object):
self.assertEqual(response.status_code, 200)
post_data = self.wizard_step_data[1]
+ post_data['form2-file1'].close()
post_data['form2-file1'] = open(__file__, 'rb')
response = self.client.post(
reverse(self.wizard_urlname,
diff --git a/django/contrib/formtools/tests/wizard/wizardtests/tests.py b/django/contrib/formtools/tests/wizard/wizardtests/tests.py
index a9a81ba70f..586bd59341 100644
--- a/django/contrib/formtools/tests/wizard/wizardtests/tests.py
+++ b/django/contrib/formtools/tests/wizard/wizardtests/tests.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
import os
from django import forms
@@ -33,8 +35,8 @@ class WizardTests(object):
self.assertEqual(response.status_code, 200)
self.assertEqual(response.context['wizard']['steps'].current, 'form1')
self.assertEqual(response.context['wizard']['form'].errors,
- {'name': [u'This field is required.'],
- 'user': [u'This field is required.']})
+ {'name': ['This field is required.'],
+ 'user': ['This field is required.']})
def test_form_post_success(self):
response = self.client.post(self.wizard_url, self.wizard_step_data[0])
@@ -93,14 +95,16 @@ class WizardTests(object):
self.assertEqual(response.status_code, 200)
all_data = response.context['form_list']
- self.assertEqual(all_data[1]['file1'].read(), open(__file__, 'rb').read())
+ with open(__file__, 'rb') as f:
+ self.assertEqual(all_data[1]['file1'].read(), f.read())
+ all_data[1]['file1'].close()
del all_data[1]['file1']
self.assertEqual(all_data, [
- {'name': u'Pony', 'thirsty': True, 'user': self.testuser},
- {'address1': u'123 Main St', 'address2': u'Djangoland'},
- {'random_crap': u'blah blah'},
- [{'random_crap': u'blah blah'},
- {'random_crap': u'blah blah'}]])
+ {'name': 'Pony', 'thirsty': True, 'user': self.testuser},
+ {'address1': '123 Main St', 'address2': 'Djangoland'},
+ {'random_crap': 'blah blah'},
+ [{'random_crap': 'blah blah'},
+ {'random_crap': 'blah blah'}]])
def test_cleaned_data(self):
response = self.client.get(self.wizard_url)
@@ -110,8 +114,9 @@ class WizardTests(object):
self.assertEqual(response.status_code, 200)
post_data = self.wizard_step_data[1]
- post_data['form2-file1'] = open(__file__, 'rb')
- response = self.client.post(self.wizard_url, post_data)
+ with open(__file__, 'rb') as post_file:
+ post_data['form2-file1'] = post_file
+ response = self.client.post(self.wizard_url, post_data)
self.assertEqual(response.status_code, 200)
response = self.client.post(self.wizard_url, self.wizard_step_data[2])
@@ -121,14 +126,16 @@ class WizardTests(object):
self.assertEqual(response.status_code, 200)
all_data = response.context['all_cleaned_data']
- self.assertEqual(all_data['file1'].read(), open(__file__, 'rb').read())
+ with open(__file__, 'rb') as f:
+ self.assertEqual(all_data['file1'].read(), f.read())
+ all_data['file1'].close()
del all_data['file1']
self.assertEqual(all_data, {
- 'name': u'Pony', 'thirsty': True, 'user': self.testuser,
- 'address1': u'123 Main St', 'address2': u'Djangoland',
- 'random_crap': u'blah blah', 'formset-form4': [
- {'random_crap': u'blah blah'},
- {'random_crap': u'blah blah'}]})
+ 'name': 'Pony', 'thirsty': True, 'user': self.testuser,
+ 'address1': '123 Main St', 'address2': 'Djangoland',
+ 'random_crap': 'blah blah', 'formset-form4': [
+ {'random_crap': 'blah blah'},
+ {'random_crap': 'blah blah'}]})
def test_manipulated_data(self):
response = self.client.get(self.wizard_url)
@@ -138,6 +145,7 @@ class WizardTests(object):
self.assertEqual(response.status_code, 200)
post_data = self.wizard_step_data[1]
+ post_data['form2-file1'].close()
post_data['form2-file1'] = open(__file__, 'rb')
response = self.client.post(self.wizard_url, post_data)
self.assertEqual(response.status_code, 200)
@@ -165,6 +173,7 @@ class WizardTests(object):
self.assertEqual(response.context['wizard']['steps'].current, 'form2')
post_data = self.wizard_step_data[1]
+ post_data['form2-file1'].close()
post_data['form2-file1'] = open(__file__, 'rb')
response = self.client.post(self.wizard_url, post_data)
self.assertEqual(response.status_code, 200)
diff --git a/django/contrib/formtools/utils.py b/django/contrib/formtools/utils.py
index 96a0092a35..76277c6b49 100644
--- a/django/contrib/formtools/utils.py
+++ b/django/contrib/formtools/utils.py
@@ -1,7 +1,10 @@
+from __future__ import unicode_literals
+
# Do not try cPickle here (see #18340)
import pickle
from django.utils.crypto import salted_hmac
+from django.utils import six
def form_hmac(form):
@@ -16,7 +19,7 @@ def form_hmac(form):
value = bf.data or ''
else:
value = bf.field.clean(bf.data) or ''
- if isinstance(value, basestring):
+ if isinstance(value, six.string_types):
value = value.strip()
data.append((bf.name, value))
diff --git a/django/contrib/formtools/wizard/storage/base.py b/django/contrib/formtools/wizard/storage/base.py
index 274e07ffbe..aafc833484 100644
--- a/django/contrib/formtools/wizard/storage/base.py
+++ b/django/contrib/formtools/wizard/storage/base.py
@@ -1,7 +1,7 @@
from django.core.files.uploadedfile import UploadedFile
from django.utils.datastructures import MultiValueDict
-from django.utils.encoding import smart_str
from django.utils.functional import lazy_property
+from django.utils import six
from django.contrib.formtools.wizard.storage.exceptions import NoFileStorageConfigured
@@ -72,9 +72,8 @@ class BaseStorage(object):
raise NoFileStorageConfigured
files = {}
- for field, field_dict in wizard_files.iteritems():
- field_dict = dict((smart_str(k), v)
- for k, v in field_dict.iteritems())
+ for field, field_dict in six.iteritems(wizard_files):
+ field_dict = field_dict.copy()
tmp_name = field_dict.pop('tmp_name')
files[field] = UploadedFile(
file=self.file_storage.open(tmp_name), **field_dict)
@@ -87,7 +86,7 @@ class BaseStorage(object):
if step not in self.data[self.step_files_key]:
self.data[self.step_files_key][step] = {}
- for field, field_file in (files or {}).iteritems():
+ for field, field_file in six.iteritems(files or {}):
tmp_filename = self.file_storage.save(field_file.name, field_file)
file_dict = {
'tmp_name': tmp_filename,
diff --git a/django/contrib/formtools/wizard/views.py b/django/contrib/formtools/wizard/views.py
index 4372c8aa6a..ea41e86852 100644
--- a/django/contrib/formtools/wizard/views.py
+++ b/django/contrib/formtools/wizard/views.py
@@ -7,6 +7,7 @@ from django.forms import formsets, ValidationError
from django.views.generic import TemplateView
from django.utils.datastructures import SortedDict
from django.utils.decorators import classonlymethod
+from django.utils import six
from django.contrib.formtools.wizard.storage import get_storage
from django.contrib.formtools.wizard.storage.exceptions import NoFileStorageConfigured
@@ -43,7 +44,7 @@ class StepsHelper(object):
@property
def all(self):
"Returns the names of all steps/forms."
- return self._wizard.get_form_list().keys()
+ return list(self._wizard.get_form_list())
@property
def count(self):
@@ -133,8 +134,9 @@ class WizardView(TemplateView):
The key should be equal to the `step_name` in the `form_list` (or
the str of the zero based counter - if no step_names added in the
`form_list`)
- * `instance_dict` - contains a dictionary of instance objects. This
- is only used when `ModelForm`s are used. The key should be equal to
+ * `instance_dict` - contains a dictionary whose values are model
+ instances if the step is based on a ``ModelForm`` and querysets if
+ the step is based on a ``ModelFormSet``. The key should be equal to
the `step_name` in the `form_list`. Same rules as for `initial_dict`
apply.
* `condition_dict` - contains a dictionary of boolean values or
@@ -156,20 +158,20 @@ class WizardView(TemplateView):
if isinstance(form, (list, tuple)):
# if the element is a tuple, add the tuple to the new created
# sorted dictionary.
- init_form_list[unicode(form[0])] = form[1]
+ init_form_list[six.text_type(form[0])] = form[1]
else:
# if not, add the form with a zero based counter as unicode
- init_form_list[unicode(i)] = form
+ init_form_list[six.text_type(i)] = form
# walk through the new created list of forms
- for form in init_form_list.itervalues():
+ for form in six.itervalues(init_form_list):
if issubclass(form, formsets.BaseFormSet):
# if the element is based on BaseFormSet (FormSet/ModelFormSet)
# we need to override the form variable.
form = form.form
# check if any form contains a FileField, if yes, we need a
# file_storage added to the wizardview (by subclassing).
- for field in form.base_fields.itervalues():
+ for field in six.itervalues(form.base_fields):
if (isinstance(field, forms.FileField) and
not hasattr(cls, 'file_storage')):
raise NoFileStorageConfigured
@@ -194,7 +196,7 @@ class WizardView(TemplateView):
could use data from other (maybe previous forms).
"""
form_list = SortedDict()
- for form_key, form_class in self.form_list.iteritems():
+ for form_key, form_class in six.iteritems(self.form_list):
# try to fetch the value from condition list, by default, the form
# gets passed to the new list.
condition = self.condition_dict.get(form_key, True)
diff --git a/django/contrib/gis/admin/widgets.py b/django/contrib/gis/admin/widgets.py
index aaffae8f5f..47570d3f9d 100644
--- a/django/contrib/gis/admin/widgets.py
+++ b/django/contrib/gis/admin/widgets.py
@@ -1,10 +1,11 @@
from django.forms.widgets import Textarea
from django.template import loader, Context
from django.templatetags.static import static
+from django.utils import six
from django.utils import translation
from django.contrib.gis.gdal import OGRException
-from django.contrib.gis.geos import GEOSGeometry, GEOSException
+from django.contrib.gis.geos import GEOSGeometry, GEOSException, fromstr
# Creating a template context that contains Django settings
# values needed by admin map templates.
@@ -25,7 +26,7 @@ class OpenLayersWidget(Textarea):
# If a string reaches here (via a validation error on another
# field) then just reconstruct the Geometry.
- if isinstance(value, basestring):
+ if isinstance(value, six.string_types):
try:
value = GEOSGeometry(value)
except (GEOSException, ValueError):
@@ -104,3 +105,25 @@ class OpenLayersWidget(Textarea):
raise TypeError
map_options[js_name] = value
return map_options
+
+ def _has_changed(self, initial, data):
+ """ Compare geographic value of data with its initial value. """
+
+ # Ensure we are dealing with a geographic object
+ if isinstance(initial, six.string_types):
+ try:
+ initial = GEOSGeometry(initial)
+ except (GEOSException, ValueError):
+ initial = None
+
+ # Only do a geographic comparison if both values are available
+ if initial and data:
+ data = fromstr(data)
+ data.transform(initial.srid)
+ # If the initial value was not added by the browser, the geometry
+ # provided may be slightly different, the first time it is saved.
+ # The comparison is done with a very low tolerance.
+ return not initial.equals_exact(data, tolerance=0.000001)
+ else:
+ # Check for change of state of existence
+ return bool(initial) != bool(data)
diff --git a/django/contrib/gis/db/backends/base.py b/django/contrib/gis/db/backends/base.py
index 26e97622a8..f7af420a8d 100644
--- a/django/contrib/gis/db/backends/base.py
+++ b/django/contrib/gis/db/backends/base.py
@@ -4,6 +4,8 @@ Base/mixin classes for the spatial backend database operations and the
"""
import re
from django.contrib.gis import gdal
+from django.utils import six
+from django.utils.encoding import python_2_unicode_compatible
class BaseSpatialOperations(object):
"""
@@ -88,7 +90,7 @@ class BaseSpatialOperations(object):
# For quoting column values, rather than columns.
def geo_quote_name(self, name):
- if isinstance(name, unicode):
+ if isinstance(name, six.text_type):
name = name.encode('ascii')
return "'%s'" % name
@@ -130,6 +132,7 @@ class BaseSpatialOperations(object):
def spatial_ref_sys(self):
raise NotImplementedError
+@python_2_unicode_compatible
class SpatialRefSysMixin(object):
"""
The SpatialRefSysMixin is a class used by the database-dependent
@@ -324,12 +327,12 @@ class SpatialRefSysMixin(object):
radius, flattening = sphere_params
return 'SPHEROID["%s",%s,%s]' % (sphere_name, radius, flattening)
- def __unicode__(self):
+ def __str__(self):
"""
Returns the string representation. If GDAL is installed,
it will be 'pretty' OGC WKT.
"""
try:
- return unicode(self.srs)
+ return six.text_type(self.srs)
except:
- return unicode(self.wkt)
+ return six.text_type(self.wkt)
diff --git a/django/contrib/gis/db/backends/mysql/operations.py b/django/contrib/gis/db/backends/mysql/operations.py
index c0e5aa6691..7152f4682d 100644
--- a/django/contrib/gis/db/backends/mysql/operations.py
+++ b/django/contrib/gis/db/backends/mysql/operations.py
@@ -3,6 +3,8 @@ from django.db.backends.mysql.base import DatabaseOperations
from django.contrib.gis.db.backends.adapter import WKTAdapter
from django.contrib.gis.db.backends.base import BaseSpatialOperations
+from django.utils import six
+
class MySQLOperations(DatabaseOperations, BaseSpatialOperations):
compiler_module = 'django.contrib.gis.db.backends.mysql.compiler'
@@ -30,7 +32,7 @@ class MySQLOperations(DatabaseOperations, BaseSpatialOperations):
'within' : 'MBRWithin',
}
- gis_terms = dict([(term, None) for term in geometry_functions.keys() + ['isnull']])
+ gis_terms = dict([(term, None) for term in list(geometry_functions) + ['isnull']])
def geo_db_type(self, f):
return f.geom_type
diff --git a/django/contrib/gis/db/backends/oracle/models.py b/django/contrib/gis/db/backends/oracle/models.py
index ed29f7bb38..b7deb3a946 100644
--- a/django/contrib/gis/db/backends/oracle/models.py
+++ b/django/contrib/gis/db/backends/oracle/models.py
@@ -9,7 +9,9 @@
"""
from django.contrib.gis.db import models
from django.contrib.gis.db.backends.base import SpatialRefSysMixin
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class GeometryColumns(models.Model):
"Maps to the Oracle USER_SDO_GEOM_METADATA table."
table_name = models.CharField(max_length=32)
@@ -36,7 +38,7 @@ class GeometryColumns(models.Model):
"""
return 'column_name'
- def __unicode__(self):
+ def __str__(self):
return '%s - %s (SRID: %s)' % (self.table_name, self.column_name, self.srid)
class SpatialRefSys(models.Model, SpatialRefSysMixin):
diff --git a/django/contrib/gis/db/backends/oracle/operations.py b/django/contrib/gis/db/backends/oracle/operations.py
index a2374bb808..392feb129b 100644
--- a/django/contrib/gis/db/backends/oracle/operations.py
+++ b/django/contrib/gis/db/backends/oracle/operations.py
@@ -16,6 +16,7 @@ from django.contrib.gis.db.backends.oracle.adapter import OracleSpatialAdapter
from django.contrib.gis.db.backends.util import SpatialFunction
from django.contrib.gis.geometry.backend import Geometry
from django.contrib.gis.measure import Distance
+from django.utils import six
class SDOOperation(SpatialFunction):
"Base class for SDO* Oracle operations."
@@ -65,7 +66,7 @@ class SDORelate(SpatialFunction):
super(SDORelate, self).__init__(self.relate_func, mask=mask)
# Valid distance types and substitutions
-dtypes = (Decimal, Distance, float, int, long)
+dtypes = (Decimal, Distance, float) + six.integer_types
class OracleOperations(DatabaseOperations, BaseSpatialOperations):
compiler_module = "django.contrib.gis.db.backends.oracle.compiler"
@@ -120,14 +121,14 @@ class OracleOperations(DatabaseOperations, BaseSpatialOperations):
'exact' : SDOOperation('SDO_EQUAL'),
'overlaps' : SDOOperation('SDO_OVERLAPS'),
'same_as' : SDOOperation('SDO_EQUAL'),
- 'relate' : (SDORelate, basestring), # Oracle uses a different syntax, e.g., 'mask=inside+touch'
+ 'relate' : (SDORelate, six.string_types), # Oracle uses a different syntax, e.g., 'mask=inside+touch'
'touches' : SDOOperation('SDO_TOUCH'),
'within' : SDOOperation('SDO_INSIDE'),
}
geometry_functions.update(distance_functions)
gis_terms = ['isnull']
- gis_terms += geometry_functions.keys()
+ gis_terms += list(geometry_functions)
gis_terms = dict([(term, None) for term in gis_terms])
truncate_params = {'relate' : None}
diff --git a/django/contrib/gis/db/backends/postgis/models.py b/django/contrib/gis/db/backends/postgis/models.py
index a38598343c..e8052594c6 100644
--- a/django/contrib/gis/db/backends/postgis/models.py
+++ b/django/contrib/gis/db/backends/postgis/models.py
@@ -3,7 +3,9 @@
"""
from django.db import models
from django.contrib.gis.db.backends.base import SpatialRefSysMixin
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class GeometryColumns(models.Model):
"""
The 'geometry_columns' table from the PostGIS. See the PostGIS
@@ -37,7 +39,7 @@ class GeometryColumns(models.Model):
"""
return 'f_geometry_column'
- def __unicode__(self):
+ def __str__(self):
return "%s.%s - %dD %s field (SRID: %d)" % \
(self.f_table_name, self.f_geometry_column,
self.coord_dimension, self.type, self.srid)
diff --git a/django/contrib/gis/db/backends/postgis/operations.py b/django/contrib/gis/db/backends/postgis/operations.py
index 964be8de0e..434d8719cc 100644
--- a/django/contrib/gis/db/backends/postgis/operations.py
+++ b/django/contrib/gis/db/backends/postgis/operations.py
@@ -10,6 +10,7 @@ from django.contrib.gis.measure import Distance
from django.core.exceptions import ImproperlyConfigured
from django.db.backends.postgresql_psycopg2.base import DatabaseOperations
from django.db.utils import DatabaseError
+from django.utils import six
#### Classes used in constructing PostGIS spatial SQL ####
class PostGISOperator(SpatialOperation):
@@ -161,11 +162,13 @@ class PostGISOperations(DatabaseOperations, BaseSpatialOperations):
'overlaps' : PostGISFunction(prefix, 'Overlaps'),
'contains' : PostGISFunction(prefix, 'Contains'),
'intersects' : PostGISFunction(prefix, 'Intersects'),
- 'relate' : (PostGISRelate, basestring),
- }
+ 'relate' : (PostGISRelate, six.string_types),
+ 'coveredby' : PostGISFunction(prefix, 'CoveredBy'),
+ 'covers' : PostGISFunction(prefix, 'Covers'),
+ }
# Valid distance types and substitutions
- dtypes = (Decimal, Distance, float, int, long)
+ dtypes = (Decimal, Distance, float) + six.integer_types
def get_dist_ops(operator):
"Returns operations for both regular and spherical distances."
return {'cartesian' : PostGISDistance(prefix, operator),
@@ -177,33 +180,12 @@ class PostGISOperations(DatabaseOperations, BaseSpatialOperations):
'distance_gte' : (get_dist_ops('>='), dtypes),
'distance_lt' : (get_dist_ops('<'), dtypes),
'distance_lte' : (get_dist_ops('<='), dtypes),
- }
-
- # Versions 1.2.2+ have KML serialization support.
- if version < (1, 2, 2):
- ASKML = False
- else:
- ASKML = 'ST_AsKML'
- self.geometry_functions.update(
- {'coveredby' : PostGISFunction(prefix, 'CoveredBy'),
- 'covers' : PostGISFunction(prefix, 'Covers'),
- })
- self.distance_functions['dwithin'] = (PostGISFunctionParam(prefix, 'DWithin'), dtypes)
+ 'dwithin' : (PostGISFunctionParam(prefix, 'DWithin'), dtypes)
+ }
# Adding the distance functions to the geometries lookup.
self.geometry_functions.update(self.distance_functions)
- # The union aggregate and topology operation use the same signature
- # in versions 1.3+.
- if version < (1, 3, 0):
- UNIONAGG = 'GeomUnion'
- UNION = 'Union'
- MAKELINE = False
- else:
- UNIONAGG = 'ST_Union'
- UNION = 'ST_Union'
- MAKELINE = 'ST_MakeLine'
-
# Only PostGIS versions 1.3.4+ have GeoJSON serialization support.
if version < (1, 3, 4):
GEOJSON = False
@@ -235,8 +217,8 @@ class PostGISOperations(DatabaseOperations, BaseSpatialOperations):
# Creating a dictionary lookup of all GIS terms for PostGIS.
gis_terms = ['isnull']
- gis_terms += self.geometry_operators.keys()
- gis_terms += self.geometry_functions.keys()
+ gis_terms += list(self.geometry_operators)
+ gis_terms += list(self.geometry_functions)
self.gis_terms = dict([(term, None) for term in gis_terms])
self.area = prefix + 'Area'
@@ -255,11 +237,11 @@ class PostGISOperations(DatabaseOperations, BaseSpatialOperations):
self.geojson = GEOJSON
self.gml = prefix + 'AsGML'
self.intersection = prefix + 'Intersection'
- self.kml = ASKML
+ self.kml = prefix + 'AsKML'
self.length = prefix + 'Length'
self.length3d = prefix + 'Length3D'
self.length_spheroid = prefix + 'length_spheroid'
- self.makeline = MAKELINE
+ self.makeline = prefix + 'MakeLine'
self.mem_size = prefix + 'mem_size'
self.num_geom = prefix + 'NumGeometries'
self.num_points =prefix + 'npoints'
@@ -274,8 +256,8 @@ class PostGISOperations(DatabaseOperations, BaseSpatialOperations):
self.sym_difference = prefix + 'SymDifference'
self.transform = prefix + 'Transform'
self.translate = prefix + 'Translate'
- self.union = UNION
- self.unionagg = UNIONAGG
+ self.union = prefix + 'Union'
+ self.unionagg = prefix + 'Union'
def check_aggregate_support(self, aggregate):
"""
diff --git a/django/contrib/gis/db/backends/spatialite/creation.py b/django/contrib/gis/db/backends/spatialite/creation.py
index 7efab3e073..27332b9b57 100644
--- a/django/contrib/gis/db/backends/spatialite/creation.py
+++ b/django/contrib/gis/db/backends/spatialite/creation.py
@@ -30,9 +30,7 @@ class SpatiaLiteCreation(DatabaseCreation):
self.connection.close()
self.connection.settings_dict["NAME"] = test_database_name
-
- # Confirm the feature set of the test database
- self.connection.features.confirm()
+ self.connection.ops.confirm_spatial_components_versions()
# Need to load the SpatiaLite initialization SQL before running `syncdb`.
self.load_spatialite_sql()
@@ -102,14 +100,14 @@ class SpatiaLiteCreation(DatabaseCreation):
"""
This routine loads up the SpatiaLite SQL file.
"""
- if self.connection.ops.spatial_version[:2] >= (3, 0):
- # Spatialite >= 3.0.x -- No need to load any SQL file, calling
+ if self.connection.ops.spatial_version[:2] >= (2, 4):
+ # Spatialite >= 2.4 -- No need to load any SQL file, calling
# InitSpatialMetaData() transparently creates the spatial metadata
# tables
cur = self.connection._cursor()
cur.execute("SELECT InitSpatialMetaData()")
else:
- # Spatialite < 3.0.x -- Load the initial SQL
+ # Spatialite < 2.4 -- Load the initial SQL
# Getting the location of the SpatiaLite SQL file, and confirming
# it exists.
diff --git a/django/contrib/gis/db/backends/spatialite/introspection.py b/django/contrib/gis/db/backends/spatialite/introspection.py
index 1b5952ceac..4f12ade114 100644
--- a/django/contrib/gis/db/backends/spatialite/introspection.py
+++ b/django/contrib/gis/db/backends/spatialite/introspection.py
@@ -1,5 +1,6 @@
from django.contrib.gis.gdal import OGRGeomType
from django.db.backends.sqlite3.introspection import DatabaseIntrospection, FlexibleFieldLookupDict
+from django.utils import six
class GeoFlexibleFieldLookupDict(FlexibleFieldLookupDict):
"""
@@ -43,7 +44,7 @@ class SpatiaLiteIntrospection(DatabaseIntrospection):
field_params = {}
if srid != 4326:
field_params['srid'] = srid
- if isinstance(dim, basestring) and 'Z' in dim:
+ if isinstance(dim, six.string_types) and 'Z' in dim:
field_params['dim'] = 3
finally:
cursor.close()
diff --git a/django/contrib/gis/db/backends/spatialite/models.py b/django/contrib/gis/db/backends/spatialite/models.py
index 684c5d8fc7..b281f0bc62 100644
--- a/django/contrib/gis/db/backends/spatialite/models.py
+++ b/django/contrib/gis/db/backends/spatialite/models.py
@@ -3,7 +3,9 @@
"""
from django.db import models
from django.contrib.gis.db.backends.base import SpatialRefSysMixin
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class GeometryColumns(models.Model):
"""
The 'geometry_columns' table from SpatiaLite.
@@ -35,7 +37,7 @@ class GeometryColumns(models.Model):
"""
return 'f_geometry_column'
- def __unicode__(self):
+ def __str__(self):
return "%s.%s - %dD %s field (SRID: %d)" % \
(self.f_table_name, self.f_geometry_column,
self.coord_dimension, self.type, self.srid)
diff --git a/django/contrib/gis/db/backends/spatialite/operations.py b/django/contrib/gis/db/backends/spatialite/operations.py
index 6adcdc5275..80f05ef076 100644
--- a/django/contrib/gis/db/backends/spatialite/operations.py
+++ b/django/contrib/gis/db/backends/spatialite/operations.py
@@ -9,6 +9,7 @@ from django.contrib.gis.measure import Distance
from django.core.exceptions import ImproperlyConfigured
from django.db.backends.sqlite3.base import DatabaseOperations
from django.db.utils import DatabaseError
+from django.utils import six
class SpatiaLiteOperator(SpatialOperation):
"For SpatiaLite operators (e.g. `&&`, `~`)."
@@ -42,7 +43,7 @@ class SpatiaLiteRelate(SpatiaLiteFunctionParam):
super(SpatiaLiteRelate, self).__init__('Relate')
# Valid distance types and substitutions
-dtypes = (Decimal, Distance, float, int, long)
+dtypes = (Decimal, Distance, float) + six.integer_types
def get_dist_ops(operator):
"Returns operations for regular distances; spherical distances are not currently supported."
return (SpatiaLiteDistance(operator),)
@@ -89,7 +90,7 @@ class SpatiaLiteOperations(DatabaseOperations, BaseSpatialOperations):
'overlaps' : SpatiaLiteFunction('Overlaps'),
'contains' : SpatiaLiteFunction('Contains'),
'intersects' : SpatiaLiteFunction('Intersects'),
- 'relate' : (SpatiaLiteRelate, basestring),
+ 'relate' : (SpatiaLiteRelate, six.string_types),
# Returns true if B's bounding box completely contains A's bounding box.
'contained' : SpatiaLiteFunction('MbrWithin'),
# Returns true if A's bounding box completely contains B's bounding box.
@@ -112,6 +113,12 @@ class SpatiaLiteOperations(DatabaseOperations, BaseSpatialOperations):
def __init__(self, connection):
super(DatabaseOperations, self).__init__(connection)
+ # Creating the GIS terms dictionary.
+ gis_terms = ['isnull']
+ gis_terms += self.geometry_functions.keys()
+ self.gis_terms = dict([(term, None) for term in gis_terms])
+
+ def confirm_spatial_components_versions(self):
# Determine the version of the SpatiaLite library.
try:
vtup = self.spatialite_version_tuple()
@@ -128,11 +135,6 @@ class SpatiaLiteOperations(DatabaseOperations, BaseSpatialOperations):
'SQL loaded on this database?' %
(self.connection.settings_dict['NAME'], msg))
- # Creating the GIS terms dictionary.
- gis_terms = ['isnull']
- gis_terms += self.geometry_functions.keys()
- self.gis_terms = dict([(term, None) for term in gis_terms])
-
if version >= (2, 4, 0):
# Spatialite 2.4.0-RC4 added AsGML and AsKML, however both
# RC2 (shipped in popular Debian/Ubuntu packages) and RC4
diff --git a/django/contrib/gis/db/backends/util.py b/django/contrib/gis/db/backends/util.py
index b50c8e222e..648fcfe963 100644
--- a/django/contrib/gis/db/backends/util.py
+++ b/django/contrib/gis/db/backends/util.py
@@ -3,14 +3,16 @@ A collection of utility routines and classes used by the spatial
backends.
"""
+from django.utils import six
+
def gqn(val):
"""
The geographic quote name function; used for quoting tables and
geometries (they use single rather than the double quotes of the
backend quotename function).
"""
- if isinstance(val, basestring):
- if isinstance(val, unicode): val = val.encode('ascii')
+ if isinstance(val, six.string_types):
+ if isinstance(val, six.text_type): val = val.encode('ascii')
return "'%s'" % val
else:
return str(val)
diff --git a/django/contrib/gis/db/models/fields.py b/django/contrib/gis/db/models/fields.py
index 2b1660763a..17630d0899 100644
--- a/django/contrib/gis/db/models/fields.py
+++ b/django/contrib/gis/db/models/fields.py
@@ -4,6 +4,7 @@ from django.utils.translation import ugettext_lazy as _
from django.contrib.gis import forms
from django.contrib.gis.db.models.proxy import GeometryProxy
from django.contrib.gis.geometry.backend import Geometry, GeometryException
+from django.utils import six
# Local cache of the spatial_ref_sys table, which holds SRID data for each
# spatial database alias. This cache exists so that the database isn't queried
@@ -159,7 +160,7 @@ class GeometryField(Field):
# from the given string input.
if isinstance(geom, Geometry):
pass
- elif isinstance(geom, basestring) or hasattr(geom, '__geo_interface__'):
+ elif isinstance(geom, six.string_types) or hasattr(geom, '__geo_interface__'):
try:
geom = Geometry(geom)
except GeometryException:
diff --git a/django/contrib/gis/db/models/proxy.py b/django/contrib/gis/db/models/proxy.py
index e569dd5c4f..413610fc5c 100644
--- a/django/contrib/gis/db/models/proxy.py
+++ b/django/contrib/gis/db/models/proxy.py
@@ -5,6 +5,7 @@ corresponding to geographic model fields.
Thanks to Robert Coup for providing this functionality (see #4322).
"""
+from django.utils import six
class GeometryProxy(object):
def __init__(self, klass, field):
@@ -53,7 +54,7 @@ class GeometryProxy(object):
if isinstance(value, self._klass) and (str(value.geom_type).upper() == gtype or gtype == 'GEOMETRY'):
# Assigning the SRID to the geometry.
if value.srid is None: value.srid = self._field.srid
- elif value is None or isinstance(value, (basestring, buffer)):
+ elif value is None or isinstance(value, six.string_types + (buffer,)):
# Set with None, WKT, HEX, or WKB
pass
else:
diff --git a/django/contrib/gis/db/models/query.py b/django/contrib/gis/db/models/query.py
index c1e360de27..cc61dfa4d2 100644
--- a/django/contrib/gis/db/models/query.py
+++ b/django/contrib/gis/db/models/query.py
@@ -1,11 +1,15 @@
from django.db import connections
from django.db.models.query import QuerySet, ValuesQuerySet, ValuesListQuerySet
+from django.utils import six
from django.contrib.gis.db.models import aggregates
from django.contrib.gis.db.models.fields import get_srid_info, PointField, LineStringField
from django.contrib.gis.db.models.sql import AreaField, DistanceField, GeomField, GeoQuery
from django.contrib.gis.geometry.backend import Geometry
from django.contrib.gis.measure import Area, Distance
+from django.utils import six
+
+from django.utils import six
class GeoQuerySet(QuerySet):
"The Geographic QuerySet."
@@ -22,7 +26,7 @@ class GeoQuerySet(QuerySet):
flat = kwargs.pop('flat', False)
if kwargs:
raise TypeError('Unexpected keyword arguments to values_list: %s'
- % (kwargs.keys(),))
+ % (list(kwargs),))
if flat and len(fields) > 1:
raise TypeError("'flat' is not valid when values_list is called with more than one field.")
return self._clone(klass=GeoValuesListQuerySet, setup=True, flat=flat,
@@ -144,7 +148,7 @@ class GeoQuerySet(QuerySet):
if not backend.geojson:
raise NotImplementedError('Only PostGIS 1.3.4+ supports GeoJSON serialization.')
- if not isinstance(precision, (int, long)):
+ if not isinstance(precision, six.integer_types):
raise TypeError('Precision keyword must be set with an integer.')
# Setting the options flag -- which depends on which version of
@@ -173,7 +177,7 @@ class GeoQuerySet(QuerySet):
The `precision` keyword may be used to custom the number of
_characters_ used in the output GeoHash, the default is 20.
"""
- s = {'desc' : 'GeoHash',
+ s = {'desc' : 'GeoHash',
'procedure_args': {'precision': precision},
'procedure_fmt': '%(geo_col)s,%(precision)s',
}
@@ -309,7 +313,7 @@ class GeoQuerySet(QuerySet):
- 2 arguments: X and Y sizes to snap the grid to.
- 4 arguments: X, Y sizes and the X, Y origins.
"""
- if False in [isinstance(arg, (float, int, long)) for arg in args]:
+ if False in [isinstance(arg, (float,) + six.integer_types) for arg in args]:
raise TypeError('Size argument(s) for the grid must be a float or integer values.')
nargs = len(args)
@@ -349,7 +353,7 @@ class GeoQuerySet(QuerySet):
digits used in output (defaults to 8).
"""
relative = int(bool(relative))
- if not isinstance(precision, (int, long)):
+ if not isinstance(precision, six.integer_types):
raise TypeError('SVG precision keyword argument must be an integer.')
s = {'desc' : 'SVG',
'procedure_fmt' : '%(geo_col)s,%(rel)s,%(precision)s',
@@ -390,7 +394,7 @@ class GeoQuerySet(QuerySet):
Transforms the given geometry field to the given SRID. If no SRID is
provided, the transformation will default to using 4326 (WGS84).
"""
- if not isinstance(srid, (int, long)):
+ if not isinstance(srid, six.integer_types):
raise TypeError('An integer SRID must be provided.')
field_name = kwargs.get('field_name', None)
tmp, geo_field = self._spatial_setup('transform', field_name=field_name)
@@ -528,12 +532,12 @@ class GeoQuerySet(QuerySet):
if settings.get('setup', True):
default_args, geo_field = self._spatial_setup(att, desc=settings['desc'], field_name=field_name,
geo_field_type=settings.get('geo_field_type', None))
- for k, v in default_args.iteritems(): settings['procedure_args'].setdefault(k, v)
+ for k, v in six.iteritems(default_args): settings['procedure_args'].setdefault(k, v)
else:
geo_field = settings['geo_field']
# The attribute to attach to the model.
- if not isinstance(model_att, basestring): model_att = att
+ if not isinstance(model_att, six.string_types): model_att = att
# Special handling for any argument that is a geometry.
for name in settings['geom_args']:
diff --git a/django/contrib/gis/db/models/sql/compiler.py b/django/contrib/gis/db/models/sql/compiler.py
index ebaee60bd0..5c8d2647f7 100644
--- a/django/contrib/gis/db/models/sql/compiler.py
+++ b/django/contrib/gis/db/models/sql/compiler.py
@@ -1,8 +1,9 @@
-from future_builtins import zip
+from django.utils.six.moves import zip
from django.db.backends.util import truncate_name, typecast_timestamp
from django.db.models.sql import compiler
from django.db.models.sql.constants import MULTI
+from django.utils import six
SQLCompiler = compiler.SQLCompiler
@@ -24,7 +25,7 @@ class GeoSQLCompiler(compiler.SQLCompiler):
qn = self.quote_name_unless_alias
qn2 = self.connection.ops.quote_name
result = ['(%s) AS %s' % (self.get_extra_select_format(alias) % col[0], qn2(alias))
- for alias, col in self.query.extra_select.iteritems()]
+ for alias, col in six.iteritems(self.query.extra_select)]
aliases = set(self.query.extra_select.keys())
if with_aliases:
col_aliases = aliases.copy()
@@ -170,7 +171,7 @@ class GeoSQLCompiler(compiler.SQLCompiler):
objects.
"""
values = []
- aliases = self.query.extra_select.keys()
+ aliases = list(self.query.extra_select)
# Have to set a starting row number offset that is used for
# determining the correct starting row index -- needed for
diff --git a/django/contrib/gis/feeds.py b/django/contrib/gis/feeds.py
index c14fb858a5..d7c52bf019 100644
--- a/django/contrib/gis/feeds.py
+++ b/django/contrib/gis/feeds.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
from django.contrib.syndication.views import Feed as BaseFeed
from django.utils.feedgenerator import Atom1Feed, Rss201rev2Feed
@@ -13,7 +15,7 @@ class GeoFeedMixin(object):
a single white space. Given a tuple of coordinates, this will return
a unicode GeoRSS representation.
"""
- return u' '.join([u'%f %f' % (coord[1], coord[0]) for coord in coords])
+ return ' '.join(['%f %f' % (coord[1], coord[0]) for coord in coords])
def add_georss_point(self, handler, coords, w3c_geo=False):
"""
@@ -23,10 +25,10 @@ class GeoFeedMixin(object):
"""
if w3c_geo:
lon, lat = coords[:2]
- handler.addQuickElement(u'geo:lat', u'%f' % lat)
- handler.addQuickElement(u'geo:lon', u'%f' % lon)
+ handler.addQuickElement('geo:lat', '%f' % lat)
+ handler.addQuickElement('geo:lon', '%f' % lon)
else:
- handler.addQuickElement(u'georss:point', self.georss_coords((coords,)))
+ handler.addQuickElement('georss:point', self.georss_coords((coords,)))
def add_georss_element(self, handler, item, w3c_geo=False):
"""
@@ -57,7 +59,7 @@ class GeoFeedMixin(object):
# If a GeoRSS box was given via tuple.
if not box_coords is None:
if w3c_geo: raise ValueError('Cannot use simple GeoRSS box in W3C Geo feeds.')
- handler.addQuickElement(u'georss:box', self.georss_coords(box_coords))
+ handler.addQuickElement('georss:box', self.georss_coords(box_coords))
else:
# Getting the lower-case geometry type.
gtype = str(geom.geom_type).lower()
@@ -68,10 +70,10 @@ class GeoFeedMixin(object):
# For formatting consistent w/the GeoRSS simple standard:
# http://georss.org/1.0#simple
if gtype in ('linestring', 'linearring'):
- handler.addQuickElement(u'georss:line', self.georss_coords(geom.coords))
+ handler.addQuickElement('georss:line', self.georss_coords(geom.coords))
elif gtype in ('polygon',):
# Only support the exterior ring.
- handler.addQuickElement(u'georss:polygon', self.georss_coords(geom[0].coords))
+ handler.addQuickElement('georss:polygon', self.georss_coords(geom[0].coords))
else:
raise ValueError('Geometry type "%s" not supported.' % geom.geom_type)
@@ -79,7 +81,7 @@ class GeoFeedMixin(object):
class GeoRSSFeed(Rss201rev2Feed, GeoFeedMixin):
def rss_attributes(self):
attrs = super(GeoRSSFeed, self).rss_attributes()
- attrs[u'xmlns:georss'] = u'http://www.georss.org/georss'
+ attrs['xmlns:georss'] = 'http://www.georss.org/georss'
return attrs
def add_item_elements(self, handler, item):
@@ -93,7 +95,7 @@ class GeoRSSFeed(Rss201rev2Feed, GeoFeedMixin):
class GeoAtom1Feed(Atom1Feed, GeoFeedMixin):
def root_attributes(self):
attrs = super(GeoAtom1Feed, self).root_attributes()
- attrs[u'xmlns:georss'] = u'http://www.georss.org/georss'
+ attrs['xmlns:georss'] = 'http://www.georss.org/georss'
return attrs
def add_item_elements(self, handler, item):
@@ -107,7 +109,7 @@ class GeoAtom1Feed(Atom1Feed, GeoFeedMixin):
class W3CGeoFeed(Rss201rev2Feed, GeoFeedMixin):
def rss_attributes(self):
attrs = super(W3CGeoFeed, self).rss_attributes()
- attrs[u'xmlns:geo'] = u'http://www.w3.org/2003/01/geo/wgs84_pos#'
+ attrs['xmlns:geo'] = 'http://www.w3.org/2003/01/geo/wgs84_pos#'
return attrs
def add_item_elements(self, handler, item):
diff --git a/django/contrib/gis/forms/fields.py b/django/contrib/gis/forms/fields.py
index f806dcb3c6..cefb6830ba 100644
--- a/django/contrib/gis/forms/fields.py
+++ b/django/contrib/gis/forms/fields.py
@@ -1,9 +1,11 @@
+from __future__ import unicode_literals
+
from django import forms
from django.utils.translation import ugettext_lazy as _
# While this couples the geographic forms to the GEOS library,
# it decouples from database (by not importing SpatialBackend).
-from django.contrib.gis.geos import GEOSGeometry
+from django.contrib.gis.geos import GEOSException, GEOSGeometry
class GeometryField(forms.Field):
"""
@@ -14,10 +16,10 @@ class GeometryField(forms.Field):
widget = forms.Textarea
default_error_messages = {
- 'no_geom' : _(u'No geometry value provided.'),
- 'invalid_geom' : _(u'Invalid geometry value.'),
- 'invalid_geom_type' : _(u'Invalid geometry type.'),
- 'transform_error' : _(u'An error occurred when transforming the geometry '
+ 'no_geom' : _('No geometry value provided.'),
+ 'invalid_geom' : _('Invalid geometry value.'),
+ 'invalid_geom_type' : _('Invalid geometry type.'),
+ 'transform_error' : _('An error occurred when transforming the geometry '
'to the SRID of the geometry form field.'),
}
@@ -29,6 +31,15 @@ class GeometryField(forms.Field):
self.null = kwargs.pop('null', True)
super(GeometryField, self).__init__(**kwargs)
+ def to_python(self, value):
+ """
+ Transforms the value to a Geometry object.
+ """
+ try:
+ return GEOSGeometry(value)
+ except (GEOSException, ValueError, TypeError):
+ raise forms.ValidationError(self.error_messages['invalid_geom'])
+
def clean(self, value):
"""
Validates that the input value can be converted to a Geometry
@@ -42,11 +53,8 @@ class GeometryField(forms.Field):
else:
raise forms.ValidationError(self.error_messages['no_geom'])
- # Trying to create a Geometry object from the form value.
- try:
- geom = GEOSGeometry(value)
- except:
- raise forms.ValidationError(self.error_messages['invalid_geom'])
+ # Transform the value to a python object first
+ geom = self.to_python(value)
# Ensuring that the geometry is of the correct type (indicated
# using the OGC string label).
diff --git a/django/contrib/gis/gdal/__init__.py b/django/contrib/gis/gdal/__init__.py
index cc47ae9bc2..adff96b47a 100644
--- a/django/contrib/gis/gdal/__init__.py
+++ b/django/contrib/gis/gdal/__init__.py
@@ -6,7 +6,7 @@
reference system to another.
Driver: Wraps an OGR data source driver.
-
+
DataSource: Wrapper for the OGR data source object, supports
OGR-supported data sources.
@@ -20,15 +20,15 @@
SpatialReference: Represents OSR Spatial Reference objects.
- The GDAL library will be imported from the system path using the default
+ The GDAL library will be imported from the system path using the default
library name for the current OS. The default library path may be overridden
- by setting `GDAL_LIBRARY_PATH` in your settings with the path to the GDAL C
- library on your system.
+ by setting `GDAL_LIBRARY_PATH` in your settings with the path to the GDAL C
+ library on your system.
- GDAL links to a large number of external libraries that consume RAM when
+ GDAL links to a large number of external libraries that consume RAM when
loaded. Thus, it may desirable to disable GDAL on systems with limited
RAM resources -- this may be accomplished by setting `GDAL_LIBRARY_PATH`
- to a non-existant file location (e.g., `GDAL_LIBRARY_PATH='/null/path'`;
+ to a non-existant file location (e.g., `GDAL_LIBRARY_PATH='/null/path'`;
setting to None/False/'' will not work as a string must be given).
"""
# Attempting to import objects that depend on the GDAL library. The
@@ -37,12 +37,12 @@
try:
from django.contrib.gis.gdal.driver import Driver
from django.contrib.gis.gdal.datasource import DataSource
- from django.contrib.gis.gdal.libgdal import gdal_version, gdal_full_version, gdal_release_date, GEOJSON, GDAL_VERSION
+ from django.contrib.gis.gdal.libgdal import gdal_version, gdal_full_version, gdal_release_date, GDAL_VERSION
from django.contrib.gis.gdal.srs import SpatialReference, CoordTransform
from django.contrib.gis.gdal.geometries import OGRGeometry
HAS_GDAL = True
except:
- HAS_GDAL, GEOJSON = False, False
+ HAS_GDAL = False
try:
from django.contrib.gis.gdal.envelope import Envelope
diff --git a/django/contrib/gis/gdal/base.py b/django/contrib/gis/gdal/base.py
index 36c03eb51e..e86277e95e 100644
--- a/django/contrib/gis/gdal/base.py
+++ b/django/contrib/gis/gdal/base.py
@@ -1,6 +1,7 @@
from ctypes import c_void_p
from django.contrib.gis.gdal.error import GDALException
+from django.utils import six
class GDALBase(object):
"""
@@ -24,7 +25,7 @@ class GDALBase(object):
def _set_ptr(self, ptr):
# Only allow the pointer to be set with pointers of the
# compatible type or None (NULL).
- if isinstance(ptr, (int, long)):
+ if isinstance(ptr, six.integer_types):
self._ptr = self.ptr_type(ptr)
elif ptr is None or isinstance(ptr, self.ptr_type):
self._ptr = ptr
diff --git a/django/contrib/gis/gdal/datasource.py b/django/contrib/gis/gdal/datasource.py
index e5f3602ddb..4ceddc6c72 100644
--- a/django/contrib/gis/gdal/datasource.py
+++ b/django/contrib/gis/gdal/datasource.py
@@ -45,6 +45,9 @@ from django.contrib.gis.gdal.layer import Layer
# Getting the ctypes prototypes for the DataSource.
from django.contrib.gis.gdal.prototypes import ds as capi
+from django.utils import six
+from django.utils.six.moves import xrange
+
# For more information, see the OGR C API source code:
# http://www.gdal.org/ogr/ogr__api_8h.html
#
@@ -65,7 +68,7 @@ class DataSource(GDALBase):
if not capi.get_driver_count():
capi.register_all()
- if isinstance(ds_input, basestring):
+ if isinstance(ds_input, six.string_types):
# The data source driver is a void pointer.
ds_driver = Driver.ptr_type()
try:
@@ -84,7 +87,7 @@ class DataSource(GDALBase):
self.ptr = ds
self.driver = Driver(ds_driver)
else:
- # Raise an exception if the returned pointer is NULL
+ # Raise an exception if the returned pointer is NULL
raise OGRException('Invalid data source file "%s"' % ds_input)
def __del__(self):
@@ -98,7 +101,7 @@ class DataSource(GDALBase):
def __getitem__(self, index):
"Allows use of the index [] operator to get a layer at the index."
- if isinstance(index, basestring):
+ if isinstance(index, six.string_types):
l = capi.get_layer_by_name(self.ptr, index)
if not l: raise OGRIndexError('invalid OGR Layer name given: "%s"' % index)
elif isinstance(index, int):
@@ -108,7 +111,7 @@ class DataSource(GDALBase):
else:
raise TypeError('Invalid index type: %s' % type(index))
return Layer(l, self)
-
+
def __len__(self):
"Returns the number of layers within the data source."
return self.layer_count
diff --git a/django/contrib/gis/gdal/driver.py b/django/contrib/gis/gdal/driver.py
index 1753db2b2b..de4dc61c63 100644
--- a/django/contrib/gis/gdal/driver.py
+++ b/django/contrib/gis/gdal/driver.py
@@ -1,9 +1,11 @@
-# prerequisites imports
+# prerequisites imports
from ctypes import c_void_p
from django.contrib.gis.gdal.base import GDALBase
from django.contrib.gis.gdal.error import OGRException
from django.contrib.gis.gdal.prototypes import ds as capi
+from django.utils import six
+
# For more information, see the OGR C API source code:
# http://www.gdal.org/ogr/ogr__api_8h.html
#
@@ -18,11 +20,11 @@ class Driver(GDALBase):
'tiger' : 'TIGER',
'tiger/line' : 'TIGER',
}
-
+
def __init__(self, dr_input):
"Initializes an OGR driver on either a string or integer input."
- if isinstance(dr_input, basestring):
+ if isinstance(dr_input, six.string_types):
# If a string name of the driver was passed in
self._register()
@@ -57,7 +59,7 @@ class Driver(GDALBase):
# Only register all if the driver count is 0 (or else all drivers
# will be registered over and over again)
if not self.driver_count: capi.register_all()
-
+
# Driver properties
@property
def driver_count(self):
diff --git a/django/contrib/gis/gdal/feature.py b/django/contrib/gis/gdal/feature.py
index 47fd9e522e..292004873d 100644
--- a/django/contrib/gis/gdal/feature.py
+++ b/django/contrib/gis/gdal/feature.py
@@ -7,6 +7,9 @@ from django.contrib.gis.gdal.geometries import OGRGeometry, OGRGeomType
# ctypes function prototypes
from django.contrib.gis.gdal.prototypes import ds as capi, geom as geom_api
+from django.utils import six
+from django.utils.six.moves import xrange
+
# For more information, see the OGR C API source code:
# http://www.gdal.org/ogr/ogr__api_8h.html
#
@@ -30,17 +33,17 @@ class Feature(GDALBase):
"""
Gets the Field object at the specified index, which may be either
an integer or the Field's string label. Note that the Field object
- is not the field's _value_ -- use the `get` method instead to
+ is not the field's _value_ -- use the `get` method instead to
retrieve the value (e.g. an integer) instead of a Field instance.
"""
- if isinstance(index, basestring):
+ if isinstance(index, six.string_types):
i = self.index(index)
else:
if index < 0 or index > self.num_fields:
raise OGRIndexError('index out of range')
i = index
return Field(self.ptr, i)
-
+
def __iter__(self):
"Iterates over each field in the Feature."
for i in xrange(self.num_fields):
@@ -49,7 +52,7 @@ class Feature(GDALBase):
def __len__(self):
"Returns the count of fields in this feature."
return self.num_fields
-
+
def __str__(self):
"The string name of the feature."
return 'Feature FID %d in Layer<%s>' % (self.fid, self.layer_name)
@@ -63,7 +66,7 @@ class Feature(GDALBase):
def fid(self):
"Returns the feature identifier."
return capi.get_fid(self.ptr)
-
+
@property
def layer_name(self):
"Returns the name of the layer for the feature."
@@ -77,7 +80,7 @@ class Feature(GDALBase):
@property
def fields(self):
"Returns a list of fields in the Feature."
- return [capi.get_field_name(capi.get_field_defn(self._fdefn, i))
+ return [capi.get_field_name(capi.get_field_defn(self._fdefn, i))
for i in xrange(self.num_fields)]
@property
@@ -91,7 +94,7 @@ class Feature(GDALBase):
def geom_type(self):
"Returns the OGR Geometry Type for this Feture."
return OGRGeomType(capi.get_fd_geom_type(self._fdefn))
-
+
#### Feature Methods ####
def get(self, field):
"""
diff --git a/django/contrib/gis/gdal/geometries.py b/django/contrib/gis/gdal/geometries.py
index b4d4ad1646..373ece777d 100644
--- a/django/contrib/gis/gdal/geometries.py
+++ b/django/contrib/gis/gdal/geometries.py
@@ -40,7 +40,7 @@
"""
# Python library requisites.
import sys
-from binascii import a2b_hex
+from binascii import a2b_hex, b2a_hex
from ctypes import byref, string_at, c_char_p, c_double, c_ubyte, c_void_p
# Getting GDAL prerequisites
@@ -48,7 +48,7 @@ from django.contrib.gis.gdal.base import GDALBase
from django.contrib.gis.gdal.envelope import Envelope, OGREnvelope
from django.contrib.gis.gdal.error import OGRException, OGRIndexError, SRSException
from django.contrib.gis.gdal.geomtype import OGRGeomType
-from django.contrib.gis.gdal.libgdal import GEOJSON, GDAL_VERSION
+from django.contrib.gis.gdal.libgdal import GDAL_VERSION
from django.contrib.gis.gdal.srs import SpatialReference, CoordTransform
# Getting the ctypes prototype functions that interface w/the GDAL C library.
@@ -57,6 +57,9 @@ from django.contrib.gis.gdal.prototypes import geom as capi, srs as srs_api
# For recognizing geometry input.
from django.contrib.gis.geometry.regex import hex_regex, wkt_regex, json_regex
+from django.utils import six
+from django.utils.six.moves import xrange
+
# For more information, see the OGR C API source code:
# http://www.gdal.org/ogr/ogr__api_8h.html
#
@@ -69,7 +72,7 @@ class OGRGeometry(GDALBase):
def __init__(self, geom_input, srs=None):
"Initializes Geometry on either WKT or an OGR pointer as input."
- str_instance = isinstance(geom_input, basestring)
+ str_instance = isinstance(geom_input, six.string_types)
# If HEX, unpack input to to a binary buffer.
if str_instance and hex_regex.match(geom_input):
@@ -79,7 +82,7 @@ class OGRGeometry(GDALBase):
# Constructing the geometry,
if str_instance:
# Checking if unicode
- if isinstance(geom_input, unicode):
+ if isinstance(geom_input, six.text_type):
# Encoding to ASCII, WKT or HEX doesn't need any more.
geom_input = geom_input.encode('ascii')
@@ -97,10 +100,7 @@ class OGRGeometry(GDALBase):
else:
g = capi.from_wkt(byref(c_char_p(wkt_m.group('wkt'))), None, byref(c_void_p()))
elif json_m:
- if GEOJSON:
- g = capi.from_json(geom_input)
- else:
- raise NotImplementedError('GeoJSON input only supported on GDAL 1.5+.')
+ g = capi.from_json(geom_input)
else:
# Seeing if the input is a valid short-hand string
# (e.g., 'Point', 'POLYGON').
@@ -284,7 +284,7 @@ class OGRGeometry(GDALBase):
# (decremented) when this geometry's destructor is called.
if isinstance(srs, SpatialReference):
srs_ptr = srs.ptr
- elif isinstance(srs, (int, long, basestring)):
+ elif isinstance(srs, six.integer_types + six.string_types):
sr = SpatialReference(srs)
srs_ptr = sr.ptr
else:
@@ -300,7 +300,7 @@ class OGRGeometry(GDALBase):
return None
def _set_srid(self, srid):
- if isinstance(srid, (int, long)):
+ if isinstance(srid, six.integer_types):
self.srs = srid
else:
raise TypeError('SRID must be set with an integer.')
@@ -322,28 +322,20 @@ class OGRGeometry(GDALBase):
@property
def hex(self):
"Returns the hexadecimal representation of the WKB (a string)."
- return str(self.wkb).encode('hex').upper()
- #return b2a_hex(self.wkb).upper()
+ return b2a_hex(self.wkb).upper()
@property
def json(self):
"""
- Returns the GeoJSON representation of this Geometry (requires
- GDAL 1.5+).
+ Returns the GeoJSON representation of this Geometry.
"""
- if GEOJSON:
- return capi.to_json(self.ptr)
- else:
- raise NotImplementedError('GeoJSON output only supported on GDAL 1.5+.')
+ return capi.to_json(self.ptr)
geojson = json
@property
def kml(self):
"Returns the KML representation of the Geometry."
- if GEOJSON:
- return capi.to_kml(self.ptr, None)
- else:
- raise NotImplementedError('KML output only supported on GDAL 1.5+.')
+ return capi.to_kml(self.ptr, None)
@property
def wkb_size(self):
@@ -420,7 +412,7 @@ class OGRGeometry(GDALBase):
capi.geom_transform(self.ptr, coord_trans.ptr)
elif isinstance(coord_trans, SpatialReference):
capi.geom_transform_to(self.ptr, coord_trans.ptr)
- elif isinstance(coord_trans, (int, long, basestring)):
+ elif isinstance(coord_trans, six.integer_types + six.string_types):
sr = SpatialReference(coord_trans)
capi.geom_transform_to(self.ptr, sr.ptr)
else:
@@ -695,7 +687,7 @@ class GeometryCollection(OGRGeometry):
for g in geom: capi.add_geom(self.ptr, g.ptr)
else:
capi.add_geom(self.ptr, geom.ptr)
- elif isinstance(geom, basestring):
+ elif isinstance(geom, six.string_types):
tmp = OGRGeometry(geom)
capi.add_geom(self.ptr, tmp.ptr)
else:
diff --git a/django/contrib/gis/gdal/geomtype.py b/django/contrib/gis/gdal/geomtype.py
index 3bf94d4815..fe4b89adeb 100644
--- a/django/contrib/gis/gdal/geomtype.py
+++ b/django/contrib/gis/gdal/geomtype.py
@@ -1,5 +1,7 @@
from django.contrib.gis.gdal.error import OGRException
+from django.utils import six
+
#### OGRGeomType ####
class OGRGeomType(object):
"Encapulates OGR Geometry Types."
@@ -32,7 +34,7 @@ class OGRGeomType(object):
"Figures out the correct OGR Type based upon the input."
if isinstance(type_input, OGRGeomType):
num = type_input.num
- elif isinstance(type_input, basestring):
+ elif isinstance(type_input, six.string_types):
type_input = type_input.lower()
if type_input == 'geometry': type_input='unknown'
num = self._str_types.get(type_input, None)
@@ -44,7 +46,7 @@ class OGRGeomType(object):
num = type_input
else:
raise TypeError('Invalid OGR input type given.')
-
+
# Setting the OGR geometry type number.
self.num = num
@@ -59,7 +61,7 @@ class OGRGeomType(object):
"""
if isinstance(other, OGRGeomType):
return self.num == other.num
- elif isinstance(other, basestring):
+ elif isinstance(other, six.string_types):
return self.name.lower() == other.lower()
elif isinstance(other, int):
return self.num == other
diff --git a/django/contrib/gis/gdal/layer.py b/django/contrib/gis/gdal/layer.py
index a2163bc3c8..2357fbb88a 100644
--- a/django/contrib/gis/gdal/layer.py
+++ b/django/contrib/gis/gdal/layer.py
@@ -14,6 +14,9 @@ from django.contrib.gis.gdal.srs import SpatialReference
# GDAL ctypes function prototypes.
from django.contrib.gis.gdal.prototypes import ds as capi, geom as geom_api, srs as srs_api
+from django.utils import six
+from django.utils.six.moves import xrange
+
# For more information, see the OGR C API source code:
# http://www.gdal.org/ogr/ogr__api_8h.html
#
@@ -25,8 +28,8 @@ class Layer(GDALBase):
def __init__(self, layer_ptr, ds):
"""
Initializes on an OGR C pointer to the Layer and the `DataSource` object
- that owns this layer. The `DataSource` object is required so that a
- reference to it is kept with this Layer. This prevents garbage
+ that owns this layer. The `DataSource` object is required so that a
+ reference to it is kept with this Layer. This prevents garbage
collection of the `DataSource` while this Layer is still active.
"""
if not layer_ptr:
@@ -39,7 +42,7 @@ class Layer(GDALBase):
def __getitem__(self, index):
"Gets the Feature at the specified index."
- if isinstance(index, (int, long)):
+ if isinstance(index, six.integer_types):
# An integer index was given -- we cannot do a check based on the
# number of features because the beginning and ending feature IDs
# are not guaranteed to be 0 and len(layer)-1, respectively.
@@ -85,7 +88,7 @@ class Layer(GDALBase):
# each feature until the given feature ID is encountered.
for feat in self:
if feat.fid == feat_id: return feat
- # Should have returned a Feature, raise an OGRIndexError.
+ # Should have returned a Feature, raise an OGRIndexError.
raise OGRIndexError('Invalid feature id: %s.' % feat_id)
#### Layer properties ####
@@ -131,9 +134,9 @@ class Layer(GDALBase):
Returns a list of string names corresponding to each of the Fields
available in this Layer.
"""
- return [capi.get_field_name(capi.get_field_defn(self._ldefn, i))
+ return [capi.get_field_name(capi.get_field_defn(self._ldefn, i))
for i in xrange(self.num_fields) ]
-
+
@property
def field_types(self):
"""
@@ -145,13 +148,13 @@ class Layer(GDALBase):
return [OGRFieldTypes[capi.get_field_type(capi.get_field_defn(self._ldefn, i))]
for i in xrange(self.num_fields)]
- @property
+ @property
def field_widths(self):
"Returns a list of the maximum field widths for the features."
return [capi.get_field_width(capi.get_field_defn(self._ldefn, i))
for i in xrange(self.num_fields)]
- @property
+ @property
def field_precisions(self):
"Returns the field precisions for the features."
return [capi.get_field_precision(capi.get_field_defn(self._ldefn, i))
diff --git a/django/contrib/gis/gdal/libgdal.py b/django/contrib/gis/gdal/libgdal.py
index f991388835..27a5b8172e 100644
--- a/django/contrib/gis/gdal/libgdal.py
+++ b/django/contrib/gis/gdal/libgdal.py
@@ -15,31 +15,32 @@ if lib_path:
lib_names = None
elif os.name == 'nt':
# Windows NT shared libraries
- lib_names = ['gdal18', 'gdal17', 'gdal16', 'gdal15']
+ lib_names = ['gdal19', 'gdal18', 'gdal17', 'gdal16', 'gdal15']
elif os.name == 'posix':
# *NIX library names.
- lib_names = ['gdal', 'GDAL', 'gdal1.8.0', 'gdal1.7.0', 'gdal1.6.0', 'gdal1.5.0', 'gdal1.4.0']
+ lib_names = ['gdal', 'GDAL', 'gdal1.9.0', 'gdal1.8.0', 'gdal1.7.0',
+ 'gdal1.6.0', 'gdal1.5.0']
else:
raise OGRException('Unsupported OS "%s"' % os.name)
-# Using the ctypes `find_library` utility to find the
+# Using the ctypes `find_library` utility to find the
# path to the GDAL library from the list of library names.
if lib_names:
for lib_name in lib_names:
lib_path = find_library(lib_name)
if not lib_path is None: break
-
+
if lib_path is None:
raise OGRException('Could not find the GDAL library (tried "%s"). '
- 'Try setting GDAL_LIBRARY_PATH in your settings.' %
+ 'Try setting GDAL_LIBRARY_PATH in your settings.' %
'", "'.join(lib_names))
# This loads the GDAL/OGR C library
lgdal = CDLL(lib_path)
-# On Windows, the GDAL binaries have some OSR routines exported with
-# STDCALL, while others are not. Thus, the library will also need to
-# be loaded up as WinDLL for said OSR functions that require the
+# On Windows, the GDAL binaries have some OSR routines exported with
+# STDCALL, while others are not. Thus, the library will also need to
+# be loaded up as WinDLL for said OSR functions that require the
# different calling convention.
if os.name == 'nt':
from ctypes import WinDLL
@@ -66,11 +67,11 @@ def gdal_version():
"Returns only the GDAL version number information."
return _version_info('RELEASE_NAME')
-def gdal_full_version():
+def gdal_full_version():
"Returns the full GDAL version information."
return _version_info('')
-def gdal_release_date(date=False):
+def gdal_release_date(date=False):
"""
Returns the release date in a string format, e.g, "2007/06/27".
If the date keyword argument is set to True, a Python datetime object
@@ -96,10 +97,3 @@ GDAL_MINOR_VERSION = int(_verinfo['minor'])
GDAL_SUBMINOR_VERSION = _verinfo['subminor'] and int(_verinfo['subminor'])
GDAL_VERSION = (GDAL_MAJOR_VERSION, GDAL_MINOR_VERSION, GDAL_SUBMINOR_VERSION)
del _verinfo
-
-# GeoJSON support is available only in GDAL 1.5+.
-if GDAL_VERSION >= (1, 5):
- GEOJSON = True
-else:
- GEOJSON = False
-
diff --git a/django/contrib/gis/gdal/prototypes/errcheck.py b/django/contrib/gis/gdal/prototypes/errcheck.py
index 91858ea572..d8ff1c7dcf 100644
--- a/django/contrib/gis/gdal/prototypes/errcheck.py
+++ b/django/contrib/gis/gdal/prototypes/errcheck.py
@@ -5,9 +5,10 @@
from ctypes import c_void_p, string_at
from django.contrib.gis.gdal.error import check_err, OGRException, SRSException
from django.contrib.gis.gdal.libgdal import lgdal
+from django.utils import six
-# Helper routines for retrieving pointers and/or values from
-# arguments passed in by reference.
+# Helper routines for retrieving pointers and/or values from
+# arguments passed in by reference.
def arg_byref(args, offset=-1):
"Returns the pointer argument's by-refernece value."
return args[offset]._obj.value
@@ -53,7 +54,7 @@ def check_string(result, func, cargs, offset=-1, str_result=False):
ptr = ptr_byref(cargs, offset)
# Getting the string value
s = ptr.value
- # Correctly freeing the allocated memory beind GDAL pointer
+ # Correctly freeing the allocated memory beind GDAL pointer
# w/the VSIFree routine.
if ptr: lgdal.VSIFree(ptr)
return s
@@ -71,9 +72,9 @@ def check_geom(result, func, cargs):
"Checks a function that returns a geometry."
# OGR_G_Clone may return an integer, even though the
# restype is set to c_void_p
- if isinstance(result, (int, long)):
+ if isinstance(result, six.integer_types):
result = c_void_p(result)
- if not result:
+ if not result:
raise OGRException('Invalid geometry pointer returned from "%s".' % func.__name__)
return result
@@ -85,7 +86,7 @@ def check_geom_offset(result, func, cargs, offset=-1):
### Spatial Reference error-checking routines ###
def check_srs(result, func, cargs):
- if isinstance(result, (int, long)):
+ if isinstance(result, six.integer_types):
result = c_void_p(result)
if not result:
raise SRSException('Invalid spatial reference pointer returned from "%s".' % func.__name__)
@@ -109,11 +110,11 @@ def check_errcode(result, func, cargs):
def check_pointer(result, func, cargs):
"Makes sure the result pointer is valid."
- if isinstance(result, (int, long)):
+ if isinstance(result, six.integer_types):
result = c_void_p(result)
- if bool(result):
+ if bool(result):
return result
- else:
+ else:
raise OGRException('Invalid pointer returned from "%s"' % func.__name__)
def check_str_arg(result, func, cargs):
diff --git a/django/contrib/gis/gdal/prototypes/geom.py b/django/contrib/gis/gdal/prototypes/geom.py
index 7fa83910c7..f2c833d576 100644
--- a/django/contrib/gis/gdal/prototypes/geom.py
+++ b/django/contrib/gis/gdal/prototypes/geom.py
@@ -1,6 +1,6 @@
from ctypes import c_char_p, c_double, c_int, c_void_p, POINTER
from django.contrib.gis.gdal.envelope import OGREnvelope
-from django.contrib.gis.gdal.libgdal import lgdal, GEOJSON
+from django.contrib.gis.gdal.libgdal import lgdal
from django.contrib.gis.gdal.prototypes.errcheck import check_bool, check_envelope
from django.contrib.gis.gdal.prototypes.generation import (const_string_output,
double_output, geom_output, int_output, srs_output, string_output, void_output)
@@ -25,15 +25,10 @@ def topology_func(f):
### OGR_G ctypes function prototypes ###
-# GeoJSON routines, if supported.
-if GEOJSON:
- from_json = geom_output(lgdal.OGR_G_CreateGeometryFromJson, [c_char_p])
- to_json = string_output(lgdal.OGR_G_ExportToJson, [c_void_p], str_result=True)
- to_kml = string_output(lgdal.OGR_G_ExportToKML, [c_void_p, c_char_p], str_result=True)
-else:
- from_json = False
- to_json = False
- to_kml = False
+# GeoJSON routines.
+from_json = geom_output(lgdal.OGR_G_CreateGeometryFromJson, [c_char_p])
+to_json = string_output(lgdal.OGR_G_ExportToJson, [c_void_p], str_result=True)
+to_kml = string_output(lgdal.OGR_G_ExportToKML, [c_void_p, c_char_p], str_result=True)
# GetX, GetY, GetZ all return doubles.
getx = pnt_func(lgdal.OGR_G_GetX)
diff --git a/django/contrib/gis/gdal/srs.py b/django/contrib/gis/gdal/srs.py
index 67049731de..cdeaaca690 100644
--- a/django/contrib/gis/gdal/srs.py
+++ b/django/contrib/gis/gdal/srs.py
@@ -33,11 +33,13 @@ from django.contrib.gis.gdal.base import GDALBase
from django.contrib.gis.gdal.error import SRSException
from django.contrib.gis.gdal.prototypes import srs as capi
+from django.utils import six
+
#### Spatial Reference class. ####
class SpatialReference(GDALBase):
"""
A wrapper for the OGRSpatialReference object. According to the GDAL Web site,
- the SpatialReference object "provide[s] services to represent coordinate
+ the SpatialReference object "provide[s] services to represent coordinate
systems (projections and datums) and to transform between them."
"""
@@ -45,16 +47,16 @@ class SpatialReference(GDALBase):
def __init__(self, srs_input=''):
"""
Creates a GDAL OSR Spatial Reference object from the given input.
- The input may be string of OGC Well Known Text (WKT), an integer
- EPSG code, a PROJ.4 string, and/or a projection "well known" shorthand
+ The input may be string of OGC Well Known Text (WKT), an integer
+ EPSG code, a PROJ.4 string, and/or a projection "well known" shorthand
string (one of 'WGS84', 'WGS72', 'NAD27', 'NAD83').
"""
buf = c_char_p('')
srs_type = 'user'
- if isinstance(srs_input, basestring):
+ if isinstance(srs_input, six.string_types):
# Encoding to ASCII if unicode passed in.
- if isinstance(srs_input, unicode):
+ if isinstance(srs_input, six.text_type):
srs_input = srs_input.encode('ascii')
try:
# If SRID is a string, e.g., '4326', then make acceptable
@@ -63,7 +65,7 @@ class SpatialReference(GDALBase):
srs_input = 'EPSG:%d' % srid
except ValueError:
pass
- elif isinstance(srs_input, (int, long)):
+ elif isinstance(srs_input, six.integer_types):
# EPSG integer code was input.
srs_type = 'epsg'
elif isinstance(srs_input, self.ptr_type):
@@ -97,8 +99,8 @@ class SpatialReference(GDALBase):
def __getitem__(self, target):
"""
- Returns the value of the given string attribute node, None if the node
- doesn't exist. Can also take a tuple as a parameter, (target, child),
+ Returns the value of the given string attribute node, None if the node
+ doesn't exist. Can also take a tuple as a parameter, (target, child),
where child is the index of the attribute in the WKT. For example:
>>> wkt = 'GEOGCS["WGS 84", DATUM["WGS_1984, ... AUTHORITY["EPSG","4326"]]')
@@ -133,14 +135,14 @@ class SpatialReference(GDALBase):
The attribute value for the given target node (e.g. 'PROJCS'). The index
keyword specifies an index of the child node to return.
"""
- if not isinstance(target, basestring) or not isinstance(index, int):
+ if not isinstance(target, six.string_types) or not isinstance(index, int):
raise TypeError
return capi.get_attr_value(self.ptr, target, index)
def auth_name(self, target):
"Returns the authority name for the given string target node."
return capi.get_auth_name(self.ptr, target)
-
+
def auth_code(self, target):
"Returns the authority code for the given string target node."
return capi.get_auth_code(self.ptr, target)
@@ -167,7 +169,7 @@ class SpatialReference(GDALBase):
def validate(self):
"Checks to see if the given spatial reference is valid."
capi.srs_validate(self.ptr)
-
+
#### Name & SRID properties ####
@property
def name(self):
@@ -184,7 +186,7 @@ class SpatialReference(GDALBase):
return int(self.attr_value('AUTHORITY', 1))
except (TypeError, ValueError):
return None
-
+
#### Unit Properties ####
@property
def linear_name(self):
@@ -213,7 +215,7 @@ class SpatialReference(GDALBase):
@property
def units(self):
"""
- Returns a 2-tuple of the units value and the units name,
+ Returns a 2-tuple of the units value and the units name,
and will automatically determines whether to return the linear
or angular units.
"""
@@ -252,7 +254,7 @@ class SpatialReference(GDALBase):
@property
def geographic(self):
"""
- Returns True if this SpatialReference is geographic
+ Returns True if this SpatialReference is geographic
(root node is GEOGCS).
"""
return bool(capi.isgeographic(self.ptr))
@@ -265,7 +267,7 @@ class SpatialReference(GDALBase):
@property
def projected(self):
"""
- Returns True if this SpatialReference is a projected coordinate system
+ Returns True if this SpatialReference is a projected coordinate system
(root node is PROJCS).
"""
return bool(capi.isprojected(self.ptr))
diff --git a/django/contrib/gis/gdal/tests/__init__.py b/django/contrib/gis/gdal/tests/__init__.py
index eb72a38775..262d294a43 100644
--- a/django/contrib/gis/gdal/tests/__init__.py
+++ b/django/contrib/gis/gdal/tests/__init__.py
@@ -19,7 +19,8 @@ test_suites = [test_driver.suite(),
def suite():
"Builds a test suite for the GDAL tests."
s = TestSuite()
- map(s.addTest, test_suites)
+ for test_suite in test_suites:
+ s.addTest(test_suite)
return s
def run(verbosity=1):
diff --git a/django/contrib/gis/gdal/tests/test_envelope.py b/django/contrib/gis/gdal/tests/test_envelope.py
index 7574284bba..07e12c0ca7 100644
--- a/django/contrib/gis/gdal/tests/test_envelope.py
+++ b/django/contrib/gis/gdal/tests/test_envelope.py
@@ -23,7 +23,7 @@ class EnvelopeTest(unittest.TestCase):
self.assertRaises(OGRException, Envelope, (0, 0, 5, 5, 3))
self.assertRaises(OGRException, Envelope, ())
self.assertRaises(ValueError, Envelope, 0, 'a', 5, 5)
- self.assertRaises(TypeError, Envelope, u'foo')
+ self.assertRaises(TypeError, Envelope, 'foo')
self.assertRaises(OGRException, Envelope, (1, 1, 0, 0))
try:
Envelope(0, 0, 0, 0)
diff --git a/django/contrib/gis/gdal/tests/test_geom.py b/django/contrib/gis/gdal/tests/test_geom.py
index b68aa41b0a..a0b2593605 100644
--- a/django/contrib/gis/gdal/tests/test_geom.py
+++ b/django/contrib/gis/gdal/tests/test_geom.py
@@ -1,13 +1,13 @@
from binascii import b2a_hex
try:
- import cPickle as pickle
+ from django.utils.six.moves import cPickle as pickle
except ImportError:
import pickle
from django.contrib.gis.gdal import (OGRGeometry, OGRGeomType, OGRException,
OGRIndexError, SpatialReference, CoordTransform, GDAL_VERSION)
-from django.contrib.gis.gdal.prototypes.geom import GEOJSON
from django.contrib.gis.geometry.test_data import TestDataMixin
+from django.utils.six.moves import xrange
from django.utils import unittest
class OGRGeomTest(unittest.TestCase, TestDataMixin):
@@ -108,7 +108,6 @@ class OGRGeomTest(unittest.TestCase, TestDataMixin):
def test01e_json(self):
"Testing GeoJSON input/output."
- if not GEOJSON: return
for g in self.geometries.json_geoms:
geom = OGRGeometry(g.wkt)
if not hasattr(g, 'not_equal'):
@@ -244,9 +243,6 @@ class OGRGeomTest(unittest.TestCase, TestDataMixin):
self.fail('Should have raised an OGRException!')
print("\nEND - expecting IllegalArgumentException; safe to ignore.\n")
- # Closing the rings -- doesn't work on GDAL versions 1.4.1 and below:
- # http://trac.osgeo.org/gdal/ticket/1673
- if GDAL_VERSION <= (1, 4, 1): return
poly.close_rings()
self.assertEqual(10, poly.point_count) # Two closing points should've been added
self.assertEqual(OGRGeometry('POINT(2.5 2.5)'), poly.centroid)
diff --git a/django/contrib/gis/geoip/base.py b/django/contrib/gis/geoip/base.py
index e00e0a4d93..944240c811 100644
--- a/django/contrib/gis/geoip/base.py
+++ b/django/contrib/gis/geoip/base.py
@@ -10,6 +10,8 @@ from django.contrib.gis.geoip.prototypes import (
GeoIP_country_code_by_addr, GeoIP_country_code_by_name,
GeoIP_country_name_by_addr, GeoIP_country_name_by_name)
+from django.utils import six
+
# Regular expressions for recognizing the GeoIP free database editions.
free_regex = re.compile(r'^GEO-\d{3}FREE')
lite_regex = re.compile(r'^GEO-\d{3}LITE')
@@ -86,7 +88,7 @@ class GeoIP(object):
if not path:
path = GEOIP_SETTINGS.get('GEOIP_PATH', None)
if not path: raise GeoIPException('GeoIP path must be provided via parameter or the GEOIP_PATH setting.')
- if not isinstance(path, basestring):
+ if not isinstance(path, six.string_types):
raise TypeError('Invalid path type: %s' % type(path).__name__)
if os.path.isdir(path):
@@ -129,7 +131,7 @@ class GeoIP(object):
def _check_query(self, query, country=False, city=False, city_or_country=False):
"Helper routine for checking the query and database availability."
# Making sure a string was passed in for the query.
- if not isinstance(query, basestring):
+ if not isinstance(query, six.string_types):
raise TypeError('GeoIP query must be a string, not type %s' % type(query).__name__)
# GeoIP only takes ASCII-encoded strings.
diff --git a/django/contrib/gis/geoip/tests.py b/django/contrib/gis/geoip/tests.py
index a629d86bbf..e53230d9ad 100644
--- a/django/contrib/gis/geoip/tests.py
+++ b/django/contrib/gis/geoip/tests.py
@@ -1,9 +1,13 @@
+from __future__ import unicode_literals
+
import os
from django.conf import settings
from django.contrib.gis.geos import GEOSGeometry
from django.contrib.gis.geoip import GeoIP, GeoIPException
from django.utils import unittest
+from django.utils import six
+
# Note: Requires use of both the GeoIP country and city datasets.
# The GEOIP_DATA path should be the only setting set (the directory
# should contain links or the actual database files 'GeoIP.dat' and
@@ -33,7 +37,7 @@ class GeoIPTest(unittest.TestCase):
bad_params = (23, 'foo', 15.23)
for bad in bad_params:
self.assertRaises(GeoIPException, GeoIP, cache=bad)
- if isinstance(bad, basestring):
+ if isinstance(bad, six.string_types):
e = GeoIPException
else:
e = TypeError
@@ -99,13 +103,13 @@ class GeoIPTest(unittest.TestCase):
"Testing that GeoIP strings are properly encoded, see #16553."
g = GeoIP()
d = g.city('62.224.93.23')
- self.assertEqual(u'Sch\xf6mberg', d['city'])
+ self.assertEqual('Schümberg', d['city'])
def test06_unicode_query(self):
"Testing that GeoIP accepts unicode string queries, see #17059."
g = GeoIP()
- d = g.country(u'whitehouse.gov')
- self.assertEqual(u'US', d['country_code'])
+ d = g.country('whitehouse.gov')
+ self.assertEqual('US', d['country_code'])
def suite():
diff --git a/django/contrib/gis/geometry/test_data.py b/django/contrib/gis/geometry/test_data.py
index f92740248e..505f0e4f4b 100644
--- a/django/contrib/gis/geometry/test_data.py
+++ b/django/contrib/gis/geometry/test_data.py
@@ -7,6 +7,7 @@ import json
import os
from django.contrib import gis
+from django.utils import six
# This global used to store reference geometry data.
@@ -25,7 +26,7 @@ def tuplize(seq):
def strconvert(d):
"Converts all keys in dictionary to str type."
- return dict([(str(k), v) for k, v in d.iteritems()])
+ return dict([(str(k), v) for k, v in six.iteritems(d)])
def get_ds_file(name, ext):
diff --git a/django/contrib/gis/geos/base.py b/django/contrib/gis/geos/base.py
index 754bcce7ad..fd2693ed59 100644
--- a/django/contrib/gis/geos/base.py
+++ b/django/contrib/gis/geos/base.py
@@ -10,7 +10,6 @@ except ImportError:
# A 'dummy' gdal module.
class GDALInfo(object):
HAS_GDAL = False
- GEOJSON = False
gdal = GDALInfo()
# NumPy supported?
diff --git a/django/contrib/gis/geos/collections.py b/django/contrib/gis/geos/collections.py
index 8b0edf5985..2b62bce22c 100644
--- a/django/contrib/gis/geos/collections.py
+++ b/django/contrib/gis/geos/collections.py
@@ -10,6 +10,7 @@ from django.contrib.gis.geos.linestring import LineString, LinearRing
from django.contrib.gis.geos.point import Point
from django.contrib.gis.geos.polygon import Polygon
from django.contrib.gis.geos import prototypes as capi
+from django.utils.six.moves import xrange
class GeometryCollection(GEOSGeometry):
_typeid = 7
@@ -100,11 +101,11 @@ class MultiLineString(GeometryCollection):
@property
def merged(self):
- """
- Returns a LineString representing the line merge of this
+ """
+ Returns a LineString representing the line merge of this
MultiLineString.
- """
- return self._topology(capi.geos_linemerge(self.ptr))
+ """
+ return self._topology(capi.geos_linemerge(self.ptr))
class MultiPolygon(GeometryCollection):
_allowed = Polygon
diff --git a/django/contrib/gis/geos/coordseq.py b/django/contrib/gis/geos/coordseq.py
index 027d34e740..acf34f7262 100644
--- a/django/contrib/gis/geos/coordseq.py
+++ b/django/contrib/gis/geos/coordseq.py
@@ -8,6 +8,7 @@ from django.contrib.gis.geos.base import GEOSBase, numpy
from django.contrib.gis.geos.error import GEOSException, GEOSIndexError
from django.contrib.gis.geos.libgeos import CS_PTR
from django.contrib.gis.geos import prototypes as capi
+from django.utils.six.moves import xrange
class GEOSCoordSeq(GEOSBase):
"The internal representation of a list of coordinates inside a Geometry."
diff --git a/django/contrib/gis/geos/factory.py b/django/contrib/gis/geos/factory.py
index ee33f14d19..fbd7d5a3e9 100644
--- a/django/contrib/gis/geos/factory.py
+++ b/django/contrib/gis/geos/factory.py
@@ -1,12 +1,14 @@
from django.contrib.gis.geos.geometry import GEOSGeometry, wkt_regex, hex_regex
+from django.utils import six
+
def fromfile(file_h):
"""
Given a string file name, returns a GEOSGeometry. The file may contain WKB,
WKT, or HEX.
"""
# If given a file name, get a real handle.
- if isinstance(file_h, basestring):
+ if isinstance(file_h, six.string_types):
with open(file_h, 'rb') as file_h:
buf = file_h.read()
else:
diff --git a/django/contrib/gis/geos/geometry.py b/django/contrib/gis/geos/geometry.py
index f411d5a353..4e5409de1d 100644
--- a/django/contrib/gis/geos/geometry.py
+++ b/django/contrib/gis/geos/geometry.py
@@ -27,6 +27,8 @@ from django.contrib.gis.geos.prototypes.io import wkt_r, wkt_w, wkb_r, wkb_w, ew
# For recognizing geometry input.
from django.contrib.gis.geometry.regex import hex_regex, wkt_regex, json_regex
+from django.utils import six
+
class GEOSGeometry(GEOSBase, ListMixin):
"A class that, generally, encapsulates a GEOS geometry."
@@ -52,8 +54,8 @@ class GEOSGeometry(GEOSBase, ListMixin):
The `srid` keyword is used to specify the Source Reference Identifier
(SRID) number for this Geometry. If not set, the SRID will be None.
"""
- if isinstance(geo_input, basestring):
- if isinstance(geo_input, unicode):
+ if isinstance(geo_input, six.string_types):
+ if isinstance(geo_input, six.text_type):
# Encoding to ASCII, WKT or HEXEWKB doesn't need any more.
geo_input = geo_input.encode('ascii')
@@ -65,7 +67,7 @@ class GEOSGeometry(GEOSBase, ListMixin):
elif hex_regex.match(geo_input):
# Handling HEXEWKB input.
g = wkb_r().read(geo_input)
- elif gdal.GEOJSON and json_regex.match(geo_input):
+ elif gdal.HAS_GDAL and json_regex.match(geo_input):
# Handling GeoJSON input.
g = wkb_r().read(gdal.OGRGeometry(geo_input).wkb)
else:
@@ -153,7 +155,7 @@ class GEOSGeometry(GEOSBase, ListMixin):
Equivalence testing, a Geometry may be compared with another Geometry
or a WKT representation.
"""
- if isinstance(other, basestring):
+ if isinstance(other, six.string_types):
return self.wkt == other
elif isinstance(other, GEOSGeometry):
return self.equals_exact(other)
@@ -333,7 +335,7 @@ class GEOSGeometry(GEOSBase, ListMixin):
Returns true if the elements in the DE-9IM intersection matrix for the
two Geometries match the elements in pattern.
"""
- if not isinstance(pattern, basestring) or len(pattern) > 9:
+ if not isinstance(pattern, six.string_types) or len(pattern) > 9:
raise GEOSException('invalid intersection matrix pattern')
return capi.geos_relatepattern(self.ptr, other.ptr, pattern)
@@ -409,13 +411,12 @@ class GEOSGeometry(GEOSBase, ListMixin):
@property
def json(self):
"""
- Returns GeoJSON representation of this Geometry if GDAL 1.5+
- is installed.
+ Returns GeoJSON representation of this Geometry if GDAL is installed.
"""
- if gdal.GEOJSON:
+ if gdal.HAS_GDAL:
return self.ogr.json
else:
- raise GEOSException('GeoJSON output only supported on GDAL 1.5+.')
+ raise GEOSException('GeoJSON output only supported when GDAL is installed.')
geojson = json
@property
diff --git a/django/contrib/gis/geos/linestring.py b/django/contrib/gis/geos/linestring.py
index ecf774145e..4784ea7c2d 100644
--- a/django/contrib/gis/geos/linestring.py
+++ b/django/contrib/gis/geos/linestring.py
@@ -4,6 +4,7 @@ from django.contrib.gis.geos.error import GEOSException
from django.contrib.gis.geos.geometry import GEOSGeometry
from django.contrib.gis.geos.point import Point
from django.contrib.gis.geos import prototypes as capi
+from django.utils.six.moves import xrange
class LineString(GEOSGeometry):
_init_func = capi.create_linestring
@@ -128,7 +129,7 @@ class LineString(GEOSGeometry):
@property
def merged(self):
"Returns the line merge of this LineString."
- return self._topology(capi.geos_linemerge(self.ptr))
+ return self._topology(capi.geos_linemerge(self.ptr))
@property
def x(self):
diff --git a/django/contrib/gis/geos/mutable_list.py b/django/contrib/gis/geos/mutable_list.py
index 1a9dcf0b5b..69e50e6b3f 100644
--- a/django/contrib/gis/geos/mutable_list.py
+++ b/django/contrib/gis/geos/mutable_list.py
@@ -9,6 +9,8 @@ See also http://www.aryehleib.com/MutableLists.html
Author: Aryeh Leib Taurog.
"""
from django.utils.functional import total_ordering
+from django.utils import six
+from django.utils.six.moves import xrange
@total_ordering
class ListMixin(object):
@@ -82,12 +84,12 @@ class ListMixin(object):
def __delitem__(self, index):
"Delete the item(s) at the specified index/slice."
- if not isinstance(index, (int, long, slice)):
+ if not isinstance(index, six.integer_types + (slice,)):
raise TypeError("%s is not a legal index" % index)
# calculate new length and dimensions
origLen = len(self)
- if isinstance(index, (int, long)):
+ if isinstance(index, six.integer_types):
index = self._checkindex(index)
indexRange = [index]
else:
@@ -195,7 +197,7 @@ class ListMixin(object):
def insert(self, index, val):
"Standard list insert method"
- if not isinstance(index, (int, long)):
+ if not isinstance(index, six.integer_types):
raise TypeError("%s is not a legal index" % index)
self[index:index] = [val]
diff --git a/django/contrib/gis/geos/point.py b/django/contrib/gis/geos/point.py
index b126856ba3..907347dbf8 100644
--- a/django/contrib/gis/geos/point.py
+++ b/django/contrib/gis/geos/point.py
@@ -2,6 +2,8 @@ from ctypes import c_uint
from django.contrib.gis.geos.error import GEOSException
from django.contrib.gis.geos.geometry import GEOSGeometry
from django.contrib.gis.geos import prototypes as capi
+from django.utils import six
+from django.utils.six.moves import xrange
class Point(GEOSGeometry):
_minlength = 2
@@ -20,9 +22,9 @@ class Point(GEOSGeometry):
# Here a tuple or list was passed in under the `x` parameter.
ndim = len(x)
coords = x
- elif isinstance(x, (int, float, long)) and isinstance(y, (int, float, long)):
+ elif isinstance(x, six.integer_types + (float,)) and isinstance(y, six.integer_types + (float,)):
# Here X, Y, and (optionally) Z were passed in individually, as parameters.
- if isinstance(z, (int, float, long)):
+ if isinstance(z, six.integer_types + (float,)):
ndim = 3
coords = [x, y, z]
else:
diff --git a/django/contrib/gis/geos/polygon.py b/django/contrib/gis/geos/polygon.py
index 77ce60cf16..c50f549e7a 100644
--- a/django/contrib/gis/geos/polygon.py
+++ b/django/contrib/gis/geos/polygon.py
@@ -3,6 +3,8 @@ from django.contrib.gis.geos.geometry import GEOSGeometry
from django.contrib.gis.geos.libgeos import get_pointer_arr, GEOM_PTR
from django.contrib.gis.geos.linestring import LinearRing
from django.contrib.gis.geos import prototypes as capi
+from django.utils import six
+from django.utils.six.moves import xrange
class Polygon(GEOSGeometry):
_minlength = 1
@@ -55,8 +57,11 @@ class Polygon(GEOSGeometry):
def from_bbox(cls, bbox):
"Constructs a Polygon from a bounding box (4-tuple)."
x0, y0, x1, y1 = bbox
- return GEOSGeometry( 'POLYGON((%s %s, %s %s, %s %s, %s %s, %s %s))' % (
- x0, y0, x0, y1, x1, y1, x1, y0, x0, y0) )
+ for z in bbox:
+ if not isinstance(z, six.integer_types + (float,)):
+ return GEOSGeometry('POLYGON((%s %s, %s %s, %s %s, %s %s, %s %s))' %
+ (x0, y0, x0, y1, x1, y1, x1, y0, x0, y0))
+ return Polygon(((x0, y0), (x0, y1), (x1, y1), (x1, y0), (x0, y0)))
### These routines are needed for list-like operation w/ListMixin ###
def _create_polygon(self, length, items):
diff --git a/django/contrib/gis/geos/prototypes/io.py b/django/contrib/gis/geos/prototypes/io.py
index 56f702243d..053b9948a2 100644
--- a/django/contrib/gis/geos/prototypes/io.py
+++ b/django/contrib/gis/geos/prototypes/io.py
@@ -6,6 +6,8 @@ from django.contrib.gis.geos.prototypes.errcheck import check_geom, check_string
from django.contrib.gis.geos.prototypes.geom import c_uchar_p, geos_char_p
from django.contrib.gis.geos.prototypes.threadsafe import GEOSFunc
+from django.utils import six
+
### The WKB/WKT Reader/Writer structures and pointers ###
class WKTReader_st(Structure): pass
class WKTWriter_st(Structure): pass
@@ -118,7 +120,7 @@ class _WKTReader(IOBase):
ptr_type = WKT_READ_PTR
def read(self, wkt):
- if not isinstance(wkt, basestring): raise TypeError
+ if not isinstance(wkt, six.string_types): raise TypeError
return wkt_reader_read(self.ptr, wkt)
class _WKBReader(IOBase):
@@ -131,7 +133,7 @@ class _WKBReader(IOBase):
if isinstance(wkb, buffer):
wkb_s = str(wkb)
return wkb_reader_read(self.ptr, wkb_s, len(wkb_s))
- elif isinstance(wkb, basestring):
+ elif isinstance(wkb, six.string_types):
return wkb_reader_read_hex(self.ptr, wkb, len(wkb))
else:
raise TypeError
@@ -195,7 +197,7 @@ class WKBWriter(IOBase):
# `ThreadLocalIO` object holds instances of the WKT and WKB reader/writer
# objects that are local to the thread. The `GEOSGeometry` internals
# access these instances by calling the module-level functions, defined
-# below.
+# below.
class ThreadLocalIO(threading.local):
wkt_r = None
wkt_w = None
diff --git a/django/contrib/gis/geos/prototypes/misc.py b/django/contrib/gis/geos/prototypes/misc.py
index fd4f78a011..5a9b5555ad 100644
--- a/django/contrib/gis/geos/prototypes/misc.py
+++ b/django/contrib/gis/geos/prototypes/misc.py
@@ -7,6 +7,7 @@ from django.contrib.gis.geos.libgeos import GEOM_PTR, GEOS_PREPARE
from django.contrib.gis.geos.prototypes.errcheck import check_dbl, check_string
from django.contrib.gis.geos.prototypes.geom import geos_char_p
from django.contrib.gis.geos.prototypes.threadsafe import GEOSFunc
+from django.utils.six.moves import xrange
__all__ = ['geos_area', 'geos_distance', 'geos_length']
diff --git a/django/contrib/gis/geos/tests/test_geos.py b/django/contrib/gis/geos/tests/test_geos.py
index 9946495f54..d621c6b4d4 100644
--- a/django/contrib/gis/geos/tests/test_geos.py
+++ b/django/contrib/gis/geos/tests/test_geos.py
@@ -1,6 +1,5 @@
import ctypes
import random
-import unittest
from django.contrib.gis.geos import (GEOSException, GEOSIndexError, GEOSGeometry,
GeometryCollection, Point, MultiPoint, Polygon, MultiPolygon, LinearRing,
@@ -9,6 +8,10 @@ from django.contrib.gis.geos.base import gdal, numpy, GEOSBase
from django.contrib.gis.geos.libgeos import GEOS_PREPARE
from django.contrib.gis.geometry.test_data import TestDataMixin
+from django.utils import six
+from django.utils.six.moves import xrange
+from django.utils import unittest
+
class GEOSTest(unittest.TestCase, TestDataMixin):
@@ -195,9 +198,9 @@ class GEOSTest(unittest.TestCase, TestDataMixin):
self.assertEqual(srid, poly.shell.srid)
self.assertEqual(srid, fromstr(poly.ewkt).srid) # Checking export
+ @unittest.skipUnless(gdal.HAS_GDAL, "gdal is required")
def test_json(self):
"Testing GeoJSON input/output (via GDAL)."
- if not gdal or not gdal.GEOJSON: return
for g in self.geometries.json_geoms:
geom = GEOSGeometry(g.wkt)
if not hasattr(g, 'not_equal'):
@@ -383,6 +386,13 @@ class GEOSTest(unittest.TestCase, TestDataMixin):
p = Polygon.from_bbox(bbox)
self.assertEqual(bbox, p.extent)
+ # Testing numerical precision
+ x = 3.14159265358979323
+ bbox = (0, 0, 1, x)
+ p = Polygon.from_bbox(bbox)
+ y = p.extent[-1]
+ self.assertEqual(format(x, '.13f'), format(y, '.13f'))
+
def test_polygons(self):
"Testing Polygon objects."
@@ -813,9 +823,9 @@ class GEOSTest(unittest.TestCase, TestDataMixin):
# And, they should be equal.
self.assertEqual(gc1, gc2)
+ @unittest.skipUnless(gdal.HAS_GDAL, "gdal is required")
def test_gdal(self):
"Testing `ogr` and `srs` properties."
- if not gdal.HAS_GDAL: return
g1 = fromstr('POINT(5 23)')
self.assertEqual(True, isinstance(g1.ogr, gdal.OGRGeometry))
self.assertEqual(g1.srs, None)
@@ -835,9 +845,9 @@ class GEOSTest(unittest.TestCase, TestDataMixin):
self.assertNotEqual(poly._ptr, cpy1._ptr)
self.assertNotEqual(poly._ptr, cpy2._ptr)
+ @unittest.skipUnless(gdal.HAS_GDAL, "gdal is required")
def test_transform(self):
"Testing `transform` method."
- if not gdal.HAS_GDAL: return
orig = GEOSGeometry('POINT (-104.609 38.255)', 4326)
trans = GEOSGeometry('POINT (992385.4472045 481455.4944650)', 2774)
@@ -943,7 +953,8 @@ class GEOSTest(unittest.TestCase, TestDataMixin):
def test_pickle(self):
"Testing pickling and unpickling support."
# Using both pickle and cPickle -- just 'cause.
- import pickle, cPickle
+ from django.utils.six.moves import cPickle
+ import pickle
# Creating a list of test geometries for pickling,
# and setting the SRID on some of them.
@@ -963,9 +974,9 @@ class GEOSTest(unittest.TestCase, TestDataMixin):
self.assertEqual(geom, tmpg)
if not no_srid: self.assertEqual(geom.srid, tmpg.srid)
+ @unittest.skipUnless(GEOS_PREPARE, "geos >= 3.1.0 is required")
def test_prepared(self):
"Testing PreparedGeometry support."
- if not GEOS_PREPARE: return
# Creating a simple multipolygon and getting a prepared version.
mpoly = GEOSGeometry('MULTIPOLYGON(((0 0,0 5,5 5,5 0,0 0)),((5 5,5 10,10 10,10 5,5 5)))')
prep = mpoly.prepared
@@ -990,14 +1001,13 @@ class GEOSTest(unittest.TestCase, TestDataMixin):
for geom, merged in zip(ref_geoms, ref_merged):
self.assertEqual(merged, geom.merged)
+ @unittest.skipUnless(GEOS_PREPARE, "geos >= 3.1.0 is required")
def test_valid_reason(self):
"Testing IsValidReason support"
- # Skipping tests if GEOS < v3.1.
- if not GEOS_PREPARE: return
g = GEOSGeometry("POINT(0 0)")
self.assertTrue(g.valid)
- self.assertTrue(isinstance(g.valid_reason, basestring))
+ self.assertTrue(isinstance(g.valid_reason, six.string_types))
self.assertEqual(g.valid_reason, "Valid Geometry")
print("\nBEGIN - expecting GEOS_NOTICE; safe to ignore.\n")
@@ -1005,7 +1015,7 @@ class GEOSTest(unittest.TestCase, TestDataMixin):
g = GEOSGeometry("LINESTRING(0 0, 0 0)")
self.assertTrue(not g.valid)
- self.assertTrue(isinstance(g.valid_reason, basestring))
+ self.assertTrue(isinstance(g.valid_reason, six.string_types))
self.assertTrue(g.valid_reason.startswith("Too few points in geometry component"))
print("\nEND - expecting GEOS_NOTICE; safe to ignore.\n")
diff --git a/django/contrib/gis/geos/tests/test_io.py b/django/contrib/gis/geos/tests/test_io.py
index 50c36684a0..ebf178a807 100644
--- a/django/contrib/gis/geos/tests/test_io.py
+++ b/django/contrib/gis/geos/tests/test_io.py
@@ -1,6 +1,7 @@
import binascii
import unittest
from django.contrib.gis.geos import GEOSGeometry, WKTReader, WKTWriter, WKBReader, WKBWriter, geos_version_info
+from django.utils import six
class GEOSIOTest(unittest.TestCase):
@@ -12,12 +13,12 @@ class GEOSIOTest(unittest.TestCase):
# read() should return a GEOSGeometry
ref = GEOSGeometry(wkt)
g1 = wkt_r.read(wkt)
- g2 = wkt_r.read(unicode(wkt))
+ g2 = wkt_r.read(six.text_type(wkt))
for geom in (g1, g2):
self.assertEqual(ref, geom)
- # Should only accept basestring objects.
+ # Should only accept six.string_types objects.
self.assertRaises(TypeError, wkt_r.read, 1)
self.assertRaises(TypeError, wkt_r.read, buffer('foo'))
@@ -48,7 +49,7 @@ class GEOSIOTest(unittest.TestCase):
bad_input = (1, 5.23, None, False)
for bad_wkb in bad_input:
self.assertRaises(TypeError, wkb_r.read, bad_wkb)
-
+
def test04_wkbwriter(self):
wkb_w = WKBWriter()
@@ -67,7 +68,7 @@ class GEOSIOTest(unittest.TestCase):
for bad_byteorder in (-1, 2, 523, 'foo', None):
# Equivalent of `wkb_w.byteorder = bad_byteorder`
self.assertRaises(ValueError, wkb_w._set_byteorder, bad_byteorder)
-
+
# Setting the byteorder to 0 (for Big Endian)
wkb_w.byteorder = 0
self.assertEqual(hex2, wkb_w.write_hex(g))
@@ -79,7 +80,7 @@ class GEOSIOTest(unittest.TestCase):
# Now, trying out the 3D and SRID flags.
g = GEOSGeometry('POINT (5 23 17)')
g.srid = 4326
-
+
hex3d = '0101000080000000000000144000000000000037400000000000003140'
wkb3d = buffer(binascii.a2b_hex(hex3d))
hex3d_srid = '01010000A0E6100000000000000000144000000000000037400000000000003140'
diff --git a/django/contrib/gis/geos/tests/test_mutable_list.py b/django/contrib/gis/geos/tests/test_mutable_list.py
index 3e63a25e95..cd174d7cfa 100644
--- a/django/contrib/gis/geos/tests/test_mutable_list.py
+++ b/django/contrib/gis/geos/tests/test_mutable_list.py
@@ -4,6 +4,7 @@
# Modified from original contribution by Aryeh Leib Taurog, which was
# released under the New BSD license.
from django.contrib.gis.geos.mutable_list import ListMixin
+from django.utils import six
from django.utils import unittest
@@ -267,7 +268,7 @@ class ListMixinTest(unittest.TestCase):
def test07_allowed_types(self):
'Type-restricted list'
pl, ul = self.lists_of_len()
- ul._allowed = (int, long)
+ ul._allowed = six.integer_types
ul[1] = 50
ul[:2] = [60, 70, 80]
def setfcn(x, i, v): x[i] = v
diff --git a/django/contrib/gis/maps/google/gmap.py b/django/contrib/gis/maps/google/gmap.py
index f0e8d73399..75b285ca76 100644
--- a/django/contrib/gis/maps/google/gmap.py
+++ b/django/contrib/gis/maps/google/gmap.py
@@ -1,6 +1,8 @@
from django.conf import settings
from django.template.loader import render_to_string
+from django.utils.html import format_html
from django.utils.safestring import mark_safe
+from django.utils.six.moves import xrange
from django.contrib.gis.maps.google.overlays import GPolygon, GPolyline, GMarker
@@ -10,7 +12,7 @@ class GoogleMapException(Exception):
# The default Google Maps URL (for the API javascript)
# TODO: Internationalize for Japan, UK, etc.
-GOOGLE_MAPS_URL='http://maps.google.com/maps?file=api&v=%s&key='
+GOOGLE_MAPS_URL='http://maps.google.com/maps?file=api&v=%s&key='
class GoogleMap(object):
@@ -48,7 +50,7 @@ class GoogleMap(object):
# Can specify the API URL in the `api_url` keyword.
if not api_url:
- self.api_url = mark_safe(getattr(settings, 'GOOGLE_MAPS_URL', GOOGLE_MAPS_URL) % self.version)
+ self.api_url = getattr(settings, 'GOOGLE_MAPS_URL', GOOGLE_MAPS_URL) % self.version
else:
self.api_url = api_url
@@ -111,17 +113,18 @@ class GoogleMap(object):
@property
def body(self):
"Returns HTML body tag for loading and unloading Google Maps javascript."
- return mark_safe('' % (self.onload, self.onunload))
+ return format_html('', self.onload, self.onunload)
@property
def onload(self):
"Returns the `onload` HTML attribute."
- return mark_safe('onload="%s.%s_load()"' % (self.js_module, self.dom_id))
+ return format_html('onload="{0}.{1}_load()"', self.js_module, self.dom_id)
@property
def api_script(self):
"Returns the ' % (self.api_url, self.key))
+ return format_html('',
+ self.api_url, self.key)
@property
def js(self):
@@ -131,17 +134,17 @@ class GoogleMap(object):
@property
def scripts(self):
"Returns all tags required with Google Maps JavaScript."
- return mark_safe('%s\n ' % (self.api_script, self.js))
+ return format_html('%s\n ', self.api_script, mark_safe(self.js))
@property
def style(self):
"Returns additional CSS styling needed for Google Maps on IE."
- return mark_safe('' % self.vml_css)
+ return format_html('', self.vml_css)
@property
def xhtml(self):
"Returns XHTML information needed for IE VML overlays."
- return mark_safe('' % self.xmlns)
+ return format_html('', self.xmlns)
@property
def icons(self):
diff --git a/django/contrib/gis/maps/google/overlays.py b/django/contrib/gis/maps/google/overlays.py
index eaf12dad6d..b82d967da6 100644
--- a/django/contrib/gis/maps/google/overlays.py
+++ b/django/contrib/gis/maps/google/overlays.py
@@ -1,8 +1,11 @@
from django.contrib.gis.geos import fromstr, Point, LineString, LinearRing, Polygon
from django.utils.functional import total_ordering
from django.utils.safestring import mark_safe
+from django.utils import six
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class GEvent(object):
"""
A Python wrapper for the Google GEvent object.
@@ -47,10 +50,11 @@ class GEvent(object):
self.event = event
self.action = action
- def __unicode__(self):
+ def __str__(self):
"Returns the parameter part of a GEvent."
return mark_safe('"%s", %s' %(self.event, self.action))
+@python_2_unicode_compatible
class GOverlayBase(object):
def __init__(self):
self.events = []
@@ -63,7 +67,7 @@ class GOverlayBase(object):
"Attaches a GEvent to the overlay object."
self.events.append(event)
- def __unicode__(self):
+ def __str__(self):
"The string representation is the JavaScript API call."
return mark_safe('%s(%s)' % (self.__class__.__name__, self.js_params))
@@ -98,7 +102,7 @@ class GPolygon(GOverlayBase):
fill_opacity:
The opacity of the polygon fill. Defaults to 0.4.
"""
- if isinstance(poly, basestring): poly = fromstr(poly)
+ if isinstance(poly, six.string_types): poly = fromstr(poly)
if isinstance(poly, (tuple, list)): poly = Polygon(poly)
if not isinstance(poly, Polygon):
raise TypeError('GPolygon may only initialize on GEOS Polygons.')
@@ -148,7 +152,7 @@ class GPolyline(GOverlayBase):
The opacity of the polyline, between 0 and 1. Defaults to 1.
"""
# If a GEOS geometry isn't passed in, try to contsruct one.
- if isinstance(geom, basestring): geom = fromstr(geom)
+ if isinstance(geom, six.string_types): geom = fromstr(geom)
if isinstance(geom, (tuple, list)): geom = Polygon(geom)
# Generating the lat/lng coordinate pairs.
if isinstance(geom, (LineString, LinearRing)):
@@ -239,9 +243,9 @@ class GIcon(object):
def __lt__(self, other):
return self.varname < other.varname
-
+
def __hash__(self):
- # XOR with hash of GIcon type so that hash('varname') won't
+ # XOR with hash of GIcon type so that hash('varname') won't
# equal hash(GIcon('varname')).
return hash(self.__class__) ^ hash(self.varname)
@@ -278,7 +282,7 @@ class GMarker(GOverlayBase):
Draggable option for GMarker, disabled by default.
"""
# If a GEOS geometry isn't passed in, try to construct one.
- if isinstance(geom, basestring): geom = fromstr(geom)
+ if isinstance(geom, six.string_types): geom = fromstr(geom)
if isinstance(geom, (tuple, list)): geom = Point(geom)
if isinstance(geom, Point):
self.latlng = self.latlng_from_coords(geom.coords)
diff --git a/django/contrib/gis/maps/google/zoom.py b/django/contrib/gis/maps/google/zoom.py
index fc9ff1db96..c93cf4ef48 100644
--- a/django/contrib/gis/maps/google/zoom.py
+++ b/django/contrib/gis/maps/google/zoom.py
@@ -1,5 +1,6 @@
from django.contrib.gis.geos import GEOSGeometry, LinearRing, Polygon, Point
from django.contrib.gis.maps.google.gmap import GoogleMapException
+from django.utils.six.moves import xrange
from math import pi, sin, log, exp, atan
# Constants used for degree to radian conversion, and vice-versa.
@@ -20,21 +21,21 @@ class GoogleZoom(object):
"Google Maps Hacks" may be found at http://safari.oreilly.com/0596101619
"""
-
+
def __init__(self, num_zoom=19, tilesize=256):
"Initializes the Google Zoom object."
# Google's tilesize is 256x256, square tiles are assumed.
self._tilesize = tilesize
-
+
# The number of zoom levels
self._nzoom = num_zoom
- # Initializing arrays to hold the parameters for each one of the
+ # Initializing arrays to hold the parameters for each one of the
# zoom levels.
self._degpp = [] # Degrees per pixel
self._radpp = [] # Radians per pixel
self._npix = [] # 1/2 the number of pixels for a tile at the given zoom level
-
+
# Incrementing through the zoom levels and populating the parameter arrays.
z = tilesize # The number of pixels per zoom level.
for i in xrange(num_zoom):
@@ -70,9 +71,9 @@ class GoogleZoom(object):
# with with the number of degrees/pixel at the given zoom level.
px_x = round(npix + (lon * self._degpp[zoom]))
- # Creating the factor, and ensuring that 1 or -1 is not passed in as the
+ # Creating the factor, and ensuring that 1 or -1 is not passed in as the
# base to the logarithm. Here's why:
- # if fac = -1, we'll get log(0) which is undefined;
+ # if fac = -1, we'll get log(0) which is undefined;
# if fac = 1, our logarithm base will be divided by 0, also undefined.
fac = min(max(sin(DTOR * lat), -0.9999), 0.9999)
@@ -98,7 +99,7 @@ class GoogleZoom(object):
# Returning the longitude, latitude coordinate pair.
return (lon, lat)
-
+
def tile(self, lonlat, zoom):
"""
Returns a Polygon corresponding to the region represented by a fictional
@@ -119,7 +120,7 @@ class GoogleZoom(object):
# Constructing the Polygon, representing the tile and returning.
return Polygon(LinearRing(ll, (ll[0], ur[1]), ur, (ur[0], ll[1]), ll), srid=4326)
-
+
def get_zoom(self, geom):
"Returns the optimal Zoom level for the given geometry."
# Checking the input type.
@@ -139,10 +140,10 @@ class GoogleZoom(object):
# When we span more than one tile, this is an approximately good
# zoom level.
if (env_w > tile_w) or (env_h > tile_h):
- if z == 0:
+ if z == 0:
raise GoogleMapException('Geometry width and height should not exceed that of the Earth.')
return z-1
-
+
# Otherwise, we've zoomed in to the max.
return self._nzoom-1
diff --git a/django/contrib/gis/measure.py b/django/contrib/gis/measure.py
index 46e198c410..6e074be355 100644
--- a/django/contrib/gis/measure.py
+++ b/django/contrib/gis/measure.py
@@ -30,7 +30,7 @@
Distance and Area objects to allow for sensible and convienient calculation
and conversions.
-Authors: Robert Coup, Justin Bronn
+Authors: Robert Coup, Justin Bronn, Riccardo Di Virgilio
Inspired by GeoPy (http://exogen.case.edu/projects/geopy/)
and Geoff Biggs' PhD work on dimensioned units for robotics.
@@ -39,15 +39,140 @@ __all__ = ['A', 'Area', 'D', 'Distance']
from decimal import Decimal
from django.utils.functional import total_ordering
+from django.utils import six
+NUMERIC_TYPES = six.integer_types + (float, Decimal)
+AREA_PREFIX = "sq_"
+
+def pretty_name(obj):
+ return obj.__name__ if obj.__class__ == type else obj.__class__.__name__
+
+
+@total_ordering
class MeasureBase(object):
+ STANDARD_UNIT = None
+ ALIAS = {}
+ UNITS = {}
+ LALIAS = {}
+
+ def __init__(self, default_unit=None, **kwargs):
+ value, self._default_unit = self.default_units(kwargs)
+ setattr(self, self.STANDARD_UNIT, value)
+ if default_unit and isinstance(default_unit, six.string_types):
+ self._default_unit = default_unit
+
+ def _get_standard(self):
+ return getattr(self, self.STANDARD_UNIT)
+
+ def _set_standard(self, value):
+ setattr(self, self.STANDARD_UNIT, value)
+
+ standard = property(_get_standard, _set_standard)
+
+ def __getattr__(self, name):
+ if name in self.UNITS:
+ return self.standard / self.UNITS[name]
+ else:
+ raise AttributeError('Unknown unit type: %s' % name)
+
+ def __repr__(self):
+ return '%s(%s=%s)' % (pretty_name(self), self._default_unit,
+ getattr(self, self._default_unit))
+
+ def __str__(self):
+ return '%s %s' % (getattr(self, self._default_unit), self._default_unit)
+
+ # **** Comparison methods ****
+
+ def __eq__(self, other):
+ if isinstance(other, self.__class__):
+ return self.standard == other.standard
+ else:
+ return NotImplemented
+
+ def __lt__(self, other):
+ if isinstance(other, self.__class__):
+ return self.standard < other.standard
+ else:
+ return NotImplemented
+
+ # **** Operators methods ****
+
+ def __add__(self, other):
+ if isinstance(other, self.__class__):
+ return self.__class__(default_unit=self._default_unit,
+ **{self.STANDARD_UNIT: (self.standard + other.standard)})
+ else:
+ raise TypeError('%(class)s must be added with %(class)s' % {"class":pretty_name(self)})
+
+ def __iadd__(self, other):
+ if isinstance(other, self.__class__):
+ self.standard += other.standard
+ return self
+ else:
+ raise TypeError('%(class)s must be added with %(class)s' % {"class":pretty_name(self)})
+
+ def __sub__(self, other):
+ if isinstance(other, self.__class__):
+ return self.__class__(default_unit=self._default_unit,
+ **{self.STANDARD_UNIT: (self.standard - other.standard)})
+ else:
+ raise TypeError('%(class)s must be subtracted from %(class)s' % {"class":pretty_name(self)})
+
+ def __isub__(self, other):
+ if isinstance(other, self.__class__):
+ self.standard -= other.standard
+ return self
+ else:
+ raise TypeError('%(class)s must be subtracted from %(class)s' % {"class":pretty_name(self)})
+
+ def __mul__(self, other):
+ if isinstance(other, NUMERIC_TYPES):
+ return self.__class__(default_unit=self._default_unit,
+ **{self.STANDARD_UNIT: (self.standard * other)})
+ else:
+ raise TypeError('%(class)s must be multiplied with number' % {"class":pretty_name(self)})
+
+ def __imul__(self, other):
+ if isinstance(other, NUMERIC_TYPES):
+ self.standard *= float(other)
+ return self
+ else:
+ raise TypeError('%(class)s must be multiplied with number' % {"class":pretty_name(self)})
+
+ def __rmul__(self, other):
+ return self * other
+
+ def __truediv__(self, other):
+ if isinstance(other, self.__class__):
+ return self.standard / other.standard
+ if isinstance(other, NUMERIC_TYPES):
+ return self.__class__(default_unit=self._default_unit,
+ **{self.STANDARD_UNIT: (self.standard / other)})
+ else:
+ raise TypeError('%(class)s must be divided with number or %(class)s' % {"class":pretty_name(self)})
+ __div__ = __truediv__ # Python 2 compatibility
+
+ def __itruediv__(self, other):
+ if isinstance(other, NUMERIC_TYPES):
+ self.standard /= float(other)
+ return self
+ else:
+ raise TypeError('%(class)s must be divided with number' % {"class":pretty_name(self)})
+ __idiv__ = __itruediv__ # Python 2 compatibility
+
+ def __bool__(self):
+ return bool(self.standard)
+ __nonzero__ = __bool__ # Python 2 compatibility
+
def default_units(self, kwargs):
"""
Return the unit value and the default units specified
from the given keyword arguments dictionary.
"""
val = 0.0
- for unit, value in kwargs.iteritems():
+ default_unit = self.STANDARD_UNIT
+ for unit, value in six.iteritems(kwargs):
if not isinstance(value, float): value = float(value)
if unit in self.UNITS:
val += self.UNITS[unit] * value
@@ -86,8 +211,8 @@ class MeasureBase(object):
else:
raise Exception('Could not find a unit keyword associated with "%s"' % unit_str)
-@total_ordering
class Distance(MeasureBase):
+ STANDARD_UNIT = "m"
UNITS = {
'chain' : 20.1168,
'chain_benoit' : 20.116782,
@@ -163,189 +288,34 @@ class Distance(MeasureBase):
}
LALIAS = dict([(k.lower(), v) for k, v in ALIAS.items()])
- def __init__(self, default_unit=None, **kwargs):
- # The base unit is in meters.
- self.m, self._default_unit = self.default_units(kwargs)
- if default_unit and isinstance(default_unit, str):
- self._default_unit = default_unit
-
- def __getattr__(self, name):
- if name in self.UNITS:
- return self.m / self.UNITS[name]
- else:
- raise AttributeError('Unknown unit type: %s' % name)
-
- def __repr__(self):
- return 'Distance(%s=%s)' % (self._default_unit, getattr(self, self._default_unit))
-
- def __str__(self):
- return '%s %s' % (getattr(self, self._default_unit), self._default_unit)
-
- def __eq__(self, other):
- if isinstance(other, Distance):
- return self.m == other.m
- else:
- return NotImplemented
-
- def __lt__(self, other):
- if isinstance(other, Distance):
- return self.m < other.m
- else:
- return NotImplemented
-
- def __add__(self, other):
- if isinstance(other, Distance):
- return Distance(default_unit=self._default_unit, m=(self.m + other.m))
- else:
- raise TypeError('Distance must be added with Distance')
-
- def __iadd__(self, other):
- if isinstance(other, Distance):
- self.m += other.m
- return self
- else:
- raise TypeError('Distance must be added with Distance')
-
- def __sub__(self, other):
- if isinstance(other, Distance):
- return Distance(default_unit=self._default_unit, m=(self.m - other.m))
- else:
- raise TypeError('Distance must be subtracted from Distance')
-
- def __isub__(self, other):
- if isinstance(other, Distance):
- self.m -= other.m
- return self
- else:
- raise TypeError('Distance must be subtracted from Distance')
-
def __mul__(self, other):
- if isinstance(other, (int, float, long, Decimal)):
- return Distance(default_unit=self._default_unit, m=(self.m * float(other)))
- elif isinstance(other, Distance):
- return Area(default_unit='sq_' + self._default_unit, sq_m=(self.m * other.m))
+ if isinstance(other, self.__class__):
+ return Area(default_unit=AREA_PREFIX + self._default_unit,
+ **{AREA_PREFIX + self.STANDARD_UNIT: (self.standard * other.standard)})
+ elif isinstance(other, NUMERIC_TYPES):
+ return self.__class__(default_unit=self._default_unit,
+ **{self.STANDARD_UNIT: (self.standard * other)})
else:
- raise TypeError('Distance must be multiplied with number or Distance')
+ raise TypeError('%(distance)s must be multiplied with number or %(distance)s' % {
+ "distance" : pretty_name(self.__class__),
+ })
- def __imul__(self, other):
- if isinstance(other, (int, float, long, Decimal)):
- self.m *= float(other)
- return self
- else:
- raise TypeError('Distance must be multiplied with number')
- def __rmul__(self, other):
- return self * other
-
- def __div__(self, other):
- if isinstance(other, (int, float, long, Decimal)):
- return Distance(default_unit=self._default_unit, m=(self.m / float(other)))
- else:
- raise TypeError('Distance must be divided with number')
-
- def __idiv__(self, other):
- if isinstance(other, (int, float, long, Decimal)):
- self.m /= float(other)
- return self
- else:
- raise TypeError('Distance must be divided with number')
-
- def __nonzero__(self):
- return bool(self.m)
-
-@total_ordering
class Area(MeasureBase):
+ STANDARD_UNIT = AREA_PREFIX + Distance.STANDARD_UNIT
# Getting the square units values and the alias dictionary.
- UNITS = dict([('sq_%s' % k, v ** 2) for k, v in Distance.UNITS.items()])
- ALIAS = dict([(k, 'sq_%s' % v) for k, v in Distance.ALIAS.items()])
+ UNITS = dict([('%s%s' % (AREA_PREFIX, k), v ** 2) for k, v in Distance.UNITS.items()])
+ ALIAS = dict([(k, '%s%s' % (AREA_PREFIX, v)) for k, v in Distance.ALIAS.items()])
LALIAS = dict([(k.lower(), v) for k, v in ALIAS.items()])
- def __init__(self, default_unit=None, **kwargs):
- self.sq_m, self._default_unit = self.default_units(kwargs)
- if default_unit and isinstance(default_unit, str):
- self._default_unit = default_unit
-
- def __getattr__(self, name):
- if name in self.UNITS:
- return self.sq_m / self.UNITS[name]
+ def __truediv__(self, other):
+ if isinstance(other, NUMERIC_TYPES):
+ return self.__class__(default_unit=self._default_unit,
+ **{self.STANDARD_UNIT: (self.standard / other)})
else:
- raise AttributeError('Unknown unit type: ' + name)
+ raise TypeError('%(class)s must be divided by a number' % {"class":pretty_name(self)})
+ __div__ = __truediv__ # Python 2 compatibility
- def __repr__(self):
- return 'Area(%s=%s)' % (self._default_unit, getattr(self, self._default_unit))
-
- def __str__(self):
- return '%s %s' % (getattr(self, self._default_unit), self._default_unit)
-
- def __eq__(self, other):
- if isinstance(other, Area):
- return self.sq_m == other.sq_m
- else:
- return NotImplemented
-
- def __lt__(self, other):
- if isinstance(other, Area):
- return self.sq_m < other.sq_m
- else:
- return NotImplemented
-
- def __add__(self, other):
- if isinstance(other, Area):
- return Area(default_unit=self._default_unit, sq_m=(self.sq_m + other.sq_m))
- else:
- raise TypeError('Area must be added with Area')
-
- def __iadd__(self, other):
- if isinstance(other, Area):
- self.sq_m += other.sq_m
- return self
- else:
- raise TypeError('Area must be added with Area')
-
- def __sub__(self, other):
- if isinstance(other, Area):
- return Area(default_unit=self._default_unit, sq_m=(self.sq_m - other.sq_m))
- else:
- raise TypeError('Area must be subtracted from Area')
-
- def __isub__(self, other):
- if isinstance(other, Area):
- self.sq_m -= other.sq_m
- return self
- else:
- raise TypeError('Area must be subtracted from Area')
-
- def __mul__(self, other):
- if isinstance(other, (int, float, long, Decimal)):
- return Area(default_unit=self._default_unit, sq_m=(self.sq_m * float(other)))
- else:
- raise TypeError('Area must be multiplied with number')
-
- def __imul__(self, other):
- if isinstance(other, (int, float, long, Decimal)):
- self.sq_m *= float(other)
- return self
- else:
- raise TypeError('Area must be multiplied with number')
-
- def __rmul__(self, other):
- return self * other
-
- def __div__(self, other):
- if isinstance(other, (int, float, long, Decimal)):
- return Area(default_unit=self._default_unit, sq_m=(self.sq_m / float(other)))
- else:
- raise TypeError('Area must be divided with number')
-
- def __idiv__(self, other):
- if isinstance(other, (int, float, long, Decimal)):
- self.sq_m /= float(other)
- return self
- else:
- raise TypeError('Area must be divided with number')
-
- def __nonzero__(self):
- return bool(self.sq_m)
# Shortcuts
D = Distance
diff --git a/django/contrib/gis/sitemaps/views.py b/django/contrib/gis/sitemaps/views.py
index 3a9acad7b0..8bcdba1b44 100644
--- a/django/contrib/gis/sitemaps/views.py
+++ b/django/contrib/gis/sitemaps/views.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
from django.http import HttpResponse, Http404
from django.template import loader
from django.contrib.sites.models import get_current_site
@@ -6,7 +8,8 @@ from django.core.paginator import EmptyPage, PageNotAnInteger
from django.contrib.gis.db.models.fields import GeometryField
from django.db import connections, DEFAULT_DB_ALIAS
from django.db.models import get_model
-from django.utils.encoding import smart_str
+from django.utils.encoding import smart_bytes
+from django.utils import six
from django.utils.translation import ugettext as _
from django.contrib.gis.shortcuts import render_to_kml, render_to_kmz
@@ -41,10 +44,10 @@ def sitemap(request, sitemaps, section=None):
maps, urls = [], []
if section is not None:
if section not in sitemaps:
- raise Http404(_(u"No sitemap available for section: %r") % section)
+ raise Http404(_("No sitemap available for section: %r") % section)
maps.append(sitemaps[section])
else:
- maps = sitemaps.values()
+ maps = list(six.itervalues(sitemaps))
page = request.GET.get("p", 1)
current_site = get_current_site(request)
@@ -55,10 +58,10 @@ def sitemap(request, sitemaps, section=None):
else:
urls.extend(site.get_urls(page=page, site=current_site))
except EmptyPage:
- raise Http404(_(u"Page %s empty") % page)
+ raise Http404(_("Page %s empty") % page)
except PageNotAnInteger:
- raise Http404(_(u"No page '%s'") % page)
- xml = smart_str(loader.render_to_string('gis/sitemaps/geo_sitemap.xml', {'urlset': urls}))
+ raise Http404(_("No page '%s'") % page)
+ xml = smart_bytes(loader.render_to_string('gis/sitemaps/geo_sitemap.xml', {'urlset': urls}))
return HttpResponse(xml, content_type='application/xml')
def kml(request, label, model, field_name=None, compress=False, using=DEFAULT_DB_ALIAS):
diff --git a/django/contrib/gis/tests/__init__.py b/django/contrib/gis/tests/__init__.py
index 3433e195a8..765c03018b 100644
--- a/django/contrib/gis/tests/__init__.py
+++ b/django/contrib/gis/tests/__init__.py
@@ -2,6 +2,10 @@ from django.conf import settings
from django.test.simple import build_suite, DjangoTestSuiteRunner
from django.utils import unittest
+from .test_geoforms import GeometryFieldTest
+from .test_measure import DistanceTest, AreaTest
+from .test_spatialrefsys import SpatialRefSysTest
+
def geo_apps(namespace=True, runtests=False):
"""
@@ -54,20 +58,12 @@ def geodjango_suite(apps=True):
from django.contrib.gis.geos import tests as geos_tests
suite.addTest(geos_tests.suite())
- # Adding the measurment tests.
- from django.contrib.gis.tests import test_measure
- suite.addTest(test_measure.suite())
-
# Adding GDAL tests, and any test suite that depends on GDAL, to the
# suite if GDAL is available.
from django.contrib.gis.gdal import HAS_GDAL
if HAS_GDAL:
from django.contrib.gis.gdal import tests as gdal_tests
suite.addTest(gdal_tests.suite())
-
- from django.contrib.gis.tests import test_spatialrefsys, test_geoforms
- suite.addTest(test_spatialrefsys.suite())
- suite.addTest(test_geoforms.suite())
else:
sys.stderr.write('GDAL not available - no tests requiring GDAL will be run.\n')
diff --git a/django/contrib/gis/tests/distapp/models.py b/django/contrib/gis/tests/distapp/models.py
index 76e7d3a03f..bf08829eae 100644
--- a/django/contrib/gis/tests/distapp/models.py
+++ b/django/contrib/gis/tests/distapp/models.py
@@ -1,50 +1,58 @@
from django.contrib.gis.db import models
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class SouthTexasCity(models.Model):
"City model on projected coordinate system for South Texas."
name = models.CharField(max_length=30)
point = models.PointField(srid=32140)
objects = models.GeoManager()
- def __unicode__(self): return self.name
+ def __str__(self): return self.name
+@python_2_unicode_compatible
class SouthTexasCityFt(models.Model):
"Same City model as above, but U.S. survey feet are the units."
name = models.CharField(max_length=30)
point = models.PointField(srid=2278)
objects = models.GeoManager()
- def __unicode__(self): return self.name
+ def __str__(self): return self.name
+@python_2_unicode_compatible
class AustraliaCity(models.Model):
"City model for Australia, using WGS84."
name = models.CharField(max_length=30)
point = models.PointField()
objects = models.GeoManager()
- def __unicode__(self): return self.name
+ def __str__(self): return self.name
+@python_2_unicode_compatible
class CensusZipcode(models.Model):
"Model for a few South Texas ZIP codes (in original Census NAD83)."
name = models.CharField(max_length=5)
poly = models.PolygonField(srid=4269)
objects = models.GeoManager()
- def __unicode__(self): return self.name
+ def __str__(self): return self.name
+@python_2_unicode_compatible
class SouthTexasZipcode(models.Model):
"Model for a few South Texas ZIP codes."
name = models.CharField(max_length=5)
poly = models.PolygonField(srid=32140, null=True)
objects = models.GeoManager()
- def __unicode__(self): return self.name
+ def __str__(self): return self.name
+@python_2_unicode_compatible
class Interstate(models.Model):
"Geodetic model for U.S. Interstates."
name = models.CharField(max_length=10)
path = models.LineStringField()
objects = models.GeoManager()
- def __unicode__(self): return self.name
+ def __str__(self): return self.name
+@python_2_unicode_compatible
class SouthTexasInterstate(models.Model):
"Projected model for South Texas Interstates."
name = models.CharField(max_length=10)
path = models.LineStringField(srid=32140)
objects = models.GeoManager()
- def __unicode__(self): return self.name
+ def __str__(self): return self.name
diff --git a/django/contrib/gis/tests/geo3d/models.py b/django/contrib/gis/tests/geo3d/models.py
index 3c4f77ee05..81e5f55f78 100644
--- a/django/contrib/gis/tests/geo3d/models.py
+++ b/django/contrib/gis/tests/geo3d/models.py
@@ -1,59 +1,67 @@
from django.contrib.gis.db import models
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class City3D(models.Model):
name = models.CharField(max_length=30)
point = models.PointField(dim=3)
objects = models.GeoManager()
- def __unicode__(self):
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class Interstate2D(models.Model):
name = models.CharField(max_length=30)
line = models.LineStringField(srid=4269)
objects = models.GeoManager()
- def __unicode__(self):
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class Interstate3D(models.Model):
name = models.CharField(max_length=30)
line = models.LineStringField(dim=3, srid=4269)
objects = models.GeoManager()
- def __unicode__(self):
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class InterstateProj2D(models.Model):
name = models.CharField(max_length=30)
line = models.LineStringField(srid=32140)
objects = models.GeoManager()
- def __unicode__(self):
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class InterstateProj3D(models.Model):
name = models.CharField(max_length=30)
line = models.LineStringField(dim=3, srid=32140)
objects = models.GeoManager()
- def __unicode__(self):
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class Polygon2D(models.Model):
name = models.CharField(max_length=30)
poly = models.PolygonField(srid=32140)
objects = models.GeoManager()
-
- def __unicode__(self):
+
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class Polygon3D(models.Model):
name = models.CharField(max_length=30)
poly = models.PolygonField(dim=3, srid=32140)
objects = models.GeoManager()
-
- def __unicode__(self):
+
+ def __str__(self):
return self.name
class Point2D(models.Model):
diff --git a/django/contrib/gis/tests/geoadmin/models.py b/django/contrib/gis/tests/geoadmin/models.py
index 51a76d1a0e..af0898823d 100644
--- a/django/contrib/gis/tests/geoadmin/models.py
+++ b/django/contrib/gis/tests/geoadmin/models.py
@@ -1,10 +1,12 @@
from django.contrib.gis.db import models
from django.contrib.gis import admin
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class City(models.Model):
name = models.CharField(max_length=30)
point = models.PointField()
objects = models.GeoManager()
- def __unicode__(self): return self.name
+ def __str__(self): return self.name
admin.site.register(City, admin.OSMGeoAdmin)
diff --git a/django/contrib/gis/tests/geoadmin/tests.py b/django/contrib/gis/tests/geoadmin/tests.py
index 53c00c6588..6fadebdb9a 100644
--- a/django/contrib/gis/tests/geoadmin/tests.py
+++ b/django/contrib/gis/tests/geoadmin/tests.py
@@ -2,7 +2,7 @@ from __future__ import absolute_import
from django.test import TestCase
from django.contrib.gis import admin
-from django.contrib.gis.geos import Point
+from django.contrib.gis.geos import GEOSGeometry, Point
from .models import City
@@ -10,7 +10,7 @@ from .models import City
class GeoAdminTest(TestCase):
urls = 'django.contrib.gis.tests.geoadmin.urls'
- def test01_ensure_geographic_media(self):
+ def test_ensure_geographic_media(self):
geoadmin = admin.site._registry[City]
admin_js = geoadmin.media.render_js()
self.assertTrue(any([geoadmin.openlayers_url in js for js in admin_js]))
@@ -33,3 +33,21 @@ class GeoAdminTest(TestCase):
self.assertIn(
"""geodjango_point.layers.base = new OpenLayers.Layer.WMS("OpenLayers WMS", "http://vmap0.tiles.osgeo.org/wms/vmap0", {layers: \'basic\', format: 'image/jpeg'});""",
result)
+
+ def test_olwidget_has_changed(self):
+ """ Check that changes are accurately noticed by OpenLayersWidget. """
+ geoadmin = admin.site._registry[City]
+ form = geoadmin.get_changelist_form(None)()
+ has_changed = form.fields['point'].widget._has_changed
+
+ initial = Point(13.4197458572965953, 52.5194108501149799, srid=4326)
+ data_same = "SRID=3857;POINT(1493879.2754093995 6894592.019687599)"
+ data_almost_same = "SRID=3857;POINT(1493879.2754093990 6894592.019687590)"
+ data_changed = "SRID=3857;POINT(1493884.0527237 6894593.8111804)"
+
+ self.assertTrue(has_changed(None, data_changed))
+ self.assertTrue(has_changed(initial, ""))
+ self.assertFalse(has_changed(None, ""))
+ self.assertFalse(has_changed(initial, data_same))
+ self.assertFalse(has_changed(initial, data_almost_same))
+ self.assertTrue(has_changed(initial, data_changed))
diff --git a/django/contrib/gis/tests/geoapp/models.py b/django/contrib/gis/tests/geoapp/models.py
index 79061e1cfc..abde509c8b 100644
--- a/django/contrib/gis/tests/geoapp/models.py
+++ b/django/contrib/gis/tests/geoapp/models.py
@@ -1,20 +1,23 @@
from django.contrib.gis.db import models
from django.contrib.gis.tests.utils import mysql, spatialite
+from django.utils.encoding import python_2_unicode_compatible
# MySQL spatial indices can't handle NULL geometries.
null_flag = not mysql
+@python_2_unicode_compatible
class Country(models.Model):
name = models.CharField(max_length=30)
mpoly = models.MultiPolygonField() # SRID, by default, is 4326
objects = models.GeoManager()
- def __unicode__(self): return self.name
+ def __str__(self): return self.name
+@python_2_unicode_compatible
class City(models.Model):
name = models.CharField(max_length=30)
point = models.PointField()
objects = models.GeoManager()
- def __unicode__(self): return self.name
+ def __str__(self): return self.name
# This is an inherited model from City
class PennsylvaniaCity(City):
@@ -22,28 +25,31 @@ class PennsylvaniaCity(City):
founded = models.DateTimeField(null=True)
objects = models.GeoManager() # TODO: This should be implicitly inherited.
+@python_2_unicode_compatible
class State(models.Model):
name = models.CharField(max_length=30)
poly = models.PolygonField(null=null_flag) # Allowing NULL geometries here.
objects = models.GeoManager()
- def __unicode__(self): return self.name
+ def __str__(self): return self.name
+@python_2_unicode_compatible
class Track(models.Model):
name = models.CharField(max_length=30)
line = models.LineStringField()
objects = models.GeoManager()
- def __unicode__(self): return self.name
+ def __str__(self): return self.name
class Truth(models.Model):
val = models.BooleanField()
objects = models.GeoManager()
if not spatialite:
+ @python_2_unicode_compatible
class Feature(models.Model):
name = models.CharField(max_length=20)
geom = models.GeometryField()
objects = models.GeoManager()
- def __unicode__(self): return self.name
+ def __str__(self): return self.name
class MinusOneSRID(models.Model):
geom = models.PointField(srid=-1) # Minus one SRID.
diff --git a/django/contrib/gis/tests/geoapp/test_feeds.py b/django/contrib/gis/tests/geoapp/test_feeds.py
index 936c1ded46..85e777ae78 100644
--- a/django/contrib/gis/tests/geoapp/test_feeds.py
+++ b/django/contrib/gis/tests/geoapp/test_feeds.py
@@ -44,7 +44,7 @@ class GeoFeedTest(TestCase):
# Incrementing through the feeds.
for feed in [feed1, feed2]:
# Ensuring the georss namespace was added to the element.
- self.assertEqual(feed.getAttribute(u'xmlns:georss'), u'http://www.georss.org/georss')
+ self.assertEqual(feed.getAttribute('xmlns:georss'), 'http://www.georss.org/georss')
chan = feed.getElementsByTagName('channel')[0]
items = chan.getElementsByTagName('item')
self.assertEqual(len(items), City.objects.count())
@@ -64,7 +64,7 @@ class GeoFeedTest(TestCase):
for feed in [feed1, feed2]:
# Ensuring the georsss namespace was added to the element.
- self.assertEqual(feed.getAttribute(u'xmlns:georss'), u'http://www.georss.org/georss')
+ self.assertEqual(feed.getAttribute('xmlns:georss'), 'http://www.georss.org/georss')
entries = feed.getElementsByTagName('entry')
self.assertEqual(len(entries), City.objects.count())
@@ -77,7 +77,7 @@ class GeoFeedTest(TestCase):
doc = minidom.parseString(self.client.get('/feeds/w3cgeo1/').content)
feed = doc.firstChild
# Ensuring the geo namespace was added to the element.
- self.assertEqual(feed.getAttribute(u'xmlns:geo'), u'http://www.w3.org/2003/01/geo/wgs84_pos#')
+ self.assertEqual(feed.getAttribute('xmlns:geo'), 'http://www.w3.org/2003/01/geo/wgs84_pos#')
chan = feed.getElementsByTagName('channel')[0]
items = chan.getElementsByTagName('item')
self.assertEqual(len(items), City.objects.count())
diff --git a/django/contrib/gis/tests/geoapp/test_regress.py b/django/contrib/gis/tests/geoapp/test_regress.py
index a9d802d8f1..fffd7d3cab 100644
--- a/django/contrib/gis/tests/geoapp/test_regress.py
+++ b/django/contrib/gis/tests/geoapp/test_regress.py
@@ -12,7 +12,7 @@ from .models import City, PennsylvaniaCity, State, Truth
class GeoRegressionTests(TestCase):
- def test01_update(self):
+ def test_update(self):
"Testing GeoQuerySet.update(). See #10411."
pnt = City.objects.get(name='Pueblo').point
bak = pnt.clone()
@@ -24,7 +24,7 @@ class GeoRegressionTests(TestCase):
City.objects.filter(name='Pueblo').update(point=bak)
self.assertEqual(bak, City.objects.get(name='Pueblo').point)
- def test02_kmz(self):
+ def test_kmz(self):
"Testing `render_to_kmz` with non-ASCII data. See #11624."
name = '\xc3\x85land Islands'.decode('iso-8859-1')
places = [{'name' : name,
@@ -35,7 +35,7 @@ class GeoRegressionTests(TestCase):
@no_spatialite
@no_mysql
- def test03_extent(self):
+ def test_extent(self):
"Testing `extent` on a table with a single point. See #11827."
pnt = City.objects.get(name='Pueblo').point
ref_ext = (pnt.x, pnt.y, pnt.x, pnt.y)
@@ -43,14 +43,14 @@ class GeoRegressionTests(TestCase):
for ref_val, val in zip(ref_ext, extent):
self.assertAlmostEqual(ref_val, val, 4)
- def test04_unicode_date(self):
+ def test_unicode_date(self):
"Testing dates are converted properly, even on SpatiaLite. See #16408."
founded = datetime(1857, 5, 23)
mansfield = PennsylvaniaCity.objects.create(name='Mansfield', county='Tioga', point='POINT(-77.071445 41.823881)',
founded=founded)
self.assertEqual(founded, PennsylvaniaCity.objects.dates('founded', 'day')[0])
- def test05_empty_count(self):
+ def test_empty_count(self):
"Testing that PostGISAdapter.__eq__ does check empty strings. See #13670."
# contrived example, but need a geo lookup paired with an id__in lookup
pueblo = City.objects.get(name='Pueblo')
@@ -60,12 +60,12 @@ class GeoRegressionTests(TestCase):
# .count() should not throw TypeError in __eq__
self.assertEqual(cities_within_state.count(), 1)
- def test06_defer_or_only_with_annotate(self):
+ def test_defer_or_only_with_annotate(self):
"Regression for #16409. Make sure defer() and only() work with annotate()"
self.assertIsInstance(list(City.objects.annotate(Count('point')).defer('name')), list)
self.assertIsInstance(list(City.objects.annotate(Count('point')).only('name')), list)
- def test07_boolean_conversion(self):
+ def test_boolean_conversion(self):
"Testing Boolean value conversion with the spatial backend, see #15169."
t1 = Truth.objects.create(val=True)
t2 = Truth.objects.create(val=False)
diff --git a/django/contrib/gis/tests/geoapp/test_sitemaps.py b/django/contrib/gis/tests/geoapp/test_sitemaps.py
index a5c8f41ba4..5f063dfba3 100644
--- a/django/contrib/gis/tests/geoapp/test_sitemaps.py
+++ b/django/contrib/gis/tests/geoapp/test_sitemaps.py
@@ -34,7 +34,7 @@ class GeoSitemapTest(TestCase):
# Getting the geo index.
doc = minidom.parseString(self.client.get('/sitemap.xml').content)
index = doc.firstChild
- self.assertEqual(index.getAttribute(u'xmlns'), u'http://www.sitemaps.org/schemas/sitemap/0.9')
+ self.assertEqual(index.getAttribute('xmlns'), 'http://www.sitemaps.org/schemas/sitemap/0.9')
self.assertEqual(3, len(index.getElementsByTagName('sitemap')))
def test_geositemap_kml(self):
@@ -44,8 +44,8 @@ class GeoSitemapTest(TestCase):
# Ensuring the right sitemaps namespaces are present.
urlset = doc.firstChild
- self.assertEqual(urlset.getAttribute(u'xmlns'), u'http://www.sitemaps.org/schemas/sitemap/0.9')
- self.assertEqual(urlset.getAttribute(u'xmlns:geo'), u'http://www.google.com/geo/schemas/sitemap/1.0')
+ self.assertEqual(urlset.getAttribute('xmlns'), 'http://www.sitemaps.org/schemas/sitemap/0.9')
+ self.assertEqual(urlset.getAttribute('xmlns:geo'), 'http://www.google.com/geo/schemas/sitemap/1.0')
urls = urlset.getElementsByTagName('url')
self.assertEqual(2, len(urls)) # Should only be 2 sitemaps.
@@ -84,8 +84,8 @@ class GeoSitemapTest(TestCase):
# Ensuring the right sitemaps namespaces are present.
urlset = doc.firstChild
- self.assertEqual(urlset.getAttribute(u'xmlns'), u'http://www.sitemaps.org/schemas/sitemap/0.9')
- self.assertEqual(urlset.getAttribute(u'xmlns:geo'), u'http://www.google.com/geo/schemas/sitemap/1.0')
+ self.assertEqual(urlset.getAttribute('xmlns'), 'http://www.sitemaps.org/schemas/sitemap/0.9')
+ self.assertEqual(urlset.getAttribute('xmlns:geo'), 'http://www.google.com/geo/schemas/sitemap/1.0')
# Making sure the correct number of feed URLs were included.
urls = urlset.getElementsByTagName('url')
diff --git a/django/contrib/gis/tests/geoapp/tests.py b/django/contrib/gis/tests/geoapp/tests.py
index 4136a65d5c..b06d6b5e1b 100644
--- a/django/contrib/gis/tests/geoapp/tests.py
+++ b/django/contrib/gis/tests/geoapp/tests.py
@@ -11,22 +11,28 @@ from django.contrib.gis.tests.utils import (
no_mysql, no_oracle, no_spatialite,
mysql, oracle, postgis, spatialite)
from django.test import TestCase
+from django.utils import six
from .models import Country, City, PennsylvaniaCity, State, Track
+from .test_feeds import GeoFeedTest
+from .test_regress import GeoRegressionTests
+from .test_sitemaps import GeoSitemapTest
+
+
if not spatialite:
from .models import Feature, MinusOneSRID
class GeoModelTest(TestCase):
- def test01_fixtures(self):
+ def test_fixtures(self):
"Testing geographic model initialization from fixtures."
# Ensuring that data was loaded from initial data fixtures.
self.assertEqual(2, Country.objects.count())
self.assertEqual(8, City.objects.count())
self.assertEqual(2, State.objects.count())
- def test02_proxy(self):
+ def test_proxy(self):
"Testing Lazy-Geometry support (using the GeometryProxy)."
## Testing on a Point
pnt = Point(0, 0)
@@ -94,165 +100,97 @@ class GeoModelTest(TestCase):
self.assertEqual(ply, State.objects.get(name='NullState').poly)
ns.delete()
- def test03a_kml(self):
- "Testing KML output from the database using GeoQuerySet.kml()."
- # Only PostGIS and Spatialite (>=2.4.0-RC4) support KML serialization
- if not (postgis or (spatialite and connection.ops.kml)):
- self.assertRaises(NotImplementedError, State.objects.all().kml, field_name='poly')
- return
-
- # Should throw a TypeError when trying to obtain KML from a
- # non-geometry field.
- qs = City.objects.all()
- self.assertRaises(TypeError, qs.kml, 'name')
-
- # The reference KML depends on the version of PostGIS used
- # (the output stopped including altitude in 1.3.3).
- if connection.ops.spatial_version >= (1, 3, 3):
- ref_kml = '-104.609252,38.255001'
- else:
- ref_kml = '-104.609252,38.255001,0'
-
- # Ensuring the KML is as expected.
- ptown1 = City.objects.kml(field_name='point', precision=9).get(name='Pueblo')
- ptown2 = City.objects.kml(precision=9).get(name='Pueblo')
- for ptown in [ptown1, ptown2]:
- self.assertEqual(ref_kml, ptown.kml)
-
- def test03b_gml(self):
- "Testing GML output from the database using GeoQuerySet.gml()."
- if mysql or (spatialite and not connection.ops.gml) :
- self.assertRaises(NotImplementedError, Country.objects.all().gml, field_name='mpoly')
- return
-
- # Should throw a TypeError when tyring to obtain GML from a
- # non-geometry field.
- qs = City.objects.all()
- self.assertRaises(TypeError, qs.gml, field_name='name')
- ptown1 = City.objects.gml(field_name='point', precision=9).get(name='Pueblo')
- ptown2 = City.objects.gml(precision=9).get(name='Pueblo')
+ @no_mysql
+ def test_lookup_insert_transform(self):
+ "Testing automatic transform for lookups and inserts."
+ # San Antonio in 'WGS84' (SRID 4326)
+ sa_4326 = 'POINT (-98.493183 29.424170)'
+ wgs_pnt = fromstr(sa_4326, srid=4326) # Our reference point in WGS84
+ # Oracle doesn't have SRID 3084, using 41157.
if oracle:
- # No precision parameter for Oracle :-/
- gml_regex = re.compile(r'^-104.60925\d+,38.25500\d+ ')
- elif spatialite:
- # Spatialite has extra colon in SrsName
- gml_regex = re.compile(r'^-104.609251\d+,38.255001')
+ # San Antonio in 'Texas 4205, Southern Zone (1983, meters)' (SRID 41157)
+ # Used the following Oracle SQL to get this value:
+ # SELECT SDO_UTIL.TO_WKTGEOMETRY(SDO_CS.TRANSFORM(SDO_GEOMETRY('POINT (-98.493183 29.424170)', 4326), 41157)) FROM DUAL;
+ nad_wkt = 'POINT (300662.034646583 5416427.45974934)'
+ nad_srid = 41157
else:
- gml_regex = re.compile(r'^-104\.60925\d+,38\.255001')
+ # San Antonio in 'NAD83(HARN) / Texas Centric Lambert Conformal' (SRID 3084)
+ nad_wkt = 'POINT (1645978.362408288754523 6276356.025927528738976)' # Used ogr.py in gdal 1.4.1 for this transform
+ nad_srid = 3084
- for ptown in [ptown1, ptown2]:
- self.assertTrue(gml_regex.match(ptown.gml))
-
-
- def test03c_geojson(self):
- "Testing GeoJSON output from the database using GeoQuerySet.geojson()."
- # Only PostGIS 1.3.4+ supports GeoJSON.
- if not connection.ops.geojson:
- self.assertRaises(NotImplementedError, Country.objects.all().geojson, field_name='mpoly')
- return
-
- if connection.ops.spatial_version >= (1, 4, 0):
- pueblo_json = '{"type":"Point","coordinates":[-104.609252,38.255001]}'
- houston_json = '{"type":"Point","crs":{"type":"name","properties":{"name":"EPSG:4326"}},"coordinates":[-95.363151,29.763374]}'
- victoria_json = '{"type":"Point","bbox":[-123.30519600,48.46261100,-123.30519600,48.46261100],"coordinates":[-123.305196,48.462611]}'
- chicago_json = '{"type":"Point","crs":{"type":"name","properties":{"name":"EPSG:4326"}},"bbox":[-87.65018,41.85039,-87.65018,41.85039],"coordinates":[-87.65018,41.85039]}'
+ # Constructing & querying with a point from a different SRID. Oracle
+ # `SDO_OVERLAPBDYINTERSECT` operates differently from
+ # `ST_Intersects`, so contains is used instead.
+ nad_pnt = fromstr(nad_wkt, srid=nad_srid)
+ if oracle:
+ tx = Country.objects.get(mpoly__contains=nad_pnt)
else:
- pueblo_json = '{"type":"Point","coordinates":[-104.60925200,38.25500100]}'
- houston_json = '{"type":"Point","crs":{"type":"EPSG","properties":{"EPSG":4326}},"coordinates":[-95.36315100,29.76337400]}'
- victoria_json = '{"type":"Point","bbox":[-123.30519600,48.46261100,-123.30519600,48.46261100],"coordinates":[-123.30519600,48.46261100]}'
- chicago_json = '{"type":"Point","crs":{"type":"EPSG","properties":{"EPSG":4326}},"bbox":[-87.65018,41.85039,-87.65018,41.85039],"coordinates":[-87.65018,41.85039]}'
+ tx = Country.objects.get(mpoly__intersects=nad_pnt)
+ self.assertEqual('Texas', tx.name)
- # Precision argument should only be an integer
- self.assertRaises(TypeError, City.objects.geojson, precision='foo')
+ # Creating San Antonio. Remember the Alamo.
+ sa = City.objects.create(name='San Antonio', point=nad_pnt)
- # Reference queries and values.
- # SELECT ST_AsGeoJson("geoapp_city"."point", 8, 0) FROM "geoapp_city" WHERE "geoapp_city"."name" = 'Pueblo';
- self.assertEqual(pueblo_json, City.objects.geojson().get(name='Pueblo').geojson)
+ # Now verifying that San Antonio was transformed correctly
+ sa = City.objects.get(name='San Antonio')
+ self.assertAlmostEqual(wgs_pnt.x, sa.point.x, 6)
+ self.assertAlmostEqual(wgs_pnt.y, sa.point.y, 6)
- # 1.3.x: SELECT ST_AsGeoJson("geoapp_city"."point", 8, 1) FROM "geoapp_city" WHERE "geoapp_city"."name" = 'Houston';
- # 1.4.x: SELECT ST_AsGeoJson("geoapp_city"."point", 8, 2) FROM "geoapp_city" WHERE "geoapp_city"."name" = 'Houston';
- # This time we want to include the CRS by using the `crs` keyword.
- self.assertEqual(houston_json, City.objects.geojson(crs=True, model_att='json').get(name='Houston').json)
+ # If the GeometryField SRID is -1, then we shouldn't perform any
+ # transformation if the SRID of the input geometry is different.
+ # SpatiaLite does not support missing SRID values.
+ if not spatialite:
+ m1 = MinusOneSRID(geom=Point(17, 23, srid=4326))
+ m1.save()
+ self.assertEqual(-1, m1.geom.srid)
- # 1.3.x: SELECT ST_AsGeoJson("geoapp_city"."point", 8, 2) FROM "geoapp_city" WHERE "geoapp_city"."name" = 'Victoria';
- # 1.4.x: SELECT ST_AsGeoJson("geoapp_city"."point", 8, 1) FROM "geoapp_city" WHERE "geoapp_city"."name" = 'Houston';
- # This time we include the bounding box by using the `bbox` keyword.
- self.assertEqual(victoria_json, City.objects.geojson(bbox=True).get(name='Victoria').geojson)
+ def test_createnull(self):
+ "Testing creating a model instance and the geometry being None"
+ c = City()
+ self.assertEqual(c.point, None)
- # 1.(3|4).x: SELECT ST_AsGeoJson("geoapp_city"."point", 5, 3) FROM "geoapp_city" WHERE "geoapp_city"."name" = 'Chicago';
- # Finally, we set every available keyword.
- self.assertEqual(chicago_json, City.objects.geojson(bbox=True, crs=True, precision=5).get(name='Chicago').geojson)
+ @no_spatialite # SpatiaLite does not support abstract geometry columns
+ def test_geometryfield(self):
+ "Testing the general GeometryField."
+ Feature(name='Point', geom=Point(1, 1)).save()
+ Feature(name='LineString', geom=LineString((0, 0), (1, 1), (5, 5))).save()
+ Feature(name='Polygon', geom=Polygon(LinearRing((0, 0), (0, 5), (5, 5), (5, 0), (0, 0)))).save()
+ Feature(name='GeometryCollection',
+ geom=GeometryCollection(Point(2, 2), LineString((0, 0), (2, 2)),
+ Polygon(LinearRing((0, 0), (0, 5), (5, 5), (5, 0), (0, 0))))).save()
- def test03d_svg(self):
- "Testing SVG output using GeoQuerySet.svg()."
- if mysql or oracle:
- self.assertRaises(NotImplementedError, City.objects.svg)
- return
+ f_1 = Feature.objects.get(name='Point')
+ self.assertEqual(True, isinstance(f_1.geom, Point))
+ self.assertEqual((1.0, 1.0), f_1.geom.tuple)
+ f_2 = Feature.objects.get(name='LineString')
+ self.assertEqual(True, isinstance(f_2.geom, LineString))
+ self.assertEqual(((0.0, 0.0), (1.0, 1.0), (5.0, 5.0)), f_2.geom.tuple)
- self.assertRaises(TypeError, City.objects.svg, precision='foo')
- # SELECT AsSVG(geoapp_city.point, 0, 8) FROM geoapp_city WHERE name = 'Pueblo';
- svg1 = 'cx="-104.609252" cy="-38.255001"'
- # Even though relative, only one point so it's practically the same except for
- # the 'c' letter prefix on the x,y values.
- svg2 = svg1.replace('c', '')
- self.assertEqual(svg1, City.objects.svg().get(name='Pueblo').svg)
- self.assertEqual(svg2, City.objects.svg(relative=5).get(name='Pueblo').svg)
+ f_3 = Feature.objects.get(name='Polygon')
+ self.assertEqual(True, isinstance(f_3.geom, Polygon))
+ f_4 = Feature.objects.get(name='GeometryCollection')
+ self.assertEqual(True, isinstance(f_4.geom, GeometryCollection))
+ self.assertEqual(f_3.geom, f_4.geom[2])
@no_mysql
- def test04_transform(self):
- "Testing the transform() GeoManager method."
- # Pre-transformed points for Houston and Pueblo.
- htown = fromstr('POINT(1947516.83115183 6322297.06040572)', srid=3084)
- ptown = fromstr('POINT(992363.390841912 481455.395105533)', srid=2774)
- prec = 3 # Precision is low due to version variations in PROJ and GDAL.
+ def test_inherited_geofields(self):
+ "Test GeoQuerySet methods on inherited Geometry fields."
+ # Creating a Pennsylvanian city.
+ mansfield = PennsylvaniaCity.objects.create(name='Mansfield', county='Tioga', point='POINT(-77.071445 41.823881)')
- # Asserting the result of the transform operation with the values in
- # the pre-transformed points. Oracle does not have the 3084 SRID.
- if not oracle:
- h = City.objects.transform(htown.srid).get(name='Houston')
- self.assertEqual(3084, h.point.srid)
- self.assertAlmostEqual(htown.x, h.point.x, prec)
- self.assertAlmostEqual(htown.y, h.point.y, prec)
+ # All transformation SQL will need to be performed on the
+ # _parent_ table.
+ qs = PennsylvaniaCity.objects.transform(32128)
- p1 = City.objects.transform(ptown.srid, field_name='point').get(name='Pueblo')
- p2 = City.objects.transform(srid=ptown.srid).get(name='Pueblo')
- for p in [p1, p2]:
- self.assertEqual(2774, p.point.srid)
- self.assertAlmostEqual(ptown.x, p.point.x, prec)
- self.assertAlmostEqual(ptown.y, p.point.y, prec)
+ self.assertEqual(1, qs.count())
+ for pc in qs: self.assertEqual(32128, pc.point.srid)
+
+
+class GeoLookupTest(TestCase):
@no_mysql
- @no_spatialite # SpatiaLite does not have an Extent function
- def test05_extent(self):
- "Testing the `extent` GeoQuerySet method."
- # Reference query:
- # `SELECT ST_extent(point) FROM geoapp_city WHERE (name='Houston' or name='Dallas');`
- # => BOX(-96.8016128540039 29.7633724212646,-95.3631439208984 32.7820587158203)
- expected = (-96.8016128540039, 29.7633724212646, -95.3631439208984, 32.782058715820)
-
- qs = City.objects.filter(name__in=('Houston', 'Dallas'))
- extent = qs.extent()
-
- for val, exp in zip(extent, expected):
- self.assertAlmostEqual(exp, val, 4)
-
- # Only PostGIS has support for the MakeLine aggregate.
- @no_mysql
- @no_oracle
- @no_spatialite
- def test06_make_line(self):
- "Testing the `make_line` GeoQuerySet method."
- # Ensuring that a `TypeError` is raised on models without PointFields.
- self.assertRaises(TypeError, State.objects.make_line)
- self.assertRaises(TypeError, Country.objects.make_line)
- # Reference query:
- # SELECT AsText(ST_MakeLine(geoapp_city.point)) FROM geoapp_city;
- ref_line = GEOSGeometry('LINESTRING(-95.363151 29.763374,-96.801611 32.782057,-97.521157 34.464642,174.783117 -41.315268,-104.609252 38.255001,-95.23506 38.971823,-87.650175 41.850385,-123.305196 48.462611)', srid=4326)
- self.assertEqual(ref_line, City.objects.make_line())
-
- @no_mysql
- def test09_disjoint(self):
+ def test_disjoint_lookup(self):
"Testing the `disjoint` lookup type."
ptown = City.objects.get(name='Pueblo')
qs1 = City.objects.filter(point__disjoint=ptown.point)
@@ -262,7 +200,7 @@ class GeoModelTest(TestCase):
self.assertEqual(1, qs2.count())
self.assertEqual('Kansas', qs2[0].name)
- def test10_contains_contained(self):
+ def test_contains_contained_lookups(self):
"Testing the 'contained', 'contains', and 'bbcontains' lookup types."
# Getting Texas, yes we were a country -- once ;)
texas = Country.objects.get(name='Texas')
@@ -307,86 +245,11 @@ class GeoModelTest(TestCase):
self.assertEqual(1, len(qs))
self.assertEqual('Texas', qs[0].name)
- @no_mysql
- def test11_lookup_insert_transform(self):
- "Testing automatic transform for lookups and inserts."
- # San Antonio in 'WGS84' (SRID 4326)
- sa_4326 = 'POINT (-98.493183 29.424170)'
- wgs_pnt = fromstr(sa_4326, srid=4326) # Our reference point in WGS84
-
- # Oracle doesn't have SRID 3084, using 41157.
- if oracle:
- # San Antonio in 'Texas 4205, Southern Zone (1983, meters)' (SRID 41157)
- # Used the following Oracle SQL to get this value:
- # SELECT SDO_UTIL.TO_WKTGEOMETRY(SDO_CS.TRANSFORM(SDO_GEOMETRY('POINT (-98.493183 29.424170)', 4326), 41157)) FROM DUAL;
- nad_wkt = 'POINT (300662.034646583 5416427.45974934)'
- nad_srid = 41157
- else:
- # San Antonio in 'NAD83(HARN) / Texas Centric Lambert Conformal' (SRID 3084)
- nad_wkt = 'POINT (1645978.362408288754523 6276356.025927528738976)' # Used ogr.py in gdal 1.4.1 for this transform
- nad_srid = 3084
-
- # Constructing & querying with a point from a different SRID. Oracle
- # `SDO_OVERLAPBDYINTERSECT` operates differently from
- # `ST_Intersects`, so contains is used instead.
- nad_pnt = fromstr(nad_wkt, srid=nad_srid)
- if oracle:
- tx = Country.objects.get(mpoly__contains=nad_pnt)
- else:
- tx = Country.objects.get(mpoly__intersects=nad_pnt)
- self.assertEqual('Texas', tx.name)
-
- # Creating San Antonio. Remember the Alamo.
- sa = City.objects.create(name='San Antonio', point=nad_pnt)
-
- # Now verifying that San Antonio was transformed correctly
- sa = City.objects.get(name='San Antonio')
- self.assertAlmostEqual(wgs_pnt.x, sa.point.x, 6)
- self.assertAlmostEqual(wgs_pnt.y, sa.point.y, 6)
-
- # If the GeometryField SRID is -1, then we shouldn't perform any
- # transformation if the SRID of the input geometry is different.
- # SpatiaLite does not support missing SRID values.
- if not spatialite:
- m1 = MinusOneSRID(geom=Point(17, 23, srid=4326))
- m1.save()
- self.assertEqual(-1, m1.geom.srid)
-
- @no_mysql
- def test12_null_geometries(self):
- "Testing NULL geometry support, and the `isnull` lookup type."
- # Creating a state with a NULL boundary.
- State.objects.create(name='Puerto Rico')
-
- # Querying for both NULL and Non-NULL values.
- nullqs = State.objects.filter(poly__isnull=True)
- validqs = State.objects.filter(poly__isnull=False)
-
- # Puerto Rico should be NULL (it's a commonwealth unincorporated territory)
- self.assertEqual(1, len(nullqs))
- self.assertEqual('Puerto Rico', nullqs[0].name)
-
- # The valid states should be Colorado & Kansas
- self.assertEqual(2, len(validqs))
- state_names = [s.name for s in validqs]
- self.assertEqual(True, 'Colorado' in state_names)
- self.assertEqual(True, 'Kansas' in state_names)
-
- # Saving another commonwealth w/a NULL geometry.
- nmi = State.objects.create(name='Northern Mariana Islands', poly=None)
- self.assertEqual(nmi.poly, None)
-
- # Assigning a geomery and saving -- then UPDATE back to NULL.
- nmi.poly = 'POLYGON((0 0,1 0,1 1,1 0,0 0))'
- nmi.save()
- State.objects.filter(name='Northern Mariana Islands').update(poly=None)
- self.assertEqual(None, State.objects.get(name='Northern Mariana Islands').poly)
-
# Only PostGIS has `left` and `right` lookup types.
@no_mysql
@no_oracle
@no_spatialite
- def test13_left_right(self):
+ def test_left_right_lookups(self):
"Testing the 'left' and 'right' lookup types."
# Left: A << B => true if xmax(A) < xmin(B)
# Right: A >> B => true if xmin(A) > xmax(B)
@@ -422,7 +285,7 @@ class GeoModelTest(TestCase):
self.assertEqual(2, len(qs))
for c in qs: self.assertEqual(True, c.name in cities)
- def test14_equals(self):
+ def test_equals_lookups(self):
"Testing the 'same_as' and 'equals' lookup types."
pnt = fromstr('POINT (-95.363151 29.763374)', srid=4326)
c1 = City.objects.get(point=pnt)
@@ -431,7 +294,37 @@ class GeoModelTest(TestCase):
for c in [c1, c2, c3]: self.assertEqual('Houston', c.name)
@no_mysql
- def test15_relate(self):
+ def test_null_geometries(self):
+ "Testing NULL geometry support, and the `isnull` lookup type."
+ # Creating a state with a NULL boundary.
+ State.objects.create(name='Puerto Rico')
+
+ # Querying for both NULL and Non-NULL values.
+ nullqs = State.objects.filter(poly__isnull=True)
+ validqs = State.objects.filter(poly__isnull=False)
+
+ # Puerto Rico should be NULL (it's a commonwealth unincorporated territory)
+ self.assertEqual(1, len(nullqs))
+ self.assertEqual('Puerto Rico', nullqs[0].name)
+
+ # The valid states should be Colorado & Kansas
+ self.assertEqual(2, len(validqs))
+ state_names = [s.name for s in validqs]
+ self.assertEqual(True, 'Colorado' in state_names)
+ self.assertEqual(True, 'Kansas' in state_names)
+
+ # Saving another commonwealth w/a NULL geometry.
+ nmi = State.objects.create(name='Northern Mariana Islands', poly=None)
+ self.assertEqual(nmi.poly, None)
+
+ # Assigning a geomery and saving -- then UPDATE back to NULL.
+ nmi.poly = 'POLYGON((0 0,1 0,1 1,1 0,0 0))'
+ nmi.save()
+ State.objects.filter(name='Northern Mariana Islands').update(poly=None)
+ self.assertEqual(None, State.objects.get(name='Northern Mariana Islands').poly)
+
+ @no_mysql
+ def test_relate_lookup(self):
"Testing the 'relate' lookup type."
# To make things more interesting, we will have our Texas reference point in
# different SRIDs.
@@ -473,60 +366,12 @@ class GeoModelTest(TestCase):
self.assertEqual('Texas', Country.objects.get(mpoly__relate=(pnt2, intersects_mask)).name)
self.assertEqual('Lawrence', City.objects.get(point__relate=(ks.poly, intersects_mask)).name)
- def test16_createnull(self):
- "Testing creating a model instance and the geometry being None"
- c = City()
- self.assertEqual(c.point, None)
+
+class GeoQuerySetTest(TestCase):
+ # Please keep the tests in GeoQuerySet method's alphabetic order
@no_mysql
- def test17_unionagg(self):
- "Testing the `unionagg` (aggregate union) GeoManager method."
- tx = Country.objects.get(name='Texas').mpoly
- # Houston, Dallas -- Oracle has different order.
- union1 = fromstr('MULTIPOINT(-96.801611 32.782057,-95.363151 29.763374)')
- union2 = fromstr('MULTIPOINT(-96.801611 32.782057,-95.363151 29.763374)')
- qs = City.objects.filter(point__within=tx)
- self.assertRaises(TypeError, qs.unionagg, 'name')
- # Using `field_name` keyword argument in one query and specifying an
- # order in the other (which should not be used because this is
- # an aggregate method on a spatial column)
- u1 = qs.unionagg(field_name='point')
- u2 = qs.order_by('name').unionagg()
- tol = 0.00001
- if oracle:
- union = union2
- else:
- union = union1
- self.assertEqual(True, union.equals_exact(u1, tol))
- self.assertEqual(True, union.equals_exact(u2, tol))
- qs = City.objects.filter(name='NotACity')
- self.assertEqual(None, qs.unionagg(field_name='point'))
-
- @no_spatialite # SpatiaLite does not support abstract geometry columns
- def test18_geometryfield(self):
- "Testing the general GeometryField."
- Feature(name='Point', geom=Point(1, 1)).save()
- Feature(name='LineString', geom=LineString((0, 0), (1, 1), (5, 5))).save()
- Feature(name='Polygon', geom=Polygon(LinearRing((0, 0), (0, 5), (5, 5), (5, 0), (0, 0)))).save()
- Feature(name='GeometryCollection',
- geom=GeometryCollection(Point(2, 2), LineString((0, 0), (2, 2)),
- Polygon(LinearRing((0, 0), (0, 5), (5, 5), (5, 0), (0, 0))))).save()
-
- f_1 = Feature.objects.get(name='Point')
- self.assertEqual(True, isinstance(f_1.geom, Point))
- self.assertEqual((1.0, 1.0), f_1.geom.tuple)
- f_2 = Feature.objects.get(name='LineString')
- self.assertEqual(True, isinstance(f_2.geom, LineString))
- self.assertEqual(((0.0, 0.0), (1.0, 1.0), (5.0, 5.0)), f_2.geom.tuple)
-
- f_3 = Feature.objects.get(name='Polygon')
- self.assertEqual(True, isinstance(f_3.geom, Polygon))
- f_4 = Feature.objects.get(name='GeometryCollection')
- self.assertEqual(True, isinstance(f_4.geom, GeometryCollection))
- self.assertEqual(f_3.geom, f_4.geom[2])
-
- @no_mysql
- def test19_centroid(self):
+ def test_centroid(self):
"Testing the `centroid` GeoQuerySet method."
qs = State.objects.exclude(poly__isnull=True).centroid()
if oracle:
@@ -539,84 +384,7 @@ class GeoModelTest(TestCase):
self.assertEqual(True, s.poly.centroid.equals_exact(s.centroid, tol))
@no_mysql
- def test20_pointonsurface(self):
- "Testing the `point_on_surface` GeoQuerySet method."
- # Reference values.
- if oracle:
- # SELECT SDO_UTIL.TO_WKTGEOMETRY(SDO_GEOM.SDO_POINTONSURFACE(GEOAPP_COUNTRY.MPOLY, 0.05)) FROM GEOAPP_COUNTRY;
- ref = {'New Zealand' : fromstr('POINT (174.616364 -36.100861)', srid=4326),
- 'Texas' : fromstr('POINT (-103.002434 36.500397)', srid=4326),
- }
-
- elif postgis or spatialite:
- # Using GEOSGeometry to compute the reference point on surface values
- # -- since PostGIS also uses GEOS these should be the same.
- ref = {'New Zealand' : Country.objects.get(name='New Zealand').mpoly.point_on_surface,
- 'Texas' : Country.objects.get(name='Texas').mpoly.point_on_surface
- }
-
- for c in Country.objects.point_on_surface():
- if spatialite:
- # XXX This seems to be a WKT-translation-related precision issue?
- tol = 0.00001
- else:
- tol = 0.000000001
- self.assertEqual(True, ref[c.name].equals_exact(c.point_on_surface, tol))
-
- @no_mysql
- @no_oracle
- def test21_scale(self):
- "Testing the `scale` GeoQuerySet method."
- xfac, yfac = 2, 3
- tol = 5 # XXX The low precision tolerance is for SpatiaLite
- qs = Country.objects.scale(xfac, yfac, model_att='scaled')
- for c in qs:
- for p1, p2 in zip(c.mpoly, c.scaled):
- for r1, r2 in zip(p1, p2):
- for c1, c2 in zip(r1.coords, r2.coords):
- self.assertAlmostEqual(c1[0] * xfac, c2[0], tol)
- self.assertAlmostEqual(c1[1] * yfac, c2[1], tol)
-
- @no_mysql
- @no_oracle
- def test22_translate(self):
- "Testing the `translate` GeoQuerySet method."
- xfac, yfac = 5, -23
- qs = Country.objects.translate(xfac, yfac, model_att='translated')
- for c in qs:
- for p1, p2 in zip(c.mpoly, c.translated):
- for r1, r2 in zip(p1, p2):
- for c1, c2 in zip(r1.coords, r2.coords):
- # XXX The low precision is for SpatiaLite
- self.assertAlmostEqual(c1[0] + xfac, c2[0], 5)
- self.assertAlmostEqual(c1[1] + yfac, c2[1], 5)
-
- @no_mysql
- def test23_numgeom(self):
- "Testing the `num_geom` GeoQuerySet method."
- # Both 'countries' only have two geometries.
- for c in Country.objects.num_geom(): self.assertEqual(2, c.num_geom)
- for c in City.objects.filter(point__isnull=False).num_geom():
- # Oracle will return 1 for the number of geometries on non-collections,
- # whereas PostGIS will return None.
- if postgis:
- self.assertEqual(None, c.num_geom)
- else:
- self.assertEqual(1, c.num_geom)
-
- @no_mysql
- @no_spatialite # SpatiaLite can only count vertices in LineStrings
- def test24_numpoints(self):
- "Testing the `num_points` GeoQuerySet method."
- for c in Country.objects.num_points():
- self.assertEqual(c.mpoly.num_points, c.num_points)
-
- if not oracle:
- # Oracle cannot count vertices in Point geometries.
- for c in City.objects.num_points(): self.assertEqual(1, c.num_points)
-
- @no_mysql
- def test25_geoset(self):
+ def test_diff_intersection_union(self):
"Testing the `difference`, `intersection`, `sym_difference`, and `union` GeoQuerySet methods."
geom = Point(5, 23)
tol = 1
@@ -643,27 +411,237 @@ class GeoModelTest(TestCase):
self.assertEqual(c.mpoly.union(geom), c.union)
@no_mysql
- def test26_inherited_geofields(self):
- "Test GeoQuerySet methods on inherited Geometry fields."
- # Creating a Pennsylvanian city.
- mansfield = PennsylvaniaCity.objects.create(name='Mansfield', county='Tioga', point='POINT(-77.071445 41.823881)')
+ @no_spatialite # SpatiaLite does not have an Extent function
+ def test_extent(self):
+ "Testing the `extent` GeoQuerySet method."
+ # Reference query:
+ # `SELECT ST_extent(point) FROM geoapp_city WHERE (name='Houston' or name='Dallas');`
+ # => BOX(-96.8016128540039 29.7633724212646,-95.3631439208984 32.7820587158203)
+ expected = (-96.8016128540039, 29.7633724212646, -95.3631439208984, 32.782058715820)
- # All transformation SQL will need to be performed on the
- # _parent_ table.
- qs = PennsylvaniaCity.objects.transform(32128)
+ qs = City.objects.filter(name__in=('Houston', 'Dallas'))
+ extent = qs.extent()
- self.assertEqual(1, qs.count())
- for pc in qs: self.assertEqual(32128, pc.point.srid)
+ for val, exp in zip(extent, expected):
+ self.assertAlmostEqual(exp, val, 4)
@no_mysql
@no_oracle
@no_spatialite
- def test27_snap_to_grid(self):
+ def test_force_rhr(self):
+ "Testing GeoQuerySet.force_rhr()."
+ rings = ( ( (0, 0), (5, 0), (0, 5), (0, 0) ),
+ ( (1, 1), (1, 3), (3, 1), (1, 1) ),
+ )
+ rhr_rings = ( ( (0, 0), (0, 5), (5, 0), (0, 0) ),
+ ( (1, 1), (3, 1), (1, 3), (1, 1) ),
+ )
+ State.objects.create(name='Foo', poly=Polygon(*rings))
+ s = State.objects.force_rhr().get(name='Foo')
+ self.assertEqual(rhr_rings, s.force_rhr.coords)
+
+ @no_mysql
+ @no_oracle
+ @no_spatialite
+ def test_geohash(self):
+ "Testing GeoQuerySet.geohash()."
+ if not connection.ops.geohash: return
+ # Reference query:
+ # SELECT ST_GeoHash(point) FROM geoapp_city WHERE name='Houston';
+ # SELECT ST_GeoHash(point, 5) FROM geoapp_city WHERE name='Houston';
+ ref_hash = '9vk1mfq8jx0c8e0386z6'
+ h1 = City.objects.geohash().get(name='Houston')
+ h2 = City.objects.geohash(precision=5).get(name='Houston')
+ self.assertEqual(ref_hash, h1.geohash)
+ self.assertEqual(ref_hash[:5], h2.geohash)
+
+ def test_geojson(self):
+ "Testing GeoJSON output from the database using GeoQuerySet.geojson()."
+ # Only PostGIS 1.3.4+ supports GeoJSON.
+ if not connection.ops.geojson:
+ self.assertRaises(NotImplementedError, Country.objects.all().geojson, field_name='mpoly')
+ return
+
+ if connection.ops.spatial_version >= (1, 4, 0):
+ pueblo_json = '{"type":"Point","coordinates":[-104.609252,38.255001]}'
+ houston_json = '{"type":"Point","crs":{"type":"name","properties":{"name":"EPSG:4326"}},"coordinates":[-95.363151,29.763374]}'
+ victoria_json = '{"type":"Point","bbox":[-123.30519600,48.46261100,-123.30519600,48.46261100],"coordinates":[-123.305196,48.462611]}'
+ chicago_json = '{"type":"Point","crs":{"type":"name","properties":{"name":"EPSG:4326"}},"bbox":[-87.65018,41.85039,-87.65018,41.85039],"coordinates":[-87.65018,41.85039]}'
+ else:
+ pueblo_json = '{"type":"Point","coordinates":[-104.60925200,38.25500100]}'
+ houston_json = '{"type":"Point","crs":{"type":"EPSG","properties":{"EPSG":4326}},"coordinates":[-95.36315100,29.76337400]}'
+ victoria_json = '{"type":"Point","bbox":[-123.30519600,48.46261100,-123.30519600,48.46261100],"coordinates":[-123.30519600,48.46261100]}'
+ chicago_json = '{"type":"Point","crs":{"type":"EPSG","properties":{"EPSG":4326}},"bbox":[-87.65018,41.85039,-87.65018,41.85039],"coordinates":[-87.65018,41.85039]}'
+
+ # Precision argument should only be an integer
+ self.assertRaises(TypeError, City.objects.geojson, precision='foo')
+
+ # Reference queries and values.
+ # SELECT ST_AsGeoJson("geoapp_city"."point", 8, 0) FROM "geoapp_city" WHERE "geoapp_city"."name" = 'Pueblo';
+ self.assertEqual(pueblo_json, City.objects.geojson().get(name='Pueblo').geojson)
+
+ # 1.3.x: SELECT ST_AsGeoJson("geoapp_city"."point", 8, 1) FROM "geoapp_city" WHERE "geoapp_city"."name" = 'Houston';
+ # 1.4.x: SELECT ST_AsGeoJson("geoapp_city"."point", 8, 2) FROM "geoapp_city" WHERE "geoapp_city"."name" = 'Houston';
+ # This time we want to include the CRS by using the `crs` keyword.
+ self.assertEqual(houston_json, City.objects.geojson(crs=True, model_att='json').get(name='Houston').json)
+
+ # 1.3.x: SELECT ST_AsGeoJson("geoapp_city"."point", 8, 2) FROM "geoapp_city" WHERE "geoapp_city"."name" = 'Victoria';
+ # 1.4.x: SELECT ST_AsGeoJson("geoapp_city"."point", 8, 1) FROM "geoapp_city" WHERE "geoapp_city"."name" = 'Houston';
+ # This time we include the bounding box by using the `bbox` keyword.
+ self.assertEqual(victoria_json, City.objects.geojson(bbox=True).get(name='Victoria').geojson)
+
+ # 1.(3|4).x: SELECT ST_AsGeoJson("geoapp_city"."point", 5, 3) FROM "geoapp_city" WHERE "geoapp_city"."name" = 'Chicago';
+ # Finally, we set every available keyword.
+ self.assertEqual(chicago_json, City.objects.geojson(bbox=True, crs=True, precision=5).get(name='Chicago').geojson)
+
+ def test_gml(self):
+ "Testing GML output from the database using GeoQuerySet.gml()."
+ if mysql or (spatialite and not connection.ops.gml) :
+ self.assertRaises(NotImplementedError, Country.objects.all().gml, field_name='mpoly')
+ return
+
+ # Should throw a TypeError when tyring to obtain GML from a
+ # non-geometry field.
+ qs = City.objects.all()
+ self.assertRaises(TypeError, qs.gml, field_name='name')
+ ptown1 = City.objects.gml(field_name='point', precision=9).get(name='Pueblo')
+ ptown2 = City.objects.gml(precision=9).get(name='Pueblo')
+
+ if oracle:
+ # No precision parameter for Oracle :-/
+ gml_regex = re.compile(r'^-104.60925\d+,38.25500\d+ ')
+ elif spatialite:
+ # Spatialite has extra colon in SrsName
+ gml_regex = re.compile(r'^-104.609251\d+,38.255001')
+ else:
+ gml_regex = re.compile(r'^-104\.60925\d+,38\.255001')
+
+ for ptown in [ptown1, ptown2]:
+ self.assertTrue(gml_regex.match(ptown.gml))
+
+ def test_kml(self):
+ "Testing KML output from the database using GeoQuerySet.kml()."
+ # Only PostGIS and Spatialite (>=2.4.0-RC4) support KML serialization
+ if not (postgis or (spatialite and connection.ops.kml)):
+ self.assertRaises(NotImplementedError, State.objects.all().kml, field_name='poly')
+ return
+
+ # Should throw a TypeError when trying to obtain KML from a
+ # non-geometry field.
+ qs = City.objects.all()
+ self.assertRaises(TypeError, qs.kml, 'name')
+
+ # The reference KML depends on the version of PostGIS used
+ # (the output stopped including altitude in 1.3.3).
+ if connection.ops.spatial_version >= (1, 3, 3):
+ ref_kml = '-104.609252,38.255001'
+ else:
+ ref_kml = '-104.609252,38.255001,0'
+
+ # Ensuring the KML is as expected.
+ ptown1 = City.objects.kml(field_name='point', precision=9).get(name='Pueblo')
+ ptown2 = City.objects.kml(precision=9).get(name='Pueblo')
+ for ptown in [ptown1, ptown2]:
+ self.assertEqual(ref_kml, ptown.kml)
+
+ # Only PostGIS has support for the MakeLine aggregate.
+ @no_mysql
+ @no_oracle
+ @no_spatialite
+ def test_make_line(self):
+ "Testing the `make_line` GeoQuerySet method."
+ # Ensuring that a `TypeError` is raised on models without PointFields.
+ self.assertRaises(TypeError, State.objects.make_line)
+ self.assertRaises(TypeError, Country.objects.make_line)
+ # Reference query:
+ # SELECT AsText(ST_MakeLine(geoapp_city.point)) FROM geoapp_city;
+ ref_line = GEOSGeometry('LINESTRING(-95.363151 29.763374,-96.801611 32.782057,-97.521157 34.464642,174.783117 -41.315268,-104.609252 38.255001,-95.23506 38.971823,-87.650175 41.850385,-123.305196 48.462611)', srid=4326)
+ self.assertEqual(ref_line, City.objects.make_line())
+
+ @no_mysql
+ def test_num_geom(self):
+ "Testing the `num_geom` GeoQuerySet method."
+ # Both 'countries' only have two geometries.
+ for c in Country.objects.num_geom(): self.assertEqual(2, c.num_geom)
+ for c in City.objects.filter(point__isnull=False).num_geom():
+ # Oracle will return 1 for the number of geometries on non-collections,
+ # whereas PostGIS will return None.
+ if postgis:
+ self.assertEqual(None, c.num_geom)
+ else:
+ self.assertEqual(1, c.num_geom)
+
+ @no_mysql
+ @no_spatialite # SpatiaLite can only count vertices in LineStrings
+ def test_num_points(self):
+ "Testing the `num_points` GeoQuerySet method."
+ for c in Country.objects.num_points():
+ self.assertEqual(c.mpoly.num_points, c.num_points)
+
+ if not oracle:
+ # Oracle cannot count vertices in Point geometries.
+ for c in City.objects.num_points(): self.assertEqual(1, c.num_points)
+
+ @no_mysql
+ def test_point_on_surface(self):
+ "Testing the `point_on_surface` GeoQuerySet method."
+ # Reference values.
+ if oracle:
+ # SELECT SDO_UTIL.TO_WKTGEOMETRY(SDO_GEOM.SDO_POINTONSURFACE(GEOAPP_COUNTRY.MPOLY, 0.05)) FROM GEOAPP_COUNTRY;
+ ref = {'New Zealand' : fromstr('POINT (174.616364 -36.100861)', srid=4326),
+ 'Texas' : fromstr('POINT (-103.002434 36.500397)', srid=4326),
+ }
+
+ elif postgis or spatialite:
+ # Using GEOSGeometry to compute the reference point on surface values
+ # -- since PostGIS also uses GEOS these should be the same.
+ ref = {'New Zealand' : Country.objects.get(name='New Zealand').mpoly.point_on_surface,
+ 'Texas' : Country.objects.get(name='Texas').mpoly.point_on_surface
+ }
+
+ for c in Country.objects.point_on_surface():
+ if spatialite:
+ # XXX This seems to be a WKT-translation-related precision issue?
+ tol = 0.00001
+ else:
+ tol = 0.000000001
+ self.assertEqual(True, ref[c.name].equals_exact(c.point_on_surface, tol))
+
+ @no_mysql
+ @no_spatialite
+ def test_reverse_geom(self):
+ "Testing GeoQuerySet.reverse_geom()."
+ coords = [ (-95.363151, 29.763374), (-95.448601, 29.713803) ]
+ Track.objects.create(name='Foo', line=LineString(coords))
+ t = Track.objects.reverse_geom().get(name='Foo')
+ coords.reverse()
+ self.assertEqual(tuple(coords), t.reverse_geom.coords)
+ if oracle:
+ self.assertRaises(TypeError, State.objects.reverse_geom)
+
+ @no_mysql
+ @no_oracle
+ def test_scale(self):
+ "Testing the `scale` GeoQuerySet method."
+ xfac, yfac = 2, 3
+ tol = 5 # XXX The low precision tolerance is for SpatiaLite
+ qs = Country.objects.scale(xfac, yfac, model_att='scaled')
+ for c in qs:
+ for p1, p2 in zip(c.mpoly, c.scaled):
+ for r1, r2 in zip(p1, p2):
+ for c1, c2 in zip(r1.coords, r2.coords):
+ self.assertAlmostEqual(c1[0] * xfac, c2[0], tol)
+ self.assertAlmostEqual(c1[1] * yfac, c2[1], tol)
+
+ @no_mysql
+ @no_oracle
+ @no_spatialite
+ def test_snap_to_grid(self):
"Testing GeoQuerySet.snap_to_grid()."
# Let's try and break snap_to_grid() with bad combinations of arguments.
for bad_args in ((), range(3), range(5)):
self.assertRaises(ValueError, Country.objects.snap_to_grid, *bad_args)
- for bad_args in (('1.0',), (1.0, None), tuple(map(unicode, range(4)))):
+ for bad_args in (('1.0',), (1.0, None), tuple(map(six.text_type, range(4)))):
self.assertRaises(TypeError, Country.objects.snap_to_grid, *bad_args)
# Boundary for San Marino, courtesy of Bjorn Sandvik of thematicmapping.org
@@ -694,48 +672,78 @@ class GeoModelTest(TestCase):
ref = fromstr('MULTIPOLYGON(((12.4 43.87,12.45 43.87,12.45 44.1,12.5 44.1,12.5 43.87,12.45 43.87,12.4 43.87)))')
self.assertTrue(ref.equals_exact(Country.objects.snap_to_grid(0.05, 0.23, 0.5, 0.17).get(name='San Marino').snap_to_grid, tol))
+ def test_svg(self):
+ "Testing SVG output using GeoQuerySet.svg()."
+ if mysql or oracle:
+ self.assertRaises(NotImplementedError, City.objects.svg)
+ return
+
+ self.assertRaises(TypeError, City.objects.svg, precision='foo')
+ # SELECT AsSVG(geoapp_city.point, 0, 8) FROM geoapp_city WHERE name = 'Pueblo';
+ svg1 = 'cx="-104.609252" cy="-38.255001"'
+ # Even though relative, only one point so it's practically the same except for
+ # the 'c' letter prefix on the x,y values.
+ svg2 = svg1.replace('c', '')
+ self.assertEqual(svg1, City.objects.svg().get(name='Pueblo').svg)
+ self.assertEqual(svg2, City.objects.svg(relative=5).get(name='Pueblo').svg)
+
@no_mysql
- @no_spatialite
- def test28_reverse(self):
- "Testing GeoQuerySet.reverse_geom()."
- coords = [ (-95.363151, 29.763374), (-95.448601, 29.713803) ]
- Track.objects.create(name='Foo', line=LineString(coords))
- t = Track.objects.reverse_geom().get(name='Foo')
- coords.reverse()
- self.assertEqual(tuple(coords), t.reverse_geom.coords)
+ def test_transform(self):
+ "Testing the transform() GeoQuerySet method."
+ # Pre-transformed points for Houston and Pueblo.
+ htown = fromstr('POINT(1947516.83115183 6322297.06040572)', srid=3084)
+ ptown = fromstr('POINT(992363.390841912 481455.395105533)', srid=2774)
+ prec = 3 # Precision is low due to version variations in PROJ and GDAL.
+
+ # Asserting the result of the transform operation with the values in
+ # the pre-transformed points. Oracle does not have the 3084 SRID.
+ if not oracle:
+ h = City.objects.transform(htown.srid).get(name='Houston')
+ self.assertEqual(3084, h.point.srid)
+ self.assertAlmostEqual(htown.x, h.point.x, prec)
+ self.assertAlmostEqual(htown.y, h.point.y, prec)
+
+ p1 = City.objects.transform(ptown.srid, field_name='point').get(name='Pueblo')
+ p2 = City.objects.transform(srid=ptown.srid).get(name='Pueblo')
+ for p in [p1, p2]:
+ self.assertEqual(2774, p.point.srid)
+ self.assertAlmostEqual(ptown.x, p.point.x, prec)
+ self.assertAlmostEqual(ptown.y, p.point.y, prec)
+
+ @no_mysql
+ @no_oracle
+ def test_translate(self):
+ "Testing the `translate` GeoQuerySet method."
+ xfac, yfac = 5, -23
+ qs = Country.objects.translate(xfac, yfac, model_att='translated')
+ for c in qs:
+ for p1, p2 in zip(c.mpoly, c.translated):
+ for r1, r2 in zip(p1, p2):
+ for c1, c2 in zip(r1.coords, r2.coords):
+ # XXX The low precision is for SpatiaLite
+ self.assertAlmostEqual(c1[0] + xfac, c2[0], 5)
+ self.assertAlmostEqual(c1[1] + yfac, c2[1], 5)
+
+ @no_mysql
+ def test_unionagg(self):
+ "Testing the `unionagg` (aggregate union) GeoQuerySet method."
+ tx = Country.objects.get(name='Texas').mpoly
+ # Houston, Dallas -- Oracle has different order.
+ union1 = fromstr('MULTIPOINT(-96.801611 32.782057,-95.363151 29.763374)')
+ union2 = fromstr('MULTIPOINT(-96.801611 32.782057,-95.363151 29.763374)')
+ qs = City.objects.filter(point__within=tx)
+ self.assertRaises(TypeError, qs.unionagg, 'name')
+ # Using `field_name` keyword argument in one query and specifying an
+ # order in the other (which should not be used because this is
+ # an aggregate method on a spatial column)
+ u1 = qs.unionagg(field_name='point')
+ u2 = qs.order_by('name').unionagg()
+ tol = 0.00001
if oracle:
- self.assertRaises(TypeError, State.objects.reverse_geom)
-
- @no_mysql
- @no_oracle
- @no_spatialite
- def test29_force_rhr(self):
- "Testing GeoQuerySet.force_rhr()."
- rings = ( ( (0, 0), (5, 0), (0, 5), (0, 0) ),
- ( (1, 1), (1, 3), (3, 1), (1, 1) ),
- )
- rhr_rings = ( ( (0, 0), (0, 5), (5, 0), (0, 0) ),
- ( (1, 1), (3, 1), (1, 3), (1, 1) ),
- )
- State.objects.create(name='Foo', poly=Polygon(*rings))
- s = State.objects.force_rhr().get(name='Foo')
- self.assertEqual(rhr_rings, s.force_rhr.coords)
-
- @no_mysql
- @no_oracle
- @no_spatialite
- def test30_geohash(self):
- "Testing GeoQuerySet.geohash()."
- if not connection.ops.geohash: return
- # Reference query:
- # SELECT ST_GeoHash(point) FROM geoapp_city WHERE name='Houston';
- # SELECT ST_GeoHash(point, 5) FROM geoapp_city WHERE name='Houston';
- ref_hash = '9vk1mfq8jx0c8e0386z6'
- h1 = City.objects.geohash().get(name='Houston')
- h2 = City.objects.geohash(precision=5).get(name='Houston')
- self.assertEqual(ref_hash, h1.geohash)
- self.assertEqual(ref_hash[:5], h2.geohash)
-
-from .test_feeds import GeoFeedTest
-from .test_regress import GeoRegressionTests
-from .test_sitemaps import GeoSitemapTest
+ union = union2
+ else:
+ union = union1
+ self.assertEqual(True, union.equals_exact(u1, tol))
+ self.assertEqual(True, union.equals_exact(u2, tol))
+ qs = City.objects.filter(name='NotACity')
+ self.assertEqual(None, qs.unionagg(field_name='point'))
diff --git a/django/contrib/gis/tests/geogapp/models.py b/django/contrib/gis/tests/geogapp/models.py
index 3696ba2ff4..7e802f9321 100644
--- a/django/contrib/gis/tests/geogapp/models.py
+++ b/django/contrib/gis/tests/geogapp/models.py
@@ -1,20 +1,24 @@
from django.contrib.gis.db import models
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class City(models.Model):
name = models.CharField(max_length=30)
point = models.PointField(geography=True)
objects = models.GeoManager()
- def __unicode__(self): return self.name
+ def __str__(self): return self.name
+@python_2_unicode_compatible
class Zipcode(models.Model):
code = models.CharField(max_length=10)
poly = models.PolygonField(geography=True)
objects = models.GeoManager()
- def __unicode__(self): return self.code
+ def __str__(self): return self.code
+@python_2_unicode_compatible
class County(models.Model):
name = models.CharField(max_length=25)
state = models.CharField(max_length=20)
mpoly = models.MultiPolygonField(geography=True)
objects = models.GeoManager()
- def __unicode__(self): return ' County, '.join([self.name, self.state])
+ def __str__(self): return ' County, '.join([self.name, self.state])
diff --git a/django/contrib/gis/tests/relatedapp/models.py b/django/contrib/gis/tests/relatedapp/models.py
index aec4e15749..659fef7a93 100644
--- a/django/contrib/gis/tests/relatedapp/models.py
+++ b/django/contrib/gis/tests/relatedapp/models.py
@@ -1,37 +1,41 @@
from django.contrib.gis.db import models
from django.contrib.localflavor.us.models import USStateField
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class Location(models.Model):
point = models.PointField()
objects = models.GeoManager()
- def __unicode__(self): return self.point.wkt
+ def __str__(self): return self.point.wkt
+@python_2_unicode_compatible
class City(models.Model):
name = models.CharField(max_length=50)
state = USStateField()
location = models.ForeignKey(Location)
objects = models.GeoManager()
- def __unicode__(self): return self.name
+ def __str__(self): return self.name
class AugmentedLocation(Location):
extra_text = models.TextField(blank=True)
objects = models.GeoManager()
-
+
class DirectoryEntry(models.Model):
listing_text = models.CharField(max_length=50)
location = models.ForeignKey(AugmentedLocation)
objects = models.GeoManager()
+@python_2_unicode_compatible
class Parcel(models.Model):
name = models.CharField(max_length=30)
city = models.ForeignKey(City)
center1 = models.PointField()
# Throwing a curveball w/`db_column` here.
- center2 = models.PointField(srid=2276, db_column='mycenter')
+ center2 = models.PointField(srid=2276, db_column='mycenter')
border1 = models.PolygonField()
border2 = models.PolygonField(srid=2276)
objects = models.GeoManager()
- def __unicode__(self): return self.name
+ def __str__(self): return self.name
# These use the GeoManager but do not have any geographic fields.
class Author(models.Model):
diff --git a/django/contrib/gis/tests/test_geoforms.py b/django/contrib/gis/tests/test_geoforms.py
index 59fab0166e..ed851df0d2 100644
--- a/django/contrib/gis/tests/test_geoforms.py
+++ b/django/contrib/gis/tests/test_geoforms.py
@@ -1,9 +1,14 @@
from django.forms import ValidationError
-from django.contrib.gis import forms
-from django.contrib.gis.geos import GEOSGeometry
+from django.contrib.gis.gdal import HAS_GDAL
+from django.contrib.gis.tests.utils import HAS_SPATIALREFSYS
from django.utils import unittest
+if HAS_SPATIALREFSYS:
+ from django.contrib.gis import forms
+ from django.contrib.gis.geos import GEOSGeometry
+
+@unittest.skipUnless(HAS_GDAL and HAS_SPATIALREFSYS, "GeometryFieldTest needs gdal support and a spatial database")
class GeometryFieldTest(unittest.TestCase):
def test00_init(self):
@@ -51,8 +56,25 @@ class GeometryFieldTest(unittest.TestCase):
pnt_fld = forms.GeometryField(geom_type='POINT')
self.assertEqual(GEOSGeometry('POINT(5 23)'), pnt_fld.clean('POINT(5 23)'))
+ # a WKT for any other geom_type will be properly transformed by `to_python`
+ self.assertEqual(GEOSGeometry('LINESTRING(0 0, 1 1)'), pnt_fld.to_python('LINESTRING(0 0, 1 1)'))
+ # but rejected by `clean`
self.assertRaises(forms.ValidationError, pnt_fld.clean, 'LINESTRING(0 0, 1 1)')
+ def test04_to_python(self):
+ """
+ Testing to_python returns a correct GEOSGeometry object or
+ a ValidationError
+ """
+ fld = forms.GeometryField()
+ # to_python returns the same GEOSGeometry for a WKT
+ for wkt in ('POINT(5 23)', 'MULTIPOLYGON(((0 0, 0 1, 1 1, 1 0, 0 0)))', 'LINESTRING(0 0, 1 1)'):
+ self.assertEqual(GEOSGeometry(wkt), fld.to_python(wkt))
+ # but raises a ValidationError for any other string
+ for wkt in ('POINT(5)', 'MULTI POLYGON(((0 0, 0 1, 1 1, 1 0, 0 0)))', 'BLAH(0 0, 1 1)'):
+ self.assertRaises(forms.ValidationError, fld.to_python, wkt)
+
+
def suite():
s = unittest.TestSuite()
s.addTest(unittest.makeSuite(GeometryFieldTest))
diff --git a/django/contrib/gis/tests/test_measure.py b/django/contrib/gis/tests/test_measure.py
index f3325628b6..0428704d6c 100644
--- a/django/contrib/gis/tests/test_measure.py
+++ b/django/contrib/gis/tests/test_measure.py
@@ -93,6 +93,8 @@ class DistanceTest(unittest.TestCase):
self.assertEqual(d4.m, 50)
d4 /= 5
self.assertEqual(d4.m, 10)
+ d5 = d1 / D(m=2)
+ self.assertEqual(d5, 50)
a5 = d1 * D(m=10)
self.assertTrue(isinstance(a5, Area))
@@ -102,10 +104,6 @@ class DistanceTest(unittest.TestCase):
d1 *= D(m=1)
self.fail('Distance *= Distance should raise TypeError')
- with self.assertRaises(TypeError):
- d5 = d1 / D(m=1)
- self.fail('Distance / Distance should raise TypeError')
-
with self.assertRaises(TypeError):
d1 /= D(m=1)
self.fail('Distance /= Distance should raise TypeError')
diff --git a/django/contrib/gis/tests/test_spatialrefsys.py b/django/contrib/gis/tests/test_spatialrefsys.py
index 608f6453c2..5cdc68a74d 100644
--- a/django/contrib/gis/tests/test_spatialrefsys.py
+++ b/django/contrib/gis/tests/test_spatialrefsys.py
@@ -1,6 +1,7 @@
from django.db import connection
-from django.contrib.gis.gdal import GDAL_VERSION
-from django.contrib.gis.tests.utils import no_mysql, oracle, postgis, spatialite
+from django.contrib.gis.gdal import HAS_GDAL
+from django.contrib.gis.tests.utils import (no_mysql, oracle, postgis,
+ spatialite, HAS_SPATIALREFSYS, SpatialRefSys)
from django.utils import unittest
@@ -28,13 +29,8 @@ test_srs = ({'srid' : 4326,
},
)
-if oracle:
- from django.contrib.gis.db.backends.oracle.models import SpatialRefSys
-elif postgis:
- from django.contrib.gis.db.backends.postgis.models import SpatialRefSys
-elif spatialite:
- from django.contrib.gis.db.backends.spatialite.models import SpatialRefSys
-
+@unittest.skipUnless(HAS_GDAL and HAS_SPATIALREFSYS,
+ "SpatialRefSysTest needs gdal support and a spatial database")
class SpatialRefSysTest(unittest.TestCase):
@no_mysql
@@ -65,6 +61,7 @@ class SpatialRefSysTest(unittest.TestCase):
@no_mysql
def test02_osr(self):
"Testing getting OSR objects from SpatialRefSys model objects."
+ from django.contrib.gis.gdal import GDAL_VERSION
for sd in test_srs:
sr = SpatialRefSys.objects.get(srid=sd['srid'])
self.assertEqual(True, sr.spheroid.startswith(sd['spheroid']))
diff --git a/django/contrib/gis/tests/utils.py b/django/contrib/gis/tests/utils.py
index b758fd0fee..a83ba8a93f 100644
--- a/django/contrib/gis/tests/utils.py
+++ b/django/contrib/gis/tests/utils.py
@@ -24,3 +24,14 @@ oracle = _default_db == 'oracle'
postgis = _default_db == 'postgis'
mysql = _default_db == 'mysql'
spatialite = _default_db == 'spatialite'
+
+HAS_SPATIALREFSYS = True
+if oracle:
+ from django.contrib.gis.db.backends.oracle.models import SpatialRefSys
+elif postgis:
+ from django.contrib.gis.db.backends.postgis.models import SpatialRefSys
+elif spatialite:
+ from django.contrib.gis.db.backends.spatialite.models import SpatialRefSys
+else:
+ HAS_SPATIALREFSYS = False
+ SpatialRefSys = None
diff --git a/django/contrib/gis/utils/layermapping.py b/django/contrib/gis/utils/layermapping.py
index 48d6c1b70e..e898f6de2e 100644
--- a/django/contrib/gis/utils/layermapping.py
+++ b/django/contrib/gis/utils/layermapping.py
@@ -17,6 +17,7 @@ from django.contrib.gis.gdal.field import (
OFTDate, OFTDateTime, OFTInteger, OFTReal, OFTString, OFTTime)
from django.db import models, transaction
from django.contrib.localflavor.us.models import USStateField
+from django.utils import six
# LayerMapping exceptions.
class LayerMapError(Exception): pass
@@ -74,7 +75,7 @@ class LayerMapping(object):
argument usage.
"""
# Getting the DataSource and the associated Layer.
- if isinstance(data, basestring):
+ if isinstance(data, six.string_types):
self.ds = DataSource(data)
else:
self.ds = data
@@ -249,7 +250,7 @@ class LayerMapping(object):
sr = source_srs
elif isinstance(source_srs, self.spatial_backend.spatial_ref_sys()):
sr = source_srs.srs
- elif isinstance(source_srs, (int, basestring)):
+ elif isinstance(source_srs, (int, six.string_types)):
sr = SpatialReference(source_srs)
else:
# Otherwise just pulling the SpatialReference from the layer
@@ -266,7 +267,7 @@ class LayerMapping(object):
# List of fields to determine uniqueness with
for attr in unique:
if not attr in self.mapping: raise ValueError
- elif isinstance(unique, basestring):
+ elif isinstance(unique, six.string_types):
# Only a single field passed in.
if unique not in self.mapping: raise ValueError
else:
@@ -312,7 +313,7 @@ class LayerMapping(object):
will construct and return the uniqueness keyword arguments -- a subset
of the feature kwargs.
"""
- if isinstance(self.unique, basestring):
+ if isinstance(self.unique, six.string_types):
return {self.unique : kwargs[self.unique]}
else:
return dict((fld, kwargs[fld]) for fld in self.unique)
@@ -329,7 +330,7 @@ class LayerMapping(object):
if self.encoding:
# The encoding for OGR data sources may be specified here
# (e.g., 'cp437' for Census Bureau boundary files).
- val = unicode(ogr_field.value, self.encoding)
+ val = six.text_type(ogr_field.value, self.encoding)
else:
val = ogr_field.value
if model_field.max_length and len(val) > model_field.max_length:
diff --git a/django/contrib/gis/utils/ogrinspect.py b/django/contrib/gis/utils/ogrinspect.py
index a9a0362eef..4266ee4b4c 100644
--- a/django/contrib/gis/utils/ogrinspect.py
+++ b/django/contrib/gis/utils/ogrinspect.py
@@ -5,10 +5,11 @@ models for GeoDjango and/or mapping dictionaries for use with the
Author: Travis Pinney, Dane Springmeyer, & Justin Bronn
"""
-from future_builtins import zip
+from django.utils.six.moves import zip
# Requires GDAL to use.
from django.contrib.gis.gdal import DataSource
from django.contrib.gis.gdal.field import OFTDate, OFTDateTime, OFTInteger, OFTReal, OFTString, OFTTime
+from django.utils import six
def mapping(data_source, geom_name='geom', layer_key=0, multi_geom=False):
"""
@@ -24,7 +25,7 @@ def mapping(data_source, geom_name='geom', layer_key=0, multi_geom=False):
`multi_geom` => Boolean (default: False) - specify as multigeometry.
"""
- if isinstance(data_source, basestring):
+ if isinstance(data_source, six.string_types):
# Instantiating the DataSource from the string.
data_source = DataSource(data_source)
elif isinstance(data_source, DataSource):
@@ -222,4 +223,4 @@ def _ogrinspect(data_source, model_name, geom_name='geom', layer_key=0, srid=Non
if name_field:
yield ''
- yield ' def __unicode__(self): return self.%s' % name_field
+ yield ' def __str__(self): return self.%s' % name_field
diff --git a/django/contrib/gis/utils/wkt.py b/django/contrib/gis/utils/wkt.py
index 4aecc6247d..d60eed31bd 100644
--- a/django/contrib/gis/utils/wkt.py
+++ b/django/contrib/gis/utils/wkt.py
@@ -2,9 +2,11 @@
Utilities for manipulating Geometry WKT.
"""
+from django.utils import six
+
def precision_wkt(geom, prec):
"""
- Returns WKT text of the geometry according to the given precision (an
+ Returns WKT text of the geometry according to the given precision (an
integer or a string). If the precision is an integer, then the decimal
places of coordinates WKT will be truncated to that number:
@@ -14,12 +16,12 @@ def precision_wkt(geom, prec):
>>> precision(geom, 1)
'POINT (5.0 23.0)'
- If the precision is a string, it must be valid Python format string
+ If the precision is a string, it must be valid Python format string
(e.g., '%20.7f') -- thus, you should know what you're doing.
"""
if isinstance(prec, int):
num_fmt = '%%.%df' % prec
- elif isinstance(prec, basestring):
+ elif isinstance(prec, six.string_types):
num_fmt = prec
else:
raise TypeError
diff --git a/django/contrib/gis/views.py b/django/contrib/gis/views.py
index fc51a0bf3a..3fa8f044de 100644
--- a/django/contrib/gis/views.py
+++ b/django/contrib/gis/views.py
@@ -1,10 +1,12 @@
+from __future__ import unicode_literals
+
from django.http import Http404
from django.utils.translation import ugettext as _
def feed(request, url, feed_dict=None):
"""Provided for backwards compatibility."""
if not feed_dict:
- raise Http404(_(u"No feeds are registered."))
+ raise Http404(_("No feeds are registered."))
try:
slug, param = url.split('/', 1)
@@ -14,7 +16,7 @@ def feed(request, url, feed_dict=None):
try:
f = feed_dict[slug]
except KeyError:
- raise Http404(_(u"Slug %r isn't registered.") % slug)
+ raise Http404(_("Slug %r isn't registered.") % slug)
instance = f()
instance.feed_url = getattr(f, 'feed_url', None) or request.path
diff --git a/django/contrib/humanize/templatetags/humanize.py b/django/contrib/humanize/templatetags/humanize.py
index b075ff05c7..7e8f163174 100644
--- a/django/contrib/humanize/templatetags/humanize.py
+++ b/django/contrib/humanize/templatetags/humanize.py
@@ -1,10 +1,11 @@
+from __future__ import unicode_literals
import re
-from datetime import date, datetime, timedelta
+from datetime import date, datetime
from django import template
from django.conf import settings
from django.template import defaultfilters
-from django.utils.encoding import force_unicode
+from django.utils.encoding import force_text
from django.utils.formats import number_format
from django.utils.translation import pgettext, ungettext, ugettext as _
from django.utils.timezone import is_aware, utc
@@ -23,8 +24,8 @@ def ordinal(value):
return value
suffixes = (_('th'), _('st'), _('nd'), _('rd'), _('th'), _('th'), _('th'), _('th'), _('th'), _('th'))
if value % 100 in (11, 12, 13): # special case
- return u"%d%s" % (value, suffixes[0])
- return u"%d%s" % (value, suffixes[value % 10])
+ return "%d%s" % (value, suffixes[0])
+ return "%d%s" % (value, suffixes[value % 10])
@register.filter(is_safe=True)
def intcomma(value, use_l10n=True):
@@ -40,7 +41,7 @@ def intcomma(value, use_l10n=True):
return intcomma(value, False)
else:
return number_format(value, force_grouping=True)
- orig = force_unicode(value)
+ orig = force_text(value)
new = re.sub("^(-?\d+)(\d{3})", '\g<1>,\g<2>', orig)
if orig == new:
return new
@@ -142,7 +143,9 @@ def apnumber(value):
return value
return (_('one'), _('two'), _('three'), _('four'), _('five'), _('six'), _('seven'), _('eight'), _('nine'))[value-1]
-@register.filter
+# Perform the comparison in the default time zone when USE_TZ = True
+# (unless a specific time zone has been applied with the |timezone filter).
+@register.filter(expects_localtime=True)
def naturalday(value, arg=None):
"""
For date values that are tomorrow, today or yesterday compared to
@@ -161,13 +164,15 @@ def naturalday(value, arg=None):
today = datetime.now(tzinfo).date()
delta = value - today
if delta.days == 0:
- return _(u'today')
+ return _('today')
elif delta.days == 1:
- return _(u'tomorrow')
+ return _('tomorrow')
elif delta.days == -1:
- return _(u'yesterday')
+ return _('yesterday')
return defaultfilters.date(value, arg)
+# This filter doesn't require expects_localtime=True because it deals properly
+# with both naive and aware datetimes. Therefore avoid the cost of conversion.
@register.filter
def naturaltime(value):
"""
@@ -183,42 +188,42 @@ def naturaltime(value):
if delta.days != 0:
return pgettext(
'naturaltime', '%(delta)s ago'
- ) % {'delta': defaultfilters.timesince(value)}
+ ) % {'delta': defaultfilters.timesince(value, now)}
elif delta.seconds == 0:
- return _(u'now')
+ return _('now')
elif delta.seconds < 60:
return ungettext(
- u'a second ago', u'%(count)s seconds ago', delta.seconds
+ 'a second ago', '%(count)s seconds ago', delta.seconds
) % {'count': delta.seconds}
elif delta.seconds // 60 < 60:
count = delta.seconds // 60
return ungettext(
- u'a minute ago', u'%(count)s minutes ago', count
+ 'a minute ago', '%(count)s minutes ago', count
) % {'count': count}
else:
count = delta.seconds // 60 // 60
return ungettext(
- u'an hour ago', u'%(count)s hours ago', count
+ 'an hour ago', '%(count)s hours ago', count
) % {'count': count}
else:
delta = value - now
if delta.days != 0:
return pgettext(
'naturaltime', '%(delta)s from now'
- ) % {'delta': defaultfilters.timeuntil(value)}
+ ) % {'delta': defaultfilters.timeuntil(value, now)}
elif delta.seconds == 0:
- return _(u'now')
+ return _('now')
elif delta.seconds < 60:
return ungettext(
- u'a second from now', u'%(count)s seconds from now', delta.seconds
+ 'a second from now', '%(count)s seconds from now', delta.seconds
) % {'count': delta.seconds}
elif delta.seconds // 60 < 60:
count = delta.seconds // 60
return ungettext(
- u'a minute from now', u'%(count)s minutes from now', count
+ 'a minute from now', '%(count)s minutes from now', count
) % {'count': count}
else:
count = delta.seconds // 60 // 60
return ungettext(
- u'an hour from now', u'%(count)s hours from now', count
+ 'an hour from now', '%(count)s hours from now', count
) % {'count': count}
diff --git a/django/contrib/humanize/tests.py b/django/contrib/humanize/tests.py
index bf6684766b..a0f13d3ee9 100644
--- a/django/contrib/humanize/tests.py
+++ b/django/contrib/humanize/tests.py
@@ -1,12 +1,31 @@
+from __future__ import unicode_literals
import datetime
-import new
+from django.contrib.humanize.templatetags import humanize
from django.template import Template, Context, defaultfilters
from django.test import TestCase
-from django.utils import translation, tzinfo
-from django.utils.translation import ugettext as _
+from django.test.utils import override_settings
from django.utils.html import escape
from django.utils.timezone import utc
+from django.utils import translation
+from django.utils.translation import ugettext as _
+from django.utils import tzinfo
+
+
+# Mock out datetime in some tests so they don't fail occasionally when they
+# run too slow. Use a fixed datetime for datetime.now(). DST change in
+# America/Chicago (the default time zone) happened on March 11th in 2012.
+
+now = datetime.datetime(2012, 3, 9, 22, 30)
+
+class MockDateTime(datetime.datetime):
+ @classmethod
+ def now(self, tz=None):
+ if tz is None or tz.utcoffset(now) is None:
+ return now
+ else:
+ # equals now.replace(tzinfo=utc)
+ return now.replace(tzinfo=tz) + tz.utcoffset(now)
class HumanizeTests(TestCase):
@@ -89,8 +108,8 @@ class HumanizeTests(TestCase):
def test_apnumber(self):
test_list = [str(x) for x in range(1, 11)]
test_list.append(None)
- result_list = (u'one', u'two', u'three', u'four', u'five', u'six',
- u'seven', u'eight', u'nine', u'10', None)
+ result_list = ('one', 'two', 'three', 'four', 'five', 'six',
+ 'seven', 'eight', 'nine', '10', None)
self.humanize_tester(test_list, result_list, 'apnumber')
@@ -99,37 +118,45 @@ class HumanizeTests(TestCase):
yesterday = today - datetime.timedelta(days=1)
tomorrow = today + datetime.timedelta(days=1)
someday = today - datetime.timedelta(days=10)
- notdate = u"I'm not a date value"
+ notdate = "I'm not a date value"
test_list = (today, yesterday, tomorrow, someday, notdate, None)
someday_result = defaultfilters.date(someday)
- result_list = (_(u'today'), _(u'yesterday'), _(u'tomorrow'),
- someday_result, u"I'm not a date value", None)
+ result_list = (_('today'), _('yesterday'), _('tomorrow'),
+ someday_result, "I'm not a date value", None)
self.humanize_tester(test_list, result_list, 'naturalday')
def test_naturalday_tz(self):
- from django.contrib.humanize.templatetags.humanize import naturalday
-
today = datetime.date.today()
tz_one = tzinfo.FixedOffset(datetime.timedelta(hours=-12))
tz_two = tzinfo.FixedOffset(datetime.timedelta(hours=12))
# Can be today or yesterday
date_one = datetime.datetime(today.year, today.month, today.day, tzinfo=tz_one)
- naturalday_one = naturalday(date_one)
+ naturalday_one = humanize.naturalday(date_one)
# Can be today or tomorrow
date_two = datetime.datetime(today.year, today.month, today.day, tzinfo=tz_two)
- naturalday_two = naturalday(date_two)
+ naturalday_two = humanize.naturalday(date_two)
# As 24h of difference they will never be the same
self.assertNotEqual(naturalday_one, naturalday_two)
+ def test_naturalday_uses_localtime(self):
+ # Regression for #18504
+ # This is 2012-03-08HT19:30:00-06:00 in Ameria/Chicago
+ dt = datetime.datetime(2012, 3, 9, 1, 30, tzinfo=utc)
+
+ orig_humanize_datetime, humanize.datetime = humanize.datetime, MockDateTime
+ try:
+ with override_settings(USE_TZ=True):
+ self.humanize_tester([dt], ['yesterday'], 'naturalday')
+ finally:
+ humanize.datetime = orig_humanize_datetime
+
def test_naturaltime(self):
class naive(datetime.tzinfo):
def utcoffset(self, dt):
return None
- # we're going to mock datetime.datetime, so use a fixed datetime
- now = datetime.datetime(2011, 8, 15)
test_list = [
now,
now - datetime.timedelta(seconds=1),
@@ -147,6 +174,7 @@ class HumanizeTests(TestCase):
now + datetime.timedelta(hours=1, minutes=30, seconds=30),
now + datetime.timedelta(hours=23, minutes=50, seconds=50),
now + datetime.timedelta(days=1),
+ now + datetime.timedelta(days=2, hours=6),
now + datetime.timedelta(days=500),
now.replace(tzinfo=naive()),
now.replace(tzinfo=utc),
@@ -168,33 +196,22 @@ class HumanizeTests(TestCase):
'an hour from now',
'23 hours from now',
'1 day from now',
+ '2 days, 6 hours from now',
'1 year, 4 months from now',
'now',
'now',
]
+ # Because of the DST change, 2 days and 6 hours after the chosen
+ # date in naive arithmetic is only 2 days and 5 hours after in
+ # aware arithmetic.
+ result_list_with_tz_support = result_list[:]
+ assert result_list_with_tz_support[-4] == '2 days, 6 hours from now'
+ result_list_with_tz_support[-4] == '2 days, 5 hours from now'
- # mock out datetime so these tests don't fail occasionally when the
- # test runs too slow
- class MockDateTime(datetime.datetime):
- @classmethod
- def now(self, tz=None):
- if tz is None or tz.utcoffset(now) is None:
- return now
- else:
- # equals now.replace(tzinfo=utc)
- return now.replace(tzinfo=tz) + tz.utcoffset(now)
-
- # naturaltime also calls timesince/timeuntil
- from django.contrib.humanize.templatetags import humanize
- from django.utils import timesince
- orig_humanize_datetime = humanize.datetime
- orig_timesince_datetime = timesince.datetime
- humanize.datetime = MockDateTime
- timesince.datetime = new.module(b"mock_datetime")
- timesince.datetime.datetime = MockDateTime
-
+ orig_humanize_datetime, humanize.datetime = humanize.datetime, MockDateTime
try:
self.humanize_tester(test_list, result_list, 'naturaltime')
+ with override_settings(USE_TZ=True):
+ self.humanize_tester(test_list, result_list_with_tz_support, 'naturaltime')
finally:
humanize.datetime = orig_humanize_datetime
- timesince.datetime = orig_timesince_datetime
diff --git a/django/contrib/localflavor/ar/ar_provinces.py b/django/contrib/localflavor/ar/ar_provinces.py
index a0efd4ba33..600ef1eb16 100644
--- a/django/contrib/localflavor/ar/ar_provinces.py
+++ b/django/contrib/localflavor/ar/ar_provinces.py
@@ -7,30 +7,31 @@ http://www.argentina.gov.ar/argentina/portal/paginas.dhtml?pagina=425
This exists in this standalone file so that it's only imported into memory
when explicitly needed.
"""
+from __future__ import unicode_literals
PROVINCE_CHOICES = (
- ('B', u'Buenos Aires'),
- ('K', u'Catamarca'),
- ('H', u'Chaco'),
- ('U', u'Chubut'),
- ('C', u'Ciudad Autónoma de Buenos Aires'),
- ('X', u'Córdoba'),
- ('W', u'Corrientes'),
- ('E', u'Entre Ríos'),
- ('P', u'Formosa'),
- ('Y', u'Jujuy'),
- ('L', u'La Pampa'),
- ('F', u'La Rioja'),
- ('M', u'Mendoza'),
- ('N', u'Misiones'),
- ('Q', u'Neuquén'),
- ('R', u'Río Negro'),
- ('A', u'Salta'),
- ('J', u'San Juan'),
- ('D', u'San Luis'),
- ('Z', u'Santa Cruz'),
- ('S', u'Santa Fe'),
- ('G', u'Santiago del Estero'),
- ('V', u'Tierra del Fuego, Antártida e Islas del Atlántico Sur'),
- ('T', u'Tucumán'),
+ ('B', 'Buenos Aires'),
+ ('K', 'Catamarca'),
+ ('H', 'Chaco'),
+ ('U', 'Chubut'),
+ ('C', 'Ciudad Autónoma de Buenos Aires'),
+ ('X', 'Córdoba'),
+ ('W', 'Corrientes'),
+ ('E', 'Entre Ríos'),
+ ('P', 'Formosa'),
+ ('Y', 'Jujuy'),
+ ('L', 'La Pampa'),
+ ('F', 'La Rioja'),
+ ('M', 'Mendoza'),
+ ('N', 'Misiones'),
+ ('Q', 'Neuquén'),
+ ('R', 'Río Negro'),
+ ('A', 'Salta'),
+ ('J', 'San Juan'),
+ ('D', 'San Luis'),
+ ('Z', 'Santa Cruz'),
+ ('S', 'Santa Fe'),
+ ('G', 'Santiago del Estero'),
+ ('V', 'Tierra del Fuego, Antártida e Islas del Atlántico Sur'),
+ ('T', 'Tucumán'),
)
diff --git a/django/contrib/localflavor/ar/forms.py b/django/contrib/localflavor/ar/forms.py
index 1805839ce4..dc4235f9dd 100644
--- a/django/contrib/localflavor/ar/forms.py
+++ b/django/contrib/localflavor/ar/forms.py
@@ -3,7 +3,7 @@
AR-specific Form helpers.
"""
-from __future__ import absolute_import
+from __future__ import absolute_import, unicode_literals
from django.contrib.localflavor.ar.ar_provinces import PROVINCE_CHOICES
from django.core.validators import EMPTY_VALUES
@@ -37,11 +37,11 @@ class ARPostalCodeField(RegexField):
def clean(self, value):
value = super(ARPostalCodeField, self).clean(value)
if value in EMPTY_VALUES:
- return u''
+ return ''
if len(value) not in (4, 8):
raise ValidationError(self.error_messages['invalid'])
if len(value) == 8:
- return u'%s%s%s' % (value[0].upper(), value[1:5], value[5:].upper())
+ return '%s%s%s' % (value[0].upper(), value[1:5], value[5:].upper())
return value
class ARDNIField(CharField):
@@ -63,7 +63,7 @@ class ARDNIField(CharField):
"""
value = super(ARDNIField, self).clean(value)
if value in EMPTY_VALUES:
- return u''
+ return ''
if not value.isdigit():
value = value.replace('.', '')
if not value.isdigit():
@@ -81,6 +81,7 @@ class ARCUITField(RegexField):
default_error_messages = {
'invalid': _('Enter a valid CUIT in XX-XXXXXXXX-X or XXXXXXXXXXXX format.'),
'checksum': _("Invalid CUIT."),
+ 'legal_type': _('Invalid legal type. Type must be 27, 20, 23 or 30.'),
}
def __init__(self, max_length=None, min_length=None, *args, **kwargs):
@@ -94,8 +95,10 @@ class ARCUITField(RegexField):
"""
value = super(ARCUITField, self).clean(value)
if value in EMPTY_VALUES:
- return u''
+ return ''
value, cd = self._canon(value)
+ if not value[:2] in ['27', '20', '23', '30']:
+ raise ValidationError(self.error_messages['legal_type'])
if self._calc_cd(value) != cd:
raise ValidationError(self.error_messages['checksum'])
return self._format(value, cd)
@@ -105,13 +108,20 @@ class ARCUITField(RegexField):
return cuit[:-1], cuit[-1]
def _calc_cd(self, cuit):
+ # Calculation code based on:
+ # http://es.wikipedia.org/wiki/C%C3%B3digo_%C3%9Anico_de_Identificaci%C3%B3n_Tributaria
mults = (5, 4, 3, 2, 7, 6, 5, 4, 3, 2)
tmp = sum([m * int(cuit[idx]) for idx, m in enumerate(mults)])
- return str(11 - tmp % 11)
+ result = 11 - (tmp % 11)
+ if result == 11:
+ result = 0
+ elif result == 10:
+ result = 9
+ return str(result)
def _format(self, cuit, check_digit=None):
if check_digit == None:
check_digit = cuit[-1]
cuit = cuit[:-1]
- return u'%s-%s-%s' % (cuit[:2], cuit[2:], check_digit)
+ return '%s-%s-%s' % (cuit[:2], cuit[2:], check_digit)
diff --git a/django/contrib/localflavor/at/forms.py b/django/contrib/localflavor/at/forms.py
index 262641bf1f..c531bec2e9 100644
--- a/django/contrib/localflavor/at/forms.py
+++ b/django/contrib/localflavor/at/forms.py
@@ -1,7 +1,7 @@
"""
AT-specific Form helpers
"""
-
+from __future__ import unicode_literals
import re
from django.core.validators import EMPTY_VALUES
@@ -47,13 +47,13 @@ class ATSocialSecurityNumberField(Field):
"""
default_error_messages = {
- 'invalid': _(u'Enter a valid Austrian Social Security Number in XXXX XXXXXX format.'),
+ 'invalid': _('Enter a valid Austrian Social Security Number in XXXX XXXXXX format.'),
}
def clean(self, value):
value = super(ATSocialSecurityNumberField, self).clean(value)
if value in EMPTY_VALUES:
- return u""
+ return ""
if not re_ssn.search(value):
raise ValidationError(self.error_messages['invalid'])
sqnr, date = value.split(" ")
@@ -66,4 +66,4 @@ class ATSocialSecurityNumberField(Field):
res = res % 11
if res != int(check):
raise ValidationError(self.error_messages['invalid'])
- return u'%s%s %s'%(sqnr, check, date,)
+ return '%s%s %s'%(sqnr, check, date,)
diff --git a/django/contrib/localflavor/au/forms.py b/django/contrib/localflavor/au/forms.py
index 19df98dc33..d3a00e200c 100644
--- a/django/contrib/localflavor/au/forms.py
+++ b/django/contrib/localflavor/au/forms.py
@@ -2,7 +2,7 @@
Australian-specific Form helpers
"""
-from __future__ import absolute_import
+from __future__ import absolute_import, unicode_literals
import re
@@ -10,7 +10,7 @@ from django.contrib.localflavor.au.au_states import STATE_CHOICES
from django.core.validators import EMPTY_VALUES
from django.forms import ValidationError
from django.forms.fields import Field, RegexField, Select
-from django.utils.encoding import smart_unicode
+from django.utils.encoding import smart_text
from django.utils.translation import ugettext_lazy as _
@@ -34,7 +34,7 @@ class AUPostCodeField(RegexField):
class AUPhoneNumberField(Field):
"""Australian phone number field."""
default_error_messages = {
- 'invalid': u'Phone numbers must contain 10 digits.',
+ 'invalid': 'Phone numbers must contain 10 digits.',
}
def clean(self, value):
@@ -43,11 +43,11 @@ class AUPhoneNumberField(Field):
"""
super(AUPhoneNumberField, self).clean(value)
if value in EMPTY_VALUES:
- return u''
- value = re.sub('(\(|\)|\s+|-)', '', smart_unicode(value))
+ return ''
+ value = re.sub('(\(|\)|\s+|-)', '', smart_text(value))
phone_match = PHONE_DIGITS_RE.search(value)
if phone_match:
- return u'%s' % phone_match.group(1)
+ return '%s' % phone_match.group(1)
raise ValidationError(self.error_messages['invalid'])
diff --git a/django/contrib/localflavor/br/br_states.py b/django/contrib/localflavor/br/br_states.py
index 98e54bca2c..ab37b1d223 100644
--- a/django/contrib/localflavor/br/br_states.py
+++ b/django/contrib/localflavor/br/br_states.py
@@ -5,33 +5,34 @@ An alphabetical list of Brazilian states for use as `choices` in a formfield.
This exists in this standalone file so that it's only imported into memory
when explicitly needed.
"""
+from __future__ import unicode_literals
STATE_CHOICES = (
('AC', 'Acre'),
('AL', 'Alagoas'),
- ('AP', u'Amapá'),
+ ('AP', 'Amapá'),
('AM', 'Amazonas'),
('BA', 'Bahia'),
- ('CE', u'Ceará'),
+ ('CE', 'Ceará'),
('DF', 'Distrito Federal'),
- ('ES', u'Espírito Santo'),
- ('GO', u'Goiás'),
- ('MA', u'Maranhão'),
+ ('ES', 'Espírito Santo'),
+ ('GO', 'Goiás'),
+ ('MA', 'Maranhão'),
('MT', 'Mato Grosso'),
('MS', 'Mato Grosso do Sul'),
('MG', 'Minas Gerais'),
- ('PA', u'Pará'),
- ('PB', u'Paraíba'),
- ('PR', u'Paraná'),
+ ('PA', 'Pará'),
+ ('PB', 'Paraíba'),
+ ('PR', 'Paraná'),
('PE', 'Pernambuco'),
- ('PI', u'Piauí'),
+ ('PI', 'Piauí'),
('RJ', 'Rio de Janeiro'),
('RN', 'Rio Grande do Norte'),
('RS', 'Rio Grande do Sul'),
- ('RO', u'Rondônia'),
+ ('RO', 'Rondônia'),
('RR', 'Roraima'),
('SC', 'Santa Catarina'),
- ('SP', u'São Paulo'),
+ ('SP', 'São Paulo'),
('SE', 'Sergipe'),
('TO', 'Tocantins'),
)
diff --git a/django/contrib/localflavor/br/forms.py b/django/contrib/localflavor/br/forms.py
index 88c7f2efcc..0f957be37f 100644
--- a/django/contrib/localflavor/br/forms.py
+++ b/django/contrib/localflavor/br/forms.py
@@ -3,7 +3,7 @@
BR-specific Form helpers
"""
-from __future__ import absolute_import
+from __future__ import absolute_import, unicode_literals
import re
@@ -11,7 +11,7 @@ from django.contrib.localflavor.br.br_states import STATE_CHOICES
from django.core.validators import EMPTY_VALUES
from django.forms import ValidationError
from django.forms.fields import Field, RegexField, CharField, Select
-from django.utils.encoding import smart_unicode
+from django.utils.encoding import smart_text
from django.utils.translation import ugettext_lazy as _
@@ -34,11 +34,11 @@ class BRPhoneNumberField(Field):
def clean(self, value):
super(BRPhoneNumberField, self).clean(value)
if value in EMPTY_VALUES:
- return u''
- value = re.sub('(\(|\)|\s+)', '', smart_unicode(value))
+ return ''
+ value = re.sub('(\(|\)|\s+)', '', smart_text(value))
m = phone_digits_re.search(value)
if m:
- return u'%s-%s-%s' % (m.group(1), m.group(2), m.group(3))
+ return '%s-%s-%s' % (m.group(1), m.group(2), m.group(3))
raise ValidationError(self.error_messages['invalid'])
class BRStateSelect(Select):
@@ -55,7 +55,7 @@ class BRStateChoiceField(Field):
"""
widget = Select
default_error_messages = {
- 'invalid': _(u'Select a valid brazilian state. That state is not one of the available states.'),
+ 'invalid': _('Select a valid brazilian state. That state is not one of the available states.'),
}
def __init__(self, required=True, widget=None, label=None,
@@ -67,11 +67,11 @@ class BRStateChoiceField(Field):
def clean(self, value):
value = super(BRStateChoiceField, self).clean(value)
if value in EMPTY_VALUES:
- value = u''
- value = smart_unicode(value)
- if value == u'':
+ value = ''
+ value = smart_text(value)
+ if value == '':
return value
- valid_values = set([smart_unicode(k) for k, v in self.widget.choices])
+ valid_values = set([smart_text(k) for k, v in self.widget.choices])
if value not in valid_values:
raise ValidationError(self.error_messages['invalid'])
return value
@@ -105,7 +105,7 @@ class BRCPFField(CharField):
"""
value = super(BRCPFField, self).clean(value)
if value in EMPTY_VALUES:
- return u''
+ return ''
orig_value = value[:]
if not value.isdigit():
value = re.sub("[-\.]", "", value)
@@ -142,7 +142,7 @@ class BRCNPJField(Field):
"""
value = super(BRCNPJField, self).clean(value)
if value in EMPTY_VALUES:
- return u''
+ return ''
orig_value = value[:]
if not value.isdigit():
value = re.sub("[-/\.]", "", value)
@@ -154,10 +154,10 @@ class BRCNPJField(Field):
raise ValidationError(self.error_messages['max_digits'])
orig_dv = value[-2:]
- new_1dv = sum([i * int(value[idx]) for idx, i in enumerate(range(5, 1, -1) + range(9, 1, -1))])
+ new_1dv = sum([i * int(value[idx]) for idx, i in enumerate(list(range(5, 1, -1)) + list(range(9, 1, -1)))])
new_1dv = DV_maker(new_1dv % 11)
value = value[:-2] + str(new_1dv) + value[-1]
- new_2dv = sum([i * int(value[idx]) for idx, i in enumerate(range(6, 1, -1) + range(9, 1, -1))])
+ new_2dv = sum([i * int(value[idx]) for idx, i in enumerate(list(range(6, 1, -1)) + list(range(9, 1, -1)))])
new_2dv = DV_maker(new_2dv % 11)
value = value[:-1] + str(new_2dv)
if value[-2:] != orig_dv:
diff --git a/django/contrib/localflavor/ca/forms.py b/django/contrib/localflavor/ca/forms.py
index c3be79968f..4ebfb06c2b 100644
--- a/django/contrib/localflavor/ca/forms.py
+++ b/django/contrib/localflavor/ca/forms.py
@@ -2,14 +2,14 @@
Canada-specific Form helpers
"""
-from __future__ import absolute_import
+from __future__ import absolute_import, unicode_literals
import re
from django.core.validators import EMPTY_VALUES
from django.forms import ValidationError
from django.forms.fields import Field, CharField, Select
-from django.utils.encoding import smart_unicode
+from django.utils.encoding import smart_text
from django.utils.translation import ugettext_lazy as _
@@ -26,7 +26,7 @@ class CAPostalCodeField(CharField):
http://www.canadapost.ca/tools/pg/manual/PGaddress-e.asp#1402170
"""
default_error_messages = {
- 'invalid': _(u'Enter a postal code in the format XXX XXX.'),
+ 'invalid': _('Enter a postal code in the format XXX XXX.'),
}
postcode_regex = re.compile(r'^([ABCEGHJKLMNPRSTVXY]\d[ABCEGHJKLMNPRSTVWXYZ]) *(\d[ABCEGHJKLMNPRSTVWXYZ]\d)$')
@@ -34,7 +34,7 @@ class CAPostalCodeField(CharField):
def clean(self, value):
value = super(CAPostalCodeField, self).clean(value)
if value in EMPTY_VALUES:
- return u''
+ return ''
postcode = value.upper().strip()
m = self.postcode_regex.match(postcode)
if not m:
@@ -44,7 +44,7 @@ class CAPostalCodeField(CharField):
class CAPhoneNumberField(Field):
"""Canadian phone number field."""
default_error_messages = {
- 'invalid': _(u'Phone numbers must be in XXX-XXX-XXXX format.'),
+ 'invalid': _('Phone numbers must be in XXX-XXX-XXXX format.'),
}
def clean(self, value):
@@ -52,11 +52,11 @@ class CAPhoneNumberField(Field):
"""
super(CAPhoneNumberField, self).clean(value)
if value in EMPTY_VALUES:
- return u''
- value = re.sub('(\(|\)|\s+)', '', smart_unicode(value))
+ return ''
+ value = re.sub('(\(|\)|\s+)', '', smart_text(value))
m = phone_digits_re.search(value)
if m:
- return u'%s-%s-%s' % (m.group(1), m.group(2), m.group(3))
+ return '%s-%s-%s' % (m.group(1), m.group(2), m.group(3))
raise ValidationError(self.error_messages['invalid'])
class CAProvinceField(Field):
@@ -66,22 +66,22 @@ class CAProvinceField(Field):
abbreviation for the given province.
"""
default_error_messages = {
- 'invalid': _(u'Enter a Canadian province or territory.'),
+ 'invalid': _('Enter a Canadian province or territory.'),
}
def clean(self, value):
super(CAProvinceField, self).clean(value)
if value in EMPTY_VALUES:
- return u''
+ return ''
try:
value = value.strip().lower()
except AttributeError:
pass
else:
# Load data in memory only when it is required, see also #17275
- from django.contrib.localflavor.ca.ca_provinces import PROVINCES_NORMALIZED
+ from .ca_provinces import PROVINCES_NORMALIZED
try:
- return PROVINCES_NORMALIZED[value.strip().lower()].decode('ascii')
+ return PROVINCES_NORMALIZED[value.strip().lower()]
except KeyError:
pass
raise ValidationError(self.error_messages['invalid'])
@@ -93,7 +93,7 @@ class CAProvinceSelect(Select):
"""
def __init__(self, attrs=None):
# Load data in memory only when it is required, see also #17275
- from django.contrib.localflavor.ca.ca_provinces import PROVINCE_CHOICES
+ from .ca_provinces import PROVINCE_CHOICES
super(CAProvinceSelect, self).__init__(attrs, choices=PROVINCE_CHOICES)
class CASocialInsuranceNumberField(Field):
@@ -113,14 +113,14 @@ class CASocialInsuranceNumberField(Field):
def clean(self, value):
super(CASocialInsuranceNumberField, self).clean(value)
if value in EMPTY_VALUES:
- return u''
+ return ''
match = re.match(sin_re, value)
if not match:
raise ValidationError(self.error_messages['invalid'])
- number = u'%s-%s-%s' % (match.group(1), match.group(2), match.group(3))
- check_number = u'%s%s%s' % (match.group(1), match.group(2), match.group(3))
+ number = '%s-%s-%s' % (match.group(1), match.group(2), match.group(3))
+ check_number = '%s%s%s' % (match.group(1), match.group(2), match.group(3))
if not self.luhn_checksum_is_valid(check_number):
raise ValidationError(self.error_messages['invalid'])
return number
diff --git a/django/contrib/localflavor/ch/forms.py b/django/contrib/localflavor/ch/forms.py
index 649a98ab71..bf71eeea32 100644
--- a/django/contrib/localflavor/ch/forms.py
+++ b/django/contrib/localflavor/ch/forms.py
@@ -2,7 +2,7 @@
Swiss-specific Form helpers
"""
-from __future__ import absolute_import
+from __future__ import absolute_import, unicode_literals
import re
@@ -10,7 +10,7 @@ from django.contrib.localflavor.ch.ch_states import STATE_CHOICES
from django.core.validators import EMPTY_VALUES
from django.forms import ValidationError
from django.forms.fields import Field, RegexField, Select
-from django.utils.encoding import smart_unicode
+from django.utils.encoding import smart_text
from django.utils.translation import ugettext_lazy as _
@@ -40,11 +40,11 @@ class CHPhoneNumberField(Field):
def clean(self, value):
super(CHPhoneNumberField, self).clean(value)
if value in EMPTY_VALUES:
- return u''
- value = re.sub('(\.|\s|/|-)', '', smart_unicode(value))
+ return ''
+ value = re.sub('(\.|\s|/|-)', '', smart_text(value))
m = phone_digits_re.search(value)
if m:
- return u'%s %s %s %s' % (value[0:3], value[3:6], value[6:8], value[8:10])
+ return '%s %s %s %s' % (value[0:3], value[3:6], value[6:8], value[8:10])
raise ValidationError(self.error_messages['invalid'])
class CHStateSelect(Select):
@@ -102,7 +102,7 @@ class CHIdentityCardNumberField(Field):
def clean(self, value):
super(CHIdentityCardNumberField, self).clean(value)
if value in EMPTY_VALUES:
- return u''
+ return ''
match = re.match(id_re, value)
if not match:
@@ -118,5 +118,5 @@ class CHIdentityCardNumberField(Field):
if not self.has_valid_checksum(all_digits):
raise ValidationError(self.error_messages['invalid'])
- return u'%s%s%s' % (idnumber, pos9, checksum)
+ return '%s%s%s' % (idnumber, pos9, checksum)
diff --git a/django/contrib/localflavor/cl/cl_regions.py b/django/contrib/localflavor/cl/cl_regions.py
index 47db6d3912..d76f6ad834 100644
--- a/django/contrib/localflavor/cl/cl_regions.py
+++ b/django/contrib/localflavor/cl/cl_regions.py
@@ -5,21 +5,22 @@ A list of Chilean regions as `choices` in a formfield.
This exists in this standalone file so that it's only imported into memory
when explicitly needed.
"""
+from __future__ import unicode_literals
REGION_CHOICES = (
- ('RM', u'Región Metropolitana de Santiago'),
- ('I', u'Región de Tarapacá'),
- ('II', u'Región de Antofagasta'),
- ('III', u'Región de Atacama'),
- ('IV', u'Región de Coquimbo'),
- ('V', u'Región de Valparaíso'),
- ('VI', u'Región del Libertador Bernardo O\'Higgins'),
- ('VII', u'Región del Maule'),
- ('VIII',u'Región del Bío Bío'),
- ('IX', u'Región de la Araucanía'),
- ('X', u'Región de los Lagos'),
- ('XI', u'Región de Aysén del General Carlos Ibáñez del Campo'),
- ('XII', u'Región de Magallanes y la Antártica Chilena'),
- ('XIV', u'Región de Los Ríos'),
- ('XV', u'Región de Arica-Parinacota'),
+ ('RM', 'Región Metropolitana de Santiago'),
+ ('I', 'Región de Tarapacá'),
+ ('II', 'Región de Antofagasta'),
+ ('III', 'Región de Atacama'),
+ ('IV', 'Región de Coquimbo'),
+ ('V', 'Región de Valparaíso'),
+ ('VI', 'Región del Libertador Bernardo O\'Higgins'),
+ ('VII', 'Región del Maule'),
+ ('VIII','Región del Bío Bío'),
+ ('IX', 'Región de la Araucanía'),
+ ('X', 'Región de los Lagos'),
+ ('XI', 'Región de Aysén del General Carlos Ibáñez del Campo'),
+ ('XII', 'Región de Magallanes y la Antártica Chilena'),
+ ('XIV', 'Región de Los Ríos'),
+ ('XV', 'Región de Arica-Parinacota'),
)
diff --git a/django/contrib/localflavor/cl/forms.py b/django/contrib/localflavor/cl/forms.py
index 7a9aa2da8c..a5340141ce 100644
--- a/django/contrib/localflavor/cl/forms.py
+++ b/django/contrib/localflavor/cl/forms.py
@@ -2,15 +2,15 @@
Chile specific form helpers.
"""
-from __future__ import absolute_import
+from __future__ import absolute_import, unicode_literals
-from django.contrib.localflavor.cl.cl_regions import REGION_CHOICES
from django.core.validators import EMPTY_VALUES
from django.forms import ValidationError
from django.forms.fields import RegexField, Select
from django.utils.translation import ugettext_lazy as _
-from django.utils.encoding import smart_unicode
+from django.utils.encoding import smart_text
+from .cl_regions import REGION_CHOICES
class CLRegionSelect(Select):
"""
@@ -50,7 +50,7 @@ class CLRutField(RegexField):
"""
super(CLRutField, self).clean(value)
if value in EMPTY_VALUES:
- return u''
+ return ''
rut, verificador = self._canonify(value)
if self._algorithm(rut) == verificador:
return self._format(rut, verificador)
@@ -68,14 +68,14 @@ class CLRutField(RegexField):
multi += 1
if multi == 8:
multi = 2
- return u'0123456789K0'[11 - suma % 11]
+ return '0123456789K0'[11 - suma % 11]
def _canonify(self, rut):
"""
Turns the RUT into one normalized format. Returns a (rut, verifier)
tuple.
"""
- rut = smart_unicode(rut).replace(' ', '').replace('.', '').replace('-', '')
+ rut = smart_text(rut).replace(' ', '').replace('.', '').replace('-', '')
return rut[:-1], rut[-1].upper()
def _format(self, code, verifier=None):
@@ -93,5 +93,5 @@ class CLRutField(RegexField):
else:
new_dot = pos - 3
code = code[:new_dot] + '.' + code[new_dot:]
- return u'%s-%s' % (code, verifier)
+ return '%s-%s' % (code, verifier)
diff --git a/django/contrib/localflavor/cn/cn_provinces.py b/django/contrib/localflavor/cn/cn_provinces.py
index fe0aa37cb6..c27cba6423 100644
--- a/django/contrib/localflavor/cn/cn_provinces.py
+++ b/django/contrib/localflavor/cn/cn_provinces.py
@@ -9,41 +9,41 @@ http://en.wikipedia.org/wiki/Province_%28China%29
http://en.wikipedia.org/wiki/Direct-controlled_municipality
http://en.wikipedia.org/wiki/Autonomous_regions_of_China
"""
-
+from __future__ import unicode_literals
CN_PROVINCE_CHOICES = (
- ("anhui", u"安徽"),
- ("beijing", u"北京"),
- ("chongqing", u"重庆"),
- ("fujian", u"福建"),
- ("gansu", u"甘肃"),
- ("guangdong", u"广东"),
- ("guangxi", u"广西壮族自治区"),
- ("guizhou", u"贵州"),
- ("hainan", u"海南"),
- ("hebei", u"河北"),
- ("heilongjiang", u"黑龙江"),
- ("henan", u"河南"),
- ("hongkong", u"香港"),
- ("hubei", u"湖北"),
- ("hunan", u"湖南"),
- ("jiangsu", u"江苏"),
- ("jiangxi", u"江西"),
- ("jilin", u"吉林"),
- ("liaoning", u"辽宁"),
- ("macao", u"澳门"),
- ("neimongol", u"内蒙古自治区"),
- ("ningxia", u"宁夏回族自治区"),
- ("qinghai", u"青海"),
- ("shaanxi", u"陕西"),
- ("shandong", u"山东"),
- ("shanghai", u"上海"),
- ("shanxi", u"山西"),
- ("sichuan", u"四川"),
- ("taiwan", u"台湾"),
- ("tianjin", u"天津"),
- ("xinjiang", u"新疆维吾尔自治区"),
- ("xizang", u"西藏自治区"),
- ("yunnan", u"云南"),
- ("zhejiang", u"浙江"),
+ ("anhui", "安徽"),
+ ("beijing", "北京"),
+ ("chongqing", "重庆"),
+ ("fujian", "福建"),
+ ("gansu", "甘肃"),
+ ("guangdong", "广东"),
+ ("guangxi", "广西壮族自治区"),
+ ("guizhou", "贵州"),
+ ("hainan", "海南"),
+ ("hebei", "河北"),
+ ("heilongjiang", "黑龙江"),
+ ("henan", "河南"),
+ ("hongkong", "香港"),
+ ("hubei", "湖北"),
+ ("hunan", "湖南"),
+ ("jiangsu", "江苏"),
+ ("jiangxi", "江西"),
+ ("jilin", "吉林"),
+ ("liaoning", "辽宁"),
+ ("macao", "澳门"),
+ ("neimongol", "内蒙古自治区"),
+ ("ningxia", "宁夏回族自治区"),
+ ("qinghai", "青海"),
+ ("shaanxi", "陕西"),
+ ("shandong", "山东"),
+ ("shanghai", "上海"),
+ ("shanxi", "山西"),
+ ("sichuan", "四川"),
+ ("taiwan", "台湾"),
+ ("tianjin", "天津"),
+ ("xinjiang", "新疆维吾尔自治区"),
+ ("xizang", "西藏自治区"),
+ ("yunnan", "云南"),
+ ("zhejiang", "浙江"),
)
diff --git a/django/contrib/localflavor/cn/forms.py b/django/contrib/localflavor/cn/forms.py
index af92ba06ec..43adcf3f01 100644
--- a/django/contrib/localflavor/cn/forms.py
+++ b/django/contrib/localflavor/cn/forms.py
@@ -3,7 +3,7 @@
"""
Chinese-specific form helpers
"""
-from __future__ import absolute_import
+from __future__ import absolute_import, unicode_literals
import re
@@ -81,7 +81,7 @@ class CNPostCodeField(RegexField):
Valid code is XXXXXX where X is digit.
"""
default_error_messages = {
- 'invalid': _(u'Enter a post code in the format XXXXXX.'),
+ 'invalid': _('Enter a post code in the format XXXXXX.'),
}
def __init__(self, *args, **kwargs):
@@ -102,10 +102,10 @@ class CNIDCardField(CharField):
The checksum algorithm is described in GB11643-1999.
"""
default_error_messages = {
- 'invalid': _(u'ID Card Number consists of 15 or 18 digits.'),
- 'checksum': _(u'Invalid ID Card Number: Wrong checksum'),
- 'birthday': _(u'Invalid ID Card Number: Wrong birthdate'),
- 'location': _(u'Invalid ID Card Number: Wrong location code'),
+ 'invalid': _('ID Card Number consists of 15 or 18 digits.'),
+ 'checksum': _('Invalid ID Card Number: Wrong checksum'),
+ 'birthday': _('Invalid ID Card Number: Wrong birthdate'),
+ 'location': _('Invalid ID Card Number: Wrong location code'),
}
def __init__(self, max_length=18, min_length=15, *args, **kwargs):
@@ -119,7 +119,7 @@ class CNIDCardField(CharField):
# Check the length of the ID card number.
super(CNIDCardField, self).clean(value)
if not value:
- return u""
+ return ""
# Check whether this ID card number has valid format
if not re.match(ID_CARD_RE, value):
raise ValidationError(self.error_messages['invalid'])
@@ -133,7 +133,7 @@ class CNIDCardField(CharField):
value = value.upper()
if not self.has_valid_checksum(value):
raise ValidationError(self.error_messages['checksum'])
- return u'%s' % value
+ return '%s' % value
def has_valid_birthday(self, value):
"""
@@ -190,7 +190,7 @@ class CNPhoneNumberField(RegexField):
010-55555555-35
"""
default_error_messages = {
- 'invalid': _(u'Enter a valid phone number.'),
+ 'invalid': _('Enter a valid phone number.'),
}
def __init__(self, *args, **kwargs):
@@ -207,7 +207,7 @@ class CNCellNumberField(RegexField):
The length of the cell number should be 11.
"""
default_error_messages = {
- 'invalid': _(u'Enter a valid cell number.'),
+ 'invalid': _('Enter a valid cell number.'),
}
def __init__(self, *args, **kwargs):
diff --git a/django/contrib/localflavor/co/co_departments.py b/django/contrib/localflavor/co/co_departments.py
index f0989b6ba6..7168f54cc2 100644
--- a/django/contrib/localflavor/co/co_departments.py
+++ b/django/contrib/localflavor/co/co_departments.py
@@ -6,39 +6,40 @@ formfield.
This exists in this standalone file so that it's only
imported into memory when explicitly needed.
"""
+from __future__ import unicode_literals
DEPARTMENT_CHOICES = (
- ('AMA', u'Amazonas'),
- ('ANT', u'Antioquia'),
- ('ARA', u'Arauca'),
- ('ATL', u'Atlántico'),
- ('DC', u'Bogotá'),
- ('BOL', u'Bolívar'),
- ('BOY', u'Boyacá'),
- ('CAL', u'Caldas'),
- ('CAQ', u'Caquetá'),
- ('CAS', u'Casanare'),
- ('CAU', u'Cauca'),
- ('CES', u'Cesar'),
- ('CHO', u'Chocó'),
- ('COR', u'Córdoba'),
- ('CUN', u'Cundinamarca'),
- ('GUA', u'Guainía'),
- ('GUV', u'Guaviare'),
- ('HUI', u'Huila'),
- ('LAG', u'La Guajira'),
- ('MAG', u'Magdalena'),
- ('MET', u'Meta'),
- ('NAR', u'Nariño'),
- ('NSA', u'Norte de Santander'),
- ('PUT', u'Putumayo'),
- ('QUI', u'Quindío'),
- ('RIS', u'Risaralda'),
- ('SAP', u'San Andrés and Providencia'),
- ('SAN', u'Santander'),
- ('SUC', u'Sucre'),
- ('TOL', u'Tolima'),
- ('VAC', u'Valle del Cauca'),
- ('VAU', u'Vaupés'),
- ('VID', u'Vichada'),
+ ('AMA', 'Amazonas'),
+ ('ANT', 'Antioquia'),
+ ('ARA', 'Arauca'),
+ ('ATL', 'Atlántico'),
+ ('DC', 'Bogotá'),
+ ('BOL', 'Bolívar'),
+ ('BOY', 'Boyacá'),
+ ('CAL', 'Caldas'),
+ ('CAQ', 'Caquetá'),
+ ('CAS', 'Casanare'),
+ ('CAU', 'Cauca'),
+ ('CES', 'Cesar'),
+ ('CHO', 'Chocó'),
+ ('COR', 'Córdoba'),
+ ('CUN', 'Cundinamarca'),
+ ('GUA', 'Guainía'),
+ ('GUV', 'Guaviare'),
+ ('HUI', 'Huila'),
+ ('LAG', 'La Guajira'),
+ ('MAG', 'Magdalena'),
+ ('MET', 'Meta'),
+ ('NAR', 'Nariño'),
+ ('NSA', 'Norte de Santander'),
+ ('PUT', 'Putumayo'),
+ ('QUI', 'Quindío'),
+ ('RIS', 'Risaralda'),
+ ('SAP', 'San Andrés and Providencia'),
+ ('SAN', 'Santander'),
+ ('SUC', 'Sucre'),
+ ('TOL', 'Tolima'),
+ ('VAC', 'Valle del Cauca'),
+ ('VAU', 'Vaupés'),
+ ('VID', 'Vichada'),
)
diff --git a/django/contrib/localflavor/cz/forms.py b/django/contrib/localflavor/cz/forms.py
index f3676b230b..c7e81e4037 100644
--- a/django/contrib/localflavor/cz/forms.py
+++ b/django/contrib/localflavor/cz/forms.py
@@ -2,7 +2,7 @@
Czech-specific form helpers
"""
-from __future__ import absolute_import
+from __future__ import absolute_import, unicode_literals
import re
@@ -29,7 +29,7 @@ class CZPostalCodeField(RegexField):
Valid form is XXXXX or XXX XX, where X represents integer.
"""
default_error_messages = {
- 'invalid': _(u'Enter a postal code in the format XXXXX or XXX XX.'),
+ 'invalid': _('Enter a postal code in the format XXXXX or XXX XX.'),
}
def __init__(self, max_length=None, min_length=None, *args, **kwargs):
@@ -49,15 +49,15 @@ class CZBirthNumberField(Field):
Czech birth number field.
"""
default_error_messages = {
- 'invalid_format': _(u'Enter a birth number in the format XXXXXX/XXXX or XXXXXXXXXX.'),
- 'invalid': _(u'Enter a valid birth number.'),
+ 'invalid_format': _('Enter a birth number in the format XXXXXX/XXXX or XXXXXXXXXX.'),
+ 'invalid': _('Enter a valid birth number.'),
}
def clean(self, value, gender=None):
super(CZBirthNumberField, self).clean(value)
if value in EMPTY_VALUES:
- return u''
+ return ''
match = re.match(birth_number, value)
if not match:
@@ -67,7 +67,7 @@ class CZBirthNumberField(Field):
# Three digits for verification number were used until 1. january 1954
if len(id) == 3:
- return u'%s' % value
+ return '%s' % value
# Birth number is in format YYMMDD. Females have month value raised by 50.
# In case that all possible number are already used (for given date),
@@ -90,7 +90,7 @@ class CZBirthNumberField(Field):
modulo = int(birth + id[:3]) % 11
if (modulo == int(id[-1])) or (modulo == 10 and id[-1] == '0'):
- return u'%s' % value
+ return '%s' % value
else:
raise ValidationError(self.error_messages['invalid'])
@@ -99,14 +99,14 @@ class CZICNumberField(Field):
Czech IC number field.
"""
default_error_messages = {
- 'invalid': _(u'Enter a valid IC number.'),
+ 'invalid': _('Enter a valid IC number.'),
}
def clean(self, value):
super(CZICNumberField, self).clean(value)
if value in EMPTY_VALUES:
- return u''
+ return ''
match = re.match(ic_number, value)
if not match:
@@ -130,7 +130,7 @@ class CZICNumberField(Field):
if (not remainder % 10 and check == 1) or \
(remainder == 1 and check == 0) or \
(check == (11 - remainder)):
- return u'%s' % value
+ return '%s' % value
raise ValidationError(self.error_messages['invalid'])
diff --git a/django/contrib/localflavor/de/forms.py b/django/contrib/localflavor/de/forms.py
index 80b6248ed4..a7891d117f 100644
--- a/django/contrib/localflavor/de/forms.py
+++ b/django/contrib/localflavor/de/forms.py
@@ -2,7 +2,7 @@
DE-specific Form helpers
"""
-from __future__ import absolute_import
+from __future__ import absolute_import, unicode_literals
import re
@@ -68,7 +68,7 @@ class DEIdentityCardNumberField(Field):
def clean(self, value):
super(DEIdentityCardNumberField, self).clean(value)
if value in EMPTY_VALUES:
- return u''
+ return ''
match = re.match(id_re, value)
if not match:
raise ValidationError(self.error_messages['invalid'])
@@ -80,9 +80,9 @@ class DEIdentityCardNumberField(Field):
if residence == '0000000000' or birthday == '0000000' or validity == '0000000':
raise ValidationError(self.error_messages['invalid'])
- all_digits = u"%s%s%s%s" % (residence, birthday, validity, checksum)
+ all_digits = "%s%s%s%s" % (residence, birthday, validity, checksum)
if not self.has_valid_checksum(residence) or not self.has_valid_checksum(birthday) or \
not self.has_valid_checksum(validity) or not self.has_valid_checksum(all_digits):
raise ValidationError(self.error_messages['invalid'])
- return u'%s%s-%s-%s-%s' % (residence, origin, birthday, validity, checksum)
+ return '%s%s-%s-%s-%s' % (residence, origin, birthday, validity, checksum)
diff --git a/django/contrib/localflavor/de_CH/formats.py b/django/contrib/localflavor/de_CH/formats.py
index d4f324a422..9d56f9f298 100644
--- a/django/contrib/localflavor/de_CH/formats.py
+++ b/django/contrib/localflavor/de_CH/formats.py
@@ -4,6 +4,8 @@
# The *_FORMAT strings use the Django date format syntax,
# see http://docs.djangoproject.com/en/dev/ref/templates/builtins/#date
+from __future__ import unicode_literals
+
DATE_FORMAT = 'j. F Y'
TIME_FORMAT = 'H:i:s'
DATETIME_FORMAT = 'j. F Y H:i:s'
@@ -39,5 +41,5 @@ DATETIME_INPUT_FORMATS = (
# For details, please refer to http://www.bk.admin.ch/dokumentation/sprachen/04915/05016/index.html?lang=de
# (in German) and the documentation
DECIMAL_SEPARATOR = ','
-THOUSAND_SEPARATOR = u'\xa0' # non-breaking space
+THOUSAND_SEPARATOR = '\xa0' # non-breaking space
NUMBER_GROUPING = 3
diff --git a/django/contrib/localflavor/ec/ec_provinces.py b/django/contrib/localflavor/ec/ec_provinces.py
index 7e55078be0..db25d26ff8 100644
--- a/django/contrib/localflavor/ec/ec_provinces.py
+++ b/django/contrib/localflavor/ec/ec_provinces.py
@@ -6,30 +6,31 @@ formfield.
This exists in this standalone file so that it's only
imported into memory when explicitly needed.
"""
+from __future__ import unicode_literals
PROVINCE_CHOICES = (
- ('A', u'Azuay'),
- ('B', u'Bolívar'),
- ('F', u'Cañar'),
- ('C', u'Carchi'),
- ('H', u'Chimborazo'),
- ('X', u'Cotopaxi'),
- ('O', u'El Oro'),
- ('E', u'Esmeraldas'),
- ('W', u'Galápagos'),
- ('G', u'Guayas'),
- ('I', u'Imbabura'),
- ('L', u'Loja'),
- ('R', u'Los Ríos'),
- ('M', u'Manabí'),
- ('S', u'Morona Santiago'),
- ('N', u'Napo'),
- ('D', u'Orellana'),
- ('Y', u'Pastaza'),
- ('P', u'Pichincha'),
- ('SE', u'Santa Elena'),
- ('SD', u'Santo Domingo de los Tsáchilas'),
- ('U', u'Sucumbíos'),
- ('T', u'Tungurahua'),
- ('Z', u'Zamora Chinchipe'),
+ ('A', 'Azuay'),
+ ('B', 'Bolívar'),
+ ('F', 'Cañar'),
+ ('C', 'Carchi'),
+ ('H', 'Chimborazo'),
+ ('X', 'Cotopaxi'),
+ ('O', 'El Oro'),
+ ('E', 'Esmeraldas'),
+ ('W', 'Galápagos'),
+ ('G', 'Guayas'),
+ ('I', 'Imbabura'),
+ ('L', 'Loja'),
+ ('R', 'Los Ríos'),
+ ('M', 'Manabí'),
+ ('S', 'Morona Santiago'),
+ ('N', 'Napo'),
+ ('D', 'Orellana'),
+ ('Y', 'Pastaza'),
+ ('P', 'Pichincha'),
+ ('SE', 'Santa Elena'),
+ ('SD', 'Santo Domingo de los Tsáchilas'),
+ ('U', 'Sucumbíos'),
+ ('T', 'Tungurahua'),
+ ('Z', 'Zamora Chinchipe'),
)
diff --git a/django/contrib/localflavor/es/forms.py b/django/contrib/localflavor/es/forms.py
index fe237270f5..da0769d2a0 100644
--- a/django/contrib/localflavor/es/forms.py
+++ b/django/contrib/localflavor/es/forms.py
@@ -3,7 +3,7 @@
Spanish-specific Form helpers
"""
-from __future__ import absolute_import
+from __future__ import absolute_import, unicode_literals
import re
@@ -91,7 +91,7 @@ class ESIdentityCardNumberField(RegexField):
def clean(self, value):
super(ESIdentityCardNumberField, self).clean(value)
if value in EMPTY_VALUES:
- return u''
+ return ''
nif_get_checksum = lambda d: self.nif_control[int(d)%23]
value = value.upper().replace(' ', '').replace('-', '')
@@ -157,7 +157,7 @@ class ESCCCField(RegexField):
def clean(self, value):
super(ESCCCField, self).clean(value)
if value in EMPTY_VALUES:
- return u''
+ return ''
control_str = [1, 2, 4, 8, 5, 10, 9, 7, 3, 6]
m = re.match(r'^(\d{4})[ -]?(\d{4})[ -]?(\d{2})[ -]?(\d{10})$', value)
entity, office, checksum, account = m.groups()
diff --git a/django/contrib/localflavor/fi/fi_municipalities.py b/django/contrib/localflavor/fi/fi_municipalities.py
index 4b8b886b8b..6f90e5e02b 100644
--- a/django/contrib/localflavor/fi/fi_municipalities.py
+++ b/django/contrib/localflavor/fi/fi_municipalities.py
@@ -7,347 +7,349 @@ This exists in this standalone file so that it's only imported into memory
when explicitly needed.
"""
+from __future__ import unicode_literals
+
MUNICIPALITY_CHOICES = (
- ('akaa', u"Akaa"),
- ('alajarvi', u"Alajärvi"),
- ('alavieska', u"Alavieska"),
- ('alavus', u"Alavus"),
- ('artjarvi', u"Artjärvi"),
- ('asikkala', u"Asikkala"),
- ('askola', u"Askola"),
- ('aura', u"Aura"),
- ('brando', u"Brändö"),
- ('eckero', u"Eckerö"),
- ('enonkoski', u"Enonkoski"),
- ('enontekio', u"Enontekiö"),
- ('espoo', u"Espoo"),
- ('eura', u"Eura"),
- ('eurajoki', u"Eurajoki"),
- ('evijarvi', u"Evijärvi"),
- ('finstrom', u"Finström"),
- ('forssa', u"Forssa"),
- ('foglo', u"Föglö"),
- ('geta', u"Geta"),
- ('haapajarvi', u"Haapajärvi"),
- ('haapavesi', u"Haapavesi"),
- ('hailuoto', u"Hailuoto"),
- ('halsua', u"Halsua"),
- ('hamina', u"Hamina"),
- ('hammarland', u"Hammarland"),
- ('hankasalmi', u"Hankasalmi"),
- ('hanko', u"Hanko"),
- ('harjavalta', u"Harjavalta"),
- ('hartola', u"Hartola"),
- ('hattula', u"Hattula"),
- ('haukipudas', u"Haukipudas"),
- ('hausjarvi', u"Hausjärvi"),
- ('heinola', u"Heinola"),
- ('heinavesi', u"Heinävesi"),
- ('helsinki', u"Helsinki"),
- ('hirvensalmi', u"Hirvensalmi"),
- ('hollola', u"Hollola"),
- ('honkajoki', u"Honkajoki"),
- ('huittinen', u"Huittinen"),
- ('humppila', u"Humppila"),
- ('hyrynsalmi', u"Hyrynsalmi"),
- ('hyvinkaa', u"Hyvinkää"),
- ('hameenkoski', u"Hämeenkoski"),
- ('hameenkyro', u"Hämeenkyrö"),
- ('hameenlinna', u"Hämeenlinna"),
- ('ii', u"Ii"),
- ('iisalmi', u"Iisalmi"),
- ('iitti', u"Iitti"),
- ('ikaalinen', u"Ikaalinen"),
- ('ilmajoki', u"Ilmajoki"),
- ('ilomantsi', u"Ilomantsi"),
- ('imatra', u"Imatra"),
- ('inari', u"Inari"),
- ('inkoo', u"Inkoo"),
- ('isojoki', u"Isojoki"),
- ('isokyro', u"Isokyrö"),
- ('jalasjarvi', u"Jalasjärvi"),
- ('janakkala', u"Janakkala"),
- ('joensuu', u"Joensuu"),
- ('jokioinen', u"Jokioinen"),
- ('jomala', u"Jomala"),
- ('joroinen', u"Joroinen"),
- ('joutsa', u"Joutsa"),
- ('juankoski', u"Juankoski"),
- ('juuka', u"Juuka"),
- ('juupajoki', u"Juupajoki"),
- ('juva', u"Juva"),
- ('jyvaskyla', u"Jyväskylä"),
- ('jamijarvi', u"Jämijärvi"),
- ('jamsa', u"Jämsä"),
- ('jarvenpaa', u"Järvenpää"),
- ('kaarina', u"Kaarina"),
- ('kaavi', u"Kaavi"),
- ('kajaani', u"Kajaani"),
- ('kalajoki', u"Kalajoki"),
- ('kangasala', u"Kangasala"),
- ('kangasniemi', u"Kangasniemi"),
- ('kankaanpaa', u"Kankaanpää"),
- ('kannonkoski', u"Kannonkoski"),
- ('kannus', u"Kannus"),
- ('karijoki', u"Karijoki"),
- ('karjalohja', u"Karjalohja"),
- ('karkkila', u"Karkkila"),
- ('karstula', u"Karstula"),
- ('karttula', u"Karttula"),
- ('karvia', u"Karvia"),
- ('kaskinen', u"Kaskinen"),
- ('kauhajoki', u"Kauhajoki"),
- ('kauhava', u"Kauhava"),
- ('kauniainen', u"Kauniainen"),
- ('kaustinen', u"Kaustinen"),
- ('keitele', u"Keitele"),
- ('kemi', u"Kemi"),
- ('kemijarvi', u"Kemijärvi"),
- ('keminmaa', u"Keminmaa"),
- ('kemionsaari', u"Kemiönsaari"),
- ('kempele', u"Kempele"),
- ('kerava', u"Kerava"),
- ('kerimaki', u"Kerimäki"),
- ('kesalahti', u"Kesälahti"),
- ('keuruu', u"Keuruu"),
- ('kihnio', u"Kihniö"),
- ('kiikoinen', u"Kiikoinen"),
- ('kiiminki', u"Kiiminki"),
- ('kinnula', u"Kinnula"),
- ('kirkkonummi', u"Kirkkonummi"),
- ('kitee', u"Kitee"),
- ('kittila', u"Kittilä"),
- ('kiuruvesi', u"Kiuruvesi"),
- ('kivijarvi', u"Kivijärvi"),
- ('kokemaki', u"Kokemäki"),
- ('kokkola', u"Kokkola"),
- ('kolari', u"Kolari"),
- ('konnevesi', u"Konnevesi"),
- ('kontiolahti', u"Kontiolahti"),
- ('korsnas', u"Korsnäs"),
- ('koskitl', u"Koski Tl"),
- ('kotka', u"Kotka"),
- ('kouvola', u"Kouvola"),
- ('kristiinankaupunki', u"Kristiinankaupunki"),
- ('kruunupyy', u"Kruunupyy"),
- ('kuhmalahti', u"Kuhmalahti"),
- ('kuhmo', u"Kuhmo"),
- ('kuhmoinen', u"Kuhmoinen"),
- ('kumlinge', u"Kumlinge"),
- ('kuopio', u"Kuopio"),
- ('kuortane', u"Kuortane"),
- ('kurikka', u"Kurikka"),
- ('kustavi', u"Kustavi"),
- ('kuusamo', u"Kuusamo"),
- ('kylmakoski', u"Kylmäkoski"),
- ('kyyjarvi', u"Kyyjärvi"),
- ('karkola', u"Kärkölä"),
- ('karsamaki', u"Kärsämäki"),
- ('kokar', u"Kökar"),
- ('koylio', u"Köyliö"),
- ('lahti', u"Lahti"),
- ('laihia', u"Laihia"),
- ('laitila', u"Laitila"),
- ('lapinjarvi', u"Lapinjärvi"),
- ('lapinlahti', u"Lapinlahti"),
- ('lappajarvi', u"Lappajärvi"),
- ('lappeenranta', u"Lappeenranta"),
- ('lapua', u"Lapua"),
- ('laukaa', u"Laukaa"),
- ('lavia', u"Lavia"),
- ('lemi', u"Lemi"),
- ('lemland', u"Lemland"),
- ('lempaala', u"Lempäälä"),
- ('leppavirta', u"Leppävirta"),
- ('lestijarvi', u"Lestijärvi"),
- ('lieksa', u"Lieksa"),
- ('lieto', u"Lieto"),
- ('liminka', u"Liminka"),
- ('liperi', u"Liperi"),
- ('lohja', u"Lohja"),
- ('loimaa', u"Loimaa"),
- ('loppi', u"Loppi"),
- ('loviisa', u"Loviisa"),
- ('luhanka', u"Luhanka"),
- ('lumijoki', u"Lumijoki"),
- ('lumparland', u"Lumparland"),
- ('luoto', u"Luoto"),
- ('luumaki', u"Luumäki"),
- ('luvia', u"Luvia"),
- ('lansi-turunmaa', u"Länsi-Turunmaa"),
- ('maalahti', u"Maalahti"),
- ('maaninka', u"Maaninka"),
- ('maarianhamina', u"Maarianhamina"),
- ('marttila', u"Marttila"),
- ('masku', u"Masku"),
- ('merijarvi', u"Merijärvi"),
- ('merikarvia', u"Merikarvia"),
- ('miehikkala', u"Miehikkälä"),
- ('mikkeli', u"Mikkeli"),
- ('muhos', u"Muhos"),
- ('multia', u"Multia"),
- ('muonio', u"Muonio"),
- ('mustasaari', u"Mustasaari"),
- ('muurame', u"Muurame"),
- ('mynamaki', u"Mynämäki"),
- ('myrskyla', u"Myrskylä"),
- ('mantsala', u"Mäntsälä"),
- ('mantta-vilppula', u"Mänttä-Vilppula"),
- ('mantyharju', u"Mäntyharju"),
- ('naantali', u"Naantali"),
- ('nakkila', u"Nakkila"),
- ('nastola', u"Nastola"),
- ('nilsia', u"Nilsiä"),
- ('nivala', u"Nivala"),
- ('nokia', u"Nokia"),
- ('nousiainen', u"Nousiainen"),
- ('nummi-pusula', u"Nummi-Pusula"),
- ('nurmes', u"Nurmes"),
- ('nurmijarvi', u"Nurmijärvi"),
- ('narpio', u"Närpiö"),
- ('oravainen', u"Oravainen"),
- ('orimattila', u"Orimattila"),
- ('oripaa', u"Oripää"),
- ('orivesi', u"Orivesi"),
- ('oulainen', u"Oulainen"),
- ('oulu', u"Oulu"),
- ('oulunsalo', u"Oulunsalo"),
- ('outokumpu', u"Outokumpu"),
- ('padasjoki', u"Padasjoki"),
- ('paimio', u"Paimio"),
- ('paltamo', u"Paltamo"),
- ('parikkala', u"Parikkala"),
- ('parkano', u"Parkano"),
- ('pedersore', u"Pedersöre"),
- ('pelkosenniemi', u"Pelkosenniemi"),
- ('pello', u"Pello"),
- ('perho', u"Perho"),
- ('pertunmaa', u"Pertunmaa"),
- ('petajavesi', u"Petäjävesi"),
- ('pieksamaki', u"Pieksämäki"),
- ('pielavesi', u"Pielavesi"),
- ('pietarsaari', u"Pietarsaari"),
- ('pihtipudas', u"Pihtipudas"),
- ('pirkkala', u"Pirkkala"),
- ('polvijarvi', u"Polvijärvi"),
- ('pomarkku', u"Pomarkku"),
- ('pori', u"Pori"),
- ('pornainen', u"Pornainen"),
- ('porvoo', u"Porvoo"),
- ('posio', u"Posio"),
- ('pudasjarvi', u"Pudasjärvi"),
- ('pukkila', u"Pukkila"),
- ('punkaharju', u"Punkaharju"),
- ('punkalaidun', u"Punkalaidun"),
- ('puolanka', u"Puolanka"),
- ('puumala', u"Puumala"),
- ('pyhtaa', u"Pyhtää"),
- ('pyhajoki', u"Pyhäjoki"),
- ('pyhajarvi', u"Pyhäjärvi"),
- ('pyhanta', u"Pyhäntä"),
- ('pyharanta', u"Pyhäranta"),
- ('palkane', u"Pälkäne"),
- ('poytya', u"Pöytyä"),
- ('raahe', u"Raahe"),
- ('raasepori', u"Raasepori"),
- ('raisio', u"Raisio"),
- ('rantasalmi', u"Rantasalmi"),
- ('ranua', u"Ranua"),
- ('rauma', u"Rauma"),
- ('rautalampi', u"Rautalampi"),
- ('rautavaara', u"Rautavaara"),
- ('rautjarvi', u"Rautjärvi"),
- ('reisjarvi', u"Reisjärvi"),
- ('riihimaki', u"Riihimäki"),
- ('ristiina', u"Ristiina"),
- ('ristijarvi', u"Ristijärvi"),
- ('rovaniemi', u"Rovaniemi"),
- ('ruokolahti', u"Ruokolahti"),
- ('ruovesi', u"Ruovesi"),
- ('rusko', u"Rusko"),
- ('raakkyla', u"Rääkkylä"),
- ('saarijarvi', u"Saarijärvi"),
- ('salla', u"Salla"),
- ('salo', u"Salo"),
- ('saltvik', u"Saltvik"),
- ('sastamala', u"Sastamala"),
- ('sauvo', u"Sauvo"),
- ('savitaipale', u"Savitaipale"),
- ('savonlinna', u"Savonlinna"),
- ('savukoski', u"Savukoski"),
- ('seinajoki', u"Seinäjoki"),
- ('sievi', u"Sievi"),
- ('siikainen', u"Siikainen"),
- ('siikajoki', u"Siikajoki"),
- ('siikalatva', u"Siikalatva"),
- ('siilinjarvi', u"Siilinjärvi"),
- ('simo', u"Simo"),
- ('sipoo', u"Sipoo"),
- ('siuntio', u"Siuntio"),
- ('sodankyla', u"Sodankylä"),
- ('soini', u"Soini"),
- ('somero', u"Somero"),
- ('sonkajarvi', u"Sonkajärvi"),
- ('sotkamo', u"Sotkamo"),
- ('sottunga', u"Sottunga"),
- ('sulkava', u"Sulkava"),
- ('sund', u"Sund"),
- ('suomenniemi', u"Suomenniemi"),
- ('suomussalmi', u"Suomussalmi"),
- ('suonenjoki', u"Suonenjoki"),
- ('sysma', u"Sysmä"),
- ('sakyla', u"Säkylä"),
- ('taipalsaari', u"Taipalsaari"),
- ('taivalkoski', u"Taivalkoski"),
- ('taivassalo', u"Taivassalo"),
- ('tammela', u"Tammela"),
- ('tampere', u"Tampere"),
- ('tarvasjoki', u"Tarvasjoki"),
- ('tervo', u"Tervo"),
- ('tervola', u"Tervola"),
- ('teuva', u"Teuva"),
- ('tohmajarvi', u"Tohmajärvi"),
- ('toholampi', u"Toholampi"),
- ('toivakka', u"Toivakka"),
- ('tornio', u"Tornio"),
- ('turku', u"Turku"),
- ('tuusniemi', u"Tuusniemi"),
- ('tuusula', u"Tuusula"),
- ('tyrnava', u"Tyrnävä"),
- ('toysa', u"Töysä"),
- ('ulvila', u"Ulvila"),
- ('urjala', u"Urjala"),
- ('utajarvi', u"Utajärvi"),
- ('utsjoki', u"Utsjoki"),
- ('uurainen', u"Uurainen"),
- ('uusikaarlepyy', u"Uusikaarlepyy"),
- ('uusikaupunki', u"Uusikaupunki"),
- ('vaala', u"Vaala"),
- ('vaasa', u"Vaasa"),
- ('valkeakoski', u"Valkeakoski"),
- ('valtimo', u"Valtimo"),
- ('vantaa', u"Vantaa"),
- ('varkaus', u"Varkaus"),
- ('varpaisjarvi', u"Varpaisjärvi"),
- ('vehmaa', u"Vehmaa"),
- ('vesanto', u"Vesanto"),
- ('vesilahti', u"Vesilahti"),
- ('veteli', u"Veteli"),
- ('vierema', u"Vieremä"),
- ('vihanti', u"Vihanti"),
- ('vihti', u"Vihti"),
- ('viitasaari', u"Viitasaari"),
- ('vimpeli', u"Vimpeli"),
- ('virolahti', u"Virolahti"),
- ('virrat', u"Virrat"),
- ('vardo', u"Vårdö"),
- ('vahakyro', u"Vähäkyrö"),
- ('voyri-maksamaa', u"Vöyri-Maksamaa"),
- ('yli-ii', u"Yli-Ii"),
- ('ylitornio', u"Ylitornio"),
- ('ylivieska', u"Ylivieska"),
- ('ylojarvi', u"Ylöjärvi"),
- ('ypaja', u"Ypäjä"),
- ('ahtari', u"Ähtäri"),
- ('aanekoski', u"Äänekoski")
-)
\ No newline at end of file
+ ('akaa', "Akaa"),
+ ('alajarvi', "Alajärvi"),
+ ('alavieska', "Alavieska"),
+ ('alavus', "Alavus"),
+ ('artjarvi', "Artjärvi"),
+ ('asikkala', "Asikkala"),
+ ('askola', "Askola"),
+ ('aura', "Aura"),
+ ('brando', "Brändö"),
+ ('eckero', "Eckerö"),
+ ('enonkoski', "Enonkoski"),
+ ('enontekio', "Enontekiö"),
+ ('espoo', "Espoo"),
+ ('eura', "Eura"),
+ ('eurajoki', "Eurajoki"),
+ ('evijarvi', "Evijärvi"),
+ ('finstrom', "Finström"),
+ ('forssa', "Forssa"),
+ ('foglo', "Föglö"),
+ ('geta', "Geta"),
+ ('haapajarvi', "Haapajärvi"),
+ ('haapavesi', "Haapavesi"),
+ ('hailuoto', "Hailuoto"),
+ ('halsua', "Halsua"),
+ ('hamina', "Hamina"),
+ ('hammarland', "Hammarland"),
+ ('hankasalmi', "Hankasalmi"),
+ ('hanko', "Hanko"),
+ ('harjavalta', "Harjavalta"),
+ ('hartola', "Hartola"),
+ ('hattula', "Hattula"),
+ ('haukipudas', "Haukipudas"),
+ ('hausjarvi', "Hausjärvi"),
+ ('heinola', "Heinola"),
+ ('heinavesi', "Heinävesi"),
+ ('helsinki', "Helsinki"),
+ ('hirvensalmi', "Hirvensalmi"),
+ ('hollola', "Hollola"),
+ ('honkajoki', "Honkajoki"),
+ ('huittinen', "Huittinen"),
+ ('humppila', "Humppila"),
+ ('hyrynsalmi', "Hyrynsalmi"),
+ ('hyvinkaa', "Hyvinkää"),
+ ('hameenkoski', "Hämeenkoski"),
+ ('hameenkyro', "Hämeenkyrö"),
+ ('hameenlinna', "Hämeenlinna"),
+ ('ii', "Ii"),
+ ('iisalmi', "Iisalmi"),
+ ('iitti', "Iitti"),
+ ('ikaalinen', "Ikaalinen"),
+ ('ilmajoki', "Ilmajoki"),
+ ('ilomantsi', "Ilomantsi"),
+ ('imatra', "Imatra"),
+ ('inari', "Inari"),
+ ('inkoo', "Inkoo"),
+ ('isojoki', "Isojoki"),
+ ('isokyro', "Isokyrö"),
+ ('jalasjarvi', "Jalasjärvi"),
+ ('janakkala', "Janakkala"),
+ ('joensuu', "Joensuu"),
+ ('jokioinen', "Jokioinen"),
+ ('jomala', "Jomala"),
+ ('joroinen', "Joroinen"),
+ ('joutsa', "Joutsa"),
+ ('juankoski', "Juankoski"),
+ ('juuka', "Juuka"),
+ ('juupajoki', "Juupajoki"),
+ ('juva', "Juva"),
+ ('jyvaskyla', "Jyväskylä"),
+ ('jamijarvi', "Jämijärvi"),
+ ('jamsa', "Jämsä"),
+ ('jarvenpaa', "Järvenpää"),
+ ('kaarina', "Kaarina"),
+ ('kaavi', "Kaavi"),
+ ('kajaani', "Kajaani"),
+ ('kalajoki', "Kalajoki"),
+ ('kangasala', "Kangasala"),
+ ('kangasniemi', "Kangasniemi"),
+ ('kankaanpaa', "Kankaanpää"),
+ ('kannonkoski', "Kannonkoski"),
+ ('kannus', "Kannus"),
+ ('karijoki', "Karijoki"),
+ ('karjalohja', "Karjalohja"),
+ ('karkkila', "Karkkila"),
+ ('karstula', "Karstula"),
+ ('karttula', "Karttula"),
+ ('karvia', "Karvia"),
+ ('kaskinen', "Kaskinen"),
+ ('kauhajoki', "Kauhajoki"),
+ ('kauhava', "Kauhava"),
+ ('kauniainen', "Kauniainen"),
+ ('kaustinen', "Kaustinen"),
+ ('keitele', "Keitele"),
+ ('kemi', "Kemi"),
+ ('kemijarvi', "Kemijärvi"),
+ ('keminmaa', "Keminmaa"),
+ ('kemionsaari', "Kemiönsaari"),
+ ('kempele', "Kempele"),
+ ('kerava', "Kerava"),
+ ('kerimaki', "Kerimäki"),
+ ('kesalahti', "Kesälahti"),
+ ('keuruu', "Keuruu"),
+ ('kihnio', "Kihniö"),
+ ('kiikoinen', "Kiikoinen"),
+ ('kiiminki', "Kiiminki"),
+ ('kinnula', "Kinnula"),
+ ('kirkkonummi', "Kirkkonummi"),
+ ('kitee', "Kitee"),
+ ('kittila', "Kittilä"),
+ ('kiuruvesi', "Kiuruvesi"),
+ ('kivijarvi', "Kivijärvi"),
+ ('kokemaki', "Kokemäki"),
+ ('kokkola', "Kokkola"),
+ ('kolari', "Kolari"),
+ ('konnevesi', "Konnevesi"),
+ ('kontiolahti', "Kontiolahti"),
+ ('korsnas', "Korsnäs"),
+ ('koskitl', "Koski Tl"),
+ ('kotka', "Kotka"),
+ ('kouvola', "Kouvola"),
+ ('kristiinankaupunki', "Kristiinankaupunki"),
+ ('kruunupyy', "Kruunupyy"),
+ ('kuhmalahti', "Kuhmalahti"),
+ ('kuhmo', "Kuhmo"),
+ ('kuhmoinen', "Kuhmoinen"),
+ ('kumlinge', "Kumlinge"),
+ ('kuopio', "Kuopio"),
+ ('kuortane', "Kuortane"),
+ ('kurikka', "Kurikka"),
+ ('kustavi', "Kustavi"),
+ ('kuusamo', "Kuusamo"),
+ ('kylmakoski', "Kylmäkoski"),
+ ('kyyjarvi', "Kyyjärvi"),
+ ('karkola', "Kärkölä"),
+ ('karsamaki', "Kärsämäki"),
+ ('kokar', "Kökar"),
+ ('koylio', "Köyliö"),
+ ('lahti', "Lahti"),
+ ('laihia', "Laihia"),
+ ('laitila', "Laitila"),
+ ('lapinjarvi', "Lapinjärvi"),
+ ('lapinlahti', "Lapinlahti"),
+ ('lappajarvi', "Lappajärvi"),
+ ('lappeenranta', "Lappeenranta"),
+ ('lapua', "Lapua"),
+ ('laukaa', "Laukaa"),
+ ('lavia', "Lavia"),
+ ('lemi', "Lemi"),
+ ('lemland', "Lemland"),
+ ('lempaala', "Lempäälä"),
+ ('leppavirta', "Leppävirta"),
+ ('lestijarvi', "Lestijärvi"),
+ ('lieksa', "Lieksa"),
+ ('lieto', "Lieto"),
+ ('liminka', "Liminka"),
+ ('liperi', "Liperi"),
+ ('lohja', "Lohja"),
+ ('loimaa', "Loimaa"),
+ ('loppi', "Loppi"),
+ ('loviisa', "Loviisa"),
+ ('luhanka', "Luhanka"),
+ ('lumijoki', "Lumijoki"),
+ ('lumparland', "Lumparland"),
+ ('luoto', "Luoto"),
+ ('luumaki', "Luumäki"),
+ ('luvia', "Luvia"),
+ ('lansi-turunmaa', "Länsi-Turunmaa"),
+ ('maalahti', "Maalahti"),
+ ('maaninka', "Maaninka"),
+ ('maarianhamina', "Maarianhamina"),
+ ('marttila', "Marttila"),
+ ('masku', "Masku"),
+ ('merijarvi', "Merijärvi"),
+ ('merikarvia', "Merikarvia"),
+ ('miehikkala', "Miehikkälä"),
+ ('mikkeli', "Mikkeli"),
+ ('muhos', "Muhos"),
+ ('multia', "Multia"),
+ ('muonio', "Muonio"),
+ ('mustasaari', "Mustasaari"),
+ ('muurame', "Muurame"),
+ ('mynamaki', "Mynämäki"),
+ ('myrskyla', "Myrskylä"),
+ ('mantsala', "Mäntsälä"),
+ ('mantta-vilppula', "Mänttä-Vilppula"),
+ ('mantyharju', "Mäntyharju"),
+ ('naantali', "Naantali"),
+ ('nakkila', "Nakkila"),
+ ('nastola', "Nastola"),
+ ('nilsia', "Nilsiä"),
+ ('nivala', "Nivala"),
+ ('nokia', "Nokia"),
+ ('nousiainen', "Nousiainen"),
+ ('nummi-pusula', "Nummi-Pusula"),
+ ('nurmes', "Nurmes"),
+ ('nurmijarvi', "Nurmijärvi"),
+ ('narpio', "Närpiö"),
+ ('oravainen', "Oravainen"),
+ ('orimattila', "Orimattila"),
+ ('oripaa', "Oripää"),
+ ('orivesi', "Orivesi"),
+ ('oulainen', "Oulainen"),
+ ('oulu', "Oulu"),
+ ('oulunsalo', "Oulunsalo"),
+ ('outokumpu', "Outokumpu"),
+ ('padasjoki', "Padasjoki"),
+ ('paimio', "Paimio"),
+ ('paltamo', "Paltamo"),
+ ('parikkala', "Parikkala"),
+ ('parkano', "Parkano"),
+ ('pedersore', "Pedersöre"),
+ ('pelkosenniemi', "Pelkosenniemi"),
+ ('pello', "Pello"),
+ ('perho', "Perho"),
+ ('pertunmaa', "Pertunmaa"),
+ ('petajavesi', "Petäjävesi"),
+ ('pieksamaki', "Pieksämäki"),
+ ('pielavesi', "Pielavesi"),
+ ('pietarsaari', "Pietarsaari"),
+ ('pihtipudas', "Pihtipudas"),
+ ('pirkkala', "Pirkkala"),
+ ('polvijarvi', "Polvijärvi"),
+ ('pomarkku', "Pomarkku"),
+ ('pori', "Pori"),
+ ('pornainen', "Pornainen"),
+ ('porvoo', "Porvoo"),
+ ('posio', "Posio"),
+ ('pudasjarvi', "Pudasjärvi"),
+ ('pukkila', "Pukkila"),
+ ('punkaharju', "Punkaharju"),
+ ('punkalaidun', "Punkalaidun"),
+ ('puolanka', "Puolanka"),
+ ('puumala', "Puumala"),
+ ('pyhtaa', "Pyhtää"),
+ ('pyhajoki', "Pyhäjoki"),
+ ('pyhajarvi', "Pyhäjärvi"),
+ ('pyhanta', "Pyhäntä"),
+ ('pyharanta', "Pyhäranta"),
+ ('palkane', "Pälkäne"),
+ ('poytya', "Pöytyä"),
+ ('raahe', "Raahe"),
+ ('raasepori', "Raasepori"),
+ ('raisio', "Raisio"),
+ ('rantasalmi', "Rantasalmi"),
+ ('ranua', "Ranua"),
+ ('rauma', "Rauma"),
+ ('rautalampi', "Rautalampi"),
+ ('rautavaara', "Rautavaara"),
+ ('rautjarvi', "Rautjärvi"),
+ ('reisjarvi', "Reisjärvi"),
+ ('riihimaki', "Riihimäki"),
+ ('ristiina', "Ristiina"),
+ ('ristijarvi', "Ristijärvi"),
+ ('rovaniemi', "Rovaniemi"),
+ ('ruokolahti', "Ruokolahti"),
+ ('ruovesi', "Ruovesi"),
+ ('rusko', "Rusko"),
+ ('raakkyla', "Rääkkylä"),
+ ('saarijarvi', "Saarijärvi"),
+ ('salla', "Salla"),
+ ('salo', "Salo"),
+ ('saltvik', "Saltvik"),
+ ('sastamala', "Sastamala"),
+ ('sauvo', "Sauvo"),
+ ('savitaipale', "Savitaipale"),
+ ('savonlinna', "Savonlinna"),
+ ('savukoski', "Savukoski"),
+ ('seinajoki', "Seinäjoki"),
+ ('sievi', "Sievi"),
+ ('siikainen', "Siikainen"),
+ ('siikajoki', "Siikajoki"),
+ ('siikalatva', "Siikalatva"),
+ ('siilinjarvi', "Siilinjärvi"),
+ ('simo', "Simo"),
+ ('sipoo', "Sipoo"),
+ ('siuntio', "Siuntio"),
+ ('sodankyla', "Sodankylä"),
+ ('soini', "Soini"),
+ ('somero', "Somero"),
+ ('sonkajarvi', "Sonkajärvi"),
+ ('sotkamo', "Sotkamo"),
+ ('sottunga', "Sottunga"),
+ ('sulkava', "Sulkava"),
+ ('sund', "Sund"),
+ ('suomenniemi', "Suomenniemi"),
+ ('suomussalmi', "Suomussalmi"),
+ ('suonenjoki', "Suonenjoki"),
+ ('sysma', "Sysmä"),
+ ('sakyla', "Säkylä"),
+ ('taipalsaari', "Taipalsaari"),
+ ('taivalkoski', "Taivalkoski"),
+ ('taivassalo', "Taivassalo"),
+ ('tammela', "Tammela"),
+ ('tampere', "Tampere"),
+ ('tarvasjoki', "Tarvasjoki"),
+ ('tervo', "Tervo"),
+ ('tervola', "Tervola"),
+ ('teuva', "Teuva"),
+ ('tohmajarvi', "Tohmajärvi"),
+ ('toholampi', "Toholampi"),
+ ('toivakka', "Toivakka"),
+ ('tornio', "Tornio"),
+ ('turku', "Turku"),
+ ('tuusniemi', "Tuusniemi"),
+ ('tuusula', "Tuusula"),
+ ('tyrnava', "Tyrnävä"),
+ ('toysa', "Töysä"),
+ ('ulvila', "Ulvila"),
+ ('urjala', "Urjala"),
+ ('utajarvi', "Utajärvi"),
+ ('utsjoki', "Utsjoki"),
+ ('uurainen', "Uurainen"),
+ ('uusikaarlepyy', "Uusikaarlepyy"),
+ ('uusikaupunki', "Uusikaupunki"),
+ ('vaala', "Vaala"),
+ ('vaasa', "Vaasa"),
+ ('valkeakoski', "Valkeakoski"),
+ ('valtimo', "Valtimo"),
+ ('vantaa', "Vantaa"),
+ ('varkaus', "Varkaus"),
+ ('varpaisjarvi', "Varpaisjärvi"),
+ ('vehmaa', "Vehmaa"),
+ ('vesanto', "Vesanto"),
+ ('vesilahti', "Vesilahti"),
+ ('veteli', "Veteli"),
+ ('vierema', "Vieremä"),
+ ('vihanti', "Vihanti"),
+ ('vihti', "Vihti"),
+ ('viitasaari', "Viitasaari"),
+ ('vimpeli', "Vimpeli"),
+ ('virolahti', "Virolahti"),
+ ('virrat', "Virrat"),
+ ('vardo', "Vårdö"),
+ ('vahakyro', "Vähäkyrö"),
+ ('voyri-maksamaa', "Vöyri-Maksamaa"),
+ ('yli-ii', "Yli-Ii"),
+ ('ylitornio', "Ylitornio"),
+ ('ylivieska', "Ylivieska"),
+ ('ylojarvi', "Ylöjärvi"),
+ ('ypaja', "Ypäjä"),
+ ('ahtari', "Ähtäri"),
+ ('aanekoski', "Äänekoski")
+)
diff --git a/django/contrib/localflavor/fi/forms.py b/django/contrib/localflavor/fi/forms.py
index ddc3b48c54..633f3e5f1b 100644
--- a/django/contrib/localflavor/fi/forms.py
+++ b/django/contrib/localflavor/fi/forms.py
@@ -2,7 +2,7 @@
FI-specific Form helpers
"""
-from __future__ import absolute_import
+from __future__ import absolute_import, unicode_literals
import re
@@ -36,7 +36,7 @@ class FISocialSecurityNumber(Field):
def clean(self, value):
super(FISocialSecurityNumber, self).clean(value)
if value in EMPTY_VALUES:
- return u''
+ return ''
checkmarks = "0123456789ABCDEFHJKLMNPRSTUVWXY"
result = re.match(r"""^
@@ -51,5 +51,5 @@ class FISocialSecurityNumber(Field):
gd = result.groupdict()
checksum = int(gd['date'] + gd['serial'])
if checkmarks[checksum % len(checkmarks)] == gd['checksum'].upper():
- return u'%s' % value.upper()
+ return '%s' % value.upper()
raise ValidationError(self.error_messages['invalid'])
diff --git a/django/contrib/localflavor/fr/forms.py b/django/contrib/localflavor/fr/forms.py
index 34e4a96bf4..8b841fff5f 100644
--- a/django/contrib/localflavor/fr/forms.py
+++ b/django/contrib/localflavor/fr/forms.py
@@ -1,15 +1,15 @@
"""
FR-specific Form helpers
"""
-from __future__ import absolute_import
+from __future__ import absolute_import, unicode_literals
import re
from django.contrib.localflavor.fr.fr_department import DEPARTMENT_CHOICES
from django.core.validators import EMPTY_VALUES
from django.forms import ValidationError
-from django.forms.fields import Field, RegexField, Select
-from django.utils.encoding import smart_unicode
+from django.forms.fields import CharField, RegexField, Select
+from django.utils.encoding import smart_text
from django.utils.translation import ugettext_lazy as _
@@ -20,11 +20,11 @@ class FRZipCodeField(RegexField):
'invalid': _('Enter a zip code in the format XXXXX.'),
}
- def __init__(self, max_length=None, min_length=None, *args, **kwargs):
+ def __init__(self, max_length=5, min_length=5, *args, **kwargs):
super(FRZipCodeField, self).__init__(r'^\d{5}$',
max_length, min_length, *args, **kwargs)
-class FRPhoneNumberField(Field):
+class FRPhoneNumberField(CharField):
"""
Validate local French phone number (not international ones)
The correct format is '0X XX XX XX XX'.
@@ -35,14 +35,18 @@ class FRPhoneNumberField(Field):
'invalid': _('Phone numbers must be in 0X XX XX XX XX format.'),
}
+ def __init__(self, max_length=14, min_length=10, *args, **kwargs):
+ super(FRPhoneNumberField, self).__init__(
+ max_length, min_length, *args, **kwargs)
+
def clean(self, value):
super(FRPhoneNumberField, self).clean(value)
if value in EMPTY_VALUES:
- return u''
- value = re.sub('(\.|\s)', '', smart_unicode(value))
+ return ''
+ value = re.sub('(\.|\s)', '', smart_text(value))
m = phone_digits_re.search(value)
if m:
- return u'%s %s %s %s %s' % (value[0:2], value[2:4], value[4:6], value[6:8], value[8:10])
+ return '%s %s %s %s %s' % (value[0:2], value[2:4], value[4:6], value[6:8], value[8:10])
raise ValidationError(self.error_messages['invalid'])
class FRDepartmentSelect(Select):
@@ -51,4 +55,3 @@ class FRDepartmentSelect(Select):
"""
def __init__(self, attrs=None):
super(FRDepartmentSelect, self).__init__(attrs, choices=DEPARTMENT_CHOICES)
-
diff --git a/django/contrib/localflavor/fr/fr_department.py b/django/contrib/localflavor/fr/fr_department.py
index 9f146ac8f9..a2cca957c2 100644
--- a/django/contrib/localflavor/fr/fr_department.py
+++ b/django/contrib/localflavor/fr/fr_department.py
@@ -1,117 +1,118 @@
# -*- coding: utf-8 -*-
# See the "Code officiel géographique" on the INSEE website .
+from __future__ import unicode_literals
DEPARTMENT_CHOICES = (
# Metropolitan departments
- ('01', u'01 - Ain'),
- ('02', u'02 - Aisne'),
- ('03', u'03 - Allier'),
- ('04', u'04 - Alpes-de-Haute-Provence'),
- ('05', u'05 - Hautes-Alpes'),
- ('06', u'06 - Alpes-Maritimes'),
- ('07', u'07 - Ardèche'),
- ('08', u'08 - Ardennes'),
- ('09', u'09 - Ariège'),
- ('10', u'10 - Aube'),
- ('11', u'11 - Aude'),
- ('12', u'12 - Aveyron'),
- ('13', u'13 - Bouches-du-Rhône'),
- ('14', u'14 - Calvados'),
- ('15', u'15 - Cantal'),
- ('16', u'16 - Charente'),
- ('17', u'17 - Charente-Maritime'),
- ('18', u'18 - Cher'),
- ('19', u'19 - Corrèze'),
- ('2A', u'2A - Corse-du-Sud'),
- ('2B', u'2B - Haute-Corse'),
- ('21', u'21 - Côte-d\'Or'),
- ('22', u'22 - Côtes-d\'Armor'),
- ('23', u'23 - Creuse'),
- ('24', u'24 - Dordogne'),
- ('25', u'25 - Doubs'),
- ('26', u'26 - Drôme'),
- ('27', u'27 - Eure'),
- ('28', u'28 - Eure-et-Loir'),
- ('29', u'29 - Finistère'),
- ('30', u'30 - Gard'),
- ('31', u'31 - Haute-Garonne'),
- ('32', u'32 - Gers'),
- ('33', u'33 - Gironde'),
- ('34', u'34 - Hérault'),
- ('35', u'35 - Ille-et-Vilaine'),
- ('36', u'36 - Indre'),
- ('37', u'37 - Indre-et-Loire'),
- ('38', u'38 - Isère'),
- ('39', u'39 - Jura'),
- ('40', u'40 - Landes'),
- ('41', u'41 - Loir-et-Cher'),
- ('42', u'42 - Loire'),
- ('43', u'43 - Haute-Loire'),
- ('44', u'44 - Loire-Atlantique'),
- ('45', u'45 - Loiret'),
- ('46', u'46 - Lot'),
- ('47', u'47 - Lot-et-Garonne'),
- ('48', u'48 - Lozère'),
- ('49', u'49 - Maine-et-Loire'),
- ('50', u'50 - Manche'),
- ('51', u'51 - Marne'),
- ('52', u'52 - Haute-Marne'),
- ('53', u'53 - Mayenne'),
- ('54', u'54 - Meurthe-et-Moselle'),
- ('55', u'55 - Meuse'),
- ('56', u'56 - Morbihan'),
- ('57', u'57 - Moselle'),
- ('58', u'58 - Nièvre'),
- ('59', u'59 - Nord'),
- ('60', u'60 - Oise'),
- ('61', u'61 - Orne'),
- ('62', u'62 - Pas-de-Calais'),
- ('63', u'63 - Puy-de-Dôme'),
- ('64', u'64 - Pyrénées-Atlantiques'),
- ('65', u'65 - Hautes-Pyrénées'),
- ('66', u'66 - Pyrénées-Orientales'),
- ('67', u'67 - Bas-Rhin'),
- ('68', u'68 - Haut-Rhin'),
- ('69', u'69 - Rhône'),
- ('70', u'70 - Haute-Saône'),
- ('71', u'71 - Saône-et-Loire'),
- ('72', u'72 - Sarthe'),
- ('73', u'73 - Savoie'),
- ('74', u'74 - Haute-Savoie'),
- ('75', u'75 - Paris'),
- ('76', u'76 - Seine-Maritime'),
- ('77', u'77 - Seine-et-Marne'),
- ('78', u'78 - Yvelines'),
- ('79', u'79 - Deux-Sèvres'),
- ('80', u'80 - Somme'),
- ('81', u'81 - Tarn'),
- ('82', u'82 - Tarn-et-Garonne'),
- ('83', u'83 - Var'),
- ('84', u'84 - Vaucluse'),
- ('85', u'85 - Vendée'),
- ('86', u'86 - Vienne'),
- ('87', u'87 - Haute-Vienne'),
- ('88', u'88 - Vosges'),
- ('89', u'89 - Yonne'),
- ('90', u'90 - Territoire de Belfort'),
- ('91', u'91 - Essonne'),
- ('92', u'92 - Hauts-de-Seine'),
- ('93', u'93 - Seine-Saint-Denis'),
- ('94', u'94 - Val-de-Marne'),
- ('95', u'95 - Val-d\'Oise'),
+ ('01', '01 - Ain'),
+ ('02', '02 - Aisne'),
+ ('03', '03 - Allier'),
+ ('04', '04 - Alpes-de-Haute-Provence'),
+ ('05', '05 - Hautes-Alpes'),
+ ('06', '06 - Alpes-Maritimes'),
+ ('07', '07 - Ardèche'),
+ ('08', '08 - Ardennes'),
+ ('09', '09 - Ariège'),
+ ('10', '10 - Aube'),
+ ('11', '11 - Aude'),
+ ('12', '12 - Aveyron'),
+ ('13', '13 - Bouches-du-Rhône'),
+ ('14', '14 - Calvados'),
+ ('15', '15 - Cantal'),
+ ('16', '16 - Charente'),
+ ('17', '17 - Charente-Maritime'),
+ ('18', '18 - Cher'),
+ ('19', '19 - Corrèze'),
+ ('2A', '2A - Corse-du-Sud'),
+ ('2B', '2B - Haute-Corse'),
+ ('21', '21 - Côte-d\'Or'),
+ ('22', '22 - Côtes-d\'Armor'),
+ ('23', '23 - Creuse'),
+ ('24', '24 - Dordogne'),
+ ('25', '25 - Doubs'),
+ ('26', '26 - Drôme'),
+ ('27', '27 - Eure'),
+ ('28', '28 - Eure-et-Loir'),
+ ('29', '29 - Finistère'),
+ ('30', '30 - Gard'),
+ ('31', '31 - Haute-Garonne'),
+ ('32', '32 - Gers'),
+ ('33', '33 - Gironde'),
+ ('34', '34 - Hérault'),
+ ('35', '35 - Ille-et-Vilaine'),
+ ('36', '36 - Indre'),
+ ('37', '37 - Indre-et-Loire'),
+ ('38', '38 - Isère'),
+ ('39', '39 - Jura'),
+ ('40', '40 - Landes'),
+ ('41', '41 - Loir-et-Cher'),
+ ('42', '42 - Loire'),
+ ('43', '43 - Haute-Loire'),
+ ('44', '44 - Loire-Atlantique'),
+ ('45', '45 - Loiret'),
+ ('46', '46 - Lot'),
+ ('47', '47 - Lot-et-Garonne'),
+ ('48', '48 - Lozère'),
+ ('49', '49 - Maine-et-Loire'),
+ ('50', '50 - Manche'),
+ ('51', '51 - Marne'),
+ ('52', '52 - Haute-Marne'),
+ ('53', '53 - Mayenne'),
+ ('54', '54 - Meurthe-et-Moselle'),
+ ('55', '55 - Meuse'),
+ ('56', '56 - Morbihan'),
+ ('57', '57 - Moselle'),
+ ('58', '58 - Nièvre'),
+ ('59', '59 - Nord'),
+ ('60', '60 - Oise'),
+ ('61', '61 - Orne'),
+ ('62', '62 - Pas-de-Calais'),
+ ('63', '63 - Puy-de-Dôme'),
+ ('64', '64 - Pyrénées-Atlantiques'),
+ ('65', '65 - Hautes-Pyrénées'),
+ ('66', '66 - Pyrénées-Orientales'),
+ ('67', '67 - Bas-Rhin'),
+ ('68', '68 - Haut-Rhin'),
+ ('69', '69 - Rhône'),
+ ('70', '70 - Haute-Saône'),
+ ('71', '71 - Saône-et-Loire'),
+ ('72', '72 - Sarthe'),
+ ('73', '73 - Savoie'),
+ ('74', '74 - Haute-Savoie'),
+ ('75', '75 - Paris'),
+ ('76', '76 - Seine-Maritime'),
+ ('77', '77 - Seine-et-Marne'),
+ ('78', '78 - Yvelines'),
+ ('79', '79 - Deux-Sèvres'),
+ ('80', '80 - Somme'),
+ ('81', '81 - Tarn'),
+ ('82', '82 - Tarn-et-Garonne'),
+ ('83', '83 - Var'),
+ ('84', '84 - Vaucluse'),
+ ('85', '85 - Vendée'),
+ ('86', '86 - Vienne'),
+ ('87', '87 - Haute-Vienne'),
+ ('88', '88 - Vosges'),
+ ('89', '89 - Yonne'),
+ ('90', '90 - Territoire de Belfort'),
+ ('91', '91 - Essonne'),
+ ('92', '92 - Hauts-de-Seine'),
+ ('93', '93 - Seine-Saint-Denis'),
+ ('94', '94 - Val-de-Marne'),
+ ('95', '95 - Val-d\'Oise'),
# Overseas departments, communities, and other territories
- ('971', u'971 - Guadeloupe'),
- ('972', u'972 - Martinique'),
- ('973', u'973 - Guyane'),
- ('974', u'974 - La Réunion'),
- ('975', u'975 - Saint-Pierre-et-Miquelon'),
- ('976', u'976 - Mayotte'),
- ('977', u'977 - Saint-Barthélemy'),
- ('978', u'978 - Saint-Martin'),
- ('984', u'984 - Terres australes et antarctiques françaises'),
- ('986', u'986 - Wallis et Futuna'),
- ('987', u'987 - Polynésie française'),
- ('988', u'988 - Nouvelle-Calédonie'),
- ('989', u'989 - Île de Clipperton'),
+ ('971', '971 - Guadeloupe'),
+ ('972', '972 - Martinique'),
+ ('973', '973 - Guyane'),
+ ('974', '974 - La Réunion'),
+ ('975', '975 - Saint-Pierre-et-Miquelon'),
+ ('976', '976 - Mayotte'),
+ ('977', '977 - Saint-Barthélemy'),
+ ('978', '978 - Saint-Martin'),
+ ('984', '984 - Terres australes et antarctiques françaises'),
+ ('986', '986 - Wallis et Futuna'),
+ ('987', '987 - Polynésie française'),
+ ('988', '988 - Nouvelle-Calédonie'),
+ ('989', '989 - Île de Clipperton'),
)
diff --git a/django/contrib/localflavor/gb/forms.py b/django/contrib/localflavor/gb/forms.py
index a6658578b1..bf90f80281 100644
--- a/django/contrib/localflavor/gb/forms.py
+++ b/django/contrib/localflavor/gb/forms.py
@@ -2,7 +2,7 @@
GB-specific Form helpers
"""
-from __future__ import absolute_import
+from __future__ import absolute_import, unicode_literals
import re
@@ -22,7 +22,7 @@ class GBPostcodeField(CharField):
The value is uppercased and a space added in the correct place, if required.
"""
default_error_messages = {
- 'invalid': _(u'Enter a valid postcode.'),
+ 'invalid': _('Enter a valid postcode.'),
}
outcode_pattern = '[A-PR-UWYZ]([0-9]{1,2}|([A-HIK-Y][0-9](|[0-9]|[ABEHMNPRVWXY]))|[0-9][A-HJKSTUW])'
incode_pattern = '[0-9][ABD-HJLNP-UW-Z]{2}'
@@ -31,7 +31,7 @@ class GBPostcodeField(CharField):
def clean(self, value):
value = super(GBPostcodeField, self).clean(value)
- if value == u'':
+ if value == '':
return value
postcode = value.upper().strip()
# Put a single space before the incode (second part).
diff --git a/django/contrib/localflavor/hk/forms.py b/django/contrib/localflavor/hk/forms.py
index 852ef7d4b2..ab4f70f193 100644
--- a/django/contrib/localflavor/hk/forms.py
+++ b/django/contrib/localflavor/hk/forms.py
@@ -1,14 +1,14 @@
"""
Hong Kong specific Form helpers
"""
-from __future__ import absolute_import
+from __future__ import absolute_import, unicode_literals
import re
from django.core.validators import EMPTY_VALUES
from django.forms import CharField
from django.forms import ValidationError
-from django.utils.encoding import smart_unicode
+from django.utils.encoding import smart_text
from django.utils.translation import ugettext_lazy as _
@@ -51,14 +51,14 @@ class HKPhoneNumberField(CharField):
super(HKPhoneNumberField, self).clean(value)
if value in EMPTY_VALUES:
- return u''
+ return ''
- value = re.sub('(\(|\)|\s+|\+)', '', smart_unicode(value))
+ value = re.sub('(\(|\)|\s+|\+)', '', smart_text(value))
m = hk_phone_digits_re.search(value)
if not m:
raise ValidationError(self.error_messages['invalid'])
- value = u'%s-%s' % (m.group(1), m.group(2))
+ value = '%s-%s' % (m.group(1), m.group(2))
for special in hk_special_numbers:
if value.startswith(special):
raise ValidationError(self.error_messages['disguise'])
diff --git a/django/contrib/localflavor/hr/forms.py b/django/contrib/localflavor/hr/forms.py
index 0ff283d6c8..b935fd8a3a 100644
--- a/django/contrib/localflavor/hr/forms.py
+++ b/django/contrib/localflavor/hr/forms.py
@@ -2,7 +2,7 @@
"""
HR-specific Form helpers
"""
-from __future__ import absolute_import
+from __future__ import absolute_import, unicode_literals
import re
@@ -12,15 +12,15 @@ from django.contrib.localflavor.hr.hr_choices import (
from django.core.validators import EMPTY_VALUES
from django.forms import ValidationError
from django.forms.fields import Field, Select, RegexField
-from django.utils.encoding import smart_unicode
+from django.utils.encoding import smart_text
from django.utils.translation import ugettext_lazy as _
jmbg_re = re.compile(r'^(?P
\d{2})(?P\d{2})(?P\d{3})' + \
r'(?P\d{2})(?P\d{3})(?P\d{1})$')
oib_re = re.compile(r'^\d{11}$')
-plate_re = re.compile(ur'^(?P[A-ZČŠŽ]{2})' + \
- ur'(?P\d{3,4})(?P[ABCDEFGHIJKLMNOPRSTUVZ]{1,2})$')
+plate_re = re.compile(r'^(?P[A-ZČŠŽ]{2})' + \
+ r'(?P\d{3,4})(?P[ABCDEFGHIJKLMNOPRSTUVZ]{1,2})$')
postal_code_re = re.compile(r'^\d{5}$')
phone_re = re.compile(r'^(\+385|00385|0)(?P\d{2})(?P\d{6,7})$')
jmbag_re = re.compile(r'^601983(?P\d{1})1(?P\d{10})(?P\d{1})$')
@@ -79,7 +79,7 @@ class HRJMBGField(Field):
def clean(self, value):
super(HRJMBGField, self).clean(value)
if value in EMPTY_VALUES:
- return u''
+ return ''
value = value.strip()
@@ -110,7 +110,7 @@ class HRJMBGField(Field):
if not str(m) == k:
raise ValidationError(self.error_messages['invalid'])
- return u'%s' % (value, )
+ return '%s' % (value, )
class HROIBField(RegexField):
@@ -130,7 +130,7 @@ class HROIBField(RegexField):
def clean(self, value):
super(HROIBField, self).clean(value)
if value in EMPTY_VALUES:
- return u''
+ return ''
return '%s' % (value, )
@@ -157,9 +157,9 @@ class HRLicensePlateField(Field):
def clean(self, value):
super(HRLicensePlateField, self).clean(value)
if value in EMPTY_VALUES:
- return u''
+ return ''
- value = re.sub(r'[\s\-]+', '', smart_unicode(value.strip())).upper()
+ value = re.sub(r'[\s\-]+', '', smart_text(value.strip())).upper()
matches = plate_re.search(value)
if matches is None:
@@ -175,7 +175,7 @@ class HRLicensePlateField(Field):
if int(number) == 0:
raise ValidationError(self.error_messages['number'])
- return u'%s %s-%s' % (prefix,number,matches.group('suffix'), )
+ return '%s %s-%s' % (prefix,number,matches.group('suffix'), )
class HRPostalCodeField(Field):
@@ -193,7 +193,7 @@ class HRPostalCodeField(Field):
def clean(self, value):
super(HRPostalCodeField, self).clean(value)
if value in EMPTY_VALUES:
- return u''
+ return ''
value = value.strip()
if not postal_code_re.search(value):
@@ -223,9 +223,9 @@ class HRPhoneNumberField(Field):
def clean(self, value):
super(HRPhoneNumberField, self).clean(value)
if value in EMPTY_VALUES:
- return u''
+ return ''
- value = re.sub(r'[\-\s\(\)]', '', smart_unicode(value))
+ value = re.sub(r'[\-\s\(\)]', '', smart_text(value))
matches = phone_re.search(value)
if matches is None:
@@ -262,7 +262,7 @@ class HRJMBAGField(Field):
def clean(self, value):
super(HRJMBAGField, self).clean(value)
if value in EMPTY_VALUES:
- return u''
+ return ''
value = re.sub(r'[\-\s]', '', value.strip())
diff --git a/django/contrib/localflavor/hr/hr_choices.py b/django/contrib/localflavor/hr/hr_choices.py
index 24d3d42c5b..beb2969405 100644
--- a/django/contrib/localflavor/hr/hr_choices.py
+++ b/django/contrib/localflavor/hr/hr_choices.py
@@ -6,30 +6,32 @@ Sources:
Croatia doesn't have official abbreviations for counties.
The ones provided are in common use.
"""
+from __future__ import unicode_literals
+
from django.utils.translation import ugettext_lazy as _
HR_COUNTY_CHOICES = (
('GZG', _('Grad Zagreb')),
- (u'BBŽ', _(u'Bjelovarsko-bilogorska županija')),
- (u'BPŽ', _(u'Brodsko-posavska županija')),
- (u'DNŽ', _(u'Dubrovačko-neretvanska županija')),
- (u'IŽ', _(u'Istarska županija')),
- (u'KŽ', _(u'Karlovačka županija')),
- (u'KKŽ', _(u'Koprivničko-križevačka županija')),
- (u'KZŽ', _(u'Krapinsko-zagorska županija')),
- (u'LSŽ', _(u'Ličko-senjska županija')),
- (u'MŽ', _(u'Međimurska županija')),
- (u'OBŽ', _(u'Osječko-baranjska županija')),
- (u'PSŽ', _(u'Požeško-slavonska županija')),
- (u'PGŽ', _(u'Primorsko-goranska županija')),
- (u'SMŽ', _(u'Sisačko-moslavačka županija')),
- (u'SDŽ', _(u'Splitsko-dalmatinska županija')),
- (u'ŠKŽ', _(u'Šibensko-kninska županija')),
- (u'VŽ', _(u'Varaždinska županija')),
- (u'VPŽ', _(u'Virovitičko-podravska županija')),
- (u'VSŽ', _(u'Vukovarsko-srijemska županija')),
- (u'ZDŽ', _(u'Zadarska županija')),
- (u'ZGŽ', _(u'Zagrebačka županija')),
+ ('BBŽ', _('Bjelovarsko-bilogorska županija')),
+ ('BPŽ', _('Brodsko-posavska županija')),
+ ('DNŽ', _('Dubrovačko-neretvanska županija')),
+ ('IŽ', _('Istarska županija')),
+ ('KŽ', _('Karlovačka županija')),
+ ('KKŽ', _('Koprivničko-križevačka županija')),
+ ('KZŽ', _('Krapinsko-zagorska županija')),
+ ('LSŽ', _('Ličko-senjska županija')),
+ ('MŽ', _('Međimurska županija')),
+ ('OBŽ', _('Osječko-baranjska županija')),
+ ('PSŽ', _('Požeško-slavonska županija')),
+ ('PGŽ', _('Primorsko-goranska županija')),
+ ('SMŽ', _('Sisačko-moslavačka županija')),
+ ('SDŽ', _('Splitsko-dalmatinska županija')),
+ ('ŠKŽ', _('Šibensko-kninska županija')),
+ ('VŽ', _('Varaždinska županija')),
+ ('VPŽ', _('Virovitičko-podravska županija')),
+ ('VSŽ', _('Vukovarsko-srijemska županija')),
+ ('ZDŽ', _('Zadarska županija')),
+ ('ZGŽ', _('Zagrebačka županija')),
)
"""
@@ -42,7 +44,7 @@ Only common license plate prefixes are provided. Special cases and obsolete pref
HR_LICENSE_PLATE_PREFIX_CHOICES = (
('BJ', 'BJ'),
('BM', 'BM'),
- (u'ČK', u'ČK'),
+ ('ČK', 'ČK'),
('DA', 'DA'),
('DE', 'DE'),
('DJ', 'DJ'),
@@ -53,27 +55,27 @@ HR_LICENSE_PLATE_PREFIX_CHOICES = (
('KC', 'KC'),
('KR', 'KR'),
('KT', 'KT'),
- (u'KŽ', u'KŽ'),
+ ('KŽ', 'KŽ'),
('MA', 'MA'),
('NA', 'NA'),
('NG', 'NG'),
('OG', 'OG'),
('OS', 'OS'),
('PU', 'PU'),
- (u'PŽ', u'PŽ'),
+ ('PŽ', 'PŽ'),
('RI', 'RI'),
('SB', 'SB'),
('SK', 'SK'),
('SL', 'SL'),
('ST', 'ST'),
- (u'ŠI', u'ŠI'),
+ ('ŠI', 'ŠI'),
('VK', 'VK'),
('VT', 'VT'),
('VU', 'VU'),
- (u'VŽ', u'VŽ'),
+ ('VŽ', 'VŽ'),
('ZD', 'ZD'),
('ZG', 'ZG'),
- (u'ŽU', u'ŽU'),
+ ('ŽU', 'ŽU'),
)
"""
diff --git a/django/contrib/localflavor/id/forms.py b/django/contrib/localflavor/id/forms.py
index 9439dba594..2005dbc75c 100644
--- a/django/contrib/localflavor/id/forms.py
+++ b/django/contrib/localflavor/id/forms.py
@@ -2,7 +2,7 @@
ID-specific Form helpers
"""
-from __future__ import absolute_import
+from __future__ import absolute_import, unicode_literals
import re
import time
@@ -11,7 +11,7 @@ from django.core.validators import EMPTY_VALUES
from django.forms import ValidationError
from django.forms.fields import Field, Select
from django.utils.translation import ugettext_lazy as _
-from django.utils.encoding import smart_unicode
+from django.utils.encoding import smart_text
postcode_re = re.compile(r'^[1-9]\d{4}$')
@@ -34,7 +34,7 @@ class IDPostCodeField(Field):
def clean(self, value):
super(IDPostCodeField, self).clean(value)
if value in EMPTY_VALUES:
- return u''
+ return ''
value = value.strip()
if not postcode_re.search(value):
@@ -47,7 +47,7 @@ class IDPostCodeField(Field):
if value[0] == '1' and value[4] != '0':
raise ValidationError(self.error_messages['invalid'])
- return u'%s' % (value, )
+ return '%s' % (value, )
class IDProvinceSelect(Select):
@@ -75,12 +75,12 @@ class IDPhoneNumberField(Field):
def clean(self, value):
super(IDPhoneNumberField, self).clean(value)
if value in EMPTY_VALUES:
- return u''
+ return ''
- phone_number = re.sub(r'[\-\s\(\)]', '', smart_unicode(value))
+ phone_number = re.sub(r'[\-\s\(\)]', '', smart_text(value))
if phone_re.search(phone_number):
- return smart_unicode(value)
+ return smart_text(value)
raise ValidationError(self.error_messages['invalid'])
@@ -117,10 +117,10 @@ class IDLicensePlateField(Field):
from django.contrib.localflavor.id.id_choices import LICENSE_PLATE_PREFIX_CHOICES
super(IDLicensePlateField, self).clean(value)
if value in EMPTY_VALUES:
- return u''
+ return ''
plate_number = re.sub(r'\s+', ' ',
- smart_unicode(value.strip())).upper()
+ smart_text(value.strip())).upper()
matches = plate_re.search(plate_number)
if matches is None:
@@ -179,9 +179,9 @@ class IDNationalIdentityNumberField(Field):
def clean(self, value):
super(IDNationalIdentityNumberField, self).clean(value)
if value in EMPTY_VALUES:
- return u''
+ return ''
- value = re.sub(r'[\s.]', '', smart_unicode(value))
+ value = re.sub(r'[\s.]', '', smart_text(value))
if not nik_re.search(value):
raise ValidationError(self.error_messages['invalid'])
diff --git a/django/contrib/localflavor/il/forms.py b/django/contrib/localflavor/il/forms.py
index a14358737e..de6ba6b23d 100644
--- a/django/contrib/localflavor/il/forms.py
+++ b/django/contrib/localflavor/il/forms.py
@@ -1,6 +1,7 @@
"""
Israeli-specific form helpers
"""
+from __future__ import unicode_literals
import re
from django.core.exceptions import ValidationError
@@ -28,7 +29,7 @@ class ILPostalCodeField(RegexField):
"""
default_error_messages = {
- 'invalid': _(u'Enter a postal code in the format XXXXX'),
+ 'invalid': _('Enter a postal code in the format XXXXX'),
}
def __init__(self, *args, **kwargs):
@@ -47,14 +48,14 @@ class ILIDNumberField(Field):
"""
default_error_messages = {
- 'invalid': _(u'Enter a valid ID number.'),
+ 'invalid': _('Enter a valid ID number.'),
}
def clean(self, value):
value = super(ILIDNumberField, self).clean(value)
if value in EMPTY_VALUES:
- return u''
+ return ''
match = id_number_re.match(value)
if not match:
diff --git a/django/contrib/localflavor/in_/forms.py b/django/contrib/localflavor/in_/forms.py
index 11011e1df2..5c1d009ef4 100644
--- a/django/contrib/localflavor/in_/forms.py
+++ b/django/contrib/localflavor/in_/forms.py
@@ -2,7 +2,7 @@
India-specific Form helpers.
"""
-from __future__ import absolute_import
+from __future__ import absolute_import, unicode_literals
import re
@@ -10,7 +10,7 @@ from django.contrib.localflavor.in_.in_states import STATES_NORMALIZED, STATE_CH
from django.core.validators import EMPTY_VALUES
from django.forms import ValidationError
from django.forms.fields import Field, RegexField, CharField, Select
-from django.utils.encoding import smart_unicode
+from django.utils.encoding import smart_text
from django.utils.translation import ugettext_lazy as _
@@ -38,7 +38,7 @@ phone_digits_re = re.compile(r"""
class INZipCodeField(RegexField):
default_error_messages = {
- 'invalid': _(u'Enter a zip code in the format XXXXXX or XXX XXX.'),
+ 'invalid': _('Enter a zip code in the format XXXXXX or XXX XXX.'),
}
def __init__(self, max_length=None, min_length=None, *args, **kwargs):
@@ -48,7 +48,7 @@ class INZipCodeField(RegexField):
def clean(self, value):
super(INZipCodeField, self).clean(value)
if value in EMPTY_VALUES:
- return u''
+ return ''
# Convert to "NNNNNN" if "NNN NNN" given
value = re.sub(r'^(\d{3})\s(\d{3})$', r'\1\2', value)
return value
@@ -61,20 +61,20 @@ class INStateField(Field):
registration abbreviation for the given state or union territory
"""
default_error_messages = {
- 'invalid': _(u'Enter an Indian state or territory.'),
+ 'invalid': _('Enter an Indian state or territory.'),
}
def clean(self, value):
super(INStateField, self).clean(value)
if value in EMPTY_VALUES:
- return u''
+ return ''
try:
value = value.strip().lower()
except AttributeError:
pass
else:
try:
- return smart_unicode(STATES_NORMALIZED[value.strip().lower()])
+ return smart_text(STATES_NORMALIZED[value.strip().lower()])
except KeyError:
pass
raise ValidationError(self.error_messages['invalid'])
@@ -106,10 +106,10 @@ class INPhoneNumberField(CharField):
def clean(self, value):
super(INPhoneNumberField, self).clean(value)
if value in EMPTY_VALUES:
- return u''
- value = smart_unicode(value)
+ return ''
+ value = smart_text(value)
m = phone_digits_re.match(value)
if m:
- return u'%s' % (value)
+ return '%s' % (value)
raise ValidationError(self.error_messages['invalid'])
diff --git a/django/contrib/localflavor/is_/forms.py b/django/contrib/localflavor/is_/forms.py
index ca7bd5004e..1ae3e012a1 100644
--- a/django/contrib/localflavor/is_/forms.py
+++ b/django/contrib/localflavor/is_/forms.py
@@ -2,14 +2,14 @@
Iceland specific form helpers.
"""
-from __future__ import absolute_import
+from __future__ import absolute_import, unicode_literals
from django.contrib.localflavor.is_.is_postalcodes import IS_POSTALCODES
from django.core.validators import EMPTY_VALUES
from django.forms import ValidationError
from django.forms.fields import RegexField
from django.forms.widgets import Select
-from django.utils.encoding import smart_unicode
+from django.utils.encoding import smart_text
from django.utils.translation import ugettext_lazy as _
@@ -20,7 +20,7 @@ class ISIdNumberField(RegexField):
"""
default_error_messages = {
'invalid': _('Enter a valid Icelandic identification number. The format is XXXXXX-XXXX.'),
- 'checksum': _(u'The Icelandic identification number is not valid.'),
+ 'checksum': _('The Icelandic identification number is not valid.'),
}
def __init__(self, max_length=11, min_length=10, *args, **kwargs):
@@ -31,7 +31,7 @@ class ISIdNumberField(RegexField):
value = super(ISIdNumberField, self).clean(value)
if value in EMPTY_VALUES:
- return u''
+ return ''
value = self._canonify(value)
if self._validate(value):
@@ -58,7 +58,7 @@ class ISIdNumberField(RegexField):
Takes in the value in canonical form and returns it in the common
display format.
"""
- return smart_unicode(value[:6]+'-'+value[6:])
+ return smart_text(value[:6]+'-'+value[6:])
class ISPhoneNumberField(RegexField):
"""
@@ -73,7 +73,7 @@ class ISPhoneNumberField(RegexField):
value = super(ISPhoneNumberField, self).clean(value)
if value in EMPTY_VALUES:
- return u''
+ return ''
return value.replace('-', '').replace(' ', '')
diff --git a/django/contrib/localflavor/is_/is_postalcodes.py b/django/contrib/localflavor/is_/is_postalcodes.py
index 4feca9c013..f1f3357c1c 100644
--- a/django/contrib/localflavor/is_/is_postalcodes.py
+++ b/django/contrib/localflavor/is_/is_postalcodes.py
@@ -1,151 +1,152 @@
# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
IS_POSTALCODES = (
- ('101', u'101 Reykjavík'),
- ('103', u'103 Reykjavík'),
- ('104', u'104 Reykjavík'),
- ('105', u'105 Reykjavík'),
- ('107', u'107 Reykjavík'),
- ('108', u'108 Reykjavík'),
- ('109', u'109 Reykjavík'),
- ('110', u'110 Reykjavík'),
- ('111', u'111 Reykjavík'),
- ('112', u'112 Reykjavík'),
- ('113', u'113 Reykjavík'),
- ('116', u'116 Kjalarnes'),
- ('121', u'121 Reykjavík'),
- ('123', u'123 Reykjavík'),
- ('124', u'124 Reykjavík'),
- ('125', u'125 Reykjavík'),
- ('127', u'127 Reykjavík'),
- ('128', u'128 Reykjavík'),
- ('129', u'129 Reykjavík'),
- ('130', u'130 Reykjavík'),
- ('132', u'132 Reykjavík'),
- ('150', u'150 Reykjavík'),
- ('155', u'155 Reykjavík'),
- ('170', u'170 Seltjarnarnes'),
- ('172', u'172 Seltjarnarnes'),
- ('190', u'190 Vogar'),
- ('200', u'200 Kópavogur'),
- ('201', u'201 Kópavogur'),
- ('202', u'202 Kópavogur'),
- ('203', u'203 Kópavogur'),
- ('210', u'210 Garðabær'),
- ('212', u'212 Garðabær'),
- ('220', u'220 Hafnarfjörður'),
- ('221', u'221 Hafnarfjörður'),
- ('222', u'222 Hafnarfjörður'),
- ('225', u'225 Álftanes'),
- ('230', u'230 Reykjanesbær'),
- ('232', u'232 Reykjanesbær'),
- ('233', u'233 Reykjanesbær'),
- ('235', u'235 Keflavíkurflugvöllur'),
- ('240', u'240 Grindavík'),
- ('245', u'245 Sandgerði'),
- ('250', u'250 Garður'),
- ('260', u'260 Reykjanesbær'),
- ('270', u'270 Mosfellsbær'),
- ('300', u'300 Akranes'),
- ('301', u'301 Akranes'),
- ('302', u'302 Akranes'),
- ('310', u'310 Borgarnes'),
- ('311', u'311 Borgarnes'),
- ('320', u'320 Reykholt í Borgarfirði'),
- ('340', u'340 Stykkishólmur'),
- ('345', u'345 Flatey á Breiðafirði'),
- ('350', u'350 Grundarfjörður'),
- ('355', u'355 Ólafsvík'),
- ('356', u'356 Snæfellsbær'),
- ('360', u'360 Hellissandur'),
- ('370', u'370 Búðardalur'),
- ('371', u'371 Búðardalur'),
- ('380', u'380 Reykhólahreppur'),
- ('400', u'400 Ísafjörður'),
- ('401', u'401 Ísafjörður'),
- ('410', u'410 Hnífsdalur'),
- ('415', u'415 Bolungarvík'),
- ('420', u'420 Súðavík'),
- ('425', u'425 Flateyri'),
- ('430', u'430 Suðureyri'),
- ('450', u'450 Patreksfjörður'),
- ('451', u'451 Patreksfjörður'),
- ('460', u'460 Tálknafjörður'),
- ('465', u'465 Bíldudalur'),
- ('470', u'470 Þingeyri'),
- ('471', u'471 Þingeyri'),
- ('500', u'500 Staður'),
- ('510', u'510 Hólmavík'),
- ('512', u'512 Hólmavík'),
- ('520', u'520 Drangsnes'),
- ('522', u'522 Kjörvogur'),
- ('523', u'523 Bær'),
- ('524', u'524 Norðurfjörður'),
- ('530', u'530 Hvammstangi'),
- ('531', u'531 Hvammstangi'),
- ('540', u'540 Blönduós'),
- ('541', u'541 Blönduós'),
- ('545', u'545 Skagaströnd'),
- ('550', u'550 Sauðárkrókur'),
- ('551', u'551 Sauðárkrókur'),
- ('560', u'560 Varmahlíð'),
- ('565', u'565 Hofsós'),
- ('566', u'566 Hofsós'),
- ('570', u'570 Fljót'),
- ('580', u'580 Siglufjörður'),
- ('600', u'600 Akureyri'),
- ('601', u'601 Akureyri'),
- ('602', u'602 Akureyri'),
- ('603', u'603 Akureyri'),
- ('610', u'610 Grenivík'),
- ('611', u'611 Grímsey'),
- ('620', u'620 Dalvík'),
- ('621', u'621 Dalvík'),
- ('625', u'625 Ólafsfjörður'),
- ('630', u'630 Hrísey'),
- ('640', u'640 Húsavík'),
- ('641', u'641 Húsavík'),
- ('645', u'645 Fosshóll'),
- ('650', u'650 Laugar'),
- ('660', u'660 Mývatn'),
- ('670', u'670 Kópasker'),
- ('671', u'671 Kópasker'),
- ('675', u'675 Raufarhöfn'),
- ('680', u'680 Þórshöfn'),
- ('681', u'681 Þórshöfn'),
- ('685', u'685 Bakkafjörður'),
- ('690', u'690 Vopnafjörður'),
- ('700', u'700 Egilsstaðir'),
- ('701', u'701 Egilsstaðir'),
- ('710', u'710 Seyðisfjörður'),
- ('715', u'715 Mjóifjörður'),
- ('720', u'720 Borgarfjörður eystri'),
- ('730', u'730 Reyðarfjörður'),
- ('735', u'735 Eskifjörður'),
- ('740', u'740 Neskaupstaður'),
- ('750', u'750 Fáskrúðsfjörður'),
- ('755', u'755 Stöðvarfjörður'),
- ('760', u'760 Breiðdalsvík'),
- ('765', u'765 Djúpivogur'),
- ('780', u'780 Höfn í Hornafirði'),
- ('781', u'781 Höfn í Hornafirði'),
- ('785', u'785 Öræfi'),
- ('800', u'800 Selfoss'),
- ('801', u'801 Selfoss'),
- ('802', u'802 Selfoss'),
- ('810', u'810 Hveragerði'),
- ('815', u'815 Þorlákshöfn'),
- ('820', u'820 Eyrarbakki'),
- ('825', u'825 Stokkseyri'),
- ('840', u'840 Laugarvatn'),
- ('845', u'845 Flúðir'),
- ('850', u'850 Hella'),
- ('851', u'851 Hella'),
- ('860', u'860 Hvolsvöllur'),
- ('861', u'861 Hvolsvöllur'),
- ('870', u'870 Vík'),
- ('871', u'871 Vík'),
- ('880', u'880 Kirkjubæjarklaustur'),
- ('900', u'900 Vestmannaeyjar'),
- ('902', u'902 Vestmannaeyjar')
+ ('101', '101 Reykjavík'),
+ ('103', '103 Reykjavík'),
+ ('104', '104 Reykjavík'),
+ ('105', '105 Reykjavík'),
+ ('107', '107 Reykjavík'),
+ ('108', '108 Reykjavík'),
+ ('109', '109 Reykjavík'),
+ ('110', '110 Reykjavík'),
+ ('111', '111 Reykjavík'),
+ ('112', '112 Reykjavík'),
+ ('113', '113 Reykjavík'),
+ ('116', '116 Kjalarnes'),
+ ('121', '121 Reykjavík'),
+ ('123', '123 Reykjavík'),
+ ('124', '124 Reykjavík'),
+ ('125', '125 Reykjavík'),
+ ('127', '127 Reykjavík'),
+ ('128', '128 Reykjavík'),
+ ('129', '129 Reykjavík'),
+ ('130', '130 Reykjavík'),
+ ('132', '132 Reykjavík'),
+ ('150', '150 Reykjavík'),
+ ('155', '155 Reykjavík'),
+ ('170', '170 Seltjarnarnes'),
+ ('172', '172 Seltjarnarnes'),
+ ('190', '190 Vogar'),
+ ('200', '200 Kópavogur'),
+ ('201', '201 Kópavogur'),
+ ('202', '202 Kópavogur'),
+ ('203', '203 Kópavogur'),
+ ('210', '210 Garðabær'),
+ ('212', '212 Garðabær'),
+ ('220', '220 Hafnarfjörður'),
+ ('221', '221 Hafnarfjörður'),
+ ('222', '222 Hafnarfjörður'),
+ ('225', '225 Álftanes'),
+ ('230', '230 Reykjanesbær'),
+ ('232', '232 Reykjanesbær'),
+ ('233', '233 Reykjanesbær'),
+ ('235', '235 Keflavíkurflugvöllur'),
+ ('240', '240 Grindavík'),
+ ('245', '245 Sandgerði'),
+ ('250', '250 Garður'),
+ ('260', '260 Reykjanesbær'),
+ ('270', '270 Mosfellsbær'),
+ ('300', '300 Akranes'),
+ ('301', '301 Akranes'),
+ ('302', '302 Akranes'),
+ ('310', '310 Borgarnes'),
+ ('311', '311 Borgarnes'),
+ ('320', '320 Reykholt í Borgarfirði'),
+ ('340', '340 Stykkishólmur'),
+ ('345', '345 Flatey á Breiðafirði'),
+ ('350', '350 Grundarfjörður'),
+ ('355', '355 Ólafsvík'),
+ ('356', '356 Snæfellsbær'),
+ ('360', '360 Hellissandur'),
+ ('370', '370 Búðardalur'),
+ ('371', '371 Búðardalur'),
+ ('380', '380 Reykhólahreppur'),
+ ('400', '400 Ísafjörður'),
+ ('401', '401 Ísafjörður'),
+ ('410', '410 Hnífsdalur'),
+ ('415', '415 Bolungarvík'),
+ ('420', '420 Súðavík'),
+ ('425', '425 Flateyri'),
+ ('430', '430 Suðureyri'),
+ ('450', '450 Patreksfjörður'),
+ ('451', '451 Patreksfjörður'),
+ ('460', '460 Tálknafjörður'),
+ ('465', '465 Bíldudalur'),
+ ('470', '470 Þingeyri'),
+ ('471', '471 Þingeyri'),
+ ('500', '500 Staður'),
+ ('510', '510 Hólmavík'),
+ ('512', '512 Hólmavík'),
+ ('520', '520 Drangsnes'),
+ ('522', '522 Kjörvogur'),
+ ('523', '523 Bær'),
+ ('524', '524 Norðurfjörður'),
+ ('530', '530 Hvammstangi'),
+ ('531', '531 Hvammstangi'),
+ ('540', '540 Blönduós'),
+ ('541', '541 Blönduós'),
+ ('545', '545 Skagaströnd'),
+ ('550', '550 Sauðárkrókur'),
+ ('551', '551 Sauðárkrókur'),
+ ('560', '560 Varmahlíð'),
+ ('565', '565 Hofsós'),
+ ('566', '566 Hofsós'),
+ ('570', '570 Fljót'),
+ ('580', '580 Siglufjörður'),
+ ('600', '600 Akureyri'),
+ ('601', '601 Akureyri'),
+ ('602', '602 Akureyri'),
+ ('603', '603 Akureyri'),
+ ('610', '610 Grenivík'),
+ ('611', '611 Grímsey'),
+ ('620', '620 Dalvík'),
+ ('621', '621 Dalvík'),
+ ('625', '625 Ólafsfjörður'),
+ ('630', '630 Hrísey'),
+ ('640', '640 Húsavík'),
+ ('641', '641 Húsavík'),
+ ('645', '645 Fosshóll'),
+ ('650', '650 Laugar'),
+ ('660', '660 Mývatn'),
+ ('670', '670 Kópasker'),
+ ('671', '671 Kópasker'),
+ ('675', '675 Raufarhöfn'),
+ ('680', '680 Þórshöfn'),
+ ('681', '681 Þórshöfn'),
+ ('685', '685 Bakkafjörður'),
+ ('690', '690 Vopnafjörður'),
+ ('700', '700 Egilsstaðir'),
+ ('701', '701 Egilsstaðir'),
+ ('710', '710 Seyðisfjörður'),
+ ('715', '715 Mjóifjörður'),
+ ('720', '720 Borgarfjörður eystri'),
+ ('730', '730 Reyðarfjörður'),
+ ('735', '735 Eskifjörður'),
+ ('740', '740 Neskaupstaður'),
+ ('750', '750 Fáskrúðsfjörður'),
+ ('755', '755 Stöðvarfjörður'),
+ ('760', '760 Breiðdalsvík'),
+ ('765', '765 Djúpivogur'),
+ ('780', '780 Höfn í Hornafirði'),
+ ('781', '781 Höfn í Hornafirði'),
+ ('785', '785 Öræfi'),
+ ('800', '800 Selfoss'),
+ ('801', '801 Selfoss'),
+ ('802', '802 Selfoss'),
+ ('810', '810 Hveragerði'),
+ ('815', '815 Þorlákshöfn'),
+ ('820', '820 Eyrarbakki'),
+ ('825', '825 Stokkseyri'),
+ ('840', '840 Laugarvatn'),
+ ('845', '845 Flúðir'),
+ ('850', '850 Hella'),
+ ('851', '851 Hella'),
+ ('860', '860 Hvolsvöllur'),
+ ('861', '861 Hvolsvöllur'),
+ ('870', '870 Vík'),
+ ('871', '871 Vík'),
+ ('880', '880 Kirkjubæjarklaustur'),
+ ('900', '900 Vestmannaeyjar'),
+ ('902', '902 Vestmannaeyjar')
)
diff --git a/django/contrib/localflavor/it/forms.py b/django/contrib/localflavor/it/forms.py
index 0060b486bd..916ce9bb3d 100644
--- a/django/contrib/localflavor/it/forms.py
+++ b/django/contrib/localflavor/it/forms.py
@@ -2,7 +2,7 @@
IT-specific Form helpers
"""
-from __future__ import absolute_import
+from __future__ import absolute_import, unicode_literals
import re
@@ -13,7 +13,7 @@ from django.core.validators import EMPTY_VALUES
from django.forms import ValidationError
from django.forms.fields import Field, RegexField, Select
from django.utils.translation import ugettext_lazy as _
-from django.utils.encoding import smart_unicode
+from django.utils.encoding import smart_text
class ITZipCodeField(RegexField):
@@ -45,7 +45,7 @@ class ITSocialSecurityNumberField(RegexField):
'Informazioni sulla codificazione delle persone fisiche'.
"""
default_error_messages = {
- 'invalid': _(u'Enter a valid Social Security number.'),
+ 'invalid': _('Enter a valid Social Security number.'),
}
def __init__(self, max_length=None, min_length=None, *args, **kwargs):
@@ -55,8 +55,8 @@ class ITSocialSecurityNumberField(RegexField):
def clean(self, value):
value = super(ITSocialSecurityNumberField, self).clean(value)
if value in EMPTY_VALUES:
- return u''
- value = re.sub('\s', u'', value).upper()
+ return ''
+ value = re.sub('\s', '', value).upper()
try:
check_digit = ssn_check_digit(value)
except ValueError:
@@ -70,13 +70,13 @@ class ITVatNumberField(Field):
A form field that validates Italian VAT numbers (partita IVA).
"""
default_error_messages = {
- 'invalid': _(u'Enter a valid VAT number.'),
+ 'invalid': _('Enter a valid VAT number.'),
}
def clean(self, value):
value = super(ITVatNumberField, self).clean(value)
if value in EMPTY_VALUES:
- return u''
+ return ''
try:
vat_number = int(value)
except ValueError:
@@ -85,4 +85,4 @@ class ITVatNumberField(Field):
check_digit = vat_number_check_digit(vat_number[0:10])
if not vat_number[10] == check_digit:
raise ValidationError(self.error_messages['invalid'])
- return smart_unicode(vat_number)
+ return smart_text(vat_number)
diff --git a/django/contrib/localflavor/it/it_province.py b/django/contrib/localflavor/it/it_province.py
index dcaad98c63..5aad1611dd 100644
--- a/django/contrib/localflavor/it/it_province.py
+++ b/django/contrib/localflavor/it/it_province.py
@@ -1,4 +1,5 @@
# -*- coding: utf-8 -*
+from __future__ import unicode_literals
PROVINCE_CHOICES = (
('AG', 'Agrigento'),
@@ -45,7 +46,7 @@ PROVINCE_CHOICES = (
('IM', 'Imperia'),
('IS', 'Isernia'),
('SP', 'La Spezia'),
- ('AQ', u'L’Aquila'),
+ ('AQ', 'L’Aquila'),
('LT', 'Latina'),
('LE', 'Lecce'),
('LC', 'Lecco'),
diff --git a/django/contrib/localflavor/it/it_region.py b/django/contrib/localflavor/it/it_region.py
index 0700b46ea8..e12a1e731b 100644
--- a/django/contrib/localflavor/it/it_region.py
+++ b/django/contrib/localflavor/it/it_region.py
@@ -1,4 +1,5 @@
# -*- coding: utf-8 -*
+from __future__ import unicode_literals
REGION_CHOICES = (
('ABR', 'Abruzzo'),
@@ -19,6 +20,6 @@ REGION_CHOICES = (
('TOS', 'Toscana'),
('TAA', 'Trentino-Alto Adige'),
('UMB', 'Umbria'),
- ('VAO', u'Valle d’Aosta'),
+ ('VAO', 'Valle d’Aosta'),
('VEN', 'Veneto'),
)
diff --git a/django/contrib/localflavor/it/util.py b/django/contrib/localflavor/it/util.py
index c162ff7eff..e1aa9c0419 100644
--- a/django/contrib/localflavor/it/util.py
+++ b/django/contrib/localflavor/it/util.py
@@ -1,4 +1,4 @@
-from django.utils.encoding import smart_str, smart_unicode
+from django.utils.encoding import smart_text
def ssn_check_digit(value):
"Calculate Italian social security number check digit."
@@ -34,11 +34,11 @@ def ssn_check_digit(value):
def vat_number_check_digit(vat_number):
"Calculate Italian VAT number check digit."
- normalized_vat_number = smart_str(vat_number).zfill(10)
+ normalized_vat_number = smart_text(vat_number).zfill(10)
total = 0
for i in range(0, 10, 2):
total += int(normalized_vat_number[i])
for i in range(1, 11, 2):
quotient , remainder = divmod(int(normalized_vat_number[i]) * 2, 10)
total += quotient + remainder
- return smart_unicode((10 - total % 10) % 10)
+ return smart_text((10 - total % 10) % 10)
diff --git a/django/contrib/localflavor/kw/forms.py b/django/contrib/localflavor/kw/forms.py
index e671408ec8..2c2b023e70 100644
--- a/django/contrib/localflavor/kw/forms.py
+++ b/django/contrib/localflavor/kw/forms.py
@@ -1,6 +1,8 @@
"""
Kuwait-specific Form helpers
"""
+from __future__ import unicode_literals
+
import re
from datetime import date
@@ -40,7 +42,7 @@ class KWCivilIDNumberField(Field):
def clean(self, value):
super(KWCivilIDNumberField, self).clean(value)
if value in EMPTY_VALUES:
- return u''
+ return ''
if not re.match(r'^\d{12}$', value):
raise ValidationError(self.error_messages['invalid'])
diff --git a/django/contrib/localflavor/mk/forms.py b/django/contrib/localflavor/mk/forms.py
index 33dbfc71a0..3189f0dec6 100644
--- a/django/contrib/localflavor/mk/forms.py
+++ b/django/contrib/localflavor/mk/forms.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import
+from __future__ import absolute_import, unicode_literals
import datetime
@@ -15,14 +15,14 @@ class MKIdentityCardNumberField(RegexField):
A Macedonian ID card number. Accepts both old and new format.
"""
default_error_messages = {
- 'invalid': _(u'Identity card numbers must contain'
+ 'invalid': _('Identity card numbers must contain'
' either 4 to 7 digits or an uppercase letter and 7 digits.'),
}
def __init__(self, *args, **kwargs):
kwargs['min_length'] = None
kwargs['max_length'] = 8
- regex = ur'(^[A-Z]{1}\d{7}$)|(^\d{4,7}$)'
+ regex = r'(^[A-Z]{1}\d{7}$)|(^\d{4,7}$)'
super(MKIdentityCardNumberField, self).__init__(regex, *args, **kwargs)
@@ -54,9 +54,9 @@ class UMCNField(RegexField):
* The last digit of the UMCN passes a checksum test
"""
default_error_messages = {
- 'invalid': _(u'This field should contain exactly 13 digits.'),
- 'date': _(u'The first 7 digits of the UMCN must represent a valid past date.'),
- 'checksum': _(u'The UMCN is not valid.'),
+ 'invalid': _('This field should contain exactly 13 digits.'),
+ 'date': _('The first 7 digits of the UMCN must represent a valid past date.'),
+ 'checksum': _('The UMCN is not valid.'),
}
def __init__(self, *args, **kwargs):
@@ -68,7 +68,7 @@ class UMCNField(RegexField):
value = super(UMCNField, self).clean(value)
if value in EMPTY_VALUES:
- return u''
+ return ''
if not self._validate_date_part(value):
raise ValidationError(self.error_messages['date'])
diff --git a/django/contrib/localflavor/mk/mk_choices.py b/django/contrib/localflavor/mk/mk_choices.py
index d6d1efa049..fb705ca820 100644
--- a/django/contrib/localflavor/mk/mk_choices.py
+++ b/django/contrib/localflavor/mk/mk_choices.py
@@ -2,91 +2,93 @@
"""
Macedonian municipalities per the reorganization from 2004.
"""
+from __future__ import unicode_literals
+
from django.utils.translation import ugettext_lazy as _
MK_MUNICIPALITIES = (
- ('AD', _(u'Aerodrom')),
- ('AR', _(u'Aračinovo')),
- ('BR', _(u'Berovo')),
- ('TL', _(u'Bitola')),
- ('BG', _(u'Bogdanci')),
- ('VJ', _(u'Bogovinje')),
- ('BS', _(u'Bosilovo')),
- ('BN', _(u'Brvenica')),
- ('BU', _(u'Butel')),
- ('VA', _(u'Valandovo')),
- ('VL', _(u'Vasilevo')),
- ('VV', _(u'Vevčani')),
- ('VE', _(u'Veles')),
- ('NI', _(u'Vinica')),
- ('VC', _(u'Vraneštica')),
- ('VH', _(u'Vrapčište')),
- ('GB', _(u'Gazi Baba')),
- ('GV', _(u'Gevgelija')),
- ('GT', _(u'Gostivar')),
- ('GR', _(u'Gradsko')),
- ('DB', _(u'Debar')),
- ('DA', _(u'Debarca')),
- ('DL', _(u'Delčevo')),
- ('DK', _(u'Demir Kapija')),
- ('DM', _(u'Demir Hisar')),
- ('DE', _(u'Dolneni')),
- ('DR', _(u'Drugovo')),
- ('GP', _(u'Gjorče Petrov')),
- ('ZE', _(u'Želino')),
- ('ZA', _(u'Zajas')),
- ('ZK', _(u'Zelenikovo')),
- ('ZR', _(u'Zrnovci')),
- ('IL', _(u'Ilinden')),
- ('JG', _(u'Jegunovce')),
- ('AV', _(u'Kavadarci')),
- ('KB', _(u'Karbinci')),
- ('KX', _(u'Karpoš')),
- ('VD', _(u'Kisela Voda')),
- ('KH', _(u'Kičevo')),
- ('KN', _(u'Konče')),
- ('OC', _(u'Koćani')),
- ('KY', _(u'Kratovo')),
- ('KZ', _(u'Kriva Palanka')),
- ('KG', _(u'Krivogaštani')),
- ('KS', _(u'Kruševo')),
- ('UM', _(u'Kumanovo')),
- ('LI', _(u'Lipkovo')),
- ('LO', _(u'Lozovo')),
- ('MR', _(u'Mavrovo i Rostuša')),
- ('MK', _(u'Makedonska Kamenica')),
- ('MD', _(u'Makedonski Brod')),
- ('MG', _(u'Mogila')),
- ('NG', _(u'Negotino')),
- ('NV', _(u'Novaci')),
- ('NS', _(u'Novo Selo')),
- ('OS', _(u'Oslomej')),
- ('OD', _(u'Ohrid')),
- ('PE', _(u'Petrovec')),
- ('PH', _(u'Pehčevo')),
- ('PN', _(u'Plasnica')),
- ('PP', _(u'Prilep')),
- ('PT', _(u'Probištip')),
- ('RV', _(u'Radoviš')),
- ('RN', _(u'Rankovce')),
- ('RE', _(u'Resen')),
- ('RO', _(u'Rosoman')),
- ('AJ', _(u'Saraj')),
- ('SL', _(u'Sveti Nikole')),
- ('SS', _(u'Sopište')),
- ('SD', _(u'Star Dojran')),
- ('NA', _(u'Staro Nagoričane')),
- ('UG', _(u'Struga')),
- ('RU', _(u'Strumica')),
- ('SU', _(u'Studeničani')),
- ('TR', _(u'Tearce')),
- ('ET', _(u'Tetovo')),
- ('CE', _(u'Centar')),
- ('CZ', _(u'Centar-Župa')),
- ('CI', _(u'Čair')),
- ('CA', _(u'Čaška')),
- ('CH', _(u'Češinovo-Obleševo')),
- ('CS', _(u'Čučer-Sandevo')),
- ('ST', _(u'Štip')),
- ('SO', _(u'Šuto Orizari')),
+ ('AD', _('Aerodrom')),
+ ('AR', _('Aračinovo')),
+ ('BR', _('Berovo')),
+ ('TL', _('Bitola')),
+ ('BG', _('Bogdanci')),
+ ('VJ', _('Bogovinje')),
+ ('BS', _('Bosilovo')),
+ ('BN', _('Brvenica')),
+ ('BU', _('Butel')),
+ ('VA', _('Valandovo')),
+ ('VL', _('Vasilevo')),
+ ('VV', _('Vevčani')),
+ ('VE', _('Veles')),
+ ('NI', _('Vinica')),
+ ('VC', _('Vraneštica')),
+ ('VH', _('Vrapčište')),
+ ('GB', _('Gazi Baba')),
+ ('GV', _('Gevgelija')),
+ ('GT', _('Gostivar')),
+ ('GR', _('Gradsko')),
+ ('DB', _('Debar')),
+ ('DA', _('Debarca')),
+ ('DL', _('Delčevo')),
+ ('DK', _('Demir Kapija')),
+ ('DM', _('Demir Hisar')),
+ ('DE', _('Dolneni')),
+ ('DR', _('Drugovo')),
+ ('GP', _('Gjorče Petrov')),
+ ('ZE', _('Želino')),
+ ('ZA', _('Zajas')),
+ ('ZK', _('Zelenikovo')),
+ ('ZR', _('Zrnovci')),
+ ('IL', _('Ilinden')),
+ ('JG', _('Jegunovce')),
+ ('AV', _('Kavadarci')),
+ ('KB', _('Karbinci')),
+ ('KX', _('Karpoš')),
+ ('VD', _('Kisela Voda')),
+ ('KH', _('Kičevo')),
+ ('KN', _('Konče')),
+ ('OC', _('Koćani')),
+ ('KY', _('Kratovo')),
+ ('KZ', _('Kriva Palanka')),
+ ('KG', _('Krivogaštani')),
+ ('KS', _('Kruševo')),
+ ('UM', _('Kumanovo')),
+ ('LI', _('Lipkovo')),
+ ('LO', _('Lozovo')),
+ ('MR', _('Mavrovo i Rostuša')),
+ ('MK', _('Makedonska Kamenica')),
+ ('MD', _('Makedonski Brod')),
+ ('MG', _('Mogila')),
+ ('NG', _('Negotino')),
+ ('NV', _('Novaci')),
+ ('NS', _('Novo Selo')),
+ ('OS', _('Oslomej')),
+ ('OD', _('Ohrid')),
+ ('PE', _('Petrovec')),
+ ('PH', _('Pehčevo')),
+ ('PN', _('Plasnica')),
+ ('PP', _('Prilep')),
+ ('PT', _('Probištip')),
+ ('RV', _('Radoviš')),
+ ('RN', _('Rankovce')),
+ ('RE', _('Resen')),
+ ('RO', _('Rosoman')),
+ ('AJ', _('Saraj')),
+ ('SL', _('Sveti Nikole')),
+ ('SS', _('Sopište')),
+ ('SD', _('Star Dojran')),
+ ('NA', _('Staro Nagoričane')),
+ ('UG', _('Struga')),
+ ('RU', _('Strumica')),
+ ('SU', _('Studeničani')),
+ ('TR', _('Tearce')),
+ ('ET', _('Tetovo')),
+ ('CE', _('Centar')),
+ ('CZ', _('Centar-Župa')),
+ ('CI', _('Čair')),
+ ('CA', _('Čaška')),
+ ('CH', _('Češinovo-Obleševo')),
+ ('CS', _('Čučer-Sandevo')),
+ ('ST', _('Štip')),
+ ('SO', _('Šuto Orizari')),
)
diff --git a/django/contrib/localflavor/mx/forms.py b/django/contrib/localflavor/mx/forms.py
index deecb4ea41..b42bf22b89 100644
--- a/django/contrib/localflavor/mx/forms.py
+++ b/django/contrib/localflavor/mx/forms.py
@@ -2,10 +2,12 @@
"""
Mexican-specific form helpers.
"""
+from __future__ import unicode_literals
import re
from django.forms import ValidationError
from django.forms.fields import Select, RegexField
+from django.utils import six
from django.utils.translation import ugettext_lazy as _
from django.core.validators import EMPTY_VALUES
from django.contrib.localflavor.mx.mx_states import STATE_CHOICES
@@ -19,12 +21,12 @@ document described in the next link:
"""
RFC_INCONVENIENT_WORDS = [
- u'BUEI', u'BUEY', u'CACA', u'CACO', u'CAGA', u'CAGO', u'CAKA', u'CAKO',
- u'COGE', u'COJA', u'COJE', u'COJI', u'COJO', u'CULO', u'FETO', u'GUEY',
- u'JOTO', u'KACA', u'KACO', u'KAGA', u'KAGO', u'KOGE', u'KOJO', u'KAKA',
- u'KULO', u'MAME', u'MAMO', u'MEAR', u'MEAS', u'MEON', u'MION', u'MOCO',
- u'MULA', u'PEDA', u'PEDO', u'PENE', u'PUTA', u'PUTO', u'QULO', u'RATA',
- u'RUIN',
+ 'BUEI', 'BUEY', 'CACA', 'CACO', 'CAGA', 'CAGO', 'CAKA', 'CAKO',
+ 'COGE', 'COJA', 'COJE', 'COJI', 'COJO', 'CULO', 'FETO', 'GUEY',
+ 'JOTO', 'KACA', 'KACO', 'KAGA', 'KAGO', 'KOGE', 'KOJO', 'KAKA',
+ 'KULO', 'MAME', 'MAMO', 'MEAR', 'MEAS', 'MEON', 'MION', 'MOCO',
+ 'MULA', 'PEDA', 'PEDO', 'PENE', 'PUTA', 'PUTO', 'QULO', 'RATA',
+ 'RUIN',
]
"""
@@ -33,17 +35,17 @@ document described in the next link:
http://portal.veracruz.gob.mx/pls/portal/url/ITEM/444112558A57C6E0E040A8C02E00695C
"""
CURP_INCONVENIENT_WORDS = [
- u'BACA', u'BAKA', u'BUEI', u'BUEY', u'CACA', u'CACO', u'CAGA', u'CAGO',
- u'CAKA', u'CAKO', u'COGE', u'COGI', u'COJA', u'COJE', u'COJI', u'COJO',
- u'COLA', u'CULO', u'FALO', u'FETO', u'GETA', u'GUEI', u'GUEY', u'JETA',
- u'JOTO', u'KACA', u'KACO', u'KAGA', u'KAGO', u'KAKA', u'KAKO', u'KOGE',
- u'KOGI', u'KOJA', u'KOJE', u'KOJI', u'KOJO', u'KOLA', u'KULO', u'LILO',
- u'LOCA', u'LOCO', u'LOKA', u'LOKO', u'MAME', u'MAMO', u'MEAR', u'MEAS',
- u'MEON', u'MIAR', u'MION', u'MOCO', u'MOKO', u'MULA', u'MULO', u'NACA',
- u'NACO', u'PEDA', u'PEDO', u'PENE', u'PIPI', u'PITO', u'POPO', u'PUTA',
- u'PUTO', u'QULO', u'RATA', u'ROBA', u'ROBE', u'ROBO', u'RUIN', u'SENO',
- u'TETA', u'VACA', u'VAGA', u'VAGO', u'VAKA', u'VUEI', u'VUEY', u'WUEI',
- u'WUEY',
+ 'BACA', 'BAKA', 'BUEI', 'BUEY', 'CACA', 'CACO', 'CAGA', 'CAGO',
+ 'CAKA', 'CAKO', 'COGE', 'COGI', 'COJA', 'COJE', 'COJI', 'COJO',
+ 'COLA', 'CULO', 'FALO', 'FETO', 'GETA', 'GUEI', 'GUEY', 'JETA',
+ 'JOTO', 'KACA', 'KACO', 'KAGA', 'KAGO', 'KAKA', 'KAKO', 'KOGE',
+ 'KOGI', 'KOJA', 'KOJE', 'KOJI', 'KOJO', 'KOLA', 'KULO', 'LILO',
+ 'LOCA', 'LOCO', 'LOKA', 'LOKO', 'MAME', 'MAMO', 'MEAR', 'MEAS',
+ 'MEON', 'MIAR', 'MION', 'MOCO', 'MOKO', 'MULA', 'MULO', 'NACA',
+ 'NACO', 'PEDA', 'PEDO', 'PENE', 'PIPI', 'PITO', 'POPO', 'PUTA',
+ 'PUTO', 'QULO', 'RATA', 'ROBA', 'ROBE', 'ROBO', 'RUIN', 'SENO',
+ 'TETA', 'VACA', 'VAGA', 'VAGO', 'VAKA', 'VUEI', 'VUEY', 'WUEI',
+ 'WUEY',
]
class MXStateSelect(Select):
@@ -62,11 +64,11 @@ class MXZipCodeField(RegexField):
http://en.wikipedia.org/wiki/List_of_postal_codes_in_Mexico
"""
default_error_messages = {
- 'invalid': _(u'Enter a valid zip code in the format XXXXX.'),
+ 'invalid': _('Enter a valid zip code in the format XXXXX.'),
}
def __init__(self, *args, **kwargs):
- zip_code_re = ur'^(0[1-9]|[1][0-6]|[2-9]\d)(\d{3})$'
+ zip_code_re = r'^(0[1-9]|[1][0-6]|[2-9]\d)(\d{3})$'
super(MXZipCodeField, self).__init__(zip_code_re, *args, **kwargs)
@@ -110,7 +112,7 @@ class MXRFCField(RegexField):
}
def __init__(self, min_length=9, max_length=13, *args, **kwargs):
- rfc_re = re.compile(ur'^([A-Z&Ññ]{3}|[A-Z][AEIOU][A-Z]{2})%s([A-Z0-9]{2}[0-9A])?$' % DATE_RE,
+ rfc_re = re.compile(r'^([A-Z&Ññ]{3}|[A-Z][AEIOU][A-Z]{2})%s([A-Z0-9]{2}[0-9A])?$' % DATE_RE,
re.IGNORECASE)
super(MXRFCField, self).__init__(rfc_re, min_length=min_length,
max_length=max_length, *args, **kwargs)
@@ -118,7 +120,7 @@ class MXRFCField(RegexField):
def clean(self, value):
value = super(MXRFCField, self).clean(value)
if value in EMPTY_VALUES:
- return u''
+ return ''
value = value.upper()
if self._has_homoclave(value):
if not value[-1] == self._checksum(value[:-1]):
@@ -133,7 +135,7 @@ class MXRFCField(RegexField):
since the current algorithm to calculate it had not been created for
the first RFCs ever in Mexico.
"""
- rfc_without_homoclave_re = re.compile(ur'^[A-Z&Ññ]{3,4}%s$' % DATE_RE,
+ rfc_without_homoclave_re = re.compile(r'^[A-Z&Ññ]{3,4}%s$' % DATE_RE,
re.IGNORECASE)
return not rfc_without_homoclave_re.match(rfc)
@@ -142,19 +144,19 @@ class MXRFCField(RegexField):
More info about this procedure:
www.sisi.org.mx/jspsi/documentos/2005/seguimiento/06101/0610100162005_065.doc
"""
- chars = u'0123456789ABCDEFGHIJKLMN&OPQRSTUVWXYZ-Ñ'
+ chars = '0123456789ABCDEFGHIJKLMN&OPQRSTUVWXYZ-Ñ'
if len(rfc) == 11:
rfc = '-' + rfc
- sum_ = sum(i * chars.index(c) for i, c in zip(reversed(xrange(14)), rfc))
+ sum_ = sum(i * chars.index(c) for i, c in zip(reversed(range(14)), rfc))
checksum = 11 - sum_ % 11
if checksum == 10:
- return u'A'
+ return 'A'
elif checksum == 11:
- return u'0'
+ return '0'
- return unicode(checksum)
+ return six.text_type(checksum)
def _has_inconvenient_word(self, rfc):
first_four = rfc[:4]
@@ -187,13 +189,13 @@ class MXCURPField(RegexField):
"""
default_error_messages = {
'invalid': _('Enter a valid CURP.'),
- 'invalid_checksum': _(u'Invalid checksum for CURP.'),
+ 'invalid_checksum': _('Invalid checksum for CURP.'),
}
def __init__(self, min_length=18, max_length=18, *args, **kwargs):
states_re = r'(AS|BC|BS|CC|CL|CM|CS|CH|DF|DG|GT|GR|HG|JC|MC|MN|MS|NT|NL|OC|PL|QT|QR|SP|SL|SR|TC|TS|TL|VZ|YN|ZS|NE)'
consonants_re = r'[B-DF-HJ-NP-TV-Z]'
- curp_re = (ur'^[A-Z][AEIOU][A-Z]{2}%s[HM]%s%s{3}[0-9A-Z]\d$' %
+ curp_re = (r'^[A-Z][AEIOU][A-Z]{2}%s[HM]%s%s{3}[0-9A-Z]\d$' %
(DATE_RE, states_re, consonants_re))
curp_re = re.compile(curp_re, re.IGNORECASE)
super(MXCURPField, self).__init__(curp_re, min_length=min_length,
@@ -202,7 +204,7 @@ class MXCURPField(RegexField):
def clean(self, value):
value = super(MXCURPField, self).clean(value)
if value in EMPTY_VALUES:
- return u''
+ return ''
value = value.upper()
if value[-1] != self._checksum(value[:-1]):
raise ValidationError(self.default_error_messages['invalid_checksum'])
@@ -211,14 +213,14 @@ class MXCURPField(RegexField):
return value
def _checksum(self, value):
- chars = u'0123456789ABCDEFGHIJKLMN&OPQRSTUVWXYZ'
+ chars = '0123456789ABCDEFGHIJKLMN&OPQRSTUVWXYZ'
- s = sum(i * chars.index(c) for i, c in zip(reversed(xrange(19)), value))
+ s = sum(i * chars.index(c) for i, c in zip(reversed(range(19)), value))
checksum = 10 - s % 10
if checksum == 10:
- return u'0'
- return unicode(checksum)
+ return '0'
+ return six.text_type(checksum)
def _has_inconvenient_word(self, curp):
first_four = curp[:4]
diff --git a/django/contrib/localflavor/mx/mx_states.py b/django/contrib/localflavor/mx/mx_states.py
index 2aba63ef26..6ae08ccb12 100644
--- a/django/contrib/localflavor/mx/mx_states.py
+++ b/django/contrib/localflavor/mx/mx_states.py
@@ -5,41 +5,42 @@ A list of Mexican states for use as `choices` in a formfield.
This exists in this standalone file so that it's only imported into memory
when explicitly needed.
"""
+from __future__ import unicode_literals
from django.utils.translation import ugettext_lazy as _
# All 31 states, plus the `Distrito Federal`.
STATE_CHOICES = (
- ('AGU', _(u'Aguascalientes')),
- ('BCN', _(u'Baja California')),
- ('BCS', _(u'Baja California Sur')),
- ('CAM', _(u'Campeche')),
- ('CHH', _(u'Chihuahua')),
- ('CHP', _(u'Chiapas')),
- ('COA', _(u'Coahuila')),
- ('COL', _(u'Colima')),
- ('DIF', _(u'Distrito Federal')),
- ('DUR', _(u'Durango')),
- ('GRO', _(u'Guerrero')),
- ('GUA', _(u'Guanajuato')),
- ('HID', _(u'Hidalgo')),
- ('JAL', _(u'Jalisco')),
- ('MEX', _(u'Estado de México')),
- ('MIC', _(u'Michoacán')),
- ('MOR', _(u'Morelos')),
- ('NAY', _(u'Nayarit')),
- ('NLE', _(u'Nuevo León')),
- ('OAX', _(u'Oaxaca')),
- ('PUE', _(u'Puebla')),
- ('QUE', _(u'Querétaro')),
- ('ROO', _(u'Quintana Roo')),
- ('SIN', _(u'Sinaloa')),
- ('SLP', _(u'San Luis Potosí')),
- ('SON', _(u'Sonora')),
- ('TAB', _(u'Tabasco')),
- ('TAM', _(u'Tamaulipas')),
- ('TLA', _(u'Tlaxcala')),
- ('VER', _(u'Veracruz')),
- ('YUC', _(u'Yucatán')),
- ('ZAC', _(u'Zacatecas')),
+ ('AGU', _('Aguascalientes')),
+ ('BCN', _('Baja California')),
+ ('BCS', _('Baja California Sur')),
+ ('CAM', _('Campeche')),
+ ('CHH', _('Chihuahua')),
+ ('CHP', _('Chiapas')),
+ ('COA', _('Coahuila')),
+ ('COL', _('Colima')),
+ ('DIF', _('Distrito Federal')),
+ ('DUR', _('Durango')),
+ ('GRO', _('Guerrero')),
+ ('GUA', _('Guanajuato')),
+ ('HID', _('Hidalgo')),
+ ('JAL', _('Jalisco')),
+ ('MEX', _('Estado de México')),
+ ('MIC', _('Michoacán')),
+ ('MOR', _('Morelos')),
+ ('NAY', _('Nayarit')),
+ ('NLE', _('Nuevo León')),
+ ('OAX', _('Oaxaca')),
+ ('PUE', _('Puebla')),
+ ('QUE', _('Querétaro')),
+ ('ROO', _('Quintana Roo')),
+ ('SIN', _('Sinaloa')),
+ ('SLP', _('San Luis Potosí')),
+ ('SON', _('Sonora')),
+ ('TAB', _('Tabasco')),
+ ('TAM', _('Tamaulipas')),
+ ('TLA', _('Tlaxcala')),
+ ('VER', _('Veracruz')),
+ ('YUC', _('Yucatán')),
+ ('ZAC', _('Zacatecas')),
)
diff --git a/django/contrib/localflavor/nl/forms.py b/django/contrib/localflavor/nl/forms.py
index 66900808c2..a05dd38f7f 100644
--- a/django/contrib/localflavor/nl/forms.py
+++ b/django/contrib/localflavor/nl/forms.py
@@ -2,7 +2,7 @@
NL-specific Form helpers
"""
-from __future__ import absolute_import
+from __future__ import absolute_import, unicode_literals
import re
@@ -10,7 +10,7 @@ from django.contrib.localflavor.nl.nl_provinces import PROVINCE_CHOICES
from django.core.validators import EMPTY_VALUES
from django.forms import ValidationError
from django.forms.fields import Field, Select
-from django.utils.encoding import smart_unicode
+from django.utils.encoding import smart_text
from django.utils.translation import ugettext_lazy as _
@@ -29,7 +29,7 @@ class NLZipCodeField(Field):
def clean(self, value):
super(NLZipCodeField, self).clean(value)
if value in EMPTY_VALUES:
- return u''
+ return ''
value = value.strip().upper().replace(' ', '')
if not pc_re.search(value):
@@ -38,7 +38,7 @@ class NLZipCodeField(Field):
if int(value[:4]) < 1000:
raise ValidationError(self.error_messages['invalid'])
- return u'%s %s' % (value[:4], value[4:])
+ return '%s %s' % (value[:4], value[4:])
class NLProvinceSelect(Select):
"""
@@ -59,9 +59,9 @@ class NLPhoneNumberField(Field):
def clean(self, value):
super(NLPhoneNumberField, self).clean(value)
if value in EMPTY_VALUES:
- return u''
+ return ''
- phone_nr = re.sub('[\-\s\(\)]', '', smart_unicode(value))
+ phone_nr = re.sub('[\-\s\(\)]', '', smart_text(value))
if len(phone_nr) == 10 and numeric_re.search(phone_nr):
return value
@@ -85,7 +85,7 @@ class NLSoFiNumberField(Field):
def clean(self, value):
super(NLSoFiNumberField, self).clean(value)
if value in EMPTY_VALUES:
- return u''
+ return ''
if not sofi_re.search(value):
raise ValidationError(self.error_messages['invalid'])
diff --git a/django/contrib/localflavor/no/forms.py b/django/contrib/localflavor/no/forms.py
index 3e5e58bd1c..4bd780a312 100644
--- a/django/contrib/localflavor/no/forms.py
+++ b/django/contrib/localflavor/no/forms.py
@@ -2,7 +2,7 @@
Norwegian-specific Form helpers
"""
-from __future__ import absolute_import
+from __future__ import absolute_import, unicode_literals
import re
import datetime
@@ -36,13 +36,13 @@ class NOSocialSecurityNumber(Field):
Algorithm is documented at http://no.wikipedia.org/wiki/Personnummer
"""
default_error_messages = {
- 'invalid': _(u'Enter a valid Norwegian social security number.'),
+ 'invalid': _('Enter a valid Norwegian social security number.'),
}
def clean(self, value):
super(NOSocialSecurityNumber, self).clean(value)
if value in EMPTY_VALUES:
- return u''
+ return ''
if not re.match(r'^\d{11}$', value):
raise ValidationError(self.error_messages['invalid'])
diff --git a/django/contrib/localflavor/no/no_municipalities.py b/django/contrib/localflavor/no/no_municipalities.py
index d6bacda275..d84915caa2 100644
--- a/django/contrib/localflavor/no/no_municipalities.py
+++ b/django/contrib/localflavor/no/no_municipalities.py
@@ -6,27 +6,28 @@ in a formfield.
This exists in this standalone file so that it's on ly imported into memory
when explicitly needed.
"""
+from __future__ import unicode_literals
MUNICIPALITY_CHOICES = (
- ('akershus', u'Akershus'),
- ('austagder', u'Aust-Agder'),
- ('buskerud', u'Buskerud'),
- ('finnmark', u'Finnmark'),
- ('hedmark', u'Hedmark'),
- ('hordaland', u'Hordaland'),
- ('janmayen', u'Jan Mayen'),
- ('moreogromsdal', u'Møre og Romsdal'),
- ('nordtrondelag', u'Nord-Trøndelag'),
- ('nordland', u'Nordland'),
- ('oppland', u'Oppland'),
- ('oslo', u'Oslo'),
- ('rogaland', u'Rogaland'),
- ('sognogfjordane', u'Sogn og Fjordane'),
- ('svalbard', u'Svalbard'),
- ('sortrondelag', u'Sør-Trøndelag'),
- ('telemark', u'Telemark'),
- ('troms', u'Troms'),
- ('vestagder', u'Vest-Agder'),
- ('vestfold', u'Vestfold'),
- ('ostfold', u'Østfold')
+ ('akershus', 'Akershus'),
+ ('austagder', 'Aust-Agder'),
+ ('buskerud', 'Buskerud'),
+ ('finnmark', 'Finnmark'),
+ ('hedmark', 'Hedmark'),
+ ('hordaland', 'Hordaland'),
+ ('janmayen', 'Jan Mayen'),
+ ('moreogromsdal', 'Møre og Romsdal'),
+ ('nordtrondelag', 'Nord-Trøndelag'),
+ ('nordland', 'Nordland'),
+ ('oppland', 'Oppland'),
+ ('oslo', 'Oslo'),
+ ('rogaland', 'Rogaland'),
+ ('sognogfjordane', 'Sogn og Fjordane'),
+ ('svalbard', 'Svalbard'),
+ ('sortrondelag', 'Sør-Trøndelag'),
+ ('telemark', 'Telemark'),
+ ('troms', 'Troms'),
+ ('vestagder', 'Vest-Agder'),
+ ('vestfold', 'Vestfold'),
+ ('ostfold', 'Østfold')
)
diff --git a/django/contrib/localflavor/pe/forms.py b/django/contrib/localflavor/pe/forms.py
index 0eca2b8ac7..5100bbf575 100644
--- a/django/contrib/localflavor/pe/forms.py
+++ b/django/contrib/localflavor/pe/forms.py
@@ -3,7 +3,7 @@
PE-specific Form helpers.
"""
-from __future__ import absolute_import
+from __future__ import absolute_import, unicode_literals
from django.contrib.localflavor.pe.pe_region import REGION_CHOICES
from django.core.validators import EMPTY_VALUES
@@ -38,7 +38,7 @@ class PEDNIField(CharField):
"""
value = super(PEDNIField, self).clean(value)
if value in EMPTY_VALUES:
- return u''
+ return ''
if not value.isdigit():
raise ValidationError(self.error_messages['invalid'])
if len(value) != 8:
@@ -66,7 +66,7 @@ class PERUCField(RegexField):
"""
value = super(PERUCField, self).clean(value)
if value in EMPTY_VALUES:
- return u''
+ return ''
if not value.isdigit():
raise ValidationError(self.error_messages['invalid'])
if len(value) != 11:
diff --git a/django/contrib/localflavor/pe/pe_region.py b/django/contrib/localflavor/pe/pe_region.py
index 9863bd3d15..9270bcecf1 100644
--- a/django/contrib/localflavor/pe/pe_region.py
+++ b/django/contrib/localflavor/pe/pe_region.py
@@ -5,31 +5,32 @@ A list of Peru regions as `choices` in a formfield.
This exists in this standalone file so that it's only imported into memory
when explicitly needed.
"""
+from __future__ import unicode_literals
REGION_CHOICES = (
- ('AMA', u'Amazonas'),
- ('ANC', u'Ancash'),
- ('APU', u'Apurímac'),
- ('ARE', u'Arequipa'),
- ('AYA', u'Ayacucho'),
- ('CAJ', u'Cajamarca'),
- ('CAL', u'Callao'),
- ('CUS', u'Cusco'),
- ('HUV', u'Huancavelica'),
- ('HUC', u'Huánuco'),
- ('ICA', u'Ica'),
- ('JUN', u'Junín'),
- ('LAL', u'La Libertad'),
- ('LAM', u'Lambayeque'),
- ('LIM', u'Lima'),
- ('LOR', u'Loreto'),
- ('MDD', u'Madre de Dios'),
- ('MOQ', u'Moquegua'),
- ('PAS', u'Pasco'),
- ('PIU', u'Piura'),
- ('PUN', u'Puno'),
- ('SAM', u'San Martín'),
- ('TAC', u'Tacna'),
- ('TUM', u'Tumbes'),
- ('UCA', u'Ucayali'),
+ ('AMA', 'Amazonas'),
+ ('ANC', 'Ancash'),
+ ('APU', 'Apurímac'),
+ ('ARE', 'Arequipa'),
+ ('AYA', 'Ayacucho'),
+ ('CAJ', 'Cajamarca'),
+ ('CAL', 'Callao'),
+ ('CUS', 'Cusco'),
+ ('HUV', 'Huancavelica'),
+ ('HUC', 'Huánuco'),
+ ('ICA', 'Ica'),
+ ('JUN', 'Junín'),
+ ('LAL', 'La Libertad'),
+ ('LAM', 'Lambayeque'),
+ ('LIM', 'Lima'),
+ ('LOR', 'Loreto'),
+ ('MDD', 'Madre de Dios'),
+ ('MOQ', 'Moquegua'),
+ ('PAS', 'Pasco'),
+ ('PIU', 'Piura'),
+ ('PUN', 'Puno'),
+ ('SAM', 'San Martín'),
+ ('TAC', 'Tacna'),
+ ('TUM', 'Tumbes'),
+ ('UCA', 'Ucayali'),
)
diff --git a/django/contrib/localflavor/pl/forms.py b/django/contrib/localflavor/pl/forms.py
index 3e8d73f0f2..12d9f3d763 100644
--- a/django/contrib/localflavor/pl/forms.py
+++ b/django/contrib/localflavor/pl/forms.py
@@ -2,7 +2,7 @@
Polish-specific form helpers
"""
-from __future__ import absolute_import
+from __future__ import absolute_import, unicode_literals
import re
@@ -39,8 +39,8 @@ class PLPESELField(RegexField):
The algorithm is documented at http://en.wikipedia.org/wiki/PESEL.
"""
default_error_messages = {
- 'invalid': _(u'National Identification Number consists of 11 digits.'),
- 'checksum': _(u'Wrong checksum for the National Identification Number.'),
+ 'invalid': _('National Identification Number consists of 11 digits.'),
+ 'checksum': _('Wrong checksum for the National Identification Number.'),
}
def __init__(self, max_length=None, min_length=None, *args, **kwargs):
@@ -50,10 +50,10 @@ class PLPESELField(RegexField):
def clean(self, value):
super(PLPESELField, self).clean(value)
if value in EMPTY_VALUES:
- return u''
+ return ''
if not self.has_valid_checksum(value):
raise ValidationError(self.error_messages['checksum'])
- return u'%s' % value
+ return '%s' % value
def has_valid_checksum(self, number):
"""
@@ -76,8 +76,8 @@ class PLNationalIDCardNumberField(RegexField):
The algorithm is documented at http://en.wikipedia.org/wiki/Polish_identity_card.
"""
default_error_messages = {
- 'invalid': _(u'National ID Card Number consists of 3 letters and 6 digits.'),
- 'checksum': _(u'Wrong checksum for the National ID Card Number.'),
+ 'invalid': _('National ID Card Number consists of 3 letters and 6 digits.'),
+ 'checksum': _('Wrong checksum for the National ID Card Number.'),
}
def __init__(self, max_length=None, min_length=None, *args, **kwargs):
@@ -87,13 +87,13 @@ class PLNationalIDCardNumberField(RegexField):
def clean(self,value):
super(PLNationalIDCardNumberField, self).clean(value)
if value in EMPTY_VALUES:
- return u''
+ return ''
value = value.upper()
if not self.has_valid_checksum(value):
raise ValidationError(self.error_messages['checksum'])
- return u'%s' % value
+ return '%s' % value
def has_valid_checksum(self, number):
"""
@@ -128,8 +128,8 @@ class PLNIPField(RegexField):
http://wipos.p.lodz.pl/zylla/ut/nip-rego.html
"""
default_error_messages = {
- 'invalid': _(u'Enter a tax number field (NIP) in the format XXX-XXX-XX-XX, XXX-XX-XX-XXX or XXXXXXXXXX.'),
- 'checksum': _(u'Wrong checksum for the Tax Number (NIP).'),
+ 'invalid': _('Enter a tax number field (NIP) in the format XXX-XXX-XX-XX, XXX-XX-XX-XXX or XXXXXXXXXX.'),
+ 'checksum': _('Wrong checksum for the Tax Number (NIP).'),
}
def __init__(self, max_length=None, min_length=None, *args, **kwargs):
@@ -139,11 +139,11 @@ class PLNIPField(RegexField):
def clean(self,value):
super(PLNIPField, self).clean(value)
if value in EMPTY_VALUES:
- return u''
+ return ''
value = re.sub("[-]", "", value)
if not self.has_valid_checksum(value):
raise ValidationError(self.error_messages['checksum'])
- return u'%s' % value
+ return '%s' % value
def has_valid_checksum(self, number):
"""
@@ -168,8 +168,8 @@ class PLREGONField(RegexField):
See http://www.stat.gov.pl/bip/regon_ENG_HTML.htm for more information.
"""
default_error_messages = {
- 'invalid': _(u'National Business Register Number (REGON) consists of 9 or 14 digits.'),
- 'checksum': _(u'Wrong checksum for the National Business Register Number (REGON).'),
+ 'invalid': _('National Business Register Number (REGON) consists of 9 or 14 digits.'),
+ 'checksum': _('Wrong checksum for the National Business Register Number (REGON).'),
}
def __init__(self, max_length=None, min_length=None, *args, **kwargs):
@@ -179,10 +179,10 @@ class PLREGONField(RegexField):
def clean(self,value):
super(PLREGONField, self).clean(value)
if value in EMPTY_VALUES:
- return u''
+ return ''
if not self.has_valid_checksum(value):
raise ValidationError(self.error_messages['checksum'])
- return u'%s' % value
+ return '%s' % value
def has_valid_checksum(self, number):
"""
@@ -209,7 +209,7 @@ class PLPostalCodeField(RegexField):
Valid code is XX-XXX where X is digit.
"""
default_error_messages = {
- 'invalid': _(u'Enter a postal code in the format XX-XXX.'),
+ 'invalid': _('Enter a postal code in the format XX-XXX.'),
}
def __init__(self, max_length=None, min_length=None, *args, **kwargs):
diff --git a/django/contrib/localflavor/pl/pl_administrativeunits.py b/django/contrib/localflavor/pl/pl_administrativeunits.py
index 9777ea2b61..f5263f19d2 100644
--- a/django/contrib/localflavor/pl/pl_administrativeunits.py
+++ b/django/contrib/localflavor/pl/pl_administrativeunits.py
@@ -2,384 +2,385 @@
"""
Polish administrative units as in http://pl.wikipedia.org/wiki/Podzia%C5%82_administracyjny_Polski
"""
+from __future__ import unicode_literals
ADMINISTRATIVE_UNIT_CHOICES = (
- ('wroclaw', u'Wrocław'),
- ('jeleniagora', u'Jelenia Góra'),
- ('legnica', u'Legnica'),
- ('boleslawiecki', u'bolesławiecki'),
- ('dzierzoniowski', u'dzierżoniowski'),
- ('glogowski', u'głogowski'),
- ('gorowski', u'górowski'),
- ('jaworski', u'jaworski'),
- ('jeleniogorski', u'jeleniogórski'),
- ('kamiennogorski', u'kamiennogórski'),
- ('klodzki', u'kłodzki'),
- ('legnicki', u'legnicki'),
- ('lubanski', u'lubański'),
- ('lubinski', u'lubiński'),
- ('lwowecki', u'lwówecki'),
- ('milicki', u'milicki'),
- ('olesnicki', u'oleśnicki'),
- ('olawski', u'oławski'),
- ('polkowicki', u'polkowicki'),
- ('strzelinski', u'strzeliński'),
- ('sredzki', u'średzki'),
- ('swidnicki', u'świdnicki'),
- ('trzebnicki', u'trzebnicki'),
- ('walbrzyski', u'wałbrzyski'),
- ('wolowski', u'wołowski'),
- ('wroclawski', u'wrocławski'),
- ('zabkowicki', u'ząbkowicki'),
- ('zgorzelecki', u'zgorzelecki'),
- ('zlotoryjski', u'złotoryjski'),
- ('bydgoszcz', u'Bydgoszcz'),
- ('torun', u'Toruń'),
- ('wloclawek', u'Włocławek'),
- ('grudziadz', u'Grudziądz'),
- ('aleksandrowski', u'aleksandrowski'),
- ('brodnicki', u'brodnicki'),
- ('bydgoski', u'bydgoski'),
- ('chelminski', u'chełmiński'),
- ('golubsko-dobrzynski', u'golubsko-dobrzyński'),
- ('grudziadzki', u'grudziądzki'),
- ('inowroclawski', u'inowrocławski'),
- ('lipnowski', u'lipnowski'),
- ('mogilenski', u'mogileński'),
- ('nakielski', u'nakielski'),
- ('radziejowski', u'radziejowski'),
- ('rypinski', u'rypiński'),
- ('sepolenski', u'sępoleński'),
- ('swiecki', u'świecki'),
- ('torunski', u'toruński'),
- ('tucholski', u'tucholski'),
- ('wabrzeski', u'wąbrzeski'),
- ('wloclawski', u'wrocławski'),
- ('zninski', u'źniński'),
- ('lublin', u'Lublin'),
- ('biala-podlaska', u'Biała Podlaska'),
- ('chelm', u'Chełm'),
- ('zamosc', u'Zamość'),
- ('bialski', u'bialski'),
- ('bilgorajski', u'biłgorajski'),
- ('chelmski', u'chełmski'),
- ('hrubieszowski', u'hrubieszowski'),
- ('janowski', u'janowski'),
- ('krasnostawski', u'krasnostawski'),
- ('krasnicki', u'kraśnicki'),
- ('lubartowski', u'lubartowski'),
- ('lubelski', u'lubelski'),
- ('leczynski', u'łęczyński'),
- ('lukowski', u'łukowski'),
- ('opolski', u'opolski'),
- ('parczewski', u'parczewski'),
- ('pulawski', u'puławski'),
- ('radzynski', u'radzyński'),
- ('rycki', u'rycki'),
- ('swidnicki', u'świdnicki'),
- ('tomaszowski', u'tomaszowski'),
- ('wlodawski', u'włodawski'),
- ('zamojski', u'zamojski'),
- ('gorzow-wielkopolski', u'Gorzów Wielkopolski'),
- ('zielona-gora', u'Zielona Góra'),
- ('gorzowski', u'gorzowski'),
- ('krosnienski', u'krośnieński'),
- ('miedzyrzecki', u'międzyrzecki'),
- ('nowosolski', u'nowosolski'),
- ('slubicki', u'słubicki'),
- ('strzelecko-drezdenecki', u'strzelecko-drezdenecki'),
- ('sulecinski', u'suleńciński'),
- ('swiebodzinski', u'świebodziński'),
- ('wschowski', u'wschowski'),
- ('zielonogorski', u'zielonogórski'),
- ('zaganski', u'żagański'),
- ('zarski', u'żarski'),
- ('lodz', u'Łódź'),
- ('piotrkow-trybunalski', u'Piotrków Trybunalski'),
- ('skierniewice', u'Skierniewice'),
- ('belchatowski', u'bełchatowski'),
- ('brzezinski', u'brzeziński'),
- ('kutnowski', u'kutnowski'),
- ('laski', u'łaski'),
- ('leczycki', u'łęczycki'),
- ('lowicki', u'łowicki'),
- ('lodzki wschodni', u'łódzki wschodni'),
- ('opoczynski', u'opoczyński'),
- ('pabianicki', u'pabianicki'),
- ('pajeczanski', u'pajęczański'),
- ('piotrkowski', u'piotrkowski'),
- ('poddebicki', u'poddębicki'),
- ('radomszczanski', u'radomszczański'),
- ('rawski', u'rawski'),
- ('sieradzki', u'sieradzki'),
- ('skierniewicki', u'skierniewicki'),
- ('tomaszowski', u'tomaszowski'),
- ('wielunski', u'wieluński'),
- ('wieruszowski', u'wieruszowski'),
- ('zdunskowolski', u'zduńskowolski'),
- ('zgierski', u'zgierski'),
- ('krakow', u'Kraków'),
- ('tarnow', u'Tarnów'),
- ('nowy-sacz', u'Nowy Sącz'),
- ('bochenski', u'bocheński'),
- ('brzeski', u'brzeski'),
- ('chrzanowski', u'chrzanowski'),
- ('dabrowski', u'dąbrowski'),
- ('gorlicki', u'gorlicki'),
- ('krakowski', u'krakowski'),
- ('limanowski', u'limanowski'),
- ('miechowski', u'miechowski'),
- ('myslenicki', u'myślenicki'),
- ('nowosadecki', u'nowosądecki'),
- ('nowotarski', u'nowotarski'),
- ('olkuski', u'olkuski'),
- ('oswiecimski', u'oświęcimski'),
- ('proszowicki', u'proszowicki'),
- ('suski', u'suski'),
- ('tarnowski', u'tarnowski'),
- ('tatrzanski', u'tatrzański'),
- ('wadowicki', u'wadowicki'),
- ('wielicki', u'wielicki'),
- ('warszawa', u'Warszawa'),
- ('ostroleka', u'Ostrołęka'),
- ('plock', u'Płock'),
- ('radom', u'Radom'),
- ('siedlce', u'Siedlce'),
- ('bialobrzeski', u'białobrzeski'),
- ('ciechanowski', u'ciechanowski'),
- ('garwolinski', u'garwoliński'),
- ('gostyninski', u'gostyniński'),
- ('grodziski', u'grodziski'),
- ('grojecki', u'grójecki'),
- ('kozienicki', u'kozenicki'),
- ('legionowski', u'legionowski'),
- ('lipski', u'lipski'),
- ('losicki', u'łosicki'),
- ('makowski', u'makowski'),
- ('minski', u'miński'),
- ('mlawski', u'mławski'),
- ('nowodworski', u'nowodworski'),
- ('ostrolecki', u'ostrołęcki'),
- ('ostrowski', u'ostrowski'),
- ('otwocki', u'otwocki'),
- ('piaseczynski', u'piaseczyński'),
- ('plocki', u'płocki'),
- ('plonski', u'płoński'),
- ('pruszkowski', u'pruszkowski'),
- ('przasnyski', u'przasnyski'),
- ('przysuski', u'przysuski'),
- ('pultuski', u'pułtuski'),
- ('radomski', u'radomski'),
- ('siedlecki', u'siedlecki'),
- ('sierpecki', u'sierpecki'),
- ('sochaczewski', u'sochaczewski'),
- ('sokolowski', u'sokołowski'),
- ('szydlowiecki', u'szydłowiecki'),
- ('warszawski-zachodni', u'warszawski zachodni'),
- ('wegrowski', u'węgrowski'),
- ('wolominski', u'wołomiński'),
- ('wyszkowski', u'wyszkowski'),
- ('zwolenski', u'zwoleński'),
- ('zurominski', u'żuromiński'),
- ('zyrardowski', u'żyrardowski'),
- ('opole', u'Opole'),
- ('brzeski', u'brzeski'),
- ('glubczycki', u'głubczyski'),
- ('kedzierzynsko-kozielski', u'kędzierzyński-kozielski'),
- ('kluczborski', u'kluczborski'),
- ('krapkowicki', u'krapkowicki'),
- ('namyslowski', u'namysłowski'),
- ('nyski', u'nyski'),
- ('oleski', u'oleski'),
- ('opolski', u'opolski'),
- ('prudnicki', u'prudnicki'),
- ('strzelecki', u'strzelecki'),
- ('rzeszow', u'Rzeszów'),
- ('krosno', u'Krosno'),
- ('przemysl', u'Przemyśl'),
- ('tarnobrzeg', u'Tarnobrzeg'),
- ('bieszczadzki', u'bieszczadzki'),
- ('brzozowski', u'brzozowski'),
- ('debicki', u'dębicki'),
- ('jaroslawski', u'jarosławski'),
- ('jasielski', u'jasielski'),
- ('kolbuszowski', u'kolbuszowski'),
- ('krosnienski', u'krośnieński'),
- ('leski', u'leski'),
- ('lezajski', u'leżajski'),
- ('lubaczowski', u'lubaczowski'),
- ('lancucki', u'łańcucki'),
- ('mielecki', u'mielecki'),
- ('nizanski', u'niżański'),
- ('przemyski', u'przemyski'),
- ('przeworski', u'przeworski'),
- ('ropczycko-sedziszowski', u'ropczycko-sędziszowski'),
- ('rzeszowski', u'rzeszowski'),
- ('sanocki', u'sanocki'),
- ('stalowowolski', u'stalowowolski'),
- ('strzyzowski', u'strzyżowski'),
- ('tarnobrzeski', u'tarnobrzeski'),
- ('bialystok', u'Białystok'),
- ('lomza', u'Łomża'),
- ('suwalki', u'Suwałki'),
- ('augustowski', u'augustowski'),
- ('bialostocki', u'białostocki'),
- ('bielski', u'bielski'),
- ('grajewski', u'grajewski'),
- ('hajnowski', u'hajnowski'),
- ('kolnenski', u'kolneński'),
- ('łomzynski', u'łomżyński'),
- ('moniecki', u'moniecki'),
- ('sejnenski', u'sejneński'),
- ('siemiatycki', u'siematycki'),
- ('sokolski', u'sokólski'),
- ('suwalski', u'suwalski'),
- ('wysokomazowiecki', u'wysokomazowiecki'),
- ('zambrowski', u'zambrowski'),
- ('gdansk', u'Gdańsk'),
- ('gdynia', u'Gdynia'),
- ('slupsk', u'Słupsk'),
- ('sopot', u'Sopot'),
- ('bytowski', u'bytowski'),
- ('chojnicki', u'chojnicki'),
- ('czluchowski', u'człuchowski'),
- ('kartuski', u'kartuski'),
- ('koscierski', u'kościerski'),
- ('kwidzynski', u'kwidzyński'),
- ('leborski', u'lęborski'),
- ('malborski', u'malborski'),
- ('nowodworski', u'nowodworski'),
- ('gdanski', u'gdański'),
- ('pucki', u'pucki'),
- ('slupski', u'słupski'),
- ('starogardzki', u'starogardzki'),
- ('sztumski', u'sztumski'),
- ('tczewski', u'tczewski'),
- ('wejherowski', u'wejcherowski'),
- ('katowice', u'Katowice'),
- ('bielsko-biala', u'Bielsko-Biała'),
- ('bytom', u'Bytom'),
- ('chorzow', u'Chorzów'),
- ('czestochowa', u'Częstochowa'),
- ('dabrowa-gornicza', u'Dąbrowa Górnicza'),
- ('gliwice', u'Gliwice'),
- ('jastrzebie-zdroj', u'Jastrzębie Zdrój'),
- ('jaworzno', u'Jaworzno'),
- ('myslowice', u'Mysłowice'),
- ('piekary-slaskie', u'Piekary Śląskie'),
- ('ruda-slaska', u'Ruda Śląska'),
- ('rybnik', u'Rybnik'),
- ('siemianowice-slaskie', u'Siemianowice Śląskie'),
- ('sosnowiec', u'Sosnowiec'),
- ('swietochlowice', u'Świętochłowice'),
- ('tychy', u'Tychy'),
- ('zabrze', u'Zabrze'),
- ('zory', u'Żory'),
- ('bedzinski', u'będziński'),
- ('bielski', u'bielski'),
- ('bierunsko-ledzinski', u'bieruńsko-lędziński'),
- ('cieszynski', u'cieszyński'),
- ('czestochowski', u'częstochowski'),
- ('gliwicki', u'gliwicki'),
- ('klobucki', u'kłobucki'),
- ('lubliniecki', u'lubliniecki'),
- ('mikolowski', u'mikołowski'),
- ('myszkowski', u'myszkowski'),
- ('pszczynski', u'pszczyński'),
- ('raciborski', u'raciborski'),
- ('rybnicki', u'rybnicki'),
- ('tarnogorski', u'tarnogórski'),
- ('wodzislawski', u'wodzisławski'),
- ('zawiercianski', u'zawierciański'),
- ('zywiecki', u'żywiecki'),
- ('kielce', u'Kielce'),
- ('buski', u'buski'),
- ('jedrzejowski', u'jędrzejowski'),
- ('kazimierski', u'kazimierski'),
- ('kielecki', u'kielecki'),
- ('konecki', u'konecki'),
- ('opatowski', u'opatowski'),
- ('ostrowiecki', u'ostrowiecki'),
- ('pinczowski', u'pińczowski'),
- ('sandomierski', u'sandomierski'),
- ('skarzyski', u'skarżyski'),
- ('starachowicki', u'starachowicki'),
- ('staszowski', u'staszowski'),
- ('wloszczowski', u'włoszczowski'),
- ('olsztyn', u'Olsztyn'),
- ('elblag', u'Elbląg'),
- ('bartoszycki', u'bartoszycki'),
- ('braniewski', u'braniewski'),
- ('dzialdowski', u'działdowski'),
- ('elblaski', u'elbląski'),
- ('elcki', u'ełcki'),
- ('gizycki', u'giżycki'),
- ('goldapski', u'gołdapski'),
- ('ilawski', u'iławski'),
- ('ketrzynski', u'kętrzyński'),
- ('lidzbarski', u'lidzbarski'),
- ('mragowski', u'mrągowski'),
- ('nidzicki', u'nidzicki'),
- ('nowomiejski', u'nowomiejski'),
- ('olecki', u'olecki'),
- ('olsztynski', u'olsztyński'),
- ('ostrodzki', u'ostródzki'),
- ('piski', u'piski'),
- ('szczycienski', u'szczycieński'),
- ('wegorzewski', u'węgorzewski'),
- ('poznan', u'Poznań'),
- ('kalisz', u'Kalisz'),
- ('konin', u'Konin'),
- ('leszno', u'Leszno'),
- ('chodzieski', u'chodziejski'),
- ('czarnkowsko-trzcianecki', u'czarnkowsko-trzcianecki'),
- ('gnieznienski', u'gnieźnieński'),
- ('gostynski', u'gostyński'),
- ('grodziski', u'grodziski'),
- ('jarocinski', u'jarociński'),
- ('kaliski', u'kaliski'),
- ('kepinski', u'kępiński'),
- ('kolski', u'kolski'),
- ('koninski', u'koniński'),
- ('koscianski', u'kościański'),
- ('krotoszynski', u'krotoszyński'),
- ('leszczynski', u'leszczyński'),
- ('miedzychodzki', u'międzychodzki'),
- ('nowotomyski', u'nowotomyski'),
- ('obornicki', u'obornicki'),
- ('ostrowski', u'ostrowski'),
- ('ostrzeszowski', u'ostrzeszowski'),
- ('pilski', u'pilski'),
- ('pleszewski', u'pleszewski'),
- ('poznanski', u'poznański'),
- ('rawicki', u'rawicki'),
- ('slupecki', u'słupecki'),
- ('szamotulski', u'szamotulski'),
- ('sredzki', u'średzki'),
- ('sremski', u'śremski'),
- ('turecki', u'turecki'),
- ('wagrowiecki', u'wągrowiecki'),
- ('wolsztynski', u'wolsztyński'),
- ('wrzesinski', u'wrzesiński'),
- ('zlotowski', u'złotowski'),
- ('bialogardzki', u'białogardzki'),
- ('choszczenski', u'choszczeński'),
- ('drawski', u'drawski'),
- ('goleniowski', u'goleniowski'),
- ('gryficki', u'gryficki'),
- ('gryfinski', u'gryfiński'),
- ('kamienski', u'kamieński'),
- ('kolobrzeski', u'kołobrzeski'),
- ('koszalinski', u'koszaliński'),
- ('lobeski', u'łobeski'),
- ('mysliborski', u'myśliborski'),
- ('policki', u'policki'),
- ('pyrzycki', u'pyrzycki'),
- ('slawienski', u'sławieński'),
- ('stargardzki', u'stargardzki'),
- ('szczecinecki', u'szczecinecki'),
- ('swidwinski', u'świdwiński'),
- ('walecki', u'wałecki'),
+ ('wroclaw', 'Wrocław'),
+ ('jeleniagora', 'Jelenia Góra'),
+ ('legnica', 'Legnica'),
+ ('boleslawiecki', 'bolesławiecki'),
+ ('dzierzoniowski', 'dzierżoniowski'),
+ ('glogowski', 'głogowski'),
+ ('gorowski', 'górowski'),
+ ('jaworski', 'jaworski'),
+ ('jeleniogorski', 'jeleniogórski'),
+ ('kamiennogorski', 'kamiennogórski'),
+ ('klodzki', 'kłodzki'),
+ ('legnicki', 'legnicki'),
+ ('lubanski', 'lubański'),
+ ('lubinski', 'lubiński'),
+ ('lwowecki', 'lwówecki'),
+ ('milicki', 'milicki'),
+ ('olesnicki', 'oleśnicki'),
+ ('olawski', 'oławski'),
+ ('polkowicki', 'polkowicki'),
+ ('strzelinski', 'strzeliński'),
+ ('sredzki', 'średzki'),
+ ('swidnicki', 'świdnicki'),
+ ('trzebnicki', 'trzebnicki'),
+ ('walbrzyski', 'wałbrzyski'),
+ ('wolowski', 'wołowski'),
+ ('wroclawski', 'wrocławski'),
+ ('zabkowicki', 'ząbkowicki'),
+ ('zgorzelecki', 'zgorzelecki'),
+ ('zlotoryjski', 'złotoryjski'),
+ ('bydgoszcz', 'Bydgoszcz'),
+ ('torun', 'Toruń'),
+ ('wloclawek', 'Włocławek'),
+ ('grudziadz', 'Grudziądz'),
+ ('aleksandrowski', 'aleksandrowski'),
+ ('brodnicki', 'brodnicki'),
+ ('bydgoski', 'bydgoski'),
+ ('chelminski', 'chełmiński'),
+ ('golubsko-dobrzynski', 'golubsko-dobrzyński'),
+ ('grudziadzki', 'grudziądzki'),
+ ('inowroclawski', 'inowrocławski'),
+ ('lipnowski', 'lipnowski'),
+ ('mogilenski', 'mogileński'),
+ ('nakielski', 'nakielski'),
+ ('radziejowski', 'radziejowski'),
+ ('rypinski', 'rypiński'),
+ ('sepolenski', 'sępoleński'),
+ ('swiecki', 'świecki'),
+ ('torunski', 'toruński'),
+ ('tucholski', 'tucholski'),
+ ('wabrzeski', 'wąbrzeski'),
+ ('wloclawski', 'wrocławski'),
+ ('zninski', 'źniński'),
+ ('lublin', 'Lublin'),
+ ('biala-podlaska', 'Biała Podlaska'),
+ ('chelm', 'Chełm'),
+ ('zamosc', 'Zamość'),
+ ('bialski', 'bialski'),
+ ('bilgorajski', 'biłgorajski'),
+ ('chelmski', 'chełmski'),
+ ('hrubieszowski', 'hrubieszowski'),
+ ('janowski', 'janowski'),
+ ('krasnostawski', 'krasnostawski'),
+ ('krasnicki', 'kraśnicki'),
+ ('lubartowski', 'lubartowski'),
+ ('lubelski', 'lubelski'),
+ ('leczynski', 'łęczyński'),
+ ('lukowski', 'łukowski'),
+ ('opolski', 'opolski'),
+ ('parczewski', 'parczewski'),
+ ('pulawski', 'puławski'),
+ ('radzynski', 'radzyński'),
+ ('rycki', 'rycki'),
+ ('swidnicki', 'świdnicki'),
+ ('tomaszowski', 'tomaszowski'),
+ ('wlodawski', 'włodawski'),
+ ('zamojski', 'zamojski'),
+ ('gorzow-wielkopolski', 'Gorzów Wielkopolski'),
+ ('zielona-gora', 'Zielona Góra'),
+ ('gorzowski', 'gorzowski'),
+ ('krosnienski', 'krośnieński'),
+ ('miedzyrzecki', 'międzyrzecki'),
+ ('nowosolski', 'nowosolski'),
+ ('slubicki', 'słubicki'),
+ ('strzelecko-drezdenecki', 'strzelecko-drezdenecki'),
+ ('sulecinski', 'suleńciński'),
+ ('swiebodzinski', 'świebodziński'),
+ ('wschowski', 'wschowski'),
+ ('zielonogorski', 'zielonogórski'),
+ ('zaganski', 'żagański'),
+ ('zarski', 'żarski'),
+ ('lodz', 'Łódź'),
+ ('piotrkow-trybunalski', 'Piotrków Trybunalski'),
+ ('skierniewice', 'Skierniewice'),
+ ('belchatowski', 'bełchatowski'),
+ ('brzezinski', 'brzeziński'),
+ ('kutnowski', 'kutnowski'),
+ ('laski', 'łaski'),
+ ('leczycki', 'łęczycki'),
+ ('lowicki', 'łowicki'),
+ ('lodzki wschodni', 'łódzki wschodni'),
+ ('opoczynski', 'opoczyński'),
+ ('pabianicki', 'pabianicki'),
+ ('pajeczanski', 'pajęczański'),
+ ('piotrkowski', 'piotrkowski'),
+ ('poddebicki', 'poddębicki'),
+ ('radomszczanski', 'radomszczański'),
+ ('rawski', 'rawski'),
+ ('sieradzki', 'sieradzki'),
+ ('skierniewicki', 'skierniewicki'),
+ ('tomaszowski', 'tomaszowski'),
+ ('wielunski', 'wieluński'),
+ ('wieruszowski', 'wieruszowski'),
+ ('zdunskowolski', 'zduńskowolski'),
+ ('zgierski', 'zgierski'),
+ ('krakow', 'Kraków'),
+ ('tarnow', 'Tarnów'),
+ ('nowy-sacz', 'Nowy Sącz'),
+ ('bochenski', 'bocheński'),
+ ('brzeski', 'brzeski'),
+ ('chrzanowski', 'chrzanowski'),
+ ('dabrowski', 'dąbrowski'),
+ ('gorlicki', 'gorlicki'),
+ ('krakowski', 'krakowski'),
+ ('limanowski', 'limanowski'),
+ ('miechowski', 'miechowski'),
+ ('myslenicki', 'myślenicki'),
+ ('nowosadecki', 'nowosądecki'),
+ ('nowotarski', 'nowotarski'),
+ ('olkuski', 'olkuski'),
+ ('oswiecimski', 'oświęcimski'),
+ ('proszowicki', 'proszowicki'),
+ ('suski', 'suski'),
+ ('tarnowski', 'tarnowski'),
+ ('tatrzanski', 'tatrzański'),
+ ('wadowicki', 'wadowicki'),
+ ('wielicki', 'wielicki'),
+ ('warszawa', 'Warszawa'),
+ ('ostroleka', 'Ostrołęka'),
+ ('plock', 'Płock'),
+ ('radom', 'Radom'),
+ ('siedlce', 'Siedlce'),
+ ('bialobrzeski', 'białobrzeski'),
+ ('ciechanowski', 'ciechanowski'),
+ ('garwolinski', 'garwoliński'),
+ ('gostyninski', 'gostyniński'),
+ ('grodziski', 'grodziski'),
+ ('grojecki', 'grójecki'),
+ ('kozienicki', 'kozenicki'),
+ ('legionowski', 'legionowski'),
+ ('lipski', 'lipski'),
+ ('losicki', 'łosicki'),
+ ('makowski', 'makowski'),
+ ('minski', 'miński'),
+ ('mlawski', 'mławski'),
+ ('nowodworski', 'nowodworski'),
+ ('ostrolecki', 'ostrołęcki'),
+ ('ostrowski', 'ostrowski'),
+ ('otwocki', 'otwocki'),
+ ('piaseczynski', 'piaseczyński'),
+ ('plocki', 'płocki'),
+ ('plonski', 'płoński'),
+ ('pruszkowski', 'pruszkowski'),
+ ('przasnyski', 'przasnyski'),
+ ('przysuski', 'przysuski'),
+ ('pultuski', 'pułtuski'),
+ ('radomski', 'radomski'),
+ ('siedlecki', 'siedlecki'),
+ ('sierpecki', 'sierpecki'),
+ ('sochaczewski', 'sochaczewski'),
+ ('sokolowski', 'sokołowski'),
+ ('szydlowiecki', 'szydłowiecki'),
+ ('warszawski-zachodni', 'warszawski zachodni'),
+ ('wegrowski', 'węgrowski'),
+ ('wolominski', 'wołomiński'),
+ ('wyszkowski', 'wyszkowski'),
+ ('zwolenski', 'zwoleński'),
+ ('zurominski', 'żuromiński'),
+ ('zyrardowski', 'żyrardowski'),
+ ('opole', 'Opole'),
+ ('brzeski', 'brzeski'),
+ ('glubczycki', 'głubczyski'),
+ ('kedzierzynsko-kozielski', 'kędzierzyński-kozielski'),
+ ('kluczborski', 'kluczborski'),
+ ('krapkowicki', 'krapkowicki'),
+ ('namyslowski', 'namysłowski'),
+ ('nyski', 'nyski'),
+ ('oleski', 'oleski'),
+ ('opolski', 'opolski'),
+ ('prudnicki', 'prudnicki'),
+ ('strzelecki', 'strzelecki'),
+ ('rzeszow', 'Rzeszów'),
+ ('krosno', 'Krosno'),
+ ('przemysl', 'Przemyśl'),
+ ('tarnobrzeg', 'Tarnobrzeg'),
+ ('bieszczadzki', 'bieszczadzki'),
+ ('brzozowski', 'brzozowski'),
+ ('debicki', 'dębicki'),
+ ('jaroslawski', 'jarosławski'),
+ ('jasielski', 'jasielski'),
+ ('kolbuszowski', 'kolbuszowski'),
+ ('krosnienski', 'krośnieński'),
+ ('leski', 'leski'),
+ ('lezajski', 'leżajski'),
+ ('lubaczowski', 'lubaczowski'),
+ ('lancucki', 'łańcucki'),
+ ('mielecki', 'mielecki'),
+ ('nizanski', 'niżański'),
+ ('przemyski', 'przemyski'),
+ ('przeworski', 'przeworski'),
+ ('ropczycko-sedziszowski', 'ropczycko-sędziszowski'),
+ ('rzeszowski', 'rzeszowski'),
+ ('sanocki', 'sanocki'),
+ ('stalowowolski', 'stalowowolski'),
+ ('strzyzowski', 'strzyżowski'),
+ ('tarnobrzeski', 'tarnobrzeski'),
+ ('bialystok', 'Białystok'),
+ ('lomza', 'Łomża'),
+ ('suwalki', 'Suwałki'),
+ ('augustowski', 'augustowski'),
+ ('bialostocki', 'białostocki'),
+ ('bielski', 'bielski'),
+ ('grajewski', 'grajewski'),
+ ('hajnowski', 'hajnowski'),
+ ('kolnenski', 'kolneński'),
+ ('łomzynski', 'łomżyński'),
+ ('moniecki', 'moniecki'),
+ ('sejnenski', 'sejneński'),
+ ('siemiatycki', 'siematycki'),
+ ('sokolski', 'sokólski'),
+ ('suwalski', 'suwalski'),
+ ('wysokomazowiecki', 'wysokomazowiecki'),
+ ('zambrowski', 'zambrowski'),
+ ('gdansk', 'Gdańsk'),
+ ('gdynia', 'Gdynia'),
+ ('slupsk', 'Słupsk'),
+ ('sopot', 'Sopot'),
+ ('bytowski', 'bytowski'),
+ ('chojnicki', 'chojnicki'),
+ ('czluchowski', 'człuchowski'),
+ ('kartuski', 'kartuski'),
+ ('koscierski', 'kościerski'),
+ ('kwidzynski', 'kwidzyński'),
+ ('leborski', 'lęborski'),
+ ('malborski', 'malborski'),
+ ('nowodworski', 'nowodworski'),
+ ('gdanski', 'gdański'),
+ ('pucki', 'pucki'),
+ ('slupski', 'słupski'),
+ ('starogardzki', 'starogardzki'),
+ ('sztumski', 'sztumski'),
+ ('tczewski', 'tczewski'),
+ ('wejherowski', 'wejcherowski'),
+ ('katowice', 'Katowice'),
+ ('bielsko-biala', 'Bielsko-Biała'),
+ ('bytom', 'Bytom'),
+ ('chorzow', 'Chorzów'),
+ ('czestochowa', 'Częstochowa'),
+ ('dabrowa-gornicza', 'Dąbrowa Górnicza'),
+ ('gliwice', 'Gliwice'),
+ ('jastrzebie-zdroj', 'Jastrzębie Zdrój'),
+ ('jaworzno', 'Jaworzno'),
+ ('myslowice', 'Mysłowice'),
+ ('piekary-slaskie', 'Piekary Śląskie'),
+ ('ruda-slaska', 'Ruda Śląska'),
+ ('rybnik', 'Rybnik'),
+ ('siemianowice-slaskie', 'Siemianowice Śląskie'),
+ ('sosnowiec', 'Sosnowiec'),
+ ('swietochlowice', 'Świętochłowice'),
+ ('tychy', 'Tychy'),
+ ('zabrze', 'Zabrze'),
+ ('zory', 'Żory'),
+ ('bedzinski', 'będziński'),
+ ('bielski', 'bielski'),
+ ('bierunsko-ledzinski', 'bieruńsko-lędziński'),
+ ('cieszynski', 'cieszyński'),
+ ('czestochowski', 'częstochowski'),
+ ('gliwicki', 'gliwicki'),
+ ('klobucki', 'kłobucki'),
+ ('lubliniecki', 'lubliniecki'),
+ ('mikolowski', 'mikołowski'),
+ ('myszkowski', 'myszkowski'),
+ ('pszczynski', 'pszczyński'),
+ ('raciborski', 'raciborski'),
+ ('rybnicki', 'rybnicki'),
+ ('tarnogorski', 'tarnogórski'),
+ ('wodzislawski', 'wodzisławski'),
+ ('zawiercianski', 'zawierciański'),
+ ('zywiecki', 'żywiecki'),
+ ('kielce', 'Kielce'),
+ ('buski', 'buski'),
+ ('jedrzejowski', 'jędrzejowski'),
+ ('kazimierski', 'kazimierski'),
+ ('kielecki', 'kielecki'),
+ ('konecki', 'konecki'),
+ ('opatowski', 'opatowski'),
+ ('ostrowiecki', 'ostrowiecki'),
+ ('pinczowski', 'pińczowski'),
+ ('sandomierski', 'sandomierski'),
+ ('skarzyski', 'skarżyski'),
+ ('starachowicki', 'starachowicki'),
+ ('staszowski', 'staszowski'),
+ ('wloszczowski', 'włoszczowski'),
+ ('olsztyn', 'Olsztyn'),
+ ('elblag', 'Elbląg'),
+ ('bartoszycki', 'bartoszycki'),
+ ('braniewski', 'braniewski'),
+ ('dzialdowski', 'działdowski'),
+ ('elblaski', 'elbląski'),
+ ('elcki', 'ełcki'),
+ ('gizycki', 'giżycki'),
+ ('goldapski', 'gołdapski'),
+ ('ilawski', 'iławski'),
+ ('ketrzynski', 'kętrzyński'),
+ ('lidzbarski', 'lidzbarski'),
+ ('mragowski', 'mrągowski'),
+ ('nidzicki', 'nidzicki'),
+ ('nowomiejski', 'nowomiejski'),
+ ('olecki', 'olecki'),
+ ('olsztynski', 'olsztyński'),
+ ('ostrodzki', 'ostródzki'),
+ ('piski', 'piski'),
+ ('szczycienski', 'szczycieński'),
+ ('wegorzewski', 'węgorzewski'),
+ ('poznan', 'Poznań'),
+ ('kalisz', 'Kalisz'),
+ ('konin', 'Konin'),
+ ('leszno', 'Leszno'),
+ ('chodzieski', 'chodziejski'),
+ ('czarnkowsko-trzcianecki', 'czarnkowsko-trzcianecki'),
+ ('gnieznienski', 'gnieźnieński'),
+ ('gostynski', 'gostyński'),
+ ('grodziski', 'grodziski'),
+ ('jarocinski', 'jarociński'),
+ ('kaliski', 'kaliski'),
+ ('kepinski', 'kępiński'),
+ ('kolski', 'kolski'),
+ ('koninski', 'koniński'),
+ ('koscianski', 'kościański'),
+ ('krotoszynski', 'krotoszyński'),
+ ('leszczynski', 'leszczyński'),
+ ('miedzychodzki', 'międzychodzki'),
+ ('nowotomyski', 'nowotomyski'),
+ ('obornicki', 'obornicki'),
+ ('ostrowski', 'ostrowski'),
+ ('ostrzeszowski', 'ostrzeszowski'),
+ ('pilski', 'pilski'),
+ ('pleszewski', 'pleszewski'),
+ ('poznanski', 'poznański'),
+ ('rawicki', 'rawicki'),
+ ('slupecki', 'słupecki'),
+ ('szamotulski', 'szamotulski'),
+ ('sredzki', 'średzki'),
+ ('sremski', 'śremski'),
+ ('turecki', 'turecki'),
+ ('wagrowiecki', 'wągrowiecki'),
+ ('wolsztynski', 'wolsztyński'),
+ ('wrzesinski', 'wrzesiński'),
+ ('zlotowski', 'złotowski'),
+ ('bialogardzki', 'białogardzki'),
+ ('choszczenski', 'choszczeński'),
+ ('drawski', 'drawski'),
+ ('goleniowski', 'goleniowski'),
+ ('gryficki', 'gryficki'),
+ ('gryfinski', 'gryfiński'),
+ ('kamienski', 'kamieński'),
+ ('kolobrzeski', 'kołobrzeski'),
+ ('koszalinski', 'koszaliński'),
+ ('lobeski', 'łobeski'),
+ ('mysliborski', 'myśliborski'),
+ ('policki', 'policki'),
+ ('pyrzycki', 'pyrzycki'),
+ ('slawienski', 'sławieński'),
+ ('stargardzki', 'stargardzki'),
+ ('szczecinecki', 'szczecinecki'),
+ ('swidwinski', 'świdwiński'),
+ ('walecki', 'wałecki'),
)
diff --git a/django/contrib/localflavor/pt/forms.py b/django/contrib/localflavor/pt/forms.py
index 3de7376eac..01cdd101b2 100644
--- a/django/contrib/localflavor/pt/forms.py
+++ b/django/contrib/localflavor/pt/forms.py
@@ -1,12 +1,14 @@
"""
PT-specific Form helpers
"""
+from __future__ import unicode_literals
+
import re
from django.core.validators import EMPTY_VALUES
from django.forms import ValidationError
from django.forms.fields import Field, RegexField
-from django.utils.encoding import smart_unicode
+from django.utils.encoding import smart_text
from django.utils.translation import ugettext_lazy as _
phone_digits_re = re.compile(r'^(\d{9}|(00|\+)\d*)$')
@@ -24,10 +26,10 @@ class PTZipCodeField(RegexField):
def clean(self,value):
cleaned = super(PTZipCodeField, self).clean(value)
if len(cleaned) == 7:
- return u'%s-%s' % (cleaned[:4],cleaned[4:])
+ return '%s-%s' % (cleaned[:4],cleaned[4:])
else:
return cleaned
-
+
class PTPhoneNumberField(Field):
"""
Validate local Portuguese phone number (including international ones)
@@ -40,9 +42,9 @@ class PTPhoneNumberField(Field):
def clean(self, value):
super(PTPhoneNumberField, self).clean(value)
if value in EMPTY_VALUES:
- return u''
- value = re.sub('(\.|\s)', '', smart_unicode(value))
+ return ''
+ value = re.sub('(\.|\s)', '', smart_text(value))
m = phone_digits_re.search(value)
if m:
- return u'%s' % value
+ return '%s' % value
raise ValidationError(self.error_messages['invalid'])
diff --git a/django/contrib/localflavor/py/py_department.py b/django/contrib/localflavor/py/py_department.py
index 28c613b9a0..619bae3edb 100644
--- a/django/contrib/localflavor/py/py_department.py
+++ b/django/contrib/localflavor/py/py_department.py
@@ -1,45 +1,46 @@
# -*- coding: utf-8 -*-
# http://www.statoids.com/upy.html
+from __future__ import unicode_literals
DEPARTMENT_CHOICES = (
- ('AG', u'Alto Paraguay'),
- ('AA', u'Alto Paraná'),
- ('AM', u'Amambay'),
- ('AS', u'Asunción'),
- ('BQ', u'Boquerón'),
- ('CG', u'Caaguazú'),
- ('CZ', u'Caazapá'),
- ('CY', u'Canindeyú'),
- ('CE', u'Central'),
- ('CN', u'Concepción'),
- ('CR', u'Cordillera'),
- ('GU', u'Guairá'),
- ('IT', u'Itapúa'),
- ('MI', u'Misiones'),
- ('NE', u'Ñeembucú'),
- ('PG', u'Paraguarí'),
- ('PH', u'Pdte. Hayes'),
- ('SP', u'San Pedro'),
+ ('AG', 'Alto Paraguay'),
+ ('AA', 'Alto Paraná'),
+ ('AM', 'Amambay'),
+ ('AS', 'Asunción'),
+ ('BQ', 'Boquerón'),
+ ('CG', 'Caaguazú'),
+ ('CZ', 'Caazapá'),
+ ('CY', 'Canindeyú'),
+ ('CE', 'Central'),
+ ('CN', 'Concepción'),
+ ('CR', 'Cordillera'),
+ ('GU', 'Guairá'),
+ ('IT', 'Itapúa'),
+ ('MI', 'Misiones'),
+ ('NE', 'Ñeembucú'),
+ ('PG', 'Paraguarí'),
+ ('PH', 'Pdte. Hayes'),
+ ('SP', 'San Pedro'),
)
DEPARTMENT_ROMAN_CHOICES = (
- ('CN', u'I Concepción'),
- ('SP', u'II San Pedro'),
- ('CR', u'III Cordillera'),
- ('GU', u'IV Guairá'),
- ('CG', u'V Caaguazú'),
- ('CZ', u'VI Caazapá'),
- ('IT', u'VII Itapúa'),
- ('MI', u'VIII Misiones'),
- ('PG', u'IX Paraguarí'),
- ('AA', u'X Alto Paraná'),
- ('CE', u'XI Central'),
- ('NE', u'XII Ñeembucú'),
- ('AM', u'XIII Amambay'),
- ('CY', u'XIV Canindeyú'),
- ('PH', u'XV Pdte. Hayes'),
- ('AG', u'XVI Alto Paraguay'),
- ('BQ', u'XVII Boquerón'),
- ('AS', u'XVIII Asunción'),
+ ('CN', 'I Concepción'),
+ ('SP', 'II San Pedro'),
+ ('CR', 'III Cordillera'),
+ ('GU', 'IV Guairá'),
+ ('CG', 'V Caaguazú'),
+ ('CZ', 'VI Caazapá'),
+ ('IT', 'VII Itapúa'),
+ ('MI', 'VIII Misiones'),
+ ('PG', 'IX Paraguarí'),
+ ('AA', 'X Alto Paraná'),
+ ('CE', 'XI Central'),
+ ('NE', 'XII Ñeembucú'),
+ ('AM', 'XIII Amambay'),
+ ('CY', 'XIV Canindeyú'),
+ ('PH', 'XV Pdte. Hayes'),
+ ('AG', 'XVI Alto Paraguay'),
+ ('BQ', 'XVII Boquerón'),
+ ('AS', 'XVIII Asunción'),
)
diff --git a/django/contrib/localflavor/ro/forms.py b/django/contrib/localflavor/ro/forms.py
index 5c458390b2..bdbed5c476 100644
--- a/django/contrib/localflavor/ro/forms.py
+++ b/django/contrib/localflavor/ro/forms.py
@@ -2,7 +2,7 @@
"""
Romanian specific form helpers.
"""
-from __future__ import absolute_import
+from __future__ import absolute_import, unicode_literals
from django.contrib.localflavor.ro.ro_counties import COUNTIES_CHOICES
from django.core.validators import EMPTY_VALUES
@@ -30,7 +30,7 @@ class ROCIFField(RegexField):
"""
value = super(ROCIFField, self).clean(value)
if value in EMPTY_VALUES:
- return u''
+ return ''
# strip RO part
if value[0:2] == 'RO':
value = value[2:]
@@ -67,7 +67,7 @@ class ROCNPField(RegexField):
"""
value = super(ROCNPField, self).clean(value)
if value in EMPTY_VALUES:
- return u''
+ return ''
# check birthdate digits
import datetime
try:
@@ -100,13 +100,13 @@ class ROCountyField(Field):
Arges => invalid
"""
default_error_messages = {
- 'invalid': u'Enter a Romanian county code or name.',
+ 'invalid': 'Enter a Romanian county code or name.',
}
def clean(self, value):
super(ROCountyField, self).clean(value)
if value in EMPTY_VALUES:
- return u''
+ return ''
try:
value = value.strip().upper()
except AttributeError:
@@ -152,7 +152,7 @@ class ROIBANField(RegexField):
"""
value = super(ROIBANField, self).clean(value)
if value in EMPTY_VALUES:
- return u''
+ return ''
value = value.replace('-','')
value = value.replace(' ','')
value = value.upper()
@@ -184,7 +184,7 @@ class ROPhoneNumberField(RegexField):
"""
value = super(ROPhoneNumberField, self).clean(value)
if value in EMPTY_VALUES:
- return u''
+ return ''
value = value.replace('-','')
value = value.replace('(','')
value = value.replace(')','')
diff --git a/django/contrib/localflavor/ro/ro_counties.py b/django/contrib/localflavor/ro/ro_counties.py
index 40423ddc87..282cfc5193 100644
--- a/django/contrib/localflavor/ro/ro_counties.py
+++ b/django/contrib/localflavor/ro/ro_counties.py
@@ -5,48 +5,49 @@ A list of Romanian counties as `choices` in a formfield.
This exists as a standalone file so that it's only imported into memory when
explicitly needed.
"""
+from __future__ import unicode_literals
COUNTIES_CHOICES = (
- ('AB', u'Alba'),
- ('AR', u'Arad'),
- ('AG', u'Argeş'),
- ('BC', u'Bacău'),
- ('BH', u'Bihor'),
- ('BN', u'Bistriţa-Năsăud'),
- ('BT', u'Botoşani'),
- ('BV', u'Braşov'),
- ('BR', u'Brăila'),
- ('B', u'Bucureşti'),
- ('BZ', u'Buzău'),
- ('CS', u'Caraş-Severin'),
- ('CL', u'Călăraşi'),
- ('CJ', u'Cluj'),
- ('CT', u'Constanţa'),
- ('CV', u'Covasna'),
- ('DB', u'Dâmboviţa'),
- ('DJ', u'Dolj'),
- ('GL', u'Galaţi'),
- ('GR', u'Giurgiu'),
- ('GJ', u'Gorj'),
- ('HR', u'Harghita'),
- ('HD', u'Hunedoara'),
- ('IL', u'Ialomiţa'),
- ('IS', u'Iaşi'),
- ('IF', u'Ilfov'),
- ('MM', u'Maramureş'),
- ('MH', u'Mehedinţi'),
- ('MS', u'Mureş'),
- ('NT', u'Neamţ'),
- ('OT', u'Olt'),
- ('PH', u'Prahova'),
- ('SM', u'Satu Mare'),
- ('SJ', u'Sălaj'),
- ('SB', u'Sibiu'),
- ('SV', u'Suceava'),
- ('TR', u'Teleorman'),
- ('TM', u'Timiş'),
- ('TL', u'Tulcea'),
- ('VS', u'Vaslui'),
- ('VL', u'Vâlcea'),
- ('VN', u'Vrancea'),
+ ('AB', 'Alba'),
+ ('AR', 'Arad'),
+ ('AG', 'Argeş'),
+ ('BC', 'Bacău'),
+ ('BH', 'Bihor'),
+ ('BN', 'Bistriţa-Năsăud'),
+ ('BT', 'Botoşani'),
+ ('BV', 'Braşov'),
+ ('BR', 'Brăila'),
+ ('B', 'Bucureşti'),
+ ('BZ', 'Buzău'),
+ ('CS', 'Caraş-Severin'),
+ ('CL', 'Călăraşi'),
+ ('CJ', 'Cluj'),
+ ('CT', 'Constanţa'),
+ ('CV', 'Covasna'),
+ ('DB', 'Dâmboviţa'),
+ ('DJ', 'Dolj'),
+ ('GL', 'Galaţi'),
+ ('GR', 'Giurgiu'),
+ ('GJ', 'Gorj'),
+ ('HR', 'Harghita'),
+ ('HD', 'Hunedoara'),
+ ('IL', 'Ialomiţa'),
+ ('IS', 'Iaşi'),
+ ('IF', 'Ilfov'),
+ ('MM', 'Maramureş'),
+ ('MH', 'Mehedinţi'),
+ ('MS', 'Mureş'),
+ ('NT', 'Neamţ'),
+ ('OT', 'Olt'),
+ ('PH', 'Prahova'),
+ ('SM', 'Satu Mare'),
+ ('SJ', 'Sălaj'),
+ ('SB', 'Sibiu'),
+ ('SV', 'Suceava'),
+ ('TR', 'Teleorman'),
+ ('TM', 'Timiş'),
+ ('TL', 'Tulcea'),
+ ('VS', 'Vaslui'),
+ ('VL', 'Vâlcea'),
+ ('VN', 'Vrancea'),
)
diff --git a/django/contrib/localflavor/ru/forms.py b/django/contrib/localflavor/ru/forms.py
index d01f5a1e3b..03114d0629 100644
--- a/django/contrib/localflavor/ru/forms.py
+++ b/django/contrib/localflavor/ru/forms.py
@@ -1,7 +1,7 @@
"""
Russian-specific forms helpers
"""
-from __future__ import absolute_import
+from __future__ import absolute_import, unicode_literals
import re
@@ -34,7 +34,7 @@ class RUPostalCodeField(RegexField):
Format: XXXXXX, where X is any digit, and first digit is not zero.
"""
default_error_messages = {
- 'invalid': _(u'Enter a postal code in the format XXXXXX.'),
+ 'invalid': _('Enter a postal code in the format XXXXXX.'),
}
def __init__(self, max_length=None, min_length=None, *args, **kwargs):
super(RUPostalCodeField, self).__init__(r'^\d{6}$',
@@ -47,7 +47,7 @@ class RUPassportNumberField(RegexField):
XXXX XXXXXX where X - any digit.
"""
default_error_messages = {
- 'invalid': _(u'Enter a passport number in the format XXXX XXXXXX.'),
+ 'invalid': _('Enter a passport number in the format XXXX XXXXXX.'),
}
def __init__(self, max_length=None, min_length=None, *args, **kwargs):
super(RUPassportNumberField, self).__init__(r'^\d{4} \d{6}$',
@@ -60,7 +60,7 @@ class RUAlienPassportNumberField(RegexField):
XX XXXXXXX where X - any digit.
"""
default_error_messages = {
- 'invalid': _(u'Enter a passport number in the format XX XXXXXXX.'),
+ 'invalid': _('Enter a passport number in the format XX XXXXXXX.'),
}
def __init__(self, max_length=None, min_length=None, *args, **kwargs):
super(RUAlienPassportNumberField, self).__init__(r'^\d{2} \d{7}$',
diff --git a/django/contrib/localflavor/se/forms.py b/django/contrib/localflavor/se/forms.py
index 5c4e2325a9..43d06a08ec 100644
--- a/django/contrib/localflavor/se/forms.py
+++ b/django/contrib/localflavor/se/forms.py
@@ -2,7 +2,7 @@
"""
Swedish specific Form helpers
"""
-from __future__ import absolute_import
+from __future__ import absolute_import, unicode_literals
import re
@@ -58,7 +58,7 @@ class SEOrganisationNumberField(forms.CharField):
value = super(SEOrganisationNumberField, self).clean(value)
if value in EMPTY_VALUES:
- return u''
+ return ''
match = SWEDISH_ID_NUMBER.match(value)
if not match:
@@ -116,7 +116,7 @@ class SEPersonalIdentityNumberField(forms.CharField):
value = super(SEPersonalIdentityNumberField, self).clean(value)
if value in EMPTY_VALUES:
- return u''
+ return ''
match = SWEDISH_ID_NUMBER.match(value)
if match is None:
diff --git a/django/contrib/localflavor/se/se_counties.py b/django/contrib/localflavor/se/se_counties.py
index db54fb9f39..20090d3b30 100644
--- a/django/contrib/localflavor/se/se_counties.py
+++ b/django/contrib/localflavor/se/se_counties.py
@@ -8,29 +8,30 @@ This exists in this standalone file so that it's only imported into memory
when explicitly needed.
"""
+from __future__ import unicode_literals
from django.utils.translation import ugettext_lazy as _
COUNTY_CHOICES = (
- ('AB', _(u'Stockholm')),
- ('AC', _(u'Västerbotten')),
- ('BD', _(u'Norrbotten')),
- ('C', _(u'Uppsala')),
- ('D', _(u'Södermanland')),
- ('E', _(u'Östergötland')),
- ('F', _(u'Jönköping')),
- ('G', _(u'Kronoberg')),
- ('H', _(u'Kalmar')),
- ('I', _(u'Gotland')),
- ('K', _(u'Blekinge')),
- ('M', _(u'Skåne')),
- ('N', _(u'Halland')),
- ('O', _(u'Västra Götaland')),
- ('S', _(u'Värmland')),
- ('T', _(u'Örebro')),
- ('U', _(u'Västmanland')),
- ('W', _(u'Dalarna')),
- ('X', _(u'Gävleborg')),
- ('Y', _(u'Västernorrland')),
- ('Z', _(u'Jämtland')),
+ ('AB', _('Stockholm')),
+ ('AC', _('Västerbotten')),
+ ('BD', _('Norrbotten')),
+ ('C', _('Uppsala')),
+ ('D', _('Södermanland')),
+ ('E', _('Östergötland')),
+ ('F', _('Jönköping')),
+ ('G', _('Kronoberg')),
+ ('H', _('Kalmar')),
+ ('I', _('Gotland')),
+ ('K', _('Blekinge')),
+ ('M', _('Skåne')),
+ ('N', _('Halland')),
+ ('O', _('Västra Götaland')),
+ ('S', _('Värmland')),
+ ('T', _('Örebro')),
+ ('U', _('Västmanland')),
+ ('W', _('Dalarna')),
+ ('X', _('Gävleborg')),
+ ('Y', _('Västernorrland')),
+ ('Z', _('Jämtland')),
)
diff --git a/django/contrib/localflavor/se/utils.py b/django/contrib/localflavor/se/utils.py
index 5e7c2b7dae..783062ebb4 100644
--- a/django/contrib/localflavor/se/utils.py
+++ b/django/contrib/localflavor/se/utils.py
@@ -1,4 +1,5 @@
import datetime
+from django.utils import six
def id_number_checksum(gd):
"""
@@ -65,7 +66,7 @@ def validate_id_birthday(gd, fix_coordination_number_day=True):
def format_personal_id_number(birth_day, gd):
# birth_day.strftime cannot be used, since it does not support dates < 1900
- return unicode(str(birth_day.year) + gd['month'] + gd['day'] + gd['serial'] + gd['checksum'])
+ return six.text_type(str(birth_day.year) + gd['month'] + gd['day'] + gd['serial'] + gd['checksum'])
def format_organisation_number(gd):
if gd['century'] is None:
@@ -73,7 +74,7 @@ def format_organisation_number(gd):
else:
century = gd['century']
- return unicode(century + gd['year'] + gd['month'] + gd['day'] + gd['serial'] + gd['checksum'])
+ return six.text_type(century + gd['year'] + gd['month'] + gd['day'] + gd['serial'] + gd['checksum'])
def valid_organisation(gd):
return gd['century'] in (None, 16) and \
diff --git a/django/contrib/localflavor/si/forms.py b/django/contrib/localflavor/si/forms.py
index f1188dd222..bab35935fd 100644
--- a/django/contrib/localflavor/si/forms.py
+++ b/django/contrib/localflavor/si/forms.py
@@ -2,7 +2,7 @@
Slovenian specific form helpers.
"""
-from __future__ import absolute_import
+from __future__ import absolute_import, unicode_literals
import datetime
import re
@@ -21,16 +21,16 @@ class SIEMSOField(CharField):
"""
default_error_messages = {
- 'invalid': _(u'This field should contain exactly 13 digits.'),
- 'date': _(u'The first 7 digits of the EMSO must represent a valid past date.'),
- 'checksum': _(u'The EMSO is not valid.'),
+ 'invalid': _('This field should contain exactly 13 digits.'),
+ 'date': _('The first 7 digits of the EMSO must represent a valid past date.'),
+ 'checksum': _('The EMSO is not valid.'),
}
emso_regex = re.compile('^(\d{2})(\d{2})(\d{3})(\d{2})(\d{3})(\d)$')
def clean(self, value):
super(SIEMSOField, self).clean(value)
if value in EMPTY_VALUES:
- return u''
+ return ''
value = value.strip()
@@ -41,7 +41,7 @@ class SIEMSOField(CharField):
# Validate EMSO
s = 0
int_values = [int(i) for i in value]
- for a, b in zip(int_values, range(7, 1, -1) * 2):
+ for a, b in zip(int_values, list(range(7, 1, -1)) * 2):
s += a * b
chk = s % 11
if chk == 0:
@@ -83,14 +83,14 @@ class SITaxNumberField(CharField):
"""
default_error_messages = {
- 'invalid': _(u'Enter a valid tax number in form SIXXXXXXXX'),
+ 'invalid': _('Enter a valid tax number in form SIXXXXXXXX'),
}
sitax_regex = re.compile('^(?:SI)?([1-9]\d{7})$')
def clean(self, value):
super(SITaxNumberField, self).clean(value)
if value in EMPTY_VALUES:
- return u''
+ return ''
value = value.strip()
@@ -148,14 +148,14 @@ class SIPhoneNumberField(CharField):
"""
default_error_messages = {
- 'invalid': _(u'Enter phone number in form +386XXXXXXXX or 0XXXXXXXX.'),
+ 'invalid': _('Enter phone number in form +386XXXXXXXX or 0XXXXXXXX.'),
}
phone_regex = re.compile('^(?:(?:00|\+)386|0)(\d{7,8})$')
def clean(self, value):
super(SIPhoneNumberField, self).clean(value)
if value in EMPTY_VALUES:
- return u''
+ return ''
value = value.replace(' ', '').replace('-', '').replace('/', '')
m = self.phone_regex.match(value)
diff --git a/django/contrib/localflavor/si/si_postalcodes.py b/django/contrib/localflavor/si/si_postalcodes.py
index 7baac94e03..4d027afcff 100644
--- a/django/contrib/localflavor/si/si_postalcodes.py
+++ b/django/contrib/localflavor/si/si_postalcodes.py
@@ -1,469 +1,470 @@
# *-* coding: utf-8 *-*
+from __future__ import unicode_literals
SI_POSTALCODES = [
- (1000, u'Ljubljana'),
- (1215, u'Medvode'),
- (1216, u'Smlednik'),
- (1217, u'Vodice'),
- (1218, u'Komenda'),
- (1219, u'Laze v Tuhinju'),
- (1221, u'Motnik'),
- (1222, u'Trojane'),
- (1223, u'Blagovica'),
- (1225, u'Lukovica'),
- (1230, u'Dom\u017eale'),
- (1233, u'Dob'),
- (1234, u'Menge\u0161'),
- (1235, u'Radomlje'),
- (1236, u'Trzin'),
- (1241, u'Kamnik'),
- (1242, u'Stahovica'),
- (1251, u'Morav\u010de'),
- (1252, u'Va\u010de'),
- (1262, u'Dol pri Ljubljani'),
- (1270, u'Litija'),
- (1272, u'Pol\u0161nik'),
- (1273, u'Dole pri Litiji'),
- (1274, u'Gabrovka'),
- (1275, u'\u0160martno pri Litiji'),
- (1276, u'Primskovo'),
- (1281, u'Kresnice'),
- (1282, u'Sava'),
- (1290, u'Grosuplje'),
- (1291, u'\u0160kofljica'),
- (1292, u'Ig'),
- (1293, u'\u0160marje - Sap'),
- (1294, u'Vi\u0161nja Gora'),
- (1295, u'Ivan\u010dna Gorica'),
- (1296, u'\u0160entvid pri Sti\u010dni'),
- (1301, u'Krka'),
- (1303, u'Zagradec'),
- (1310, u'Ribnica'),
- (1311, u'Turjak'),
- (1312, u'Videm - Dobrepolje'),
- (1313, u'Struge'),
- (1314, u'Rob'),
- (1315, u'Velike La\u0161\u010de'),
- (1316, u'Ortnek'),
- (1317, u'Sodra\u017eica'),
- (1318, u'Lo\u0161ki Potok'),
- (1319, u'Draga'),
- (1330, u'Ko\u010devje'),
- (1331, u'Dolenja vas'),
- (1332, u'Stara Cerkev'),
- (1336, u'Kostel'),
- (1337, u'Osilnica'),
- (1338, u'Ko\u010devska Reka'),
- (1351, u'Brezovica pri Ljubljani'),
- (1352, u'Preserje'),
- (1353, u'Borovnica'),
- (1354, u'Horjul'),
- (1355, u'Polhov Gradec'),
- (1356, u'Dobrova'),
- (1357, u'Notranje Gorice'),
- (1358, u'Log pri Brezovici'),
- (1360, u'Vrhnika'),
- (1370, u'Logatec'),
- (1372, u'Hotedr\u0161ica'),
- (1373, u'Rovte'),
- (1380, u'Cerknica'),
- (1381, u'Rakek'),
- (1382, u'Begunje pri Cerknici'),
- (1384, u'Grahovo'),
- (1385, u'Nova vas'),
- (1386, u'Stari trg pri Lo\u017eu'),
- (1410, u'Zagorje ob Savi'),
- (1411, u'Izlake'),
- (1412, u'Kisovec'),
- (1413, u'\u010cem\u0161enik'),
- (1414, u'Podkum'),
- (1420, u'Trbovlje'),
- (1423, u'Dobovec'),
- (1430, u'Hrastnik'),
- (1431, u'Dol pri Hrastniku'),
- (1432, u'Zidani Most'),
- (1433, u'Rade\u010de'),
- (1434, u'Loka pri Zidanem Mostu'),
- (2000, u'Maribor'),
- (2201, u'Zgornja Kungota'),
- (2204, u'Miklav\u017e na Dravskem polju'),
- (2205, u'Star\u0161e'),
- (2206, u'Marjeta na Dravskem polju'),
- (2208, u'Pohorje'),
- (2211, u'Pesnica pri Mariboru'),
- (2212, u'\u0160entilj v Slovenskih goricah'),
- (2213, u'Zgornja Velka'),
- (2214, u'Sladki vrh'),
- (2215, u'Cer\u0161ak'),
- (2221, u'Jarenina'),
- (2222, u'Jakobski Dol'),
- (2223, u'Jurovski Dol'),
- (2229, u'Male\u010dnik'),
- (2230, u'Lenart v Slovenskih goricah'),
- (2231, u'Pernica'),
- (2232, u'Voli\u010dina'),
- (2233, u'Sveta Ana v Slovenskih goricah'),
- (2234, u'Benedikt'),
- (2235, u'Sveta Trojica v Slovenskih goricah'),
- (2236, u'Cerkvenjak'),
- (2241, u'Spodnji Duplek'),
- (2242, u'Zgornja Korena'),
- (2250, u'Ptuj'),
- (2252, u'Dornava'),
- (2253, u'Destrnik'),
- (2254, u'Trnovska vas'),
- (2255, u'Vitomarci'),
- (2256, u'Jur\u0161inci'),
- (2257, u'Polen\u0161ak'),
- (2258, u'Sveti Toma\u017e'),
- (2259, u'Ivanjkovci'),
- (2270, u'Ormo\u017e'),
- (2272, u'Gori\u0161nica'),
- (2273, u'Podgorci'),
- (2274, u'Velika Nedelja'),
- (2275, u'Miklav\u017e pri Ormo\u017eu'),
- (2276, u'Kog'),
- (2277, u'Sredi\u0161\u010de ob Dravi'),
- (2281, u'Markovci'),
- (2282, u'Cirkulane'),
- (2283, u'Zavr\u010d'),
- (2284, u'Videm pri Ptuju'),
- (2285, u'Zgornji Leskovec'),
- (2286, u'Podlehnik'),
- (2287, u'\u017detale'),
- (2288, u'Hajdina'),
- (2289, u'Stoperce'),
- (2310, u'Slovenska Bistrica'),
- (2311, u'Ho\u010de'),
- (2312, u'Orehova vas'),
- (2313, u'Fram'),
- (2314, u'Zgornja Polskava'),
- (2315, u'\u0160martno na Pohorju'),
- (2316, u'Zgornja Lo\u017enica'),
- (2317, u'Oplotnica'),
- (2318, u'Laporje'),
- (2319, u'Polj\u010dane'),
- (2321, u'Makole'),
- (2322, u'Maj\u0161perk'),
- (2323, u'Ptujska Gora'),
- (2324, u'Lovrenc na Dravskem polju'),
- (2325, u'Kidri\u010devo'),
- (2326, u'Cirkovce'),
- (2327, u'Ra\u010de'),
- (2331, u'Pragersko'),
- (2341, u'Limbu\u0161'),
- (2342, u'Ru\u0161e'),
- (2343, u'Fala'),
- (2344, u'Lovrenc na Pohorju'),
- (2345, u'Bistrica ob Dravi'),
- (2351, u'Kamnica'),
- (2352, u'Selnica ob Dravi'),
- (2353, u'Sv. Duh na Ostrem Vrhu'),
- (2354, u'Bresternica'),
- (2360, u'Radlje ob Dravi'),
- (2361, u'O\u017ebalt'),
- (2362, u'Kapla'),
- (2363, u'Podvelka'),
- (2364, u'Ribnica na Pohorju'),
- (2365, u'Vuhred'),
- (2366, u'Muta'),
- (2367, u'Vuzenica'),
- (2370, u'Dravograd'),
- (2371, u'Trbonje'),
- (2372, u'Libeli\u010de'),
- (2373, u'\u0160entjan\u017e pri Dravogradu'),
- (2380, u'Slovenj Gradec'),
- (2381, u'Podgorje pri Slovenj Gradcu'),
- (2382, u'Mislinja'),
- (2383, u'\u0160martno pri Slovenj Gradcu'),
- (2390, u'Ravne na Koro\u0161kem'),
- (2391, u'Prevalje'),
- (2392, u'Me\u017eica'),
- (2393, u'\u010crna na Koro\u0161kem'),
- (2394, u'Kotlje'),
- (3000, u'Celje'),
- (3201, u'\u0160martno v Ro\u017eni dolini'),
- (3202, u'Ljube\u010dna'),
- (3203, u'Nova Cerkev'),
- (3204, u'Dobrna'),
- (3205, u'Vitanje'),
- (3206, u'Stranice'),
- (3210, u'Slovenske Konjice'),
- (3211, u'\u0160kofja vas'),
- (3212, u'Vojnik'),
- (3213, u'Frankolovo'),
- (3214, u'Zre\u010de'),
- (3215, u'Lo\u010de'),
- (3220, u'\u0160tore'),
- (3221, u'Teharje'),
- (3222, u'Dramlje'),
- (3223, u'Loka pri \u017dusmu'),
- (3224, u'Dobje pri Planini'),
- (3225, u'Planina pri Sevnici'),
- (3230, u'\u0160entjur'),
- (3231, u'Grobelno'),
- (3232, u'Ponikva'),
- (3233, u'Kalobje'),
- (3240, u'\u0160marje pri Jel\u0161ah'),
- (3241, u'Podplat'),
- (3250, u'Roga\u0161ka Slatina'),
- (3252, u'Rogatec'),
- (3253, u'Pristava pri Mestinju'),
- (3254, u'Pod\u010detrtek'),
- (3255, u'Bu\u010de'),
- (3256, u'Bistrica ob Sotli'),
- (3257, u'Podsreda'),
- (3260, u'Kozje'),
- (3261, u'Lesi\u010dno'),
- (3262, u'Prevorje'),
- (3263, u'Gorica pri Slivnici'),
- (3264, u'Sveti \u0160tefan'),
- (3270, u'La\u0161ko'),
- (3271, u'\u0160entrupert'),
- (3272, u'Rimske Toplice'),
- (3273, u'Jurklo\u0161ter'),
- (3301, u'Petrov\u010de'),
- (3302, u'Gri\u017ee'),
- (3303, u'Gomilsko'),
- (3304, u'Tabor'),
- (3305, u'Vransko'),
- (3310, u'\u017dalec'),
- (3311, u'\u0160empeter v Savinjski dolini'),
- (3312, u'Prebold'),
- (3313, u'Polzela'),
- (3314, u'Braslov\u010de'),
- (3320, u'Velenje - dostava'),
- (3322, u'Velenje - po\u0161tni predali'),
- (3325, u'\u0160o\u0161tanj'),
- (3326, u'Topol\u0161ica'),
- (3327, u'\u0160martno ob Paki'),
- (3330, u'Mozirje'),
- (3331, u'Nazarje'),
- (3332, u'Re\u010dica ob Savinji'),
- (3333, u'Ljubno ob Savinji'),
- (3334, u'Lu\u010de'),
- (3335, u'Sol\u010dava'),
- (3341, u'\u0160martno ob Dreti'),
- (3342, u'Gornji Grad'),
- (4000, u'Kranj'),
- (4201, u'Zgornja Besnica'),
- (4202, u'Naklo'),
- (4203, u'Duplje'),
- (4204, u'Golnik'),
- (4205, u'Preddvor'),
- (4206, u'Zgornje Jezersko'),
- (4207, u'Cerklje na Gorenjskem'),
- (4208, u'\u0160en\u010dur'),
- (4209, u'\u017dabnica'),
- (4210, u'Brnik - aerodrom'),
- (4211, u'Mav\u010di\u010de'),
- (4212, u'Visoko'),
- (4220, u'\u0160kofja Loka'),
- (4223, u'Poljane nad \u0160kofjo Loko'),
- (4224, u'Gorenja vas'),
- (4225, u'Sovodenj'),
- (4226, u'\u017diri'),
- (4227, u'Selca'),
- (4228, u'\u017delezniki'),
- (4229, u'Sorica'),
- (4240, u'Radovljica'),
- (4243, u'Brezje'),
- (4244, u'Podnart'),
- (4245, u'Kropa'),
- (4246, u'Kamna Gorica'),
- (4247, u'Zgornje Gorje'),
- (4248, u'Lesce'),
- (4260, u'Bled'),
- (4263, u'Bohinjska Bela'),
- (4264, u'Bohinjska Bistrica'),
- (4265, u'Bohinjsko jezero'),
- (4267, u'Srednja vas v Bohinju'),
- (4270, u'Jesenice'),
- (4273, u'Blejska Dobrava'),
- (4274, u'\u017dirovnica'),
- (4275, u'Begunje na Gorenjskem'),
- (4276, u'Hru\u0161ica'),
- (4280, u'Kranjska Gora'),
- (4281, u'Mojstrana'),
- (4282, u'Gozd Martuljek'),
- (4283, u'Rate\u010de - Planica'),
- (4290, u'Tr\u017ei\u010d'),
- (4294, u'Kri\u017ee'),
- (5000, u'Nova Gorica'),
- (5210, u'Deskle'),
- (5211, u'Kojsko'),
- (5212, u'Dobrovo v Brdih'),
- (5213, u'Kanal'),
- (5214, u'Kal nad Kanalom'),
- (5215, u'Ro\u010dinj'),
- (5216, u'Most na So\u010di'),
- (5220, u'Tolmin'),
- (5222, u'Kobarid'),
- (5223, u'Breginj'),
- (5224, u'Srpenica'),
- (5230, u'Bovec'),
- (5231, u'Log pod Mangartom'),
- (5232, u'So\u010da'),
- (5242, u'Grahovo ob Ba\u010di'),
- (5243, u'Podbrdo'),
- (5250, u'Solkan'),
- (5251, u'Grgar'),
- (5252, u'Trnovo pri Gorici'),
- (5253, u'\u010cepovan'),
- (5261, u'\u0160empas'),
- (5262, u'\u010crni\u010de'),
- (5263, u'Dobravlje'),
- (5270, u'Ajdov\u0161\u010dina'),
- (5271, u'Vipava'),
- (5272, u'Podnanos'),
- (5273, u'Col'),
- (5274, u'\u010crni Vrh nad Idrijo'),
- (5275, u'Godovi\u010d'),
- (5280, u'Idrija'),
- (5281, u'Spodnja Idrija'),
- (5282, u'Cerkno'),
- (5283, u'Slap ob Idrijci'),
- (5290, u'\u0160empeter pri Gorici'),
- (5291, u'Miren'),
- (5292, u'Ren\u010de'),
- (5293, u'Vol\u010dja Draga'),
- (5294, u'Dornberk'),
- (5295, u'Branik'),
- (5296, u'Kostanjevica na Krasu'),
- (5297, u'Prva\u010dina'),
- (6000, u'Koper'),
- (6210, u'Se\u017eana'),
- (6215, u'Diva\u010da'),
- (6216, u'Podgorje'),
- (6217, u'Vremski Britof'),
- (6219, u'Lokev'),
- (6221, u'Dutovlje'),
- (6222, u'\u0160tanjel'),
- (6223, u'Komen'),
- (6224, u'Seno\u017ee\u010de'),
- (6225, u'Hru\u0161evje'),
- (6230, u'Postojna'),
- (6232, u'Planina'),
- (6240, u'Kozina'),
- (6242, u'Materija'),
- (6243, u'Obrov'),
- (6244, u'Podgrad'),
- (6250, u'Ilirska Bistrica'),
- (6251, u'Ilirska Bistrica - Trnovo'),
- (6253, u'Kne\u017eak'),
- (6254, u'Jel\u0161ane'),
- (6255, u'Prem'),
- (6256, u'Ko\u0161ana'),
- (6257, u'Pivka'),
- (6258, u'Prestranek'),
- (6271, u'Dekani'),
- (6272, u'Gra\u010di\u0161\u010de'),
- (6273, u'Marezige'),
- (6274, u'\u0160marje'),
- (6275, u'\u010crni Kal'),
- (6276, u'Pobegi'),
- (6280, u'Ankaran - Ancarano'),
- (6281, u'\u0160kofije'),
- (6310, u'Izola - Isola'),
- (6320, u'Portoro\u017e - Portorose'),
- (6330, u'Piran - Pirano'),
- (6333, u'Se\u010dovlje - Sicciole'),
- (8000, u'Novo mesto'),
- (8210, u'Trebnje'),
- (8211, u'Dobrni\u010d'),
- (8212, u'Velika Loka'),
- (8213, u'Veliki Gaber'),
- (8216, u'Mirna Pe\u010d'),
- (8220, u'\u0160marje\u0161ke Toplice'),
- (8222, u'Oto\u010dec'),
- (8230, u'Mokronog'),
- (8231, u'Trebelno'),
- (8232, u'\u0160entrupert'),
- (8233, u'Mirna'),
- (8250, u'Bre\u017eice'),
- (8251, u'\u010cate\u017e ob Savi'),
- (8253, u'Arti\u010de'),
- (8254, u'Globoko'),
- (8255, u'Pi\u0161ece'),
- (8256, u'Sromlje'),
- (8257, u'Dobova'),
- (8258, u'Kapele'),
- (8259, u'Bizeljsko'),
- (8261, u'Jesenice na Dolenjskem'),
- (8262, u'Kr\u0161ka vas'),
- (8263, u'Cerklje ob Krki'),
- (8270, u'Kr\u0161ko'),
- (8272, u'Zdole'),
- (8273, u'Leskovec pri Kr\u0161kem'),
- (8274, u'Raka'),
- (8275, u'\u0160kocjan'),
- (8276, u'Bu\u010dka'),
- (8280, u'Brestanica'),
- (8281, u'Senovo'),
- (8282, u'Koprivnica'),
- (8283, u'Blanca'),
- (8290, u'Sevnica'),
- (8292, u'Zabukovje'),
- (8293, u'Studenec'),
- (8294, u'Bo\u0161tanj'),
- (8295, u'Tr\u017ei\u0161\u010de'),
- (8296, u'Krmelj'),
- (8297, u'\u0160entjan\u017e'),
- (8310, u'\u0160entjernej'),
- (8311, u'Kostanjevica na Krki'),
- (8312, u'Podbo\u010dje'),
- (8321, u'Brusnice'),
- (8322, u'Stopi\u010de'),
- (8323, u'Ur\u0161na sela'),
- (8330, u'Metlika'),
- (8331, u'Suhor'),
- (8332, u'Gradac'),
- (8333, u'Semi\u010d'),
- (8340, u'\u010crnomelj'),
- (8341, u'Adle\u0161i\u010di'),
- (8342, u'Stari trg ob Kolpi'),
- (8343, u'Dragatu\u0161'),
- (8344, u'Vinica pri \u010crnomlju'),
- (8350, u'Dolenjske Toplice'),
- (8351, u'Stra\u017ea'),
- (8360, u'\u017du\u017eemberk'),
- (8361, u'Dvor'),
- (8362, u'Hinje'),
- (9000, u'Murska Sobota'),
- (9201, u'Puconci'),
- (9202, u'Ma\u010dkovci'),
- (9203, u'Petrovci'),
- (9204, u'\u0160alovci'),
- (9205, u'Hodo\u0161 - Hodos'),
- (9206, u'Kri\u017eevci'),
- (9207, u'Prosenjakovci - Partosfalva'),
- (9208, u'Fokovci'),
- (9220, u'Lendava - Lendva'),
- (9221, u'Martjanci'),
- (9222, u'Bogojina'),
- (9223, u'Dobrovnik - Dobronak'),
- (9224, u'Turni\u0161\u010de'),
- (9225, u'Velika Polana'),
- (9226, u'Moravske Toplice'),
- (9227, u'Kobilje'),
- (9231, u'Beltinci'),
- (9232, u'\u010cren\u0161ovci'),
- (9233, u'Odranci'),
- (9240, u'Ljutomer'),
- (9241, u'Ver\u017eej'),
- (9242, u'Kri\u017eevci pri Ljutomeru'),
- (9243, u'Mala Nedelja'),
- (9244, u'Sveti Jurij ob \u0160\u010davnici'),
- (9245, u'Spodnji Ivanjci'),
- (9250, u'Gornja Radgona'),
- (9251, u'Ti\u0161ina'),
- (9252, u'Radenci'),
- (9253, u'Apa\u010de'),
- (9261, u'Cankova'),
- (9262, u'Roga\u0161ovci'),
- (9263, u'Kuzma'),
- (9264, u'Grad'),
- (9265, u'Bodonci'),
+ (1000, 'Ljubljana'),
+ (1215, 'Medvode'),
+ (1216, 'Smlednik'),
+ (1217, 'Vodice'),
+ (1218, 'Komenda'),
+ (1219, 'Laze v Tuhinju'),
+ (1221, 'Motnik'),
+ (1222, 'Trojane'),
+ (1223, 'Blagovica'),
+ (1225, 'Lukovica'),
+ (1230, 'Dom\u017eale'),
+ (1233, 'Dob'),
+ (1234, 'Menge\u0161'),
+ (1235, 'Radomlje'),
+ (1236, 'Trzin'),
+ (1241, 'Kamnik'),
+ (1242, 'Stahovica'),
+ (1251, 'Morav\u010de'),
+ (1252, 'Va\u010de'),
+ (1262, 'Dol pri Ljubljani'),
+ (1270, 'Litija'),
+ (1272, 'Pol\u0161nik'),
+ (1273, 'Dole pri Litiji'),
+ (1274, 'Gabrovka'),
+ (1275, '\u0160martno pri Litiji'),
+ (1276, 'Primskovo'),
+ (1281, 'Kresnice'),
+ (1282, 'Sava'),
+ (1290, 'Grosuplje'),
+ (1291, '\u0160kofljica'),
+ (1292, 'Ig'),
+ (1293, '\u0160marje - Sap'),
+ (1294, 'Vi\u0161nja Gora'),
+ (1295, 'Ivan\u010dna Gorica'),
+ (1296, '\u0160entvid pri Sti\u010dni'),
+ (1301, 'Krka'),
+ (1303, 'Zagradec'),
+ (1310, 'Ribnica'),
+ (1311, 'Turjak'),
+ (1312, 'Videm - Dobrepolje'),
+ (1313, 'Struge'),
+ (1314, 'Rob'),
+ (1315, 'Velike La\u0161\u010de'),
+ (1316, 'Ortnek'),
+ (1317, 'Sodra\u017eica'),
+ (1318, 'Lo\u0161ki Potok'),
+ (1319, 'Draga'),
+ (1330, 'Ko\u010devje'),
+ (1331, 'Dolenja vas'),
+ (1332, 'Stara Cerkev'),
+ (1336, 'Kostel'),
+ (1337, 'Osilnica'),
+ (1338, 'Ko\u010devska Reka'),
+ (1351, 'Brezovica pri Ljubljani'),
+ (1352, 'Preserje'),
+ (1353, 'Borovnica'),
+ (1354, 'Horjul'),
+ (1355, 'Polhov Gradec'),
+ (1356, 'Dobrova'),
+ (1357, 'Notranje Gorice'),
+ (1358, 'Log pri Brezovici'),
+ (1360, 'Vrhnika'),
+ (1370, 'Logatec'),
+ (1372, 'Hotedr\u0161ica'),
+ (1373, 'Rovte'),
+ (1380, 'Cerknica'),
+ (1381, 'Rakek'),
+ (1382, 'Begunje pri Cerknici'),
+ (1384, 'Grahovo'),
+ (1385, 'Nova vas'),
+ (1386, 'Stari trg pri Lo\u017eu'),
+ (1410, 'Zagorje ob Savi'),
+ (1411, 'Izlake'),
+ (1412, 'Kisovec'),
+ (1413, '\u010cem\u0161enik'),
+ (1414, 'Podkum'),
+ (1420, 'Trbovlje'),
+ (1423, 'Dobovec'),
+ (1430, 'Hrastnik'),
+ (1431, 'Dol pri Hrastniku'),
+ (1432, 'Zidani Most'),
+ (1433, 'Rade\u010de'),
+ (1434, 'Loka pri Zidanem Mostu'),
+ (2000, 'Maribor'),
+ (2201, 'Zgornja Kungota'),
+ (2204, 'Miklav\u017e na Dravskem polju'),
+ (2205, 'Star\u0161e'),
+ (2206, 'Marjeta na Dravskem polju'),
+ (2208, 'Pohorje'),
+ (2211, 'Pesnica pri Mariboru'),
+ (2212, '\u0160entilj v Slovenskih goricah'),
+ (2213, 'Zgornja Velka'),
+ (2214, 'Sladki vrh'),
+ (2215, 'Cer\u0161ak'),
+ (2221, 'Jarenina'),
+ (2222, 'Jakobski Dol'),
+ (2223, 'Jurovski Dol'),
+ (2229, 'Male\u010dnik'),
+ (2230, 'Lenart v Slovenskih goricah'),
+ (2231, 'Pernica'),
+ (2232, 'Voli\u010dina'),
+ (2233, 'Sveta Ana v Slovenskih goricah'),
+ (2234, 'Benedikt'),
+ (2235, 'Sveta Trojica v Slovenskih goricah'),
+ (2236, 'Cerkvenjak'),
+ (2241, 'Spodnji Duplek'),
+ (2242, 'Zgornja Korena'),
+ (2250, 'Ptuj'),
+ (2252, 'Dornava'),
+ (2253, 'Destrnik'),
+ (2254, 'Trnovska vas'),
+ (2255, 'Vitomarci'),
+ (2256, 'Jur\u0161inci'),
+ (2257, 'Polen\u0161ak'),
+ (2258, 'Sveti Toma\u017e'),
+ (2259, 'Ivanjkovci'),
+ (2270, 'Ormo\u017e'),
+ (2272, 'Gori\u0161nica'),
+ (2273, 'Podgorci'),
+ (2274, 'Velika Nedelja'),
+ (2275, 'Miklav\u017e pri Ormo\u017eu'),
+ (2276, 'Kog'),
+ (2277, 'Sredi\u0161\u010de ob Dravi'),
+ (2281, 'Markovci'),
+ (2282, 'Cirkulane'),
+ (2283, 'Zavr\u010d'),
+ (2284, 'Videm pri Ptuju'),
+ (2285, 'Zgornji Leskovec'),
+ (2286, 'Podlehnik'),
+ (2287, '\u017detale'),
+ (2288, 'Hajdina'),
+ (2289, 'Stoperce'),
+ (2310, 'Slovenska Bistrica'),
+ (2311, 'Ho\u010de'),
+ (2312, 'Orehova vas'),
+ (2313, 'Fram'),
+ (2314, 'Zgornja Polskava'),
+ (2315, '\u0160martno na Pohorju'),
+ (2316, 'Zgornja Lo\u017enica'),
+ (2317, 'Oplotnica'),
+ (2318, 'Laporje'),
+ (2319, 'Polj\u010dane'),
+ (2321, 'Makole'),
+ (2322, 'Maj\u0161perk'),
+ (2323, 'Ptujska Gora'),
+ (2324, 'Lovrenc na Dravskem polju'),
+ (2325, 'Kidri\u010devo'),
+ (2326, 'Cirkovce'),
+ (2327, 'Ra\u010de'),
+ (2331, 'Pragersko'),
+ (2341, 'Limbu\u0161'),
+ (2342, 'Ru\u0161e'),
+ (2343, 'Fala'),
+ (2344, 'Lovrenc na Pohorju'),
+ (2345, 'Bistrica ob Dravi'),
+ (2351, 'Kamnica'),
+ (2352, 'Selnica ob Dravi'),
+ (2353, 'Sv. Duh na Ostrem Vrhu'),
+ (2354, 'Bresternica'),
+ (2360, 'Radlje ob Dravi'),
+ (2361, 'O\u017ebalt'),
+ (2362, 'Kapla'),
+ (2363, 'Podvelka'),
+ (2364, 'Ribnica na Pohorju'),
+ (2365, 'Vuhred'),
+ (2366, 'Muta'),
+ (2367, 'Vuzenica'),
+ (2370, 'Dravograd'),
+ (2371, 'Trbonje'),
+ (2372, 'Libeli\u010de'),
+ (2373, '\u0160entjan\u017e pri Dravogradu'),
+ (2380, 'Slovenj Gradec'),
+ (2381, 'Podgorje pri Slovenj Gradcu'),
+ (2382, 'Mislinja'),
+ (2383, '\u0160martno pri Slovenj Gradcu'),
+ (2390, 'Ravne na Koro\u0161kem'),
+ (2391, 'Prevalje'),
+ (2392, 'Me\u017eica'),
+ (2393, '\u010crna na Koro\u0161kem'),
+ (2394, 'Kotlje'),
+ (3000, 'Celje'),
+ (3201, '\u0160martno v Ro\u017eni dolini'),
+ (3202, 'Ljube\u010dna'),
+ (3203, 'Nova Cerkev'),
+ (3204, 'Dobrna'),
+ (3205, 'Vitanje'),
+ (3206, 'Stranice'),
+ (3210, 'Slovenske Konjice'),
+ (3211, '\u0160kofja vas'),
+ (3212, 'Vojnik'),
+ (3213, 'Frankolovo'),
+ (3214, 'Zre\u010de'),
+ (3215, 'Lo\u010de'),
+ (3220, '\u0160tore'),
+ (3221, 'Teharje'),
+ (3222, 'Dramlje'),
+ (3223, 'Loka pri \u017dusmu'),
+ (3224, 'Dobje pri Planini'),
+ (3225, 'Planina pri Sevnici'),
+ (3230, '\u0160entjur'),
+ (3231, 'Grobelno'),
+ (3232, 'Ponikva'),
+ (3233, 'Kalobje'),
+ (3240, '\u0160marje pri Jel\u0161ah'),
+ (3241, 'Podplat'),
+ (3250, 'Roga\u0161ka Slatina'),
+ (3252, 'Rogatec'),
+ (3253, 'Pristava pri Mestinju'),
+ (3254, 'Pod\u010detrtek'),
+ (3255, 'Bu\u010de'),
+ (3256, 'Bistrica ob Sotli'),
+ (3257, 'Podsreda'),
+ (3260, 'Kozje'),
+ (3261, 'Lesi\u010dno'),
+ (3262, 'Prevorje'),
+ (3263, 'Gorica pri Slivnici'),
+ (3264, 'Sveti \u0160tefan'),
+ (3270, 'La\u0161ko'),
+ (3271, '\u0160entrupert'),
+ (3272, 'Rimske Toplice'),
+ (3273, 'Jurklo\u0161ter'),
+ (3301, 'Petrov\u010de'),
+ (3302, 'Gri\u017ee'),
+ (3303, 'Gomilsko'),
+ (3304, 'Tabor'),
+ (3305, 'Vransko'),
+ (3310, '\u017dalec'),
+ (3311, '\u0160empeter v Savinjski dolini'),
+ (3312, 'Prebold'),
+ (3313, 'Polzela'),
+ (3314, 'Braslov\u010de'),
+ (3320, 'Velenje - dostava'),
+ (3322, 'Velenje - po\u0161tni predali'),
+ (3325, '\u0160o\u0161tanj'),
+ (3326, 'Topol\u0161ica'),
+ (3327, '\u0160martno ob Paki'),
+ (3330, 'Mozirje'),
+ (3331, 'Nazarje'),
+ (3332, 'Re\u010dica ob Savinji'),
+ (3333, 'Ljubno ob Savinji'),
+ (3334, 'Lu\u010de'),
+ (3335, 'Sol\u010dava'),
+ (3341, '\u0160martno ob Dreti'),
+ (3342, 'Gornji Grad'),
+ (4000, 'Kranj'),
+ (4201, 'Zgornja Besnica'),
+ (4202, 'Naklo'),
+ (4203, 'Duplje'),
+ (4204, 'Golnik'),
+ (4205, 'Preddvor'),
+ (4206, 'Zgornje Jezersko'),
+ (4207, 'Cerklje na Gorenjskem'),
+ (4208, '\u0160en\u010dur'),
+ (4209, '\u017dabnica'),
+ (4210, 'Brnik - aerodrom'),
+ (4211, 'Mav\u010di\u010de'),
+ (4212, 'Visoko'),
+ (4220, '\u0160kofja Loka'),
+ (4223, 'Poljane nad \u0160kofjo Loko'),
+ (4224, 'Gorenja vas'),
+ (4225, 'Sovodenj'),
+ (4226, '\u017diri'),
+ (4227, 'Selca'),
+ (4228, '\u017delezniki'),
+ (4229, 'Sorica'),
+ (4240, 'Radovljica'),
+ (4243, 'Brezje'),
+ (4244, 'Podnart'),
+ (4245, 'Kropa'),
+ (4246, 'Kamna Gorica'),
+ (4247, 'Zgornje Gorje'),
+ (4248, 'Lesce'),
+ (4260, 'Bled'),
+ (4263, 'Bohinjska Bela'),
+ (4264, 'Bohinjska Bistrica'),
+ (4265, 'Bohinjsko jezero'),
+ (4267, 'Srednja vas v Bohinju'),
+ (4270, 'Jesenice'),
+ (4273, 'Blejska Dobrava'),
+ (4274, '\u017dirovnica'),
+ (4275, 'Begunje na Gorenjskem'),
+ (4276, 'Hru\u0161ica'),
+ (4280, 'Kranjska Gora'),
+ (4281, 'Mojstrana'),
+ (4282, 'Gozd Martuljek'),
+ (4283, 'Rate\u010de - Planica'),
+ (4290, 'Tr\u017ei\u010d'),
+ (4294, 'Kri\u017ee'),
+ (5000, 'Nova Gorica'),
+ (5210, 'Deskle'),
+ (5211, 'Kojsko'),
+ (5212, 'Dobrovo v Brdih'),
+ (5213, 'Kanal'),
+ (5214, 'Kal nad Kanalom'),
+ (5215, 'Ro\u010dinj'),
+ (5216, 'Most na So\u010di'),
+ (5220, 'Tolmin'),
+ (5222, 'Kobarid'),
+ (5223, 'Breginj'),
+ (5224, 'Srpenica'),
+ (5230, 'Bovec'),
+ (5231, 'Log pod Mangartom'),
+ (5232, 'So\u010da'),
+ (5242, 'Grahovo ob Ba\u010di'),
+ (5243, 'Podbrdo'),
+ (5250, 'Solkan'),
+ (5251, 'Grgar'),
+ (5252, 'Trnovo pri Gorici'),
+ (5253, '\u010cepovan'),
+ (5261, '\u0160empas'),
+ (5262, '\u010crni\u010de'),
+ (5263, 'Dobravlje'),
+ (5270, 'Ajdov\u0161\u010dina'),
+ (5271, 'Vipava'),
+ (5272, 'Podnanos'),
+ (5273, 'Col'),
+ (5274, '\u010crni Vrh nad Idrijo'),
+ (5275, 'Godovi\u010d'),
+ (5280, 'Idrija'),
+ (5281, 'Spodnja Idrija'),
+ (5282, 'Cerkno'),
+ (5283, 'Slap ob Idrijci'),
+ (5290, '\u0160empeter pri Gorici'),
+ (5291, 'Miren'),
+ (5292, 'Ren\u010de'),
+ (5293, 'Vol\u010dja Draga'),
+ (5294, 'Dornberk'),
+ (5295, 'Branik'),
+ (5296, 'Kostanjevica na Krasu'),
+ (5297, 'Prva\u010dina'),
+ (6000, 'Koper'),
+ (6210, 'Se\u017eana'),
+ (6215, 'Diva\u010da'),
+ (6216, 'Podgorje'),
+ (6217, 'Vremski Britof'),
+ (6219, 'Lokev'),
+ (6221, 'Dutovlje'),
+ (6222, '\u0160tanjel'),
+ (6223, 'Komen'),
+ (6224, 'Seno\u017ee\u010de'),
+ (6225, 'Hru\u0161evje'),
+ (6230, 'Postojna'),
+ (6232, 'Planina'),
+ (6240, 'Kozina'),
+ (6242, 'Materija'),
+ (6243, 'Obrov'),
+ (6244, 'Podgrad'),
+ (6250, 'Ilirska Bistrica'),
+ (6251, 'Ilirska Bistrica - Trnovo'),
+ (6253, 'Kne\u017eak'),
+ (6254, 'Jel\u0161ane'),
+ (6255, 'Prem'),
+ (6256, 'Ko\u0161ana'),
+ (6257, 'Pivka'),
+ (6258, 'Prestranek'),
+ (6271, 'Dekani'),
+ (6272, 'Gra\u010di\u0161\u010de'),
+ (6273, 'Marezige'),
+ (6274, '\u0160marje'),
+ (6275, '\u010crni Kal'),
+ (6276, 'Pobegi'),
+ (6280, 'Ankaran - Ancarano'),
+ (6281, '\u0160kofije'),
+ (6310, 'Izola - Isola'),
+ (6320, 'Portoro\u017e - Portorose'),
+ (6330, 'Piran - Pirano'),
+ (6333, 'Se\u010dovlje - Sicciole'),
+ (8000, 'Novo mesto'),
+ (8210, 'Trebnje'),
+ (8211, 'Dobrni\u010d'),
+ (8212, 'Velika Loka'),
+ (8213, 'Veliki Gaber'),
+ (8216, 'Mirna Pe\u010d'),
+ (8220, '\u0160marje\u0161ke Toplice'),
+ (8222, 'Oto\u010dec'),
+ (8230, 'Mokronog'),
+ (8231, 'Trebelno'),
+ (8232, '\u0160entrupert'),
+ (8233, 'Mirna'),
+ (8250, 'Bre\u017eice'),
+ (8251, '\u010cate\u017e ob Savi'),
+ (8253, 'Arti\u010de'),
+ (8254, 'Globoko'),
+ (8255, 'Pi\u0161ece'),
+ (8256, 'Sromlje'),
+ (8257, 'Dobova'),
+ (8258, 'Kapele'),
+ (8259, 'Bizeljsko'),
+ (8261, 'Jesenice na Dolenjskem'),
+ (8262, 'Kr\u0161ka vas'),
+ (8263, 'Cerklje ob Krki'),
+ (8270, 'Kr\u0161ko'),
+ (8272, 'Zdole'),
+ (8273, 'Leskovec pri Kr\u0161kem'),
+ (8274, 'Raka'),
+ (8275, '\u0160kocjan'),
+ (8276, 'Bu\u010dka'),
+ (8280, 'Brestanica'),
+ (8281, 'Senovo'),
+ (8282, 'Koprivnica'),
+ (8283, 'Blanca'),
+ (8290, 'Sevnica'),
+ (8292, 'Zabukovje'),
+ (8293, 'Studenec'),
+ (8294, 'Bo\u0161tanj'),
+ (8295, 'Tr\u017ei\u0161\u010de'),
+ (8296, 'Krmelj'),
+ (8297, '\u0160entjan\u017e'),
+ (8310, '\u0160entjernej'),
+ (8311, 'Kostanjevica na Krki'),
+ (8312, 'Podbo\u010dje'),
+ (8321, 'Brusnice'),
+ (8322, 'Stopi\u010de'),
+ (8323, 'Ur\u0161na sela'),
+ (8330, 'Metlika'),
+ (8331, 'Suhor'),
+ (8332, 'Gradac'),
+ (8333, 'Semi\u010d'),
+ (8340, '\u010crnomelj'),
+ (8341, 'Adle\u0161i\u010di'),
+ (8342, 'Stari trg ob Kolpi'),
+ (8343, 'Dragatu\u0161'),
+ (8344, 'Vinica pri \u010crnomlju'),
+ (8350, 'Dolenjske Toplice'),
+ (8351, 'Stra\u017ea'),
+ (8360, '\u017du\u017eemberk'),
+ (8361, 'Dvor'),
+ (8362, 'Hinje'),
+ (9000, 'Murska Sobota'),
+ (9201, 'Puconci'),
+ (9202, 'Ma\u010dkovci'),
+ (9203, 'Petrovci'),
+ (9204, '\u0160alovci'),
+ (9205, 'Hodo\u0161 - Hodos'),
+ (9206, 'Kri\u017eevci'),
+ (9207, 'Prosenjakovci - Partosfalva'),
+ (9208, 'Fokovci'),
+ (9220, 'Lendava - Lendva'),
+ (9221, 'Martjanci'),
+ (9222, 'Bogojina'),
+ (9223, 'Dobrovnik - Dobronak'),
+ (9224, 'Turni\u0161\u010de'),
+ (9225, 'Velika Polana'),
+ (9226, 'Moravske Toplice'),
+ (9227, 'Kobilje'),
+ (9231, 'Beltinci'),
+ (9232, '\u010cren\u0161ovci'),
+ (9233, 'Odranci'),
+ (9240, 'Ljutomer'),
+ (9241, 'Ver\u017eej'),
+ (9242, 'Kri\u017eevci pri Ljutomeru'),
+ (9243, 'Mala Nedelja'),
+ (9244, 'Sveti Jurij ob \u0160\u010davnici'),
+ (9245, 'Spodnji Ivanjci'),
+ (9250, 'Gornja Radgona'),
+ (9251, 'Ti\u0161ina'),
+ (9252, 'Radenci'),
+ (9253, 'Apa\u010de'),
+ (9261, 'Cankova'),
+ (9262, 'Roga\u0161ovci'),
+ (9263, 'Kuzma'),
+ (9264, 'Grad'),
+ (9265, 'Bodonci'),
]
SI_POSTALCODES_CHOICES = sorted(SI_POSTALCODES, key=lambda k: k[1])
diff --git a/django/contrib/localflavor/sk/forms.py b/django/contrib/localflavor/sk/forms.py
index 83afeb41b9..11d44cc4d2 100644
--- a/django/contrib/localflavor/sk/forms.py
+++ b/django/contrib/localflavor/sk/forms.py
@@ -2,7 +2,7 @@
Slovak-specific form helpers
"""
-from __future__ import absolute_import
+from __future__ import absolute_import, unicode_literals
from django.contrib.localflavor.sk.sk_districts import DISTRICT_CHOICES
from django.contrib.localflavor.sk.sk_regions import REGION_CHOICES
@@ -30,7 +30,7 @@ class SKPostalCodeField(RegexField):
Valid form is XXXXX or XXX XX, where X represents integer.
"""
default_error_messages = {
- 'invalid': _(u'Enter a postal code in the format XXXXX or XXX XX.'),
+ 'invalid': _('Enter a postal code in the format XXXXX or XXX XX.'),
}
def __init__(self, max_length=None, min_length=None, *args, **kwargs):
diff --git a/django/contrib/localflavor/tr/forms.py b/django/contrib/localflavor/tr/forms.py
index 77a2b41986..c4f928e670 100644
--- a/django/contrib/localflavor/tr/forms.py
+++ b/django/contrib/localflavor/tr/forms.py
@@ -2,7 +2,7 @@
TR-specific Form helpers
"""
-from __future__ import absolute_import
+from __future__ import absolute_import, unicode_literals
import re
@@ -10,7 +10,7 @@ from django.contrib.localflavor.tr.tr_provinces import PROVINCE_CHOICES
from django.core.validators import EMPTY_VALUES
from django.forms import ValidationError
from django.forms.fields import Field, RegexField, Select, CharField
-from django.utils.encoding import smart_unicode
+from django.utils.encoding import smart_text
from django.utils.translation import ugettext_lazy as _
@@ -18,7 +18,7 @@ phone_digits_re = re.compile(r'^(\+90|0)? ?(([1-9]\d{2})|\([1-9]\d{2}\)) ?([2-9]
class TRPostalCodeField(RegexField):
default_error_messages = {
- 'invalid': _(u'Enter a postal code in the format XXXXX.'),
+ 'invalid': _('Enter a postal code in the format XXXXX.'),
}
def __init__(self, max_length=5, min_length=5, *args, **kwargs):
@@ -28,7 +28,7 @@ class TRPostalCodeField(RegexField):
def clean(self, value):
value = super(TRPostalCodeField, self).clean(value)
if value in EMPTY_VALUES:
- return u''
+ return ''
if len(value) != 5:
raise ValidationError(self.error_messages['invalid'])
province_code = int(value[:2])
@@ -39,17 +39,17 @@ class TRPostalCodeField(RegexField):
class TRPhoneNumberField(CharField):
default_error_messages = {
- 'invalid': _(u'Phone numbers must be in 0XXX XXX XXXX format.'),
+ 'invalid': _('Phone numbers must be in 0XXX XXX XXXX format.'),
}
def clean(self, value):
super(TRPhoneNumberField, self).clean(value)
if value in EMPTY_VALUES:
- return u''
- value = re.sub('(\(|\)|\s+)', '', smart_unicode(value))
+ return ''
+ value = re.sub('(\(|\)|\s+)', '', smart_text(value))
m = phone_digits_re.search(value)
if m:
- return u'%s%s' % (m.group(2), m.group(4))
+ return '%s%s' % (m.group(2), m.group(4))
raise ValidationError(self.error_messages['invalid'])
class TRIdentificationNumberField(Field):
@@ -66,24 +66,24 @@ class TRIdentificationNumberField(Field):
sum(1st to 10th) % 10 = 11th digit
"""
default_error_messages = {
- 'invalid': _(u'Enter a valid Turkish Identification number.'),
- 'not_11': _(u'Turkish Identification number must be 11 digits.'),
+ 'invalid': _('Enter a valid Turkish Identification number.'),
+ 'not_11': _('Turkish Identification number must be 11 digits.'),
}
def clean(self, value):
super(TRIdentificationNumberField, self).clean(value)
if value in EMPTY_VALUES:
- return u''
+ return ''
if len(value) != 11:
raise ValidationError(self.error_messages['not_11'])
if not re.match(r'^\d{11}$', value):
raise ValidationError(self.error_messages['invalid'])
if int(value[0]) == 0:
raise ValidationError(self.error_messages['invalid'])
- chksum = (sum([int(value[i]) for i in xrange(0,9,2)])*7-
- sum([int(value[i]) for i in xrange(1,9,2)])) % 10
+ chksum = (sum([int(value[i]) for i in range(0, 9, 2)]) * 7 -
+ sum([int(value[i]) for i in range(1, 9, 2)])) % 10
if chksum != int(value[9]) or \
- (sum([int(value[i]) for i in xrange(10)]) % 10) != int(value[10]):
+ (sum([int(value[i]) for i in range(10)]) % 10) != int(value[10]):
raise ValidationError(self.error_messages['invalid'])
return value
diff --git a/django/contrib/localflavor/tr/tr_provinces.py b/django/contrib/localflavor/tr/tr_provinces.py
index 060a6cdaf6..edad74710d 100644
--- a/django/contrib/localflavor/tr/tr_provinces.py
+++ b/django/contrib/localflavor/tr/tr_provinces.py
@@ -3,6 +3,7 @@
This exists in this standalone file so that it's only imported into memory
when explicitly needed.
"""
+from __future__ import unicode_literals
PROVINCE_CHOICES = (
('01', ('Adana')),
diff --git a/django/contrib/localflavor/us/forms.py b/django/contrib/localflavor/us/forms.py
index 0a79c40a47..437bb7c466 100644
--- a/django/contrib/localflavor/us/forms.py
+++ b/django/contrib/localflavor/us/forms.py
@@ -2,14 +2,14 @@
USA-specific Form helpers
"""
-from __future__ import absolute_import
+from __future__ import absolute_import, unicode_literals
import re
from django.core.validators import EMPTY_VALUES
from django.forms import ValidationError
from django.forms.fields import Field, RegexField, Select, CharField
-from django.utils.encoding import smart_unicode
+from django.utils.encoding import smart_text
from django.utils.translation import ugettext_lazy as _
@@ -33,11 +33,11 @@ class USPhoneNumberField(CharField):
def clean(self, value):
super(USPhoneNumberField, self).clean(value)
if value in EMPTY_VALUES:
- return u''
- value = re.sub('(\(|\)|\s+)', '', smart_unicode(value))
+ return ''
+ value = re.sub('(\(|\)|\s+)', '', smart_text(value))
m = phone_digits_re.search(value)
if m:
- return u'%s-%s-%s' % (m.group(1), m.group(2), m.group(3))
+ return '%s-%s-%s' % (m.group(1), m.group(2), m.group(3))
raise ValidationError(self.error_messages['invalid'])
class USSocialSecurityNumberField(Field):
@@ -62,7 +62,7 @@ class USSocialSecurityNumberField(Field):
def clean(self, value):
super(USSocialSecurityNumberField, self).clean(value)
if value in EMPTY_VALUES:
- return u''
+ return ''
match = re.match(ssn_re, value)
if not match:
raise ValidationError(self.error_messages['invalid'])
@@ -80,7 +80,7 @@ class USSocialSecurityNumberField(Field):
value == '078-05-1120' or \
value == '219-09-9999':
raise ValidationError(self.error_messages['invalid'])
- return u'%s-%s-%s' % (area, group, serial)
+ return '%s-%s-%s' % (area, group, serial)
class USStateField(Field):
"""
@@ -93,17 +93,17 @@ class USStateField(Field):
}
def clean(self, value):
- from django.contrib.localflavor.us.us_states import STATES_NORMALIZED
+ from .us_states import STATES_NORMALIZED
super(USStateField, self).clean(value)
if value in EMPTY_VALUES:
- return u''
+ return ''
try:
value = value.strip().lower()
except AttributeError:
pass
else:
try:
- return STATES_NORMALIZED[value.strip().lower()].decode('ascii')
+ return STATES_NORMALIZED[value.strip().lower()]
except KeyError:
pass
raise ValidationError(self.error_messages['invalid'])
@@ -113,7 +113,7 @@ class USStateSelect(Select):
A Select widget that uses a list of U.S. states/territories as its choices.
"""
def __init__(self, attrs=None):
- from django.contrib.localflavor.us.us_states import STATE_CHOICES
+ from .us_states import STATE_CHOICES
super(USStateSelect, self).__init__(attrs, choices=STATE_CHOICES)
class USPSSelect(Select):
@@ -122,5 +122,5 @@ class USPSSelect(Select):
choices.
"""
def __init__(self, attrs=None):
- from django.contrib.localflavor.us.us_states import USPS_CHOICES
+ from .us_states import USPS_CHOICES
super(USPSSelect, self).__init__(attrs, choices=USPS_CHOICES)
diff --git a/django/contrib/localflavor/uy/forms.py b/django/contrib/localflavor/uy/forms.py
index 211216222d..658defc0f0 100644
--- a/django/contrib/localflavor/uy/forms.py
+++ b/django/contrib/localflavor/uy/forms.py
@@ -3,7 +3,7 @@
UY-specific form helpers.
"""
-from __future__ import absolute_import
+from __future__ import absolute_import, unicode_literals
from django.core.validators import EMPTY_VALUES
from django.forms.fields import Select, RegexField
@@ -47,7 +47,7 @@ class UYCIField(RegexField):
value = super(UYCIField, self).clean(value)
if value in EMPTY_VALUES:
- return u''
+ return ''
match = self.regex.match(value)
if not match:
raise ValidationError(self.error_messages['invalid'])
diff --git a/django/contrib/localflavor/uy/uy_departaments.py b/django/contrib/localflavor/uy/uy_departaments.py
index 97795f8e82..800937c582 100644
--- a/django/contrib/localflavor/uy/uy_departaments.py
+++ b/django/contrib/localflavor/uy/uy_departaments.py
@@ -1,24 +1,25 @@
# -*- coding: utf-8 -*-
"""A list of Urguayan departaments as `choices` in a formfield."""
+from __future__ import unicode_literals
DEPARTAMENT_CHOICES = (
- ('G', u'Artigas'),
- ('A', u'Canelones'),
- ('E', u'Cerro Largo'),
- ('L', u'Colonia'),
- ('Q', u'Durazno'),
- ('N', u'Flores'),
- ('O', u'Florida'),
- ('P', u'Lavalleja'),
- ('B', u'Maldonado'),
- ('S', u'Montevideo'),
- ('I', u'Paysandú'),
- ('J', u'Río Negro'),
- ('F', u'Rivera'),
- ('C', u'Rocha'),
- ('H', u'Salto'),
- ('M', u'San José'),
- ('K', u'Soriano'),
- ('R', u'Tacuarembó'),
- ('D', u'Treinta y Tres'),
+ ('G', 'Artigas'),
+ ('A', 'Canelones'),
+ ('E', 'Cerro Largo'),
+ ('L', 'Colonia'),
+ ('Q', 'Durazno'),
+ ('N', 'Flores'),
+ ('O', 'Florida'),
+ ('P', 'Lavalleja'),
+ ('B', 'Maldonado'),
+ ('S', 'Montevideo'),
+ ('I', 'Paysandú'),
+ ('J', 'Río Negro'),
+ ('F', 'Rivera'),
+ ('C', 'Rocha'),
+ ('H', 'Salto'),
+ ('M', 'San José'),
+ ('K', 'Soriano'),
+ ('R', 'Tacuarembó'),
+ ('D', 'Treinta y Tres'),
)
diff --git a/django/contrib/localflavor/za/forms.py b/django/contrib/localflavor/za/forms.py
index a9e2cd60c8..a818c14428 100644
--- a/django/contrib/localflavor/za/forms.py
+++ b/django/contrib/localflavor/za/forms.py
@@ -1,6 +1,7 @@
"""
South Africa-specific Form helpers
"""
+from __future__ import unicode_literals
from django.core.validators import EMPTY_VALUES
from django.forms import ValidationError
@@ -18,14 +19,14 @@ class ZAIDField(CharField):
check for the birthdate
"""
default_error_messages = {
- 'invalid': _(u'Enter a valid South African ID number'),
+ 'invalid': _('Enter a valid South African ID number'),
}
def clean(self, value):
super(ZAIDField, self).clean(value)
if value in EMPTY_VALUES:
- return u''
+ return ''
# strip spaces and dashes
value = value.strip().replace(' ', '').replace('-', '')
@@ -52,7 +53,7 @@ class ZAIDField(CharField):
class ZAPostCodeField(RegexField):
default_error_messages = {
- 'invalid': _(u'Enter a valid South African postal code'),
+ 'invalid': _('Enter a valid South African postal code'),
}
def __init__(self, max_length=None, min_length=None, *args, **kwargs):
diff --git a/django/contrib/markup/templatetags/markup.py b/django/contrib/markup/templatetags/markup.py
index 84251cf30a..af9c842f42 100644
--- a/django/contrib/markup/templatetags/markup.py
+++ b/django/contrib/markup/templatetags/markup.py
@@ -13,7 +13,7 @@ markup syntaxes to HTML; currently there is support for:
from django import template
from django.conf import settings
-from django.utils.encoding import smart_str, force_unicode
+from django.utils.encoding import smart_bytes, force_text
from django.utils.safestring import mark_safe
register = template.Library()
@@ -25,9 +25,9 @@ def textile(value):
except ImportError:
if settings.DEBUG:
raise template.TemplateSyntaxError("Error in 'textile' filter: The Python textile library isn't installed.")
- return force_unicode(value)
+ return force_text(value)
else:
- return mark_safe(force_unicode(textile.textile(smart_str(value), encoding='utf-8', output='utf-8')))
+ return mark_safe(force_text(textile.textile(smart_bytes(value), encoding='utf-8', output='utf-8')))
@register.filter(is_safe=True)
def markdown(value, arg=''):
@@ -52,23 +52,23 @@ def markdown(value, arg=''):
except ImportError:
if settings.DEBUG:
raise template.TemplateSyntaxError("Error in 'markdown' filter: The Python markdown library isn't installed.")
- return force_unicode(value)
+ return force_text(value)
else:
markdown_vers = getattr(markdown, "version_info", 0)
if markdown_vers < (2, 1):
if settings.DEBUG:
raise template.TemplateSyntaxError(
"Error in 'markdown' filter: Django does not support versions of the Python markdown library < 2.1.")
- return force_unicode(value)
+ return force_text(value)
else:
extensions = [e for e in arg.split(",") if e]
if extensions and extensions[0] == "safe":
extensions = extensions[1:]
return mark_safe(markdown.markdown(
- force_unicode(value), extensions, safe_mode=True, enable_attributes=False))
+ force_text(value), extensions, safe_mode=True, enable_attributes=False))
else:
return mark_safe(markdown.markdown(
- force_unicode(value), extensions, safe_mode=False))
+ force_text(value), extensions, safe_mode=False))
@register.filter(is_safe=True)
def restructuredtext(value):
@@ -77,8 +77,8 @@ def restructuredtext(value):
except ImportError:
if settings.DEBUG:
raise template.TemplateSyntaxError("Error in 'restructuredtext' filter: The Python docutils library isn't installed.")
- return force_unicode(value)
+ return force_text(value)
else:
docutils_settings = getattr(settings, "RESTRUCTUREDTEXT_FILTER_SETTINGS", {})
- parts = publish_parts(source=smart_str(value), writer_name="html4css1", settings_overrides=docutils_settings)
- return mark_safe(force_unicode(parts["fragment"]))
+ parts = publish_parts(source=smart_bytes(value), writer_name="html4css1", settings_overrides=docutils_settings)
+ return mark_safe(force_text(parts["fragment"]))
diff --git a/django/contrib/messages/storage/base.py b/django/contrib/messages/storage/base.py
index 65e8526b5c..7fe8a077ed 100644
--- a/django/contrib/messages/storage/base.py
+++ b/django/contrib/messages/storage/base.py
@@ -1,12 +1,15 @@
+from __future__ import unicode_literals
+
from django.conf import settings
-from django.utils.encoding import force_unicode, StrAndUnicode
+from django.utils.encoding import force_text, python_2_unicode_compatible
from django.contrib.messages import constants, utils
LEVEL_TAGS = utils.get_level_tags()
-class Message(StrAndUnicode):
+@python_2_unicode_compatible
+class Message(object):
"""
Represents an actual message that can be stored in any of the supported
storage classes (typically session- or cookie-based) and rendered in a view
@@ -24,24 +27,24 @@ class Message(StrAndUnicode):
and ``extra_tags`` to unicode in case they are lazy translations.
Known "safe" types (None, int, etc.) are not converted (see Django's
- ``force_unicode`` implementation for details).
+ ``force_text`` implementation for details).
"""
- self.message = force_unicode(self.message, strings_only=True)
- self.extra_tags = force_unicode(self.extra_tags, strings_only=True)
+ self.message = force_text(self.message, strings_only=True)
+ self.extra_tags = force_text(self.extra_tags, strings_only=True)
def __eq__(self, other):
return isinstance(other, Message) and self.level == other.level and \
self.message == other.message
- def __unicode__(self):
- return force_unicode(self.message)
+ def __str__(self):
+ return force_text(self.message)
def _get_tags(self):
- label_tag = force_unicode(LEVEL_TAGS.get(self.level, ''),
+ label_tag = force_text(LEVEL_TAGS.get(self.level, ''),
strings_only=True)
- extra_tags = force_unicode(self.extra_tags, strings_only=True)
+ extra_tags = force_text(self.extra_tags, strings_only=True)
if extra_tags and label_tag:
- return u' '.join([extra_tags, label_tag])
+ return ' '.join([extra_tags, label_tag])
elif extra_tags:
return extra_tags
elif label_tag:
diff --git a/django/contrib/messages/storage/cookie.py b/django/contrib/messages/storage/cookie.py
index 07620050c7..5f64ccd0c5 100644
--- a/django/contrib/messages/storage/cookie.py
+++ b/django/contrib/messages/storage/cookie.py
@@ -4,6 +4,7 @@ from django.conf import settings
from django.contrib.messages.storage.base import BaseStorage, Message
from django.http import SimpleCookie
from django.utils.crypto import salted_hmac, constant_time_compare
+from django.utils import six
class MessageEncoder(json.JSONEncoder):
@@ -33,7 +34,7 @@ class MessageDecoder(json.JSONDecoder):
return [self.process_messages(item) for item in obj]
if isinstance(obj, dict):
return dict([(key, self.process_messages(value))
- for key, value in obj.iteritems()])
+ for key, value in six.iteritems(obj)])
return obj
def decode(self, s, **kwargs):
diff --git a/django/contrib/messages/tests/base.py b/django/contrib/messages/tests/base.py
index 1f64c61ecb..e9a67b0500 100644
--- a/django/contrib/messages/tests/base.py
+++ b/django/contrib/messages/tests/base.py
@@ -152,7 +152,7 @@ class BaseTest(TestCase):
cycle.
"""
data = {
- 'messages': ['Test message %d' % x for x in xrange(10)],
+ 'messages': ['Test message %d' % x for x in range(10)],
}
show_url = reverse('django.contrib.messages.tests.urls.show')
for level in ('debug', 'info', 'success', 'warning', 'error'):
@@ -170,7 +170,7 @@ class BaseTest(TestCase):
@override_settings(MESSAGE_LEVEL=constants.DEBUG)
def test_with_template_response(self):
data = {
- 'messages': ['Test message %d' % x for x in xrange(10)],
+ 'messages': ['Test message %d' % x for x in range(10)],
}
show_url = reverse('django.contrib.messages.tests.urls.show_template_response')
for level in self.levels.keys():
@@ -194,7 +194,7 @@ class BaseTest(TestCase):
before a GET.
"""
data = {
- 'messages': ['Test message %d' % x for x in xrange(10)],
+ 'messages': ['Test message %d' % x for x in range(10)],
}
show_url = reverse('django.contrib.messages.tests.urls.show')
messages = []
@@ -226,7 +226,7 @@ class BaseTest(TestCase):
when one attempts to store a message.
"""
data = {
- 'messages': ['Test message %d' % x for x in xrange(10)],
+ 'messages': ['Test message %d' % x for x in range(10)],
}
show_url = reverse('django.contrib.messages.tests.urls.show')
for level in ('debug', 'info', 'success', 'warning', 'error'):
@@ -251,7 +251,7 @@ class BaseTest(TestCase):
raised if 'fail_silently' = True
"""
data = {
- 'messages': ['Test message %d' % x for x in xrange(10)],
+ 'messages': ['Test message %d' % x for x in range(10)],
'fail_silently': True,
}
show_url = reverse('django.contrib.messages.tests.urls.show')
diff --git a/django/contrib/messages/tests/cookie.py b/django/contrib/messages/tests/cookie.py
index 19d0e08384..e0668ab604 100644
--- a/django/contrib/messages/tests/cookie.py
+++ b/django/contrib/messages/tests/cookie.py
@@ -39,7 +39,7 @@ def stored_cookie_messages_count(storage, response):
return len(data)
-@override_settings(SESSION_COOKIE_DOMAIN='.lawrence.com')
+@override_settings(SESSION_COOKIE_DOMAIN='.example.com')
class CookieTest(BaseTest):
storage_class = CookieStorage
@@ -65,7 +65,7 @@ class CookieTest(BaseTest):
storage.add(constants.INFO, 'test')
storage.update(response)
self.assertTrue('test' in response.cookies['messages'].value)
- self.assertEqual(response.cookies['messages']['domain'], '.lawrence.com')
+ self.assertEqual(response.cookies['messages']['domain'], '.example.com')
self.assertEqual(response.cookies['messages']['expires'], '')
# Test after the messages have been consumed
@@ -76,7 +76,7 @@ class CookieTest(BaseTest):
pass # Iterate through the storage to simulate consumption of messages.
storage.update(response)
self.assertEqual(response.cookies['messages'].value, '')
- self.assertEqual(response.cookies['messages']['domain'], '.lawrence.com')
+ self.assertEqual(response.cookies['messages']['domain'], '.example.com')
self.assertEqual(response.cookies['messages']['expires'], 'Thu, 01-Jan-1970 00:00:00 GMT')
def test_get_bad_cookie(self):
@@ -123,7 +123,7 @@ class CookieTest(BaseTest):
{
'message': Message(constants.INFO, 'Test message'),
'message_list': [Message(constants.INFO, 'message %s') \
- for x in xrange(5)] + [{'another-message': \
+ for x in range(5)] + [{'another-message': \
Message(constants.ERROR, 'error')}],
},
Message(constants.INFO, 'message %s'),
diff --git a/django/contrib/redirects/models.py b/django/contrib/redirects/models.py
index 4233d55793..a0376b5578 100644
--- a/django/contrib/redirects/models.py
+++ b/django/contrib/redirects/models.py
@@ -1,7 +1,9 @@
from django.db import models
from django.contrib.sites.models import Site
from django.utils.translation import ugettext_lazy as _
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class Redirect(models.Model):
site = models.ForeignKey(Site)
old_path = models.CharField(_('redirect from'), max_length=200, db_index=True,
@@ -15,6 +17,6 @@ class Redirect(models.Model):
db_table = 'django_redirect'
unique_together=(('site', 'old_path'),)
ordering = ('old_path',)
-
- def __unicode__(self):
+
+ def __str__(self):
return "%s ---> %s" % (self.old_path, self.new_path)
diff --git a/django/contrib/sessions/backends/base.py b/django/contrib/sessions/backends/base.py
index 5a637e24d2..2fb7991b49 100644
--- a/django/contrib/sessions/backends/base.py
+++ b/django/contrib/sessions/backends/base.py
@@ -1,8 +1,10 @@
+from __future__ import unicode_literals
+
import base64
import time
from datetime import datetime, timedelta
try:
- import cPickle as pickle
+ from django.utils.six.moves import cPickle as pickle
except ImportError:
import pickle
@@ -12,6 +14,7 @@ from django.utils.crypto import constant_time_compare
from django.utils.crypto import get_random_string
from django.utils.crypto import salted_hmac
from django.utils import timezone
+from django.utils.encoding import smart_bytes
class CreateError(Exception):
"""
@@ -78,15 +81,15 @@ class SessionBase(object):
"Returns the given session dictionary pickled and encoded as a string."
pickled = pickle.dumps(session_dict, pickle.HIGHEST_PROTOCOL)
hash = self._hash(pickled)
- return base64.encodestring(hash + ":" + pickled)
+ return base64.b64encode(hash.encode() + b":" + pickled).decode('ascii')
def decode(self, session_data):
- encoded_data = base64.decodestring(session_data)
+ encoded_data = base64.b64decode(smart_bytes(session_data))
try:
# could produce ValueError if there is no ':'
- hash, pickled = encoded_data.split(':', 1)
+ hash, pickled = encoded_data.split(b':', 1)
expected_hash = self._hash(pickled)
- if not constant_time_compare(hash, expected_hash):
+ if not constant_time_compare(hash.decode(), expected_hash):
raise SuspiciousOperation("Session data corrupted")
else:
return pickle.loads(pickled)
diff --git a/django/contrib/sessions/backends/cache.py b/django/contrib/sessions/backends/cache.py
index 467d5f1265..b66123b915 100644
--- a/django/contrib/sessions/backends/cache.py
+++ b/django/contrib/sessions/backends/cache.py
@@ -1,5 +1,6 @@
from django.contrib.sessions.backends.base import SessionBase, CreateError
from django.core.cache import cache
+from django.utils.six.moves import xrange
KEY_PREFIX = "django.contrib.sessions.cache"
diff --git a/django/contrib/sessions/backends/db.py b/django/contrib/sessions/backends/db.py
index 3dd0d9516c..babdb72c27 100644
--- a/django/contrib/sessions/backends/db.py
+++ b/django/contrib/sessions/backends/db.py
@@ -1,7 +1,6 @@
from django.contrib.sessions.backends.base import SessionBase, CreateError
from django.core.exceptions import SuspiciousOperation
from django.db import IntegrityError, transaction, router
-from django.utils.encoding import force_unicode
from django.utils import timezone
@@ -18,7 +17,7 @@ class SessionStore(SessionBase):
session_key = self.session_key,
expire_date__gt=timezone.now()
)
- return self.decode(force_unicode(s.session_data))
+ return self.decode(s.session_data)
except (Session.DoesNotExist, SuspiciousOperation):
self.create()
return {}
diff --git a/django/contrib/sessions/backends/file.py b/django/contrib/sessions/backends/file.py
index 0f869088ac..20ac2c2087 100644
--- a/django/contrib/sessions/backends/file.py
+++ b/django/contrib/sessions/backends/file.py
@@ -115,7 +115,7 @@ class SessionStore(SessionBase):
renamed = False
try:
try:
- os.write(output_file_fd, self.encode(session_data))
+ os.write(output_file_fd, self.encode(session_data).encode())
finally:
os.close(output_file_fd)
os.rename(output_file_name, session_file_name)
diff --git a/django/contrib/sessions/backends/signed_cookies.py b/django/contrib/sessions/backends/signed_cookies.py
index 2a0f261441..41ba7af634 100644
--- a/django/contrib/sessions/backends/signed_cookies.py
+++ b/django/contrib/sessions/backends/signed_cookies.py
@@ -1,5 +1,5 @@
try:
- import cPickle as pickle
+ from django.utils.six.moves import cPickle as pickle
except ImportError:
import pickle
diff --git a/django/contrib/sessions/middleware.py b/django/contrib/sessions/middleware.py
index 68cb77f7e1..9f65255f47 100644
--- a/django/contrib/sessions/middleware.py
+++ b/django/contrib/sessions/middleware.py
@@ -33,11 +33,13 @@ class SessionMiddleware(object):
expires_time = time.time() + max_age
expires = cookie_date(expires_time)
# Save the session data and refresh the client cookie.
- request.session.save()
- response.set_cookie(settings.SESSION_COOKIE_NAME,
- request.session.session_key, max_age=max_age,
- expires=expires, domain=settings.SESSION_COOKIE_DOMAIN,
- path=settings.SESSION_COOKIE_PATH,
- secure=settings.SESSION_COOKIE_SECURE or None,
- httponly=settings.SESSION_COOKIE_HTTPONLY or None)
+ # Skip session save for 500 responses, refs #3881.
+ if response.status_code != 500:
+ request.session.save()
+ response.set_cookie(settings.SESSION_COOKIE_NAME,
+ request.session.session_key, max_age=max_age,
+ expires=expires, domain=settings.SESSION_COOKIE_DOMAIN,
+ path=settings.SESSION_COOKIE_PATH,
+ secure=settings.SESSION_COOKIE_SECURE or None,
+ httponly=settings.SESSION_COOKIE_HTTPONLY or None)
return response
diff --git a/django/contrib/sessions/tests.py b/django/contrib/sessions/tests.py
index 92ea6bbd91..7de2941122 100644
--- a/django/contrib/sessions/tests.py
+++ b/django/contrib/sessions/tests.py
@@ -16,6 +16,7 @@ from django.core.exceptions import ImproperlyConfigured, SuspiciousOperation
from django.http import HttpResponse
from django.test import TestCase, RequestFactory
from django.test.utils import override_settings
+from django.utils import six
from django.utils import timezone
from django.utils import unittest
@@ -86,16 +87,16 @@ class SessionTestsMixin(object):
self.assertFalse(self.session.modified)
def test_values(self):
- self.assertEqual(self.session.values(), [])
+ self.assertEqual(list(self.session.values()), [])
self.assertTrue(self.session.accessed)
self.session['some key'] = 1
- self.assertEqual(self.session.values(), [1])
+ self.assertEqual(list(self.session.values()), [1])
def test_iterkeys(self):
self.session['x'] = 1
self.session.modified = False
self.session.accessed = False
- i = self.session.iterkeys()
+ i = six.iterkeys(self.session)
self.assertTrue(hasattr(i, '__iter__'))
self.assertTrue(self.session.accessed)
self.assertFalse(self.session.modified)
@@ -105,7 +106,7 @@ class SessionTestsMixin(object):
self.session['x'] = 1
self.session.modified = False
self.session.accessed = False
- i = self.session.itervalues()
+ i = six.itervalues(self.session)
self.assertTrue(hasattr(i, '__iter__'))
self.assertTrue(self.session.accessed)
self.assertFalse(self.session.modified)
@@ -115,7 +116,7 @@ class SessionTestsMixin(object):
self.session['x'] = 1
self.session.modified = False
self.session.accessed = False
- i = self.session.iteritems()
+ i = six.iteritems(self.session)
self.assertTrue(hasattr(i, '__iter__'))
self.assertTrue(self.session.accessed)
self.assertFalse(self.session.modified)
@@ -125,9 +126,9 @@ class SessionTestsMixin(object):
self.session['x'] = 1
self.session.modified = False
self.session.accessed = False
- self.assertEqual(self.session.items(), [('x', 1)])
+ self.assertEqual(list(self.session.items()), [('x', 1)])
self.session.clear()
- self.assertEqual(self.session.items(), [])
+ self.assertEqual(list(self.session.items()), [])
self.assertTrue(self.session.accessed)
self.assertTrue(self.session.modified)
@@ -154,10 +155,10 @@ class SessionTestsMixin(object):
self.session['a'], self.session['b'] = 'c', 'd'
self.session.save()
prev_key = self.session.session_key
- prev_data = self.session.items()
+ prev_data = list(self.session.items())
self.session.cycle_key()
self.assertNotEqual(self.session.session_key, prev_key)
- self.assertEqual(self.session.items(), prev_data)
+ self.assertEqual(list(self.session.items()), prev_data)
def test_invalid_key(self):
# Submitting an invalid session key (either by guessing, or if the db has
@@ -409,6 +410,22 @@ class SessionMiddlewareTests(unittest.TestCase):
self.assertNotIn('httponly',
str(response.cookies[settings.SESSION_COOKIE_NAME]))
+ def test_session_save_on_500(self):
+ request = RequestFactory().get('/')
+ response = HttpResponse('Horrible error')
+ response.status_code = 500
+ middleware = SessionMiddleware()
+
+ # Simulate a request the modifies the session
+ middleware.process_request(request)
+ request.session['hello'] = 'world'
+
+ # Handle the response through the middleware
+ response = middleware.process_response(request, response)
+
+ # Check that the value wasn't saved above.
+ self.assertNotIn('hello', request.session.load())
+
class CookieSessionTests(SessionTestsMixin, TestCase):
diff --git a/django/contrib/sitemaps/__init__.py b/django/contrib/sitemaps/__init__.py
index 53b375a48b..7d03ef19f5 100644
--- a/django/contrib/sitemaps/__init__.py
+++ b/django/contrib/sitemaps/__init__.py
@@ -1,7 +1,11 @@
from django.contrib.sites.models import Site
from django.core import urlresolvers, paginator
from django.core.exceptions import ImproperlyConfigured
-import urllib
+try:
+ from urllib.parse import urlencode
+ from urllib.request import urlopen
+except ImportError: # Python 2
+ from urllib import urlencode, urlopen
PING_URL = "http://www.google.com/webmasters/tools/ping"
@@ -32,8 +36,8 @@ def ping_google(sitemap_url=None, ping_url=PING_URL):
from django.contrib.sites.models import Site
current_site = Site.objects.get_current()
url = "http://%s%s" % (current_site.domain, sitemap_url)
- params = urllib.urlencode({'sitemap':url})
- urllib.urlopen("%s?%s" % (ping_url, params))
+ params = urlencode({'sitemap':url})
+ urlopen("%s?%s" % (ping_url, params))
class Sitemap(object):
# This limit is defined by Google. See the index documentation at
diff --git a/django/contrib/sitemaps/tests/flatpages.py b/django/contrib/sitemaps/tests/flatpages.py
index a40876e859..930f24f22c 100644
--- a/django/contrib/sitemaps/tests/flatpages.py
+++ b/django/contrib/sitemaps/tests/flatpages.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
from django.conf import settings
from django.utils.unittest import skipUnless
@@ -17,15 +19,15 @@ class FlatpagesSitemapTests(SitemapTestsBase):
from django.contrib.flatpages.models import FlatPage
public = FlatPage.objects.create(
- url=u'/public/',
- title=u'Public Page',
+ url='/public/',
+ title='Public Page',
enable_comments=True,
registration_required=False,
)
public.sites.add(settings.SITE_ID)
private = FlatPage.objects.create(
- url=u'/private/',
- title=u'Private Page',
+ url='/private/',
+ title='Private Page',
enable_comments=True,
registration_required=True
)
diff --git a/django/contrib/sitemaps/tests/generic.py b/django/contrib/sitemaps/tests/generic.py
index 5f8b6b8be0..e0b0a827a6 100644
--- a/django/contrib/sitemaps/tests/generic.py
+++ b/django/contrib/sitemaps/tests/generic.py
@@ -1,7 +1,11 @@
+from __future__ import unicode_literals
+
from django.contrib.auth.models import User
+from django.test.utils import override_settings
from .base import SitemapTestsBase
+@override_settings(ABSOLUTE_URL_OVERRIDES={})
class GenericViewsSitemapTests(SitemapTestsBase):
def test_generic_sitemap(self):
@@ -10,8 +14,9 @@ class GenericViewsSitemapTests(SitemapTestsBase):
expected = ''
for username in User.objects.values_list("username", flat=True):
expected += "%s/users/%s/" % (self.base_url, username)
- self.assertEqual(response.content, """
+ expected_content = """
%s
-""" % expected)
+""" % expected
+ self.assertEqual(response.content, expected_content.encode('utf-8'))
diff --git a/django/contrib/sitemaps/tests/http.py b/django/contrib/sitemaps/tests/http.py
index 5786aa48d5..8da971876f 100644
--- a/django/contrib/sitemaps/tests/http.py
+++ b/django/contrib/sitemaps/tests/http.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
import os
from datetime import date
@@ -19,11 +21,12 @@ class HTTPSitemapTests(SitemapTestsBase):
def test_simple_sitemap_index(self):
"A simple sitemap index can be rendered"
response = self.client.get('/simple/index.xml')
- self.assertEqual(response.content, """
+ expected_content = """
%s/simple/sitemap-simple.xml
-""" % self.base_url)
+""" % self.base_url
+ self.assertEqual(response.content, expected_content.encode('utf-8'))
@override_settings(
TEMPLATE_DIRS=(os.path.join(os.path.dirname(__file__), 'templates'),)
@@ -31,30 +34,34 @@ class HTTPSitemapTests(SitemapTestsBase):
def test_simple_sitemap_custom_index(self):
"A simple sitemap index can be rendered with a custom template"
response = self.client.get('/simple/custom-index.xml')
- self.assertEqual(response.content, """
+ expected_content = """
%s/simple/sitemap-simple.xml
-""" % self.base_url)
+""" % self.base_url
+ self.assertEqual(response.content, expected_content.encode('utf-8'))
+
def test_simple_sitemap_section(self):
"A simple sitemap section can be rendered"
response = self.client.get('/simple/sitemap-simple.xml')
- self.assertEqual(response.content, """
+ expected_content = """
%s/location/%snever0.5
-""" % (self.base_url, date.today()))
+""" % (self.base_url, date.today())
+ self.assertEqual(response.content, expected_content.encode('utf-8'))
def test_simple_sitemap(self):
"A simple sitemap can be rendered"
response = self.client.get('/simple/sitemap.xml')
- self.assertEqual(response.content, """
+ expected_content = """
%s/location/%snever0.5
-""" % (self.base_url, date.today()))
+""" % (self.base_url, date.today())
+ self.assertEqual(response.content, expected_content.encode('utf-8'))
@override_settings(
TEMPLATE_DIRS=(os.path.join(os.path.dirname(__file__), 'templates'),)
@@ -62,19 +69,20 @@ class HTTPSitemapTests(SitemapTestsBase):
def test_simple_custom_sitemap(self):
"A simple sitemap can be rendered with a custom template"
response = self.client.get('/simple/custom-sitemap.xml')
- self.assertEqual(response.content, """
+ expected_content = """
%s/location/%snever0.5
-""" % (self.base_url, date.today()))
+""" % (self.base_url, date.today())
+ self.assertEqual(response.content, expected_content.encode('utf-8'))
@skipUnless(settings.USE_I18N, "Internationalization is not enabled")
@override_settings(USE_L10N=True)
def test_localized_priority(self):
"The priority value should not be localized (Refs #14164)"
activate('fr')
- self.assertEqual(u'0,3', localize(0.3))
+ self.assertEqual('0,3', localize(0.3))
# Retrieve the sitemap. Check that priorities
# haven't been rendered in localized format
@@ -88,11 +96,12 @@ class HTTPSitemapTests(SitemapTestsBase):
# installed doesn't raise an exception
Site._meta.installed = False
response = self.client.get('/simple/sitemap.xml')
- self.assertEqual(response.content, """
+ expected_content = """
http://testserver/location/%snever0.5
-""" % date.today())
+""" % date.today()
+ self.assertEqual(response.content, expected_content.encode('utf-8'))
@skipUnless("django.contrib.sites" in settings.INSTALLED_APPS,
"django.contrib.sites app not installed.")
@@ -129,8 +138,9 @@ class HTTPSitemapTests(SitemapTestsBase):
Check that a cached sitemap index can be rendered (#2713).
"""
response = self.client.get('/cached/index.xml')
- self.assertEqual(response.content, """
+ expected_content = """
%s/cached/sitemap-simple.xml
-""" % self.base_url)
+""" % self.base_url
+ self.assertEqual(response.content, expected_content.encode('utf-8'))
diff --git a/django/contrib/sitemaps/tests/https.py b/django/contrib/sitemaps/tests/https.py
index d4f9053fc8..26241eb30b 100644
--- a/django/contrib/sitemaps/tests/https.py
+++ b/django/contrib/sitemaps/tests/https.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
from datetime import date
from django.test.utils import override_settings
@@ -11,20 +13,22 @@ class HTTPSSitemapTests(SitemapTestsBase):
def test_secure_sitemap_index(self):
"A secure sitemap index can be rendered"
response = self.client.get('/secure/index.xml')
- self.assertEqual(response.content, """
+ expected_content = """
%s/secure/sitemap-simple.xml
-""" % self.base_url)
+""" % self.base_url
+ self.assertEqual(response.content, expected_content.encode('utf-8'))
def test_secure_sitemap_section(self):
"A secure sitemap section can be rendered"
response = self.client.get('/secure/sitemap-simple.xml')
- self.assertEqual(response.content, """
+ expected_content = """
%s/location/%snever0.5
-""" % (self.base_url, date.today()))
+""" % (self.base_url, date.today())
+ self.assertEqual(response.content, expected_content.encode('utf-8'))
@override_settings(SECURE_PROXY_SSL_HEADER=False)
@@ -34,17 +38,19 @@ class HTTPSDetectionSitemapTests(SitemapTestsBase):
def test_sitemap_index_with_https_request(self):
"A sitemap index requested in HTTPS is rendered with HTTPS links"
response = self.client.get('/simple/index.xml', **self.extra)
- self.assertEqual(response.content, """
+ expected_content = """
%s/simple/sitemap-simple.xml
-""" % self.base_url.replace('http://', 'https://'))
+""" % self.base_url.replace('http://', 'https://')
+ self.assertEqual(response.content, expected_content.encode('utf-8'))
def test_sitemap_section_with_https_request(self):
"A sitemap section requested in HTTPS is rendered with HTTPS links"
response = self.client.get('/simple/sitemap-simple.xml', **self.extra)
- self.assertEqual(response.content, """
+ expected_content = """
%s/location/%snever0.5
-""" % (self.base_url.replace('http://', 'https://'), date.today()))
+""" % (self.base_url.replace('http://', 'https://'), date.today())
+ self.assertEqual(response.content, expected_content.encode('utf-8'))
diff --git a/django/contrib/sitemaps/views.py b/django/contrib/sitemaps/views.py
index b90a39e954..cfe3aa66a9 100644
--- a/django/contrib/sitemaps/views.py
+++ b/django/contrib/sitemaps/views.py
@@ -3,6 +3,7 @@ from django.core import urlresolvers
from django.core.paginator import EmptyPage, PageNotAnInteger
from django.http import Http404
from django.template.response import TemplateResponse
+from django.utils import six
def index(request, sitemaps,
template_name='sitemap_index.xml', mimetype='application/xml',
@@ -35,7 +36,7 @@ def sitemap(request, sitemaps, section=None,
raise Http404("No sitemap available for section: %r" % section)
maps = [sitemaps[section]]
else:
- maps = sitemaps.values()
+ maps = list(six.itervalues(sitemaps))
page = request.GET.get("p", 1)
urls = []
diff --git a/django/contrib/sites/models.py b/django/contrib/sites/models.py
index fecbff79d8..8590740658 100644
--- a/django/contrib/sites/models.py
+++ b/django/contrib/sites/models.py
@@ -1,5 +1,6 @@
from django.db import models
from django.utils.translation import ugettext_lazy as _
+from django.utils.encoding import python_2_unicode_compatible
SITE_CACHE = {}
@@ -32,6 +33,7 @@ class SiteManager(models.Manager):
SITE_CACHE = {}
+@python_2_unicode_compatible
class Site(models.Model):
domain = models.CharField(_('domain name'), max_length=100)
@@ -44,7 +46,7 @@ class Site(models.Model):
verbose_name_plural = _('sites')
ordering = ('domain',)
- def __unicode__(self):
+ def __str__(self):
return self.domain
def save(self, *args, **kwargs):
@@ -62,6 +64,7 @@ class Site(models.Model):
pass
+@python_2_unicode_compatible
class RequestSite(object):
"""
A class that shares the primary interface of Site (i.e., it has
@@ -73,7 +76,7 @@ class RequestSite(object):
def __init__(self, request):
self.domain = self.name = request.get_host()
- def __unicode__(self):
+ def __str__(self):
return self.domain
def save(self, force_insert=False, force_update=False):
diff --git a/django/contrib/sites/tests.py b/django/contrib/sites/tests.py
index 828badb386..1bb2495e6b 100644
--- a/django/contrib/sites/tests.py
+++ b/django/contrib/sites/tests.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
from django.conf import settings
from django.contrib.sites.models import Site, RequestSite, get_current_site
from django.core.exceptions import ObjectDoesNotExist
@@ -32,12 +34,12 @@ class SitesFrameworkTests(TestCase):
# After updating a Site object (e.g. via the admin), we shouldn't return a
# bogus value from the SITE_CACHE.
site = Site.objects.get_current()
- self.assertEqual(u"example.com", site.name)
+ self.assertEqual("example.com", site.name)
s2 = Site.objects.get(id=settings.SITE_ID)
s2.name = "Example site"
s2.save()
site = Site.objects.get_current()
- self.assertEqual(u"Example site", site.name)
+ self.assertEqual("Example site", site.name)
def test_get_current_site(self):
# Test that the correct Site object is returned
@@ -59,4 +61,4 @@ class SitesFrameworkTests(TestCase):
Site._meta.installed = False
site = get_current_site(request)
self.assertTrue(isinstance(site, RequestSite))
- self.assertEqual(site.name, u"example.com")
+ self.assertEqual(site.name, "example.com")
diff --git a/django/contrib/staticfiles/finders.py b/django/contrib/staticfiles/finders.py
index 766687cf7d..9b06c2cf60 100644
--- a/django/contrib/staticfiles/finders.py
+++ b/django/contrib/staticfiles/finders.py
@@ -6,6 +6,7 @@ from django.utils.datastructures import SortedDict
from django.utils.functional import empty, memoize, LazyObject
from django.utils.importlib import import_module
from django.utils._os import safe_join
+from django.utils import six
from django.contrib.staticfiles import utils
from django.contrib.staticfiles.storage import AppStaticStorage
@@ -132,7 +133,7 @@ class AppDirectoriesFinder(BaseFinder):
"""
List all files in all app storages.
"""
- for storage in self.storages.itervalues():
+ for storage in six.itervalues(self.storages):
if storage.exists(''): # check if storage location exists
for path in utils.get_files(storage, ignore_patterns):
yield path, storage
diff --git a/django/contrib/staticfiles/handlers.py b/django/contrib/staticfiles/handlers.py
index f475b22d9c..9067a0e75e 100644
--- a/django/contrib/staticfiles/handlers.py
+++ b/django/contrib/staticfiles/handlers.py
@@ -1,5 +1,9 @@
-import urllib
-from urlparse import urlparse
+try:
+ from urllib.parse import urlparse
+ from urllib.request import url2pathname
+except ImportError: # Python 2
+ from urllib import url2pathname
+ from urlparse import urlparse
from django.conf import settings
from django.core.handlers.wsgi import WSGIHandler
@@ -42,7 +46,7 @@ class StaticFilesHandler(WSGIHandler):
Returns the relative path to the media file on disk for the given URL.
"""
relative_url = url[len(self.base_url[2]):]
- return urllib.url2pathname(relative_url)
+ return url2pathname(relative_url)
def serve(self, request):
"""
diff --git a/django/contrib/staticfiles/management/commands/collectstatic.py b/django/contrib/staticfiles/management/commands/collectstatic.py
index 669c04043b..7dac0ffb4c 100644
--- a/django/contrib/staticfiles/management/commands/collectstatic.py
+++ b/django/contrib/staticfiles/management/commands/collectstatic.py
@@ -1,11 +1,14 @@
+from __future__ import unicode_literals
+
import os
import sys
from optparse import make_option
from django.core.files.storage import FileSystemStorage
from django.core.management.base import CommandError, NoArgsCommand
-from django.utils.encoding import smart_unicode
+from django.utils.encoding import smart_text
from django.utils.datastructures import SortedDict
+from django.utils.six.moves import input
from django.contrib.staticfiles import finders, storage
@@ -117,11 +120,11 @@ class Command(NoArgsCommand):
dry_run=self.dry_run)
for original_path, processed_path, processed in processor:
if processed:
- self.log(u"Post-processed '%s' as '%s" %
+ self.log("Post-processed '%s' as '%s" %
(original_path, processed_path), level=1)
self.post_processed_files.append(original_path)
else:
- self.log(u"Skipped post-processing '%s'" % original_path)
+ self.log("Skipped post-processing '%s'" % original_path)
return {
'modified': self.copied_files + self.symlinked_files,
@@ -146,7 +149,7 @@ class Command(NoArgsCommand):
clear_display = 'This will overwrite existing files!'
if self.interactive:
- confirm = raw_input(u"""
+ confirm = input("""
You have requested to collect static files at the destination
location as specified in your settings%s
@@ -195,10 +198,10 @@ Type 'yes' to continue, or 'no' to cancel: """
for f in files:
fpath = os.path.join(path, f)
if self.dry_run:
- self.log(u"Pretending to delete '%s'" %
- smart_unicode(fpath), level=1)
+ self.log("Pretending to delete '%s'" %
+ smart_text(fpath), level=1)
else:
- self.log(u"Deleting '%s'" % smart_unicode(fpath), level=1)
+ self.log("Deleting '%s'" % smart_text(fpath), level=1)
self.storage.delete(fpath)
for d in dirs:
self.clear_dir(os.path.join(path, d))
@@ -235,13 +238,13 @@ Type 'yes' to continue, or 'no' to cancel: """
and os.path.islink(full_path))):
if prefixed_path not in self.unmodified_files:
self.unmodified_files.append(prefixed_path)
- self.log(u"Skipping '%s' (not modified)" % path)
+ self.log("Skipping '%s' (not modified)" % path)
return False
# Then delete the existing file if really needed
if self.dry_run:
- self.log(u"Pretending to delete '%s'" % path)
+ self.log("Pretending to delete '%s'" % path)
else:
- self.log(u"Deleting '%s'" % path)
+ self.log("Deleting '%s'" % path)
self.storage.delete(prefixed_path)
return True
@@ -251,7 +254,7 @@ Type 'yes' to continue, or 'no' to cancel: """
"""
# Skip this file if it was already copied earlier
if prefixed_path in self.symlinked_files:
- return self.log(u"Skipping '%s' (already linked earlier)" % path)
+ return self.log("Skipping '%s' (already linked earlier)" % path)
# Delete the target file if needed or break
if not self.delete_file(path, prefixed_path, source_storage):
return
@@ -259,9 +262,9 @@ Type 'yes' to continue, or 'no' to cancel: """
source_path = source_storage.path(path)
# Finally link the file
if self.dry_run:
- self.log(u"Pretending to link '%s'" % source_path, level=1)
+ self.log("Pretending to link '%s'" % source_path, level=1)
else:
- self.log(u"Linking '%s'" % source_path, level=1)
+ self.log("Linking '%s'" % source_path, level=1)
full_path = self.storage.path(prefixed_path)
try:
os.makedirs(os.path.dirname(full_path))
@@ -277,7 +280,7 @@ Type 'yes' to continue, or 'no' to cancel: """
"""
# Skip this file if it was already copied earlier
if prefixed_path in self.copied_files:
- return self.log(u"Skipping '%s' (already copied earlier)" % path)
+ return self.log("Skipping '%s' (already copied earlier)" % path)
# Delete the target file if needed or break
if not self.delete_file(path, prefixed_path, source_storage):
return
@@ -285,9 +288,9 @@ Type 'yes' to continue, or 'no' to cancel: """
source_path = source_storage.path(path)
# Finally start copying
if self.dry_run:
- self.log(u"Pretending to copy '%s'" % source_path, level=1)
+ self.log("Pretending to copy '%s'" % source_path, level=1)
else:
- self.log(u"Copying '%s'" % source_path, level=1)
+ self.log("Copying '%s'" % source_path, level=1)
if self.local:
full_path = self.storage.path(prefixed_path)
try:
diff --git a/django/contrib/staticfiles/management/commands/findstatic.py b/django/contrib/staticfiles/management/commands/findstatic.py
index dc4406e458..dc1e88d778 100644
--- a/django/contrib/staticfiles/management/commands/findstatic.py
+++ b/django/contrib/staticfiles/management/commands/findstatic.py
@@ -1,7 +1,9 @@
+from __future__ import unicode_literals
+
import os
from optparse import make_option
from django.core.management.base import LabelCommand
-from django.utils.encoding import smart_str, smart_unicode
+from django.utils.encoding import smart_text
from django.contrib.staticfiles import finders
@@ -17,13 +19,13 @@ class Command(LabelCommand):
def handle_label(self, path, **options):
verbosity = int(options.get('verbosity', 1))
result = finders.find(path, all=options['all'])
- path = smart_unicode(path)
+ path = smart_text(path)
if result:
if not isinstance(result, (list, tuple)):
result = [result]
- output = u'\n '.join(
- (smart_unicode(os.path.realpath(path)) for path in result))
- self.stdout.write(u"Found '%s' here:\n %s" % (path, output))
+ output = '\n '.join(
+ (smart_text(os.path.realpath(path)) for path in result))
+ self.stdout.write("Found '%s' here:\n %s" % (path, output))
else:
if verbosity >= 1:
self.stderr.write("No matching file found for '%s'." % path)
diff --git a/django/contrib/staticfiles/storage.py b/django/contrib/staticfiles/storage.py
index fd8f9efb02..4be7540c6e 100644
--- a/django/contrib/staticfiles/storage.py
+++ b/django/contrib/staticfiles/storage.py
@@ -1,9 +1,13 @@
+from __future__ import unicode_literals
import hashlib
import os
import posixpath
import re
-from urllib import unquote
-from urlparse import urlsplit, urlunsplit, urldefrag
+try:
+ from urllib.parse import unquote, urlsplit, urlunsplit, urldefrag
+except ImportError: # Python 2
+ from urllib import unquote
+ from urlparse import urlsplit, urlunsplit, urldefrag
from django.conf import settings
from django.core.cache import (get_cache, InvalidCacheBackendError,
@@ -12,7 +16,7 @@ from django.core.exceptions import ImproperlyConfigured
from django.core.files.base import ContentFile
from django.core.files.storage import FileSystemStorage, get_storage_class
from django.utils.datastructures import SortedDict
-from django.utils.encoding import force_unicode, smart_str
+from django.utils.encoding import force_text, smart_bytes
from django.utils.functional import LazyObject
from django.utils.importlib import import_module
@@ -44,10 +48,11 @@ class StaticFilesStorage(FileSystemStorage):
class CachedFilesMixin(object):
+ default_template = """url("%s")"""
patterns = (
("*.css", (
r"""(url\(['"]{0,1}\s*(.*?)["']{0,1}\))""",
- r"""(@import\s*["']\s*(.*?)["'])""",
+ (r"""(@import\s*["']\s*(.*?)["'])""", """@import url("%s")"""),
)),
)
@@ -61,8 +66,12 @@ class CachedFilesMixin(object):
self._patterns = SortedDict()
for extension, patterns in self.patterns:
for pattern in patterns:
+ if isinstance(pattern, (tuple, list)):
+ pattern, template = pattern
+ else:
+ template = self.default_template
compiled = re.compile(pattern)
- self._patterns.setdefault(extension, []).append(compiled)
+ self._patterns.setdefault(extension, []).append((compiled, template))
def file_hash(self, name, content=None):
"""
@@ -78,6 +87,7 @@ class CachedFilesMixin(object):
def hashed_name(self, name, content=None):
parsed_name = urlsplit(unquote(name))
clean_name = parsed_name.path.strip()
+ opened = False
if content is None:
if not self.exists(clean_name):
raise ValueError("The file '%s' could not be found with %r." %
@@ -87,12 +97,17 @@ class CachedFilesMixin(object):
except IOError:
# Handle directory paths and fragments
return name
+ opened = True
+ try:
+ file_hash = self.file_hash(clean_name, content)
+ finally:
+ if opened:
+ content.close()
path, filename = os.path.split(clean_name)
root, ext = os.path.splitext(filename)
- file_hash = self.file_hash(clean_name, content)
if file_hash is not None:
- file_hash = u".%s" % file_hash
- hashed_name = os.path.join(path, u"%s%s%s" %
+ file_hash = ".%s" % file_hash
+ hashed_name = os.path.join(path, "%s%s%s" %
(root, file_hash, ext))
unparsed_name = list(parsed_name)
unparsed_name[2] = hashed_name
@@ -103,7 +118,7 @@ class CachedFilesMixin(object):
return urlunsplit(unparsed_name)
def cache_key(self, name):
- return u'staticfiles:%s' % hashlib.md5(smart_str(name)).hexdigest()
+ return 'staticfiles:%s' % hashlib.md5(smart_bytes(name)).hexdigest()
def url(self, name, force=False):
"""
@@ -139,10 +154,13 @@ class CachedFilesMixin(object):
return unquote(final_url)
- def url_converter(self, name):
+ def url_converter(self, name, template=None):
"""
Returns the custom URL converter for the given file name.
"""
+ if template is None:
+ template = self.default_template
+
def converter(matchobj):
"""
Converts the matched URL depending on the parent level (`..`)
@@ -152,7 +170,7 @@ class CachedFilesMixin(object):
matched, url = matchobj.groups()
# Completely ignore http(s) prefixed URLs,
# fragments and data-uri URLs
- if url.startswith(('#', 'http:', 'https:', 'data:')):
+ if url.startswith(('#', 'http:', 'https:', 'data:', '//')):
return matched
name_parts = name.split(os.sep)
# Using posix normpath here to remove duplicates
@@ -177,7 +195,8 @@ class CachedFilesMixin(object):
relative_url = '/'.join(url.split('/')[:-1] + file_name)
# Return the hashed version to the file
- return 'url("%s")' % unquote(relative_url)
+ return template % unquote(relative_url)
+
return converter
def post_process(self, paths, dry_run=False, **options):
@@ -227,17 +246,17 @@ class CachedFilesMixin(object):
# ..to apply each replacement pattern to the content
if name in adjustable_paths:
- content = original_file.read()
- converter = self.url_converter(name)
+ content = original_file.read().decode(settings.FILE_CHARSET)
for patterns in self._patterns.values():
- for pattern in patterns:
+ for pattern, template in patterns:
+ converter = self.url_converter(name, template)
content = pattern.sub(converter, content)
if hashed_file_exists:
self.delete(hashed_name)
# then save the processed result
- content_file = ContentFile(smart_str(content))
+ content_file = ContentFile(smart_bytes(content))
saved_name = self._save(hashed_name, content_file)
- hashed_name = force_unicode(saved_name.replace('\\', '/'))
+ hashed_name = force_text(saved_name.replace('\\', '/'))
processed = True
else:
# or handle the case in which neither processing nor
@@ -245,10 +264,10 @@ class CachedFilesMixin(object):
if not hashed_file_exists:
processed = True
saved_name = self._save(hashed_name, original_file)
- hashed_name = force_unicode(saved_name.replace('\\', '/'))
+ hashed_name = force_text(saved_name.replace('\\', '/'))
# and then set the cache accordingly
- hashed_paths[self.cache_key(name)] = hashed_name
+ hashed_paths[self.cache_key(name.replace('\\', '/'))] = hashed_name
yield name, hashed_name, processed
# Finally set the cache
diff --git a/django/contrib/staticfiles/templatetags/staticfiles.py b/django/contrib/staticfiles/templatetags/staticfiles.py
index 788f06ec16..71339ea8cd 100644
--- a/django/contrib/staticfiles/templatetags/staticfiles.py
+++ b/django/contrib/staticfiles/templatetags/staticfiles.py
@@ -1,13 +1,37 @@
from django import template
+from django.templatetags.static import StaticNode
from django.contrib.staticfiles.storage import staticfiles_storage
register = template.Library()
-@register.simple_tag
-def static(path):
+class StaticFilesNode(StaticNode):
+
+ def url(self, context):
+ path = self.path.resolve(context)
+ return staticfiles_storage.url(path)
+
+
+@register.tag('static')
+def do_static(parser, token):
"""
A template tag that returns the URL to a file
using staticfiles' storage backend
+
+ Usage::
+
+ {% static path [as varname] %}
+
+ Examples::
+
+ {% static "myapp/css/base.css" %}
+ {% static variable_with_path %}
+ {% static "myapp/css/base.css" as admin_base_css %}
+ {% static variable_with_path as varname %}
+
"""
- return staticfiles_storage.url(path)
+ return StaticFilesNode.handle_token(parser, token)
+
+
+def static(path):
+ return StaticNode.handle_simple(path)
diff --git a/django/contrib/staticfiles/views.py b/django/contrib/staticfiles/views.py
index 1a9c166ad7..85459812ad 100644
--- a/django/contrib/staticfiles/views.py
+++ b/django/contrib/staticfiles/views.py
@@ -5,7 +5,10 @@ development, and SHOULD NOT be used in a production setting.
"""
import os
import posixpath
-import urllib
+try:
+ from urllib.parse import unquote
+except ImportError: # Python 2
+ from urllib import unquote
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
@@ -31,7 +34,7 @@ def serve(request, path, document_root=None, insecure=False, **kwargs):
raise ImproperlyConfigured("The staticfiles view can only be used in "
"debug mode or if the the --insecure "
"option of 'runserver' is used")
- normalized_path = posixpath.normpath(urllib.unquote(path)).lstrip('/')
+ normalized_path = posixpath.normpath(unquote(path)).lstrip('/')
absolute_path = finders.find(normalized_path)
if not absolute_path:
if path.endswith('/') or path == '':
diff --git a/django/contrib/syndication/views.py b/django/contrib/syndication/views.py
index 462b3e94cf..4815ce5567 100644
--- a/django/contrib/syndication/views.py
+++ b/django/contrib/syndication/views.py
@@ -1,13 +1,16 @@
+from __future__ import unicode_literals
+
from django.conf import settings
from django.contrib.sites.models import get_current_site
from django.core.exceptions import ImproperlyConfigured, ObjectDoesNotExist
from django.http import HttpResponse, Http404
from django.template import loader, TemplateDoesNotExist, RequestContext
from django.utils import feedgenerator, tzinfo
-from django.utils.encoding import force_unicode, iri_to_uri, smart_unicode
+from django.utils.encoding import force_text, iri_to_uri, smart_text
from django.utils.html import escape
from django.utils.timezone import is_naive
+
def add_domain(domain, url, secure=False):
protocol = 'https' if secure else 'http'
if url.startswith('//'):
@@ -16,9 +19,7 @@ def add_domain(domain, url, secure=False):
elif not (url.startswith('http://')
or url.startswith('https://')
or url.startswith('mailto:')):
- # 'url' must already be ASCII and URL-quoted, so no need for encoding
- # conversions here.
- url = iri_to_uri(u'%s://%s%s' % (protocol, domain, url))
+ url = iri_to_uri('%s://%s%s' % (protocol, domain, url))
return url
class FeedDoesNotExist(ObjectDoesNotExist):
@@ -42,10 +43,10 @@ class Feed(object):
def item_title(self, item):
# Titles should be double escaped by default (see #6533)
- return escape(force_unicode(item))
+ return escape(force_text(item))
def item_description(self, item):
- return force_unicode(item)
+ return force_text(item)
def item_link(self, item):
try:
@@ -59,14 +60,14 @@ class Feed(object):
except AttributeError:
return default
if callable(attr):
- # Check func_code.co_argcount rather than try/excepting the
+ # Check __code__.co_argcount rather than try/excepting the
# function and catching the TypeError, because something inside
# the function may raise the TypeError. This technique is more
# accurate.
- if hasattr(attr, 'func_code'):
- argcount = attr.func_code.co_argcount
+ if hasattr(attr, '__code__'):
+ argcount = attr.__code__.co_argcount
else:
- argcount = attr.__call__.func_code.co_argcount
+ argcount = attr.__call__.__code__.co_argcount
if argcount == 2: # one argument is 'self'
return attr(obj)
else:
@@ -105,7 +106,7 @@ class Feed(object):
subtitle = self.__get_dynamic_attr('subtitle', obj),
link = link,
description = self.__get_dynamic_attr('description', obj),
- language = settings.LANGUAGE_CODE.decode(),
+ language = settings.LANGUAGE_CODE,
feed_url = add_domain(
current_site.domain,
self.__get_dynamic_attr('feed_url', obj) or request.path,
@@ -153,9 +154,9 @@ class Feed(object):
enc_url = self.__get_dynamic_attr('item_enclosure_url', item)
if enc_url:
enc = feedgenerator.Enclosure(
- url = smart_unicode(enc_url),
- length = smart_unicode(self.__get_dynamic_attr('item_enclosure_length', item)),
- mime_type = smart_unicode(self.__get_dynamic_attr('item_enclosure_mime_type', item))
+ url = smart_text(enc_url),
+ length = smart_text(self.__get_dynamic_attr('item_enclosure_length', item)),
+ mime_type = smart_text(self.__get_dynamic_attr('item_enclosure_mime_type', item))
)
author_name = self.__get_dynamic_attr('item_author_name', item)
if author_name is not None:
diff --git a/django/contrib/webdesign/lorem_ipsum.py b/django/contrib/webdesign/lorem_ipsum.py
index 4ad175d033..01d8f220f5 100644
--- a/django/contrib/webdesign/lorem_ipsum.py
+++ b/django/contrib/webdesign/lorem_ipsum.py
@@ -2,6 +2,8 @@
Utility functions for generating "lorem ipsum" Latin text.
"""
+from __future__ import unicode_literals
+
import random
COMMON_P = 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.'
@@ -49,10 +51,10 @@ def sentence():
"""
# Determine the number of comma-separated sections and number of words in
# each section for this sentence.
- sections = [u' '.join(random.sample(WORDS, random.randint(3, 12))) for i in range(random.randint(1, 5))]
- s = u', '.join(sections)
+ sections = [' '.join(random.sample(WORDS, random.randint(3, 12))) for i in range(random.randint(1, 5))]
+ s = ', '.join(sections)
# Convert to sentence case and add end punctuation.
- return u'%s%s%s' % (s[0].upper(), s[1:], random.choice('?.'))
+ return '%s%s%s' % (s[0].upper(), s[1:], random.choice('?.'))
def paragraph():
"""
@@ -60,7 +62,7 @@ def paragraph():
The paragraph consists of between 1 and 4 sentences, inclusive.
"""
- return u' '.join([sentence() for i in range(random.randint(1, 4))])
+ return ' '.join([sentence() for i in range(random.randint(1, 4))])
def paragraphs(count, common=True):
"""
@@ -98,4 +100,4 @@ def words(count, common=True):
word_list += random.sample(WORDS, c)
else:
word_list = word_list[:count]
- return u' '.join(word_list)
+ return ' '.join(word_list)
diff --git a/django/contrib/webdesign/templatetags/webdesign.py b/django/contrib/webdesign/templatetags/webdesign.py
index 05d8dc7f54..b870299cda 100644
--- a/django/contrib/webdesign/templatetags/webdesign.py
+++ b/django/contrib/webdesign/templatetags/webdesign.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
from django.contrib.webdesign.lorem_ipsum import words, paragraphs
from django import template
@@ -18,7 +20,7 @@ class LoremNode(template.Node):
paras = paragraphs(count, common=self.common)
if self.method == 'p':
paras = ['
%s
' % p for p in paras]
- return u'\n\n'.join(paras)
+ return '\n\n'.join(paras)
@register.tag
def lorem(parser, token):
diff --git a/django/contrib/webdesign/tests.py b/django/contrib/webdesign/tests.py
index 8907ea3ba7..16ec501e44 100644
--- a/django/contrib/webdesign/tests.py
+++ b/django/contrib/webdesign/tests.py
@@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
import unittest
@@ -9,7 +10,7 @@ from django.template import loader, Context
class WebdesignTest(unittest.TestCase):
def test_words(self):
- self.assertEqual(words(7), u'lorem ipsum dolor sit amet consectetur adipisicing')
+ self.assertEqual(words(7), 'lorem ipsum dolor sit amet consectetur adipisicing')
def test_paragraphs(self):
self.assertEqual(paragraphs(1),
@@ -18,4 +19,4 @@ class WebdesignTest(unittest.TestCase):
def test_lorem_tag(self):
t = loader.get_template_from_string("{% load webdesign %}{% lorem 3 w %}")
self.assertEqual(t.render(Context({})),
- u'lorem ipsum dolor')
+ 'lorem ipsum dolor')
diff --git a/django/core/cache/__init__.py b/django/core/cache/__init__.py
index 2a9e1a700b..f496c35e2b 100644
--- a/django/core/cache/__init__.py
+++ b/django/core/cache/__init__.py
@@ -14,7 +14,10 @@ cache class.
See docs/topics/cache.txt for information on the public API.
"""
-from urlparse import parse_qsl
+try:
+ from urllib.parse import parse_qsl
+except ImportError: # Python 2
+ from urlparse import parse_qsl
from django.conf import settings
from django.core import signals
diff --git a/django/core/cache/backends/base.py b/django/core/cache/backends/base.py
index f7573b2e31..06e8952bfb 100644
--- a/django/core/cache/backends/base.py
+++ b/django/core/cache/backends/base.py
@@ -1,9 +1,9 @@
"Base Cache class."
+from __future__ import unicode_literals
import warnings
from django.core.exceptions import ImproperlyConfigured, DjangoRuntimeWarning
-from django.utils.encoding import smart_str
from django.utils.importlib import import_module
class InvalidCacheBackendError(ImproperlyConfigured):
@@ -23,7 +23,7 @@ def default_key_func(key, key_prefix, version):
the `key_prefix'. KEY_FUNCTION can be used to specify an alternate
function with custom key making behavior.
"""
- return ':'.join([key_prefix, str(version), smart_str(key)])
+ return ':'.join([key_prefix, str(version), key])
def get_key_func(key_func):
"""
@@ -62,7 +62,7 @@ class BaseCache(object):
except (ValueError, TypeError):
self._cull_frequency = 3
- self.key_prefix = smart_str(params.get('KEY_PREFIX', ''))
+ self.key_prefix = params.get('KEY_PREFIX', '')
self.version = params.get('VERSION', 1)
self.key_func = get_key_func(params.get('KEY_FUNCTION', None))
diff --git a/django/core/cache/backends/db.py b/django/core/cache/backends/db.py
index 62ea5c420b..52db4d1b1d 100644
--- a/django/core/cache/backends/db.py
+++ b/django/core/cache/backends/db.py
@@ -4,7 +4,7 @@ import time
from datetime import datetime
try:
- import cPickle as pickle
+ from django.utils.six.moves import cPickle as pickle
except ImportError:
import pickle
@@ -12,6 +12,7 @@ from django.conf import settings
from django.core.cache.backends.base import BaseCache
from django.db import connections, router, transaction, DatabaseError
from django.utils import timezone
+from django.utils.encoding import smart_bytes
class Options(object):
@@ -72,7 +73,7 @@ class DatabaseCache(BaseDatabaseCache):
transaction.commit_unless_managed(using=db)
return default
value = connections[db].ops.process_clob(row[1])
- return pickle.loads(base64.decodestring(value))
+ return pickle.loads(base64.b64decode(smart_bytes(value)))
def set(self, key, value, timeout=None, version=None):
key = self.make_key(key, version=version)
@@ -103,7 +104,7 @@ class DatabaseCache(BaseDatabaseCache):
if num > self._max_entries:
self._cull(db, cursor, now)
pickled = pickle.dumps(value, pickle.HIGHEST_PROTOCOL)
- encoded = base64.encodestring(pickled).strip()
+ encoded = base64.b64encode(pickled).strip()
cursor.execute("SELECT cache_key, expires FROM %s "
"WHERE cache_key = %%s" % table, [key])
try:
@@ -166,18 +167,10 @@ class DatabaseCache(BaseDatabaseCache):
cursor.execute("SELECT COUNT(*) FROM %s" % table)
num = cursor.fetchone()[0]
if num > self._max_entries:
- cull_num = num / self._cull_frequency
- if connections[db].vendor == 'oracle':
- # Oracle doesn't support LIMIT + OFFSET
- cursor.execute("""SELECT cache_key FROM
-(SELECT ROW_NUMBER() OVER (ORDER BY cache_key) AS counter, cache_key FROM %s)
-WHERE counter > %%s AND COUNTER <= %%s""" % table, [cull_num, cull_num + 1])
- else:
- # This isn't standard SQL, it's likely to break
- # with some non officially supported databases
- cursor.execute("SELECT cache_key FROM %s "
- "ORDER BY cache_key "
- "LIMIT 1 OFFSET %%s" % table, [cull_num])
+ cull_num = num // self._cull_frequency
+ cursor.execute(
+ connections[db].ops.cache_key_culling_sql() % table,
+ [cull_num])
cursor.execute("DELETE FROM %s "
"WHERE cache_key < %%s" % table,
[cursor.fetchone()[0]])
diff --git a/django/core/cache/backends/filebased.py b/django/core/cache/backends/filebased.py
index 7f9f7175be..c54e8d280f 100644
--- a/django/core/cache/backends/filebased.py
+++ b/django/core/cache/backends/filebased.py
@@ -5,11 +5,12 @@ import os
import shutil
import time
try:
- import cPickle as pickle
+ from django.utils.six.moves import cPickle as pickle
except ImportError:
import pickle
from django.core.cache.backends.base import BaseCache
+from django.utils.encoding import smart_bytes
class FileBasedCache(BaseCache):
def __init__(self, dir, params):
@@ -136,7 +137,7 @@ class FileBasedCache(BaseCache):
Thus, a cache key of "foo" gets turnned into a file named
``{cache-dir}ac/bd/18db4cc2f85cedef654fccc4a4d8``.
"""
- path = hashlib.md5(key).hexdigest()
+ path = hashlib.md5(smart_bytes(key)).hexdigest()
path = os.path.join(path[:2], path[2:4], path[4:])
return os.path.join(self._dir, path)
diff --git a/django/core/cache/backends/locmem.py b/django/core/cache/backends/locmem.py
index 9196b3b42b..76667e9609 100644
--- a/django/core/cache/backends/locmem.py
+++ b/django/core/cache/backends/locmem.py
@@ -2,7 +2,7 @@
import time
try:
- import cPickle as pickle
+ from django.utils.six.moves import cPickle as pickle
except ImportError:
import pickle
diff --git a/django/core/cache/backends/memcached.py b/django/core/cache/backends/memcached.py
index 951c1eda26..75ce26d20e 100644
--- a/django/core/cache/backends/memcached.py
+++ b/django/core/cache/backends/memcached.py
@@ -5,10 +5,13 @@ from threading import local
from django.core.cache.backends.base import BaseCache, InvalidCacheBackendError
+from django.utils import six
+from django.utils.encoding import smart_str
+
class BaseMemcachedCache(BaseCache):
def __init__(self, server, params, library, value_not_found_exception):
super(BaseMemcachedCache, self).__init__(params)
- if isinstance(server, basestring):
+ if isinstance(server, six.string_types):
self._servers = server.split(';')
else:
self._servers = server
@@ -48,6 +51,10 @@ class BaseMemcachedCache(BaseCache):
timeout += int(time.time())
return int(timeout)
+ def make_key(self, key, version=None):
+ # Python 2 memcache requires the key to be a byte string.
+ return smart_str(super(BaseMemcachedCache, self).make_key(key, version))
+
def add(self, key, value, timeout=0, version=None):
key = self.make_key(key, version=version)
return self._cache.add(key, value, self._get_memcache_timeout(timeout))
diff --git a/django/core/context_processors.py b/django/core/context_processors.py
index 3ba519188b..ca1ac68f55 100644
--- a/django/core/context_processors.py
+++ b/django/core/context_processors.py
@@ -6,11 +6,15 @@ and returns a dictionary to add to the context.
These are referenced from the setting TEMPLATE_CONTEXT_PROCESSORS and used by
RequestContext.
"""
+from __future__ import unicode_literals
from django.conf import settings
from django.middleware.csrf import get_token
+from django.utils import six
+from django.utils.encoding import smart_text
from django.utils.functional import lazy
+
def csrf(request):
"""
Context processor that provides a CSRF token, or the string 'NOTPROVIDED' if
@@ -22,10 +26,10 @@ def csrf(request):
# In order to be able to provide debugging info in the
# case of misconfiguration, we use a sentinel value
# instead of returning an empty dict.
- return b'NOTPROVIDED'
+ return 'NOTPROVIDED'
else:
- return token
- _get_val = lazy(_get_val, str)
+ return smart_text(token)
+ _get_val = lazy(_get_val, six.text_type)
return {'csrf_token': _get_val() }
diff --git a/django/core/exceptions.py b/django/core/exceptions.py
index 4856ada911..233af40f88 100644
--- a/django/core/exceptions.py
+++ b/django/core/exceptions.py
@@ -55,7 +55,7 @@ class ValidationError(Exception):
"""An error while validating data."""
def __init__(self, message, code=None, params=None):
import operator
- from django.utils.encoding import force_unicode
+ from django.utils.encoding import force_text
"""
ValidationError can be passed any object that can be printed (usually
a string), a list of objects or a dictionary.
@@ -66,11 +66,11 @@ class ValidationError(Exception):
message = reduce(operator.add, message.values())
if isinstance(message, list):
- self.messages = [force_unicode(msg) for msg in message]
+ self.messages = [force_text(msg) for msg in message]
else:
self.code = code
self.params = params
- message = force_unicode(message)
+ message = force_text(message)
self.messages = [message]
def __str__(self):
diff --git a/django/core/files/base.py b/django/core/files/base.py
index a2d703c963..4a422be90d 100644
--- a/django/core/files/base.py
+++ b/django/core/files/base.py
@@ -1,9 +1,13 @@
+from __future__ import unicode_literals
+
import os
-from io import BytesIO
+from io import BytesIO, UnsupportedOperation
-from django.utils.encoding import smart_str, smart_unicode
+from django.utils.encoding import smart_bytes, smart_text
from django.core.files.utils import FileProxyMixin
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class File(FileProxyMixin):
DEFAULT_CHUNK_SIZE = 64 * 2**10
@@ -16,16 +20,14 @@ class File(FileProxyMixin):
self.mode = file.mode
def __str__(self):
- return smart_str(self.name or '')
-
- def __unicode__(self):
- return smart_unicode(self.name or u'')
+ return smart_text(self.name or '')
def __repr__(self):
return "<%s: %s>" % (self.__class__.__name__, self or "None")
- def __nonzero__(self):
+ def __bool__(self):
return bool(self.name)
+ __nonzero__ = __bool__ # Python 2
def __len__(self):
return self.size
@@ -62,8 +64,10 @@ class File(FileProxyMixin):
if not chunk_size:
chunk_size = self.DEFAULT_CHUNK_SIZE
- if hasattr(self, 'seek'):
+ try:
self.seek(0)
+ except (AttributeError, UnsupportedOperation):
+ pass
while True:
data = self.read(chunk_size)
@@ -121,6 +125,7 @@ class File(FileProxyMixin):
def close(self):
self.file.close()
+@python_2_unicode_compatible
class ContentFile(File):
"""
A File-like object that takes just raw content, rather than an actual file.
@@ -133,8 +138,9 @@ class ContentFile(File):
def __str__(self):
return 'Raw content'
- def __nonzero__(self):
+ def __bool__(self):
return True
+ __nonzero__ = __bool__ # Python 2
def open(self, mode=None):
self.seek(0)
diff --git a/django/core/files/images.py b/django/core/files/images.py
index 228a7118c5..7d7eac65db 100644
--- a/django/core/files/images.py
+++ b/django/core/files/images.py
@@ -47,13 +47,18 @@ def get_image_dimensions(file_or_path, close=False):
file = open(file_or_path, 'rb')
close = True
try:
+ # Most of the time PIL only needs a small chunk to parse the image and
+ # get the dimensions, but with some TIFF files PIL needs to parse the
+ # whole file.
+ chunk_size = 1024
while 1:
- data = file.read(1024)
+ data = file.read(chunk_size)
if not data:
break
p.feed(data)
if p.image:
return p.image.size
+ chunk_size = chunk_size*2
return None
finally:
if close:
diff --git a/django/core/files/move.py b/django/core/files/move.py
index f9060fd3d8..3af02634fe 100644
--- a/django/core/files/move.py
+++ b/django/core/files/move.py
@@ -66,7 +66,7 @@ def file_move_safe(old_file_name, new_file_name, chunk_size = 1024*64, allow_ove
try:
locks.lock(fd, locks.LOCK_EX)
current_chunk = None
- while current_chunk != '':
+ while current_chunk != b'':
current_chunk = old_file.read(chunk_size)
os.write(fd, current_chunk)
finally:
diff --git a/django/core/files/storage.py b/django/core/files/storage.py
index ba88674dbd..7542dcda46 100644
--- a/django/core/files/storage.py
+++ b/django/core/files/storage.py
@@ -1,6 +1,9 @@
import os
import errno
-import urlparse
+try:
+ from urllib.parse import urljoin
+except ImportError: # Python 2
+ from urlparse import urljoin
import itertools
from datetime import datetime
@@ -8,7 +11,7 @@ from django.conf import settings
from django.core.exceptions import ImproperlyConfigured, SuspiciousOperation
from django.core.files import locks, File
from django.core.files.move import file_move_safe
-from django.utils.encoding import force_unicode, filepath_to_uri
+from django.utils.encoding import force_text, filepath_to_uri
from django.utils.functional import LazyObject
from django.utils.importlib import import_module
from django.utils.text import get_valid_filename
@@ -45,7 +48,7 @@ class Storage(object):
name = self._save(name, content)
# Store filenames with forward slashes, even on Windows
- return force_unicode(name.replace('\\', '/'))
+ return force_text(name.replace('\\', '/'))
# These methods are part of the public API, with default implementations.
@@ -252,7 +255,7 @@ class FileSystemStorage(Storage):
def url(self, name):
if self.base_url is None:
raise ValueError("This file is not accessible via a URL.")
- return urlparse.urljoin(self.base_url, filepath_to_uri(name))
+ return urljoin(self.base_url, filepath_to_uri(name))
def accessed_time(self, name):
return datetime.fromtimestamp(os.path.getatime(self.path(name)))
diff --git a/django/core/files/uploadhandler.py b/django/core/files/uploadhandler.py
index 88f78904bb..c422945d6f 100644
--- a/django/core/files/uploadhandler.py
+++ b/django/core/files/uploadhandler.py
@@ -2,12 +2,15 @@
Base file upload handler classes, and the built-in concrete subclasses
"""
+from __future__ import unicode_literals
+
from io import BytesIO
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
from django.core.files.uploadedfile import TemporaryUploadedFile, InMemoryUploadedFile
from django.utils import importlib
+from django.utils.encoding import python_2_unicode_compatible
__all__ = ['UploadFileException','StopUpload', 'SkipFile', 'FileUploadHandler',
'TemporaryFileUploadHandler', 'MemoryFileUploadHandler',
@@ -19,6 +22,7 @@ class UploadFileException(Exception):
"""
pass
+@python_2_unicode_compatible
class StopUpload(UploadFileException):
"""
This exception is raised when an upload must abort.
@@ -31,11 +35,11 @@ class StopUpload(UploadFileException):
"""
self.connection_reset = connection_reset
- def __unicode__(self):
+ def __str__(self):
if self.connection_reset:
- return u'StopUpload: Halt current upload.'
+ return 'StopUpload: Halt current upload.'
else:
- return u'StopUpload: Consume request data, then halt.'
+ return 'StopUpload: Consume request data, then halt.'
class SkipFile(UploadFileException):
"""
diff --git a/django/core/handlers/base.py b/django/core/handlers/base.py
index 4c9dfc07bc..791382bac0 100644
--- a/django/core/handlers/base.py
+++ b/django/core/handlers/base.py
@@ -1,10 +1,14 @@
+from __future__ import unicode_literals
+
import sys
+import types
from django import http
from django.core import signals
-from django.utils.encoding import force_unicode
+from django.utils.encoding import force_text
from django.utils.importlib import import_module
from django.utils.log import getLogger
+from django.utils import six
logger = getLogger('django.request')
@@ -122,10 +126,10 @@ class BaseHandler(object):
# Complain if the view returned None (a common error).
if response is None:
- try:
- view_name = callback.func_name # If it's a function
- except AttributeError:
- view_name = callback.__class__.__name__ + '.__call__' # If it's a class
+ if isinstance(callback, types.FunctionType): # FBV
+ view_name = callback.__name__
+ else: # CBV
+ view_name = callback.__class__.__name__ + '.__call__'
raise ValueError("The view %s.%s didn't return an HttpResponse object." % (callback.__module__, view_name))
# If the response supports deferred rendering, apply template
@@ -149,10 +153,8 @@ class BaseHandler(object):
callback, param_dict = resolver.resolve404()
response = callback(request, **param_dict)
except:
- try:
- response = self.handle_uncaught_exception(request, resolver, sys.exc_info())
- finally:
- signals.got_request_exception.send(sender=self.__class__, request=request)
+ signals.got_request_exception.send(sender=self.__class__, request=request)
+ response = self.handle_uncaught_exception(request, resolver, sys.exc_info())
except exceptions.PermissionDenied:
logger.warning(
'Forbidden (Permission denied): %s', request.path,
@@ -164,12 +166,10 @@ class BaseHandler(object):
callback, param_dict = resolver.resolve403()
response = callback(request, **param_dict)
except:
- try:
- response = self.handle_uncaught_exception(request,
- resolver, sys.exc_info())
- finally:
- signals.got_request_exception.send(
+ signals.got_request_exception.send(
sender=self.__class__, request=request)
+ response = self.handle_uncaught_exception(request,
+ resolver, sys.exc_info())
except SystemExit:
# Allow sys.exit() to actually exit. See tickets #1023 and #4701
raise
@@ -222,7 +222,7 @@ class BaseHandler(object):
# If Http500 handler is not installed, re-raise last exception
if resolver.urlconf_module is None:
- raise exc_info[1], None, exc_info[2]
+ six.reraise(*exc_info)
# Return an HttpResponse that displays a friendly error message.
callback, param_dict = resolver.resolve500()
return callback(request, **param_dict)
@@ -247,16 +247,16 @@ def get_script_name(environ):
"""
from django.conf import settings
if settings.FORCE_SCRIPT_NAME is not None:
- return force_unicode(settings.FORCE_SCRIPT_NAME)
+ return force_text(settings.FORCE_SCRIPT_NAME)
# If Apache's mod_rewrite had a whack at the URL, Apache set either
# SCRIPT_URL or REDIRECT_URL to the full resource URL before applying any
# rewrites. Unfortunately not every Web server (lighttpd!) passes this
# information through all the time, so FORCE_SCRIPT_NAME, above, is still
# needed.
- script_url = environ.get('SCRIPT_URL', u'')
+ script_url = environ.get('SCRIPT_URL', '')
if not script_url:
- script_url = environ.get('REDIRECT_URL', u'')
+ script_url = environ.get('REDIRECT_URL', '')
if script_url:
- return force_unicode(script_url[:-len(environ.get('PATH_INFO', ''))])
- return force_unicode(environ.get('SCRIPT_NAME', u''))
+ return force_text(script_url[:-len(environ.get('PATH_INFO', ''))])
+ return force_text(environ.get('SCRIPT_NAME', ''))
diff --git a/django/core/handlers/wsgi.py b/django/core/handlers/wsgi.py
index 128ff7ac64..a0186e552f 100644
--- a/django/core/handlers/wsgi.py
+++ b/django/core/handlers/wsgi.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
import sys
from io import BytesIO
from threading import Lock
@@ -7,7 +9,7 @@ from django.core import signals
from django.core.handlers import base
from django.core.urlresolvers import set_script_prefix
from django.utils import datastructures
-from django.utils.encoding import force_unicode, iri_to_uri
+from django.utils.encoding import force_text, smart_str, iri_to_uri
from django.utils.log import getLogger
logger = getLogger('django.request')
@@ -125,7 +127,7 @@ class LimitedStream(object):
class WSGIRequest(http.HttpRequest):
def __init__(self, environ):
script_name = base.get_script_name(environ)
- path_info = force_unicode(environ.get('PATH_INFO', u'/'))
+ path_info = force_text(environ.get('PATH_INFO', '/'))
if not path_info or path_info == script_name:
# Sometimes PATH_INFO exists, but is empty (e.g. accessing
# the SCRIPT_NAME URL without a trailing slash). We really need to
@@ -134,7 +136,7 @@ class WSGIRequest(http.HttpRequest):
#
# (The comparison of path_info to script_name is to work around an
# apparent bug in flup 1.0.1. See Django ticket #8490).
- path_info = u'/'
+ path_info = '/'
self.environ = environ
self.path_info = path_info
self.path = '%s%s' % (script_name, path_info)
@@ -208,8 +210,7 @@ class WSGIHandler(base.BaseHandler):
# Set up middleware if needed. We couldn't do this earlier, because
# settings weren't available.
if self._request_middleware is None:
- self.initLock.acquire()
- try:
+ with self.initLock:
try:
# Check that middleware is still uninitialised.
if self._request_middleware is None:
@@ -218,8 +219,6 @@ class WSGIHandler(base.BaseHandler):
# Unload whatever middleware we got
self._request_middleware = None
raise
- finally:
- self.initLock.release()
set_script_prefix(base.get_script_name(environ))
signals.request_started.send(sender=self.__class__)
@@ -246,6 +245,6 @@ class WSGIHandler(base.BaseHandler):
status = '%s %s' % (response.status_code, status_text)
response_headers = [(str(k), str(v)) for k, v in response.items()]
for c in response.cookies.values():
- response_headers.append(('Set-Cookie', str(c.output(header=''))))
- start_response(status, response_headers)
+ response_headers.append((str('Set-Cookie'), str(c.output(header=''))))
+ start_response(smart_str(status), response_headers)
return response
diff --git a/django/core/mail/__init__.py b/django/core/mail/__init__.py
index 1bee0cac9f..08f9702934 100644
--- a/django/core/mail/__init__.py
+++ b/django/core/mail/__init__.py
@@ -1,6 +1,7 @@
"""
Tools for sending email.
"""
+from __future__ import unicode_literals
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
@@ -89,7 +90,7 @@ def mail_admins(subject, message, fail_silently=False, connection=None,
"""Sends a message to the admins, as defined by the ADMINS setting."""
if not settings.ADMINS:
return
- mail = EmailMultiAlternatives(u'%s%s' % (settings.EMAIL_SUBJECT_PREFIX, subject),
+ mail = EmailMultiAlternatives('%s%s' % (settings.EMAIL_SUBJECT_PREFIX, subject),
message, settings.SERVER_EMAIL, [a[1] for a in settings.ADMINS],
connection=connection)
if html_message:
@@ -102,7 +103,7 @@ def mail_managers(subject, message, fail_silently=False, connection=None,
"""Sends a message to the managers, as defined by the MANAGERS setting."""
if not settings.MANAGERS:
return
- mail = EmailMultiAlternatives(u'%s%s' % (settings.EMAIL_SUBJECT_PREFIX, subject),
+ mail = EmailMultiAlternatives('%s%s' % (settings.EMAIL_SUBJECT_PREFIX, subject),
message, settings.SERVER_EMAIL, [a[1] for a in settings.MANAGERS],
connection=connection)
if html_message:
diff --git a/django/core/mail/backends/console.py b/django/core/mail/backends/console.py
index 705497520a..0baae0c01e 100644
--- a/django/core/mail/backends/console.py
+++ b/django/core/mail/backends/console.py
@@ -16,19 +16,17 @@ class EmailBackend(BaseEmailBackend):
"""Write all messages to the stream in a thread-safe way."""
if not email_messages:
return
- self._lock.acquire()
- try:
- stream_created = self.open()
- for message in email_messages:
- self.stream.write('%s\n' % message.message().as_string())
- self.stream.write('-'*79)
- self.stream.write('\n')
- self.stream.flush() # flush after each message
- if stream_created:
- self.close()
- except:
- if not self.fail_silently:
- raise
- finally:
- self._lock.release()
+ with self._lock:
+ try:
+ stream_created = self.open()
+ for message in email_messages:
+ self.stream.write('%s\n' % message.message().as_string())
+ self.stream.write('-'*79)
+ self.stream.write('\n')
+ self.stream.flush() # flush after each message
+ if stream_created:
+ self.close()
+ except:
+ if not self.fail_silently:
+ raise
return len(email_messages)
diff --git a/django/core/mail/backends/filebased.py b/django/core/mail/backends/filebased.py
index 674ca32f3f..4a74c34f1f 100644
--- a/django/core/mail/backends/filebased.py
+++ b/django/core/mail/backends/filebased.py
@@ -6,6 +6,7 @@ import os
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
from django.core.mail.backends.console import EmailBackend as ConsoleEmailBackend
+from django.utils import six
class EmailBackend(ConsoleEmailBackend):
def __init__(self, *args, **kwargs):
@@ -15,7 +16,7 @@ class EmailBackend(ConsoleEmailBackend):
else:
self.file_path = getattr(settings, 'EMAIL_FILE_PATH',None)
# Make sure self.file_path is a string.
- if not isinstance(self.file_path, basestring):
+ if not isinstance(self.file_path, six.string_types):
raise ImproperlyConfigured('Path for saving emails is invalid: %r' % self.file_path)
self.file_path = os.path.abspath(self.file_path)
# Make sure that self.file_path is an directory if it exists.
diff --git a/django/core/mail/backends/smtp.py b/django/core/mail/backends/smtp.py
index 3ee283b5f1..18437c6282 100644
--- a/django/core/mail/backends/smtp.py
+++ b/django/core/mail/backends/smtp.py
@@ -80,8 +80,7 @@ class EmailBackend(BaseEmailBackend):
"""
if not email_messages:
return
- self._lock.acquire()
- try:
+ with self._lock:
new_conn_created = self.open()
if not self.connection:
# We failed silently on open().
@@ -94,8 +93,6 @@ class EmailBackend(BaseEmailBackend):
num_sent += 1
if new_conn_created:
self.close()
- finally:
- self._lock.release()
return num_sent
def _send(self, email_message):
diff --git a/django/core/mail/message.py b/django/core/mail/message.py
index 2618c7f17d..db9023a0bb 100644
--- a/django/core/mail/message.py
+++ b/django/core/mail/message.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
import mimetypes
import os
import random
@@ -9,11 +11,11 @@ from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
from email.header import Header
from email.utils import formatdate, getaddresses, formataddr, parseaddr
-from io import BytesIO
from django.conf import settings
from django.core.mail.utils import DNS_NAME
-from django.utils.encoding import smart_str, force_unicode
+from django.utils.encoding import force_text
+from django.utils import six
# Don't BASE64-encode UTF-8 messages so that we avoid unwanted attention from
@@ -76,38 +78,43 @@ ADDRESS_HEADERS = set([
def forbid_multi_line_headers(name, val, encoding):
"""Forbids multi-line headers, to prevent header injection."""
encoding = encoding or settings.DEFAULT_CHARSET
- val = force_unicode(val)
+ val = force_text(val)
if '\n' in val or '\r' in val:
raise BadHeaderError("Header values can't contain newlines (got %r for header %r)" % (val, name))
try:
- val = val.encode('ascii')
+ val.encode('ascii')
except UnicodeEncodeError:
if name.lower() in ADDRESS_HEADERS:
val = ', '.join(sanitize_address(addr, encoding)
for addr in getaddresses((val,)))
else:
- val = str(Header(val, encoding))
+ val = Header(val, encoding).encode()
else:
if name.lower() == 'subject':
- val = Header(val)
- return name, val
+ val = Header(val).encode()
+ return str(name), val
def sanitize_address(addr, encoding):
- if isinstance(addr, basestring):
- addr = parseaddr(force_unicode(addr))
+ if isinstance(addr, six.string_types):
+ addr = parseaddr(force_text(addr))
nm, addr = addr
- nm = str(Header(nm, encoding))
+ # This try-except clause is needed on Python 3 < 3.2.4
+ # http://bugs.python.org/issue14291
try:
- addr = addr.encode('ascii')
+ nm = Header(nm, encoding).encode()
+ except UnicodeEncodeError:
+ nm = Header(nm, 'utf-8').encode()
+ try:
+ addr.encode('ascii')
except UnicodeEncodeError: # IDN
- if u'@' in addr:
- localpart, domain = addr.split(u'@', 1)
+ if '@' in addr:
+ localpart, domain = addr.split('@', 1)
localpart = str(Header(localpart, encoding))
- domain = domain.encode('idna')
+ domain = domain.encode('idna').decode('ascii')
addr = '@'.join([localpart, domain])
else:
- addr = str(Header(addr, encoding))
+ addr = Header(addr, encoding).encode()
return formataddr((nm, addr))
@@ -129,7 +136,7 @@ class SafeMIMEText(MIMEText):
This overrides the default as_string() implementation to not mangle
lines that begin with 'From '. See bug #13433 for details.
"""
- fp = BytesIO()
+ fp = six.StringIO()
g = Generator(fp, mangle_from_ = False)
g.flatten(self, unixfrom=unixfrom)
return fp.getvalue()
@@ -153,7 +160,7 @@ class SafeMIMEMultipart(MIMEMultipart):
This overrides the default as_string() implementation to not mangle
lines that begin with 'From '. See bug #13433 for details.
"""
- fp = BytesIO()
+ fp = six.StringIO()
g = Generator(fp, mangle_from_ = False)
g.flatten(self, unixfrom=unixfrom)
return fp.getvalue()
@@ -178,17 +185,17 @@ class EmailMessage(object):
necessary encoding conversions.
"""
if to:
- assert not isinstance(to, basestring), '"to" argument must be a list or tuple'
+ assert not isinstance(to, six.string_types), '"to" argument must be a list or tuple'
self.to = list(to)
else:
self.to = []
if cc:
- assert not isinstance(cc, basestring), '"cc" argument must be a list or tuple'
+ assert not isinstance(cc, six.string_types), '"cc" argument must be a list or tuple'
self.cc = list(cc)
else:
self.cc = []
if bcc:
- assert not isinstance(bcc, basestring), '"bcc" argument must be a list or tuple'
+ assert not isinstance(bcc, six.string_types), '"bcc" argument must be a list or tuple'
self.bcc = list(bcc)
else:
self.bcc = []
@@ -207,8 +214,7 @@ class EmailMessage(object):
def message(self):
encoding = self.encoding or settings.DEFAULT_CHARSET
- msg = SafeMIMEText(smart_str(self.body, encoding),
- self.content_subtype, encoding)
+ msg = SafeMIMEText(self.body, self.content_subtype, encoding)
msg = self._create_message(msg)
msg['Subject'] = self.subject
msg['From'] = self.extra_headers.get('From', self.from_email)
@@ -290,7 +296,7 @@ class EmailMessage(object):
basetype, subtype = mimetype.split('/', 1)
if basetype == 'text':
encoding = self.encoding or settings.DEFAULT_CHARSET
- attachment = SafeMIMEText(smart_str(content, encoding), subtype, encoding)
+ attachment = SafeMIMEText(content, subtype, encoding)
else:
# Encode non-text attachments with base64.
attachment = MIMEBase(basetype, subtype)
@@ -310,9 +316,11 @@ class EmailMessage(object):
attachment = self._create_mime_attachment(content, mimetype)
if filename:
try:
- filename = filename.encode('ascii')
+ filename.encode('ascii')
except UnicodeEncodeError:
- filename = ('utf-8', '', filename.encode('utf-8'))
+ if not six.PY3:
+ filename = filename.encode('utf-8')
+ filename = ('utf-8', '', filename)
attachment.add_header('Content-Disposition', 'attachment',
filename=filename)
return attachment
diff --git a/django/core/management/__init__.py b/django/core/management/__init__.py
index 0464eb27bb..98f75e0310 100644
--- a/django/core/management/__init__.py
+++ b/django/core/management/__init__.py
@@ -8,6 +8,7 @@ import warnings
from django.core.management.base import BaseCommand, CommandError, handle_default_options
from django.core.management.color import color_style
from django.utils.importlib import import_module
+from django.utils import six
# For backwards compatibility: get_version() used to be in this module.
from django import get_version
@@ -50,14 +51,19 @@ def find_management_module(app_name):
# module, we need look for the case where the project name is part
# of the app_name but the project directory itself isn't on the path.
try:
- f, path, descr = imp.find_module(part,path)
+ f, path, descr = imp.find_module(part, path)
except ImportError as e:
if os.path.basename(os.getcwd()) != part:
raise e
+ else:
+ if f:
+ f.close()
while parts:
part = parts.pop()
f, path, descr = imp.find_module(part, path and [path] or None)
+ if f:
+ f.close()
return path
def load_command_class(app_name, name):
@@ -228,7 +234,7 @@ class ManagementUtility(object):
"Available subcommands:",
]
commands_dict = collections.defaultdict(lambda: [])
- for name, app in get_commands().iteritems():
+ for name, app in six.iteritems(get_commands()):
if app == 'django.core':
app = 'django'
else:
@@ -294,7 +300,7 @@ class ManagementUtility(object):
except IndexError:
curr = ''
- subcommands = get_commands().keys() + ['help']
+ subcommands = list(get_commands()) + ['help']
options = [('--help', None)]
# subcommand
@@ -324,7 +330,7 @@ class ManagementUtility(object):
subcommand_cls.option_list]
# filter out previously specified options from available options
prev_opts = [x.split('=')[0] for x in cwords[1:cword-1]]
- options = filter(lambda (x, v): x not in prev_opts, options)
+ options = [opt for opt in options if opt[0] not in prev_opts]
# filter options by current input
options = sorted([(k, v) for k, v in options if k.startswith(curr)])
diff --git a/django/core/management/base.py b/django/core/management/base.py
index a204f6f0bc..5e630d5207 100644
--- a/django/core/management/base.py
+++ b/django/core/management/base.py
@@ -6,7 +6,6 @@ be executed through ``django-admin.py`` or ``manage.py``).
import os
import sys
-from io import BytesIO
from optparse import make_option, OptionParser
import traceback
@@ -14,6 +13,7 @@ import django
from django.core.exceptions import ImproperlyConfigured
from django.core.management.color import color_style
from django.utils.encoding import smart_str
+from django.utils.six import StringIO
class CommandError(Exception):
@@ -273,7 +273,7 @@ class BaseCommand(object):
"""
from django.core.management.validation import get_validation_errors
- s = BytesIO()
+ s = StringIO()
num_errors = get_validation_errors(s, app)
if num_errors:
s.seek(0)
diff --git a/django/core/management/commands/compilemessages.py b/django/core/management/commands/compilemessages.py
index fdc3535cf6..b7392b9173 100644
--- a/django/core/management/commands/compilemessages.py
+++ b/django/core/management/commands/compilemessages.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
import codecs
import os
import sys
@@ -7,7 +9,7 @@ from django.core.management.base import BaseCommand, CommandError
def has_bom(fn):
with open(fn, 'rb') as f:
sample = f.read(4)
- return sample[:3] == '\xef\xbb\xbf' or \
+ return sample[:3] == b'\xef\xbb\xbf' or \
sample.startswith(codecs.BOM_UTF16_LE) or \
sample.startswith(codecs.BOM_UTF16_BE)
diff --git a/django/core/management/commands/createcachetable.py b/django/core/management/commands/createcachetable.py
index bcc47e17c8..411042ee76 100644
--- a/django/core/management/commands/createcachetable.py
+++ b/django/core/management/commands/createcachetable.py
@@ -4,6 +4,8 @@ from django.core.cache.backends.db import BaseDatabaseCache
from django.core.management.base import LabelCommand, CommandError
from django.db import connections, router, transaction, models, DEFAULT_DB_ALIAS
from django.db.utils import DatabaseError
+from django.utils.encoding import force_text
+
class Command(LabelCommand):
help = "Creates the table needed to use the SQL cache backend."
@@ -58,7 +60,7 @@ class Command(LabelCommand):
transaction.rollback_unless_managed(using=db)
raise CommandError(
"Cache table '%s' could not be created.\nThe error was: %s." %
- (tablename, e))
+ (tablename, force_text(e)))
for statement in index_output:
curs.execute(statement)
transaction.commit_unless_managed(using=db)
diff --git a/django/core/management/commands/diffsettings.py b/django/core/management/commands/diffsettings.py
index 98b53b405d..aa7395e5ee 100644
--- a/django/core/management/commands/diffsettings.py
+++ b/django/core/management/commands/diffsettings.py
@@ -22,9 +22,7 @@ class Command(NoArgsCommand):
default_settings = module_to_dict(global_settings)
output = []
- keys = user_settings.keys()
- keys.sort()
- for key in keys:
+ for key in sorted(user_settings.keys()):
if key not in default_settings:
output.append("%s = %s ###" % (key, user_settings[key]))
elif user_settings[key] != default_settings[key]:
diff --git a/django/core/management/commands/dumpdata.py b/django/core/management/commands/dumpdata.py
index 9059625dec..d3650b1eb8 100644
--- a/django/core/management/commands/dumpdata.py
+++ b/django/core/management/commands/dumpdata.py
@@ -150,11 +150,11 @@ def sort_dependencies(app_list):
for field in model._meta.fields:
if hasattr(field.rel, 'to'):
rel_model = field.rel.to
- if hasattr(rel_model, 'natural_key'):
+ if hasattr(rel_model, 'natural_key') and rel_model != model:
deps.append(rel_model)
for field in model._meta.many_to_many:
rel_model = field.rel.to
- if hasattr(rel_model, 'natural_key'):
+ if hasattr(rel_model, 'natural_key') and rel_model != model:
deps.append(rel_model)
model_dependencies.append((model, deps))
diff --git a/django/core/management/commands/flush.py b/django/core/management/commands/flush.py
index ce3c6e856b..b8b78434ce 100644
--- a/django/core/management/commands/flush.py
+++ b/django/core/management/commands/flush.py
@@ -7,6 +7,7 @@ from django.core.management.base import NoArgsCommand, CommandError
from django.core.management.color import no_style
from django.core.management.sql import sql_flush, emit_post_sync_signal
from django.utils.importlib import import_module
+from django.utils.six.moves import input
class Command(NoArgsCommand):
@@ -16,6 +17,8 @@ class Command(NoArgsCommand):
make_option('--database', action='store', dest='database',
default=DEFAULT_DB_ALIAS, help='Nominates a database to flush. '
'Defaults to the "default" database.'),
+ make_option('--no-initial-data', action='store_false', dest='load_initial_data', default=True,
+ help='Tells Django not to load any initial data after database synchronization.'),
)
help = ('Returns the database to the state it was in immediately after '
'syncdb was executed. This means that all data will be removed '
@@ -27,6 +30,8 @@ class Command(NoArgsCommand):
connection = connections[db]
verbosity = int(options.get('verbosity'))
interactive = options.get('interactive')
+ # 'reset_sequences' is a stealth option
+ reset_sequences = options.get('reset_sequences', True)
self.style = no_style()
@@ -38,10 +43,10 @@ class Command(NoArgsCommand):
except ImportError:
pass
- sql_list = sql_flush(self.style, connection, only_django=True)
+ sql_list = sql_flush(self.style, connection, only_django=True, reset_sequences=reset_sequences)
if interactive:
- confirm = raw_input("""You have requested a flush of the database.
+ confirm = input("""You have requested a flush of the database.
This will IRREVERSIBLY DESTROY all data currently in the %r database,
and return each table to the state it was in after syncdb.
Are you sure you want to do this?
@@ -79,7 +84,9 @@ The full error: %s""" % (connection.settings_dict['NAME'], e))
# Reinstall the initial_data fixture.
kwargs = options.copy()
kwargs['database'] = db
- call_command('loaddata', 'initial_data', **kwargs)
+ if options.get('load_initial_data'):
+ # Reinstall the initial_data fixture.
+ call_command('loaddata', 'initial_data', **options)
else:
self.stdout.write("Flush cancelled.\n")
diff --git a/django/core/management/commands/inspectdb.py b/django/core/management/commands/inspectdb.py
index a524e64f65..7c868e4b60 100644
--- a/django/core/management/commands/inspectdb.py
+++ b/django/core/management/commands/inspectdb.py
@@ -3,6 +3,7 @@ from optparse import make_option
from django.core.management.base import NoArgsCommand, CommandError
from django.db import connections, DEFAULT_DB_ALIAS
+from django.utils import six
class Command(NoArgsCommand):
help = "Introspects the database tables in the given database and outputs a Django model module."
@@ -115,7 +116,7 @@ class Command(NoArgsCommand):
if att_name[0].isdigit():
att_name = 'number_%s' % att_name
- extra_params['db_column'] = unicode(column_name)
+ extra_params['db_column'] = six.text_type(column_name)
comment_notes.append("Field renamed because it wasn't a "
"valid Python identifier.")
diff --git a/django/core/management/commands/loaddata.py b/django/core/management/commands/loaddata.py
index f44edf7ade..1896e53cee 100644
--- a/django/core/management/commands/loaddata.py
+++ b/django/core/management/commands/loaddata.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
import sys
import os
import gzip
@@ -7,11 +9,12 @@ import traceback
from django.conf import settings
from django.core import serializers
-from django.core.management.base import BaseCommand
+from django.core.management.base import BaseCommand, CommandError
from django.core.management.color import no_style
from django.db import (connections, router, transaction, DEFAULT_DB_ALIAS,
IntegrityError, DatabaseError)
from django.db.models import get_apps
+from django.utils.encoding import force_text
from itertools import product
try:
@@ -36,11 +39,10 @@ class Command(BaseCommand):
connection = connections[using]
if not len(fixture_labels):
- self.stderr.write(
+ raise CommandError(
"No database fixture specified. Please provide the path of at "
"least one fixture in the command line."
)
- return
verbosity = int(options.get('verbosity'))
show_traceback = options.get('traceback')
@@ -126,13 +128,9 @@ class Command(BaseCommand):
if verbosity >= 2:
self.stdout.write("Loading '%s' fixtures..." % fixture_name)
else:
- self.stderr.write(
+ raise CommandError(
"Problem installing fixture '%s': %s is not a known serialization format." %
(fixture_name, format))
- if commit:
- transaction.rollback(using=using)
- transaction.leave_transaction_management(using=using)
- return
if os.path.isabs(fixture_name):
fixture_dirs = [fixture_name]
@@ -167,12 +165,8 @@ class Command(BaseCommand):
else:
try:
if label_found:
- self.stderr.write("Multiple fixtures named '%s' in %s. Aborting." %
+ raise CommandError("Multiple fixtures named '%s' in %s. Aborting." %
(fixture_name, humanize(fixture_dir)))
- if commit:
- transaction.rollback(using=using)
- transaction.leave_transaction_management(using=using)
- return
fixture_count += 1
objects_in_fixture = 0
@@ -191,13 +185,13 @@ class Command(BaseCommand):
try:
obj.save(using=using)
except (DatabaseError, IntegrityError) as e:
- msg = "Could not load %(app_label)s.%(object_name)s(pk=%(pk)s): %(error_msg)s" % {
+ e.args = ("Could not load %(app_label)s.%(object_name)s(pk=%(pk)s): %(error_msg)s" % {
'app_label': obj.object._meta.app_label,
'object_name': obj.object._meta.object_name,
'pk': obj.object.pk,
- 'error_msg': e
- }
- raise e.__class__, e.__class__(msg), sys.exc_info()[2]
+ 'error_msg': force_text(e)
+ },)
+ raise
loaded_object_count += loaded_objects_in_fixture
fixture_object_count += objects_in_fixture
@@ -208,13 +202,9 @@ class Command(BaseCommand):
# If the fixture we loaded contains 0 objects, assume that an
# error was encountered during fixture loading.
if objects_in_fixture == 0:
- self.stderr.write(
+ raise CommandError(
"No fixture data found for '%s'. (File format may be invalid.)" %
(fixture_name))
- if commit:
- transaction.rollback(using=using)
- transaction.leave_transaction_management(using=using)
- return
# Since we disabled constraint checks, we must manually check for
# any invalid keys that might have been added
@@ -223,19 +213,13 @@ class Command(BaseCommand):
except (SystemExit, KeyboardInterrupt):
raise
- except Exception:
+ except Exception as e:
if commit:
transaction.rollback(using=using)
transaction.leave_transaction_management(using=using)
- if show_traceback:
- traceback.print_exc()
- else:
- self.stderr.write(
- "Problem installing fixture '%s': %s" %
- (full_path, ''.join(traceback.format_exception(sys.exc_type,
- sys.exc_value, sys.exc_traceback))))
- return
-
+ if not isinstance(e, CommandError):
+ e.args = ("Problem installing fixture '%s': %s" % (full_path, e),)
+ raise
# If we found even one object in a fixture, we need to reset the
# database sequences.
diff --git a/django/core/management/commands/makemessages.py b/django/core/management/commands/makemessages.py
index 046ffb48f2..7bdd2472d3 100644
--- a/django/core/management/commands/makemessages.py
+++ b/django/core/management/commands/makemessages.py
@@ -13,6 +13,7 @@ from django.utils.text import get_text_list
from django.utils.jslex import prepare_js_for_gettext
plural_forms_re = re.compile(r'^(?P"Plural-Forms.+?\\n")\s*$', re.MULTILINE | re.DOTALL)
+STATUS_OK = 0
def handle_extensions(extensions=('html',), ignored=('py',)):
"""
@@ -43,7 +44,8 @@ def _popen(cmd):
Friendly wrapper around Popen for Windows
"""
p = Popen(cmd, shell=True, stdout=PIPE, stderr=PIPE, close_fds=os.name != 'nt', universal_newlines=True)
- return p.communicate()
+ output, errors = p.communicate()
+ return output, errors, p.returncode
def walk(root, topdown=True, onerror=None, followlinks=False,
ignore_patterns=None, verbosity=0, stdout=sys.stdout):
@@ -53,8 +55,7 @@ def walk(root, topdown=True, onerror=None, followlinks=False,
if ignore_patterns is None:
ignore_patterns = []
dir_suffix = '%s*' % os.sep
- norm_patterns = map(lambda p: p.endswith(dir_suffix)
- and p[:-len(dir_suffix)] or p, ignore_patterns)
+ norm_patterns = [p[:-len(dir_suffix)] if p.endswith(dir_suffix) else p for p in ignore_patterns]
for dirpath, dirnames, filenames in os.walk(root, topdown, onerror):
remove_dirs = []
for dirname in dirnames:
@@ -142,7 +143,7 @@ def write_pot_file(potfile, msgs, file, work_file, is_templatized):
msgs = '\n'.join(dropwhile(len, msgs.split('\n')))
else:
msgs = msgs.replace('charset=CHARSET', 'charset=UTF-8')
- with open(potfile, 'ab') as fp:
+ with open(potfile, 'a') as fp:
fp.write(msgs)
def process_file(file, dirpath, potfile, domain, verbosity,
@@ -198,15 +199,19 @@ def process_file(file, dirpath, potfile, domain, verbosity,
(domain, wrap, location, work_file))
else:
return
- msgs, errors = _popen(cmd)
+ msgs, errors, status = _popen(cmd)
if errors:
- if is_templatized:
- os.unlink(work_file)
- if os.path.exists(potfile):
- os.unlink(potfile)
- raise CommandError(
- "errors happened while running xgettext on %s\n%s" %
- (file, errors))
+ if status != STATUS_OK:
+ if is_templatized:
+ os.unlink(work_file)
+ if os.path.exists(potfile):
+ os.unlink(potfile)
+ raise CommandError(
+ "errors happened while running xgettext on %s\n%s" %
+ (file, errors))
+ elif verbosity > 0:
+ # Print warnings
+ stdout.write(errors)
if msgs:
write_pot_file(potfile, msgs, orig_file, work_file, is_templatized)
if is_templatized:
@@ -220,33 +225,45 @@ def write_po_file(pofile, potfile, domain, locale, verbosity, stdout,
Uses mguniq, msgmerge, and msgattrib GNU gettext utilities.
"""
- msgs, errors = _popen('msguniq %s %s --to-code=utf-8 "%s"' %
- (wrap, location, potfile))
+ msgs, errors, status = _popen('msguniq %s %s --to-code=utf-8 "%s"' %
+ (wrap, location, potfile))
if errors:
- os.unlink(potfile)
- raise CommandError("errors happened while running msguniq\n%s" % errors)
+ if status != STATUS_OK:
+ os.unlink(potfile)
+ raise CommandError(
+ "errors happened while running msguniq\n%s" % errors)
+ elif verbosity > 0:
+ stdout.write(errors)
+
if os.path.exists(pofile):
with open(potfile, 'w') as fp:
fp.write(msgs)
- msgs, errors = _popen('msgmerge %s %s -q "%s" "%s"' %
- (wrap, location, pofile, potfile))
+ msgs, errors, status = _popen('msgmerge %s %s -q "%s" "%s"' %
+ (wrap, location, pofile, potfile))
if errors:
- os.unlink(potfile)
- raise CommandError(
- "errors happened while running msgmerge\n%s" % errors)
+ if status != STATUS_OK:
+ os.unlink(potfile)
+ raise CommandError(
+ "errors happened while running msgmerge\n%s" % errors)
+ elif verbosity > 0:
+ stdout.write(errors)
elif copy_pforms:
msgs = copy_plural_forms(msgs, locale, domain, verbosity, stdout)
msgs = msgs.replace(
"#. #-#-#-#-# %s.pot (PACKAGE VERSION) #-#-#-#-#\n" % domain, "")
- with open(pofile, 'wb') as fp:
+ with open(pofile, 'w') as fp:
fp.write(msgs)
os.unlink(potfile)
if no_obsolete:
- msgs, errors = _popen('msgattrib %s %s -o "%s" --no-obsolete "%s"' %
- (wrap, location, pofile, pofile))
+ msgs, errors, status = _popen(
+ 'msgattrib %s %s -o "%s" --no-obsolete "%s"' %
+ (wrap, location, pofile, pofile))
if errors:
- raise CommandError(
- "errors happened while running msgattrib\n%s" % errors)
+ if status != STATUS_OK:
+ raise CommandError(
+ "errors happened while running msgattrib\n%s" % errors)
+ elif verbosity > 0:
+ stdout.write(errors)
def make_messages(locale=None, domain='django', verbosity=1, all=False,
extensions=None, symlinks=False, ignore_patterns=None, no_wrap=False,
@@ -291,7 +308,10 @@ def make_messages(locale=None, domain='django', verbosity=1, all=False,
raise CommandError(message)
# We require gettext version 0.15 or newer.
- output = _popen('xgettext --version')[0]
+ output, errors, status = _popen('xgettext --version')
+ if status != STATUS_OK:
+ raise CommandError("Error running xgettext. Note that Django "
+ "internationalization requires GNU gettext 0.15 or newer.")
match = re.search(r'(?P\d+)\.(?P\d+)', output)
if match:
xversion = (int(match.group('major')), int(match.group('minor')))
diff --git a/django/core/management/commands/shell.py b/django/core/management/commands/shell.py
index 26cbd7f005..4e7d1dbbf4 100644
--- a/django/core/management/commands/shell.py
+++ b/django/core/management/commands/shell.py
@@ -2,13 +2,19 @@ import os
from django.core.management.base import NoArgsCommand
from optparse import make_option
+
class Command(NoArgsCommand):
+ shells = ['ipython', 'bpython']
+
option_list = NoArgsCommand.option_list + (
make_option('--plain', action='store_true', dest='plain',
- help='Tells Django to use plain Python, not IPython.'),
+ help='Tells Django to use plain Python, not IPython or bpython.'),
+ make_option('-i', '--interface', action='store', type='choice', choices=shells,
+ dest='interface',
+ help='Specify an interactive interpreter interface. Available options: "ipython" and "bpython"'),
+
)
- help = "Runs a Python interactive interpreter. Tries to use IPython, if it's available."
- shells = ['ipython', 'bpython']
+ help = "Runs a Python interactive interpreter. Tries to use IPython or bpython, if one of them is available."
requires_model_validation = False
def ipython(self):
@@ -31,8 +37,10 @@ class Command(NoArgsCommand):
import bpython
bpython.embed()
- def run_shell(self):
- for shell in self.shells:
+ def run_shell(self, shell=None):
+ available_shells = [shell] if shell else self.shells
+
+ for shell in available_shells:
try:
return getattr(self, shell)()
except ImportError:
@@ -46,19 +54,21 @@ class Command(NoArgsCommand):
get_models()
use_plain = options.get('plain', False)
+ interface = options.get('interface', None)
try:
if use_plain:
# Don't bother loading IPython, because the user wants plain Python.
raise ImportError
- self.run_shell()
+
+ self.run_shell(shell=interface)
except ImportError:
import code
# Set up a dictionary to serve as the environment for the shell, so
# that tab completion works on objects that are imported at runtime.
# See ticket 5082.
imported_objects = {}
- try: # Try activating rlcompleter, because it's handy.
+ try: # Try activating rlcompleter, because it's handy.
import readline
except ImportError:
pass
diff --git a/django/core/management/commands/sql.py b/django/core/management/commands/sql.py
index 59b2e77b69..52b2058650 100644
--- a/django/core/management/commands/sql.py
+++ b/django/core/management/commands/sql.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
from optparse import make_option
from django.core.management.base import AppCommand
@@ -16,4 +18,4 @@ class Command(AppCommand):
output_transaction = True
def handle_app(self, app, **options):
- return u'\n'.join(sql_create(app, self.style, connections[options.get('database')])).encode('utf-8')
+ return '\n'.join(sql_create(app, self.style, connections[options.get('database')]))
diff --git a/django/core/management/commands/sqlall.py b/django/core/management/commands/sqlall.py
index 15966ece66..0e2c05ba82 100644
--- a/django/core/management/commands/sqlall.py
+++ b/django/core/management/commands/sqlall.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
from optparse import make_option
from django.core.management.base import AppCommand
@@ -17,4 +19,4 @@ class Command(AppCommand):
output_transaction = True
def handle_app(self, app, **options):
- return u'\n'.join(sql_all(app, self.style, connections[options.get('database')])).encode('utf-8')
+ return '\n'.join(sql_all(app, self.style, connections[options.get('database')]))
diff --git a/django/core/management/commands/sqlclear.py b/django/core/management/commands/sqlclear.py
index b8f491392b..ec2602d2a3 100644
--- a/django/core/management/commands/sqlclear.py
+++ b/django/core/management/commands/sqlclear.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
from optparse import make_option
from django.core.management.base import AppCommand
@@ -16,4 +18,4 @@ class Command(AppCommand):
output_transaction = True
def handle_app(self, app, **options):
- return u'\n'.join(sql_delete(app, self.style, connections[options.get('database')])).encode('utf-8')
+ return '\n'.join(sql_delete(app, self.style, connections[options.get('database')]))
diff --git a/django/core/management/commands/sqlcustom.py b/django/core/management/commands/sqlcustom.py
index 6a984560de..0d46c4ec70 100644
--- a/django/core/management/commands/sqlcustom.py
+++ b/django/core/management/commands/sqlcustom.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
from optparse import make_option
from django.core.management.base import AppCommand
@@ -16,4 +18,4 @@ class Command(AppCommand):
output_transaction = True
def handle_app(self, app, **options):
- return u'\n'.join(sql_custom(app, self.style, connections[options.get('database')])).encode('utf-8')
+ return '\n'.join(sql_custom(app, self.style, connections[options.get('database')]))
diff --git a/django/core/management/commands/sqlflush.py b/django/core/management/commands/sqlflush.py
index 19054fbfa9..b98ecfd8ff 100644
--- a/django/core/management/commands/sqlflush.py
+++ b/django/core/management/commands/sqlflush.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
from optparse import make_option
from django.core.management.base import NoArgsCommand
@@ -16,4 +18,4 @@ class Command(NoArgsCommand):
output_transaction = True
def handle_noargs(self, **options):
- return u'\n'.join(sql_flush(self.style, connections[options.get('database')], only_django=True)).encode('utf-8')
+ return '\n'.join(sql_flush(self.style, connections[options.get('database')], only_django=True))
diff --git a/django/core/management/commands/sqlindexes.py b/django/core/management/commands/sqlindexes.py
index bf55b0dffc..f95d4f158c 100644
--- a/django/core/management/commands/sqlindexes.py
+++ b/django/core/management/commands/sqlindexes.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
from optparse import make_option
from django.core.management.base import AppCommand
@@ -17,4 +19,4 @@ class Command(AppCommand):
output_transaction = True
def handle_app(self, app, **options):
- return u'\n'.join(sql_indexes(app, self.style, connections[options.get('database')])).encode('utf-8')
+ return '\n'.join(sql_indexes(app, self.style, connections[options.get('database')]))
diff --git a/django/core/management/commands/sqlsequencereset.py b/django/core/management/commands/sqlsequencereset.py
index 6460f00062..7b9e85a9ee 100644
--- a/django/core/management/commands/sqlsequencereset.py
+++ b/django/core/management/commands/sqlsequencereset.py
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
from optparse import make_option
from django.core.management.base import AppCommand
@@ -17,4 +19,4 @@ class Command(AppCommand):
def handle_app(self, app, **options):
connection = connections[options.get('database')]
- return u'\n'.join(connection.ops.sequence_reset_sql(self.style, models.get_models(app, include_auto_created=True))).encode('utf-8')
+ return '\n'.join(connection.ops.sequence_reset_sql(self.style, models.get_models(app, include_auto_created=True)))
diff --git a/django/core/management/commands/syncdb.py b/django/core/management/commands/syncdb.py
index 973441dc1c..4ce2910fb5 100644
--- a/django/core/management/commands/syncdb.py
+++ b/django/core/management/commands/syncdb.py
@@ -2,6 +2,7 @@ from optparse import make_option
import traceback
from django.conf import settings
+from django.core.management import call_command
from django.core.management.base import NoArgsCommand
from django.core.management.color import no_style
from django.core.management.sql import custom_sql_for_model, emit_post_sync_signal
@@ -14,6 +15,8 @@ class Command(NoArgsCommand):
option_list = NoArgsCommand.option_list + (
make_option('--noinput', action='store_false', dest='interactive', default=True,
help='Tells Django to NOT prompt the user for input of any kind.'),
+ make_option('--no-initial-data', action='store_false', dest='load_initial_data', default=True,
+ help='Tells Django not to load any initial data after database synchronization.'),
make_option('--database', action='store', dest='database',
default=DEFAULT_DB_ALIAS, help='Nominates a database to synchronize. '
'Defaults to the "default" database.'),
@@ -25,10 +28,7 @@ class Command(NoArgsCommand):
verbosity = int(options.get('verbosity'))
interactive = options.get('interactive')
show_traceback = options.get('traceback')
-
- # Stealth option -- 'load_initial_data' is used by the testing setup
- # process to disable initial fixture loading.
- load_initial_data = options.get('load_initial_data', True)
+ load_initial_data = options.get('load_initial_data')
self.style = no_style()
@@ -76,7 +76,7 @@ class Command(NoArgsCommand):
(opts.auto_created and converter(opts.auto_created._meta.db_table) in tables))
manifest = SortedDict(
- (app_name, filter(model_installed, model_list))
+ (app_name, list(filter(model_installed, model_list)))
for app_name, model_list in all_models
)
@@ -159,6 +159,5 @@ class Command(NoArgsCommand):
# Load initial_data fixtures (unless that has been disabled)
if load_initial_data:
- from django.core.management import call_command
call_command('loaddata', 'initial_data', verbosity=verbosity,
database=db, skip_validation=True)
diff --git a/django/core/management/sql.py b/django/core/management/sql.py
index c10c100214..ac16a5b358 100644
--- a/django/core/management/sql.py
+++ b/django/core/management/sql.py
@@ -1,3 +1,6 @@
+from __future__ import unicode_literals
+
+import codecs
import os
import re
@@ -99,7 +102,7 @@ def sql_delete(app, style, connection):
return output[::-1] # Reverse it, to deal with table dependencies.
-def sql_flush(style, connection, only_django=False):
+def sql_flush(style, connection, only_django=False, reset_sequences=True):
"""
Returns a list of the SQL statements used to flush the database.
@@ -110,9 +113,8 @@ def sql_flush(style, connection, only_django=False):
tables = connection.introspection.django_table_names(only_existing=True)
else:
tables = connection.introspection.table_names()
- statements = connection.ops.sql_flush(
- style, tables, connection.introspection.sequence_list()
- )
+ seqs = connection.introspection.sequence_list() if reset_sequences else ()
+ statements = connection.ops.sql_flush(style, tables, seqs)
return statements
@@ -141,6 +143,21 @@ def sql_all(app, style, connection):
return sql_create(app, style, connection) + sql_custom(app, style, connection) + sql_indexes(app, style, connection)
+def _split_statements(content):
+ comment_re = re.compile(r"^((?:'[^']*'|[^'])*?)--.*$")
+ statements = []
+ statement = ""
+ for line in content.split("\n"):
+ cleaned_line = comment_re.sub(r"\1", line).strip()
+ if not cleaned_line:
+ continue
+ statement += cleaned_line
+ if statement.endswith(";"):
+ statements.append(statement)
+ statement = ""
+ return statements
+
+
def custom_sql_for_model(model, style, connection):
opts = model._meta
app_dir = os.path.normpath(os.path.join(os.path.dirname(models.get_app(model._meta.app_label).__file__), 'sql'))
@@ -154,23 +171,16 @@ def custom_sql_for_model(model, style, connection):
for f in post_sql_fields:
output.extend(f.post_create_sql(style, model._meta.db_table))
- # Some backends can't execute more than one SQL statement at a time,
- # so split into separate statements.
- statements = re.compile(r";[ \t]*$", re.M)
-
# Find custom SQL, if it's available.
backend_name = connection.settings_dict['ENGINE'].split('.')[-1]
sql_files = [os.path.join(app_dir, "%s.%s.sql" % (opts.object_name.lower(), backend_name)),
os.path.join(app_dir, "%s.sql" % opts.object_name.lower())]
for sql_file in sql_files:
if os.path.exists(sql_file):
- with open(sql_file, 'U') as fp:
- for statement in statements.split(fp.read().decode(settings.FILE_CHARSET)):
- # Remove any comments from the file
- statement = re.sub(ur"--.*([\n\Z]|$)", "", statement)
- if statement.strip():
- output.append(statement + u";")
-
+ with codecs.open(sql_file, 'U', encoding=settings.FILE_CHARSET) as fp:
+ # Some backends can't execute more than one SQL statement at a time,
+ # so split into separate statements.
+ output.extend(_split_statements(fp.read()))
return output
diff --git a/django/core/management/templates.py b/django/core/management/templates.py
index 623aa69deb..52d0e5c89d 100644
--- a/django/core/management/templates.py
+++ b/django/core/management/templates.py
@@ -8,7 +8,10 @@ import shutil
import stat
import sys
import tempfile
-import urllib
+try:
+ from urllib.request import urlretrieve
+except ImportError: # Python 2
+ from urllib import urlretrieve
from optparse import make_option
from os import path
@@ -112,7 +115,7 @@ class TemplateCommand(BaseCommand):
context = Context(dict(options, **{
base_name: name,
base_directory: top_dir,
- }))
+ }), autoescape=False)
# Setup a stub settings environment for template rendering
from django.conf import settings
@@ -227,8 +230,7 @@ class TemplateCommand(BaseCommand):
if self.verbosity >= 2:
self.stdout.write("Downloading %s\n" % display_url)
try:
- the_path, info = urllib.urlretrieve(url,
- path.join(tempdir, filename))
+ the_path, info = urlretrieve(url, path.join(tempdir, filename))
except IOError as e:
raise CommandError("couldn't download URL %s to %s: %s" %
(url, filename, e))
diff --git a/django/core/management/validation.py b/django/core/management/validation.py
index f613009e98..c1cd3d8776 100644
--- a/django/core/management/validation.py
+++ b/django/core/management/validation.py
@@ -1,7 +1,9 @@
import sys
from django.core.management.color import color_style
+from django.utils.encoding import smart_str
from django.utils.itercompat import is_iterable
+from django.utils import six
class ModelErrorCollection:
@@ -12,7 +14,7 @@ class ModelErrorCollection:
def add(self, context, error):
self.errors.append((context, error))
- self.outfile.write(self.style.ERROR("%s: %s\n" % (context, error)))
+ self.outfile.write(self.style.ERROR(smart_str("%s: %s\n" % (context, error))))
def get_validation_errors(outfile, app=None):
@@ -94,7 +96,7 @@ def get_validation_errors(outfile, app=None):
if isinstance(f, models.FilePathField) and not (f.allow_files or f.allow_folders):
e.add(opts, '"%s": FilePathFields must have either allow_files or allow_folders set to True.' % f.name)
if f.choices:
- if isinstance(f.choices, basestring) or not is_iterable(f.choices):
+ if isinstance(f.choices, six.string_types) or not is_iterable(f.choices):
e.add(opts, '"%s": "choices" should be iterable (e.g., a tuple or list).' % f.name)
else:
for c in f.choices:
@@ -120,7 +122,7 @@ def get_validation_errors(outfile, app=None):
e.add(opts, "'%s' has a relation with model %s, which has either not been installed or is abstract." % (f.name, f.rel.to))
# it is a string and we could not find the model it refers to
# so skip the next section
- if isinstance(f.rel.to, (str, unicode)):
+ if isinstance(f.rel.to, six.string_types):
continue
# Make sure the model we're related hasn't been swapped out
@@ -166,7 +168,7 @@ def get_validation_errors(outfile, app=None):
e.add(opts, "'%s' has an m2m relation with model %s, which has either not been installed or is abstract." % (f.name, f.rel.to))
# it is a string and we could not find the model it refers to
# so skip the next section
- if isinstance(f.rel.to, (str, unicode)):
+ if isinstance(f.rel.to, six.string_types):
continue
# Make sure the model we're related hasn't been swapped out
@@ -177,7 +179,7 @@ def get_validation_errors(outfile, app=None):
if f.unique:
e.add(opts, "ManyToManyFields cannot be unique. Remove the unique argument on '%s'." % f.name)
- if f.rel.through is not None and not isinstance(f.rel.through, basestring):
+ if f.rel.through is not None and not isinstance(f.rel.through, six.string_types):
from_model, to_model = cls, f.rel.to
if from_model == to_model and f.rel.symmetrical and not f.rel.through._meta.auto_created:
e.add(opts, "Many-to-many fields with intermediate tables cannot be symmetrical.")
@@ -248,7 +250,7 @@ def get_validation_errors(outfile, app=None):
"to %s and %s" % (f.name, f.rel.through._meta.object_name,
f.rel.to._meta.object_name, cls._meta.object_name)
)
- elif isinstance(f.rel.through, basestring):
+ elif isinstance(f.rel.through, six.string_types):
e.add(opts, "'%s' specifies an m2m relation through model %s, "
"which has not been installed" % (f.name, f.rel.through)
)
diff --git a/django/core/paginator.py b/django/core/paginator.py
index 8b4d2891b2..6b0b3542f8 100644
--- a/django/core/paginator.py
+++ b/django/core/paginator.py
@@ -132,10 +132,10 @@ class Page(object):
return self.has_previous() or self.has_next()
def next_page_number(self):
- return self.number + 1
+ return self.paginator.validate_number(self.number + 1)
def previous_page_number(self):
- return self.number - 1
+ return self.paginator.validate_number(self.number - 1)
def start_index(self):
"""
diff --git a/django/core/serializers/__init__.py b/django/core/serializers/__init__.py
index 09bcb651d5..cf7e66190f 100644
--- a/django/core/serializers/__init__.py
+++ b/django/core/serializers/__init__.py
@@ -18,6 +18,7 @@ To add your own serializers, use the SERIALIZATION_MODULES setting::
from django.conf import settings
from django.utils import importlib
+from django.utils import six
from django.core.serializers.base import SerializerDoesNotExist
# Built-in serializers
@@ -75,12 +76,12 @@ def get_serializer(format):
def get_serializer_formats():
if not _serializers:
_load_serializers()
- return _serializers.keys()
+ return list(_serializers)
def get_public_serializer_formats():
if not _serializers:
_load_serializers()
- return [k for k, v in _serializers.iteritems() if not v.Serializer.internal_use_only]
+ return [k for k, v in six.iteritems(_serializers) if not v.Serializer.internal_use_only]
def get_deserializer(format):
if not _serializers:
diff --git a/django/core/serializers/base.py b/django/core/serializers/base.py
index 04053c1f8f..276f9a4738 100644
--- a/django/core/serializers/base.py
+++ b/django/core/serializers/base.py
@@ -2,10 +2,9 @@
Module for abstract serializer/unserializer base classes.
"""
-from io import BytesIO
-
from django.db import models
-from django.utils.encoding import smart_unicode
+from django.utils.encoding import smart_text
+from django.utils import six
class SerializerDoesNotExist(KeyError):
"""The requested serializer was not found."""
@@ -34,7 +33,7 @@ class Serializer(object):
"""
self.options = options
- self.stream = options.pop("stream", BytesIO())
+ self.stream = options.pop("stream", six.StringIO())
self.selected_fields = options.pop("fields", None)
self.use_natural_keys = options.pop("use_natural_keys", False)
@@ -123,8 +122,8 @@ class Deserializer(object):
Init this serializer given a stream or a string
"""
self.options = options
- if isinstance(stream_or_string, basestring):
- self.stream = BytesIO(stream_or_string)
+ if isinstance(stream_or_string, six.string_types):
+ self.stream = six.StringIO(stream_or_string)
else:
self.stream = stream_or_string
# hack to make sure that the models have all been loaded before
@@ -135,10 +134,12 @@ class Deserializer(object):
def __iter__(self):
return self
- def next(self):
+ def __next__(self):
"""Iteration iterface -- return the next item in the stream"""
raise NotImplementedError
+ next = __next__ # Python 2 compatibility
+
class DeserializedObject(object):
"""
A deserialized model.
diff --git a/django/core/serializers/json.py b/django/core/serializers/json.py
index fce00600f4..4ba0d7fd79 100644
--- a/django/core/serializers/json.py
+++ b/django/core/serializers/json.py
@@ -8,11 +8,12 @@ from __future__ import absolute_import
import datetime
import decimal
import json
-from io import BytesIO
from django.core.serializers.base import DeserializationError
from django.core.serializers.python import Serializer as PythonSerializer
from django.core.serializers.python import Deserializer as PythonDeserializer
+from django.utils.encoding import smart_bytes
+from django.utils import six
from django.utils.timezone import is_aware
class Serializer(PythonSerializer):
@@ -52,21 +53,21 @@ class Serializer(PythonSerializer):
self._current = None
def getvalue(self):
- # overwrite PythonSerializer.getvalue() with base Serializer.getvalue()
- if callable(getattr(self.stream, 'getvalue', None)):
- return self.stream.getvalue()
+ # Grand-parent super
+ return super(PythonSerializer, self).getvalue()
def Deserializer(stream_or_string, **options):
"""
Deserialize a stream or string of JSON data.
"""
- if isinstance(stream_or_string, basestring):
- stream = BytesIO(stream_or_string)
- else:
- stream = stream_or_string
+ if not isinstance(stream_or_string, (bytes, six.string_types)):
+ stream_or_string = stream_or_string.read()
+ if isinstance(stream_or_string, bytes):
+ stream_or_string = stream_or_string.decode('utf-8')
try:
- for obj in PythonDeserializer(json.load(stream), **options):
+ objects = json.loads(stream_or_string)
+ for obj in PythonDeserializer(objects, **options):
yield obj
except GeneratorExit:
raise
diff --git a/django/core/serializers/python.py b/django/core/serializers/python.py
index 49120434eb..a1fff6f9bb 100644
--- a/django/core/serializers/python.py
+++ b/django/core/serializers/python.py
@@ -3,11 +3,13 @@ A Python "serializer". Doesn't do much serializing per se -- just converts to
and from basic Python data types (lists, dicts, strings, etc.). Useful as a basis for
other serializers.
"""
+from __future__ import unicode_literals
from django.conf import settings
from django.core.serializers import base
from django.db import models, DEFAULT_DB_ALIAS
-from django.utils.encoding import smart_unicode, is_protected_type
+from django.utils.encoding import smart_text, is_protected_type
+from django.utils import six
class Serializer(base.Serializer):
"""
@@ -32,8 +34,8 @@ class Serializer(base.Serializer):
def get_dump_object(self, obj):
return {
- "pk": smart_unicode(obj._get_pk_val(), strings_only=True),
- "model": smart_unicode(obj._meta),
+ "pk": smart_text(obj._get_pk_val(), strings_only=True),
+ "model": smart_text(obj._meta),
"fields": self._current
}
@@ -63,7 +65,7 @@ class Serializer(base.Serializer):
if self.use_natural_keys and hasattr(field.rel.to, 'natural_key'):
m2m_value = lambda value: value.natural_key()
else:
- m2m_value = lambda value: smart_unicode(value._get_pk_val(), strings_only=True)
+ m2m_value = lambda value: smart_text(value._get_pk_val(), strings_only=True)
self._current[field.name] = [m2m_value(related)
for related in getattr(obj, field.name).iterator()]
@@ -86,9 +88,9 @@ def Deserializer(object_list, **options):
m2m_data = {}
# Handle each field
- for (field_name, field_value) in d["fields"].iteritems():
+ for (field_name, field_value) in six.iteritems(d["fields"]):
if isinstance(field_value, str):
- field_value = smart_unicode(field_value, options.get("encoding", settings.DEFAULT_CHARSET), strings_only=True)
+ field_value = smart_text(field_value, options.get("encoding", settings.DEFAULT_CHARSET), strings_only=True)
field = Model._meta.get_field(field_name)
@@ -96,19 +98,19 @@ def Deserializer(object_list, **options):
if field.rel and isinstance(field.rel, models.ManyToManyRel):
if hasattr(field.rel.to._default_manager, 'get_by_natural_key'):
def m2m_convert(value):
- if hasattr(value, '__iter__'):
+ if hasattr(value, '__iter__') and not isinstance(value, six.text_type):
return field.rel.to._default_manager.db_manager(db).get_by_natural_key(*value).pk
else:
- return smart_unicode(field.rel.to._meta.pk.to_python(value))
+ return smart_text(field.rel.to._meta.pk.to_python(value))
else:
- m2m_convert = lambda v: smart_unicode(field.rel.to._meta.pk.to_python(v))
+ m2m_convert = lambda v: smart_text(field.rel.to._meta.pk.to_python(v))
m2m_data[field.name] = [m2m_convert(pk) for pk in field_value]
# Handle FK fields
elif field.rel and isinstance(field.rel, models.ManyToOneRel):
if field_value is not None:
if hasattr(field.rel.to._default_manager, 'get_by_natural_key'):
- if hasattr(field_value, '__iter__'):
+ if hasattr(field_value, '__iter__') and not isinstance(field_value, six.text_type):
obj = field.rel.to._default_manager.db_manager(db).get_by_natural_key(*field_value)
value = getattr(obj, field.rel.field_name)
# If this is a natural foreign key to an object that
@@ -138,5 +140,5 @@ def _get_model(model_identifier):
except TypeError:
Model = None
if Model is None:
- raise base.DeserializationError(u"Invalid model identifier: '%s'" % model_identifier)
+ raise base.DeserializationError("Invalid model identifier: '%s'" % model_identifier)
return Model
diff --git a/django/core/serializers/pyyaml.py b/django/core/serializers/pyyaml.py
index 5effda5b46..9be1ea4492 100644
--- a/django/core/serializers/pyyaml.py
+++ b/django/core/serializers/pyyaml.py
@@ -6,12 +6,15 @@ Requires PyYaml (http://pyyaml.org/), but that's checked for in __init__.
import decimal
import yaml
-from io import BytesIO
+from io import StringIO
from django.db import models
from django.core.serializers.base import DeserializationError
from django.core.serializers.python import Serializer as PythonSerializer
from django.core.serializers.python import Deserializer as PythonDeserializer
+from django.utils.encoding import smart_bytes
+from django.utils import six
+
class DjangoSafeDumper(yaml.SafeDumper):
def represent_decimal(self, data):
@@ -42,14 +45,17 @@ class Serializer(PythonSerializer):
yaml.dump(self.objects, self.stream, Dumper=DjangoSafeDumper, **self.options)
def getvalue(self):
- return self.stream.getvalue()
+ # Grand-parent super
+ return super(PythonSerializer, self).getvalue()
def Deserializer(stream_or_string, **options):
"""
Deserialize a stream or string of YAML data.
"""
- if isinstance(stream_or_string, basestring):
- stream = BytesIO(stream_or_string)
+ if isinstance(stream_or_string, bytes):
+ stream_or_string = stream_or_string.decode('utf-8')
+ if isinstance(stream_or_string, six.string_types):
+ stream = StringIO(stream_or_string)
else:
stream = stream_or_string
try:
diff --git a/django/core/serializers/xml_serializer.py b/django/core/serializers/xml_serializer.py
index a5edeac5af..666587dc77 100644
--- a/django/core/serializers/xml_serializer.py
+++ b/django/core/serializers/xml_serializer.py
@@ -2,11 +2,13 @@
XML serializer.
"""
+from __future__ import unicode_literals
+
from django.conf import settings
from django.core.serializers import base
from django.db import models, DEFAULT_DB_ALIAS
from django.utils.xmlutils import SimplerXMLGenerator
-from django.utils.encoding import smart_unicode
+from django.utils.encoding import smart_text
from xml.dom import pulldom
class Serializer(base.Serializer):
@@ -44,11 +46,11 @@ class Serializer(base.Serializer):
self.indent(1)
obj_pk = obj._get_pk_val()
if obj_pk is None:
- attrs = {"model": smart_unicode(obj._meta),}
+ attrs = {"model": smart_text(obj._meta),}
else:
attrs = {
- "pk": smart_unicode(obj._get_pk_val()),
- "model": smart_unicode(obj._meta),
+ "pk": smart_text(obj._get_pk_val()),
+ "model": smart_text(obj._meta),
}
self.xml.startElement("object", attrs)
@@ -94,10 +96,10 @@ class Serializer(base.Serializer):
# Iterable natural keys are rolled out as subelements
for key_value in related:
self.xml.startElement("natural", {})
- self.xml.characters(smart_unicode(key_value))
+ self.xml.characters(smart_text(key_value))
self.xml.endElement("natural")
else:
- self.xml.characters(smart_unicode(related_att))
+ self.xml.characters(smart_text(related_att))
else:
self.xml.addQuickElement("None")
self.xml.endElement("field")
@@ -118,13 +120,13 @@ class Serializer(base.Serializer):
self.xml.startElement("object", {})
for key_value in natural:
self.xml.startElement("natural", {})
- self.xml.characters(smart_unicode(key_value))
+ self.xml.characters(smart_text(key_value))
self.xml.endElement("natural")
self.xml.endElement("object")
else:
def handle_m2m(value):
self.xml.addQuickElement("object", attrs={
- 'pk' : smart_unicode(value._get_pk_val())
+ 'pk' : smart_text(value._get_pk_val())
})
for relobj in getattr(obj, field.name).iterator():
handle_m2m(relobj)
@@ -139,7 +141,7 @@ class Serializer(base.Serializer):
self.xml.startElement("field", {
"name" : field.name,
"rel" : field.rel.__class__.__name__,
- "to" : smart_unicode(field.rel.to._meta),
+ "to" : smart_text(field.rel.to._meta),
})
class Deserializer(base.Deserializer):
@@ -152,13 +154,15 @@ class Deserializer(base.Deserializer):
self.event_stream = pulldom.parse(self.stream)
self.db = options.pop('using', DEFAULT_DB_ALIAS)
- def next(self):
+ def __next__(self):
for event, node in self.event_stream:
if event == "START_ELEMENT" and node.nodeName == "object":
self.event_stream.expandNode(node)
return self._handle_object(node)
raise StopIteration
+ next = __next__ # Python 2 compatibility
+
def _handle_object(self, node):
"""
Convert an
') and
@@ -208,33 +210,33 @@ class BaseForm(StrAndUnicode):
# If there aren't any rows in the output, just append the
# hidden fields.
output.append(str_hidden)
- return mark_safe(u'\n'.join(output))
+ return mark_safe('\n'.join(output))
def as_table(self):
"Returns this form rendered as HTML
',
+ row_ender = '',
+ help_text_html = ' %s',
errors_on_separate_row = False)
def as_ul(self):
"Returns this form rendered as HTML
s -- excluding the
."
return self._html_output(
- normal_row = u'
%(errors)s%(label)s %(field)s%(help_text)s
',
- error_row = u'
%s
',
+ normal_row = '
%(errors)s%(label)s %(field)s%(help_text)s
',
+ error_row = '
%s
',
row_ender = '',
- help_text_html = u' %s',
+ help_text_html = ' %s',
errors_on_separate_row = False)
def as_p(self):
"Returns this form rendered as HTML
s."
return self._html_output(
- normal_row = u'
%(label)s %(field)s%(help_text)s
',
- error_row = u'%s',
+ normal_row = '
%(label)s %(field)s%(help_text)s
',
+ error_row = '%s',
row_ender = '
',
- help_text_html = u' %s',
+ help_text_html = ' %s',
errors_on_separate_row = True)
def non_field_errors(self):
@@ -270,8 +272,6 @@ class BaseForm(StrAndUnicode):
self._clean_fields()
self._clean_form()
self._post_clean()
- if self._errors:
- del self.cleaned_data
def _clean_fields(self):
for name, field in self.fields.items():
@@ -380,16 +380,16 @@ class BaseForm(StrAndUnicode):
"""
return [field for field in self if not field.is_hidden]
-class Form(BaseForm):
+class Form(six.with_metaclass(DeclarativeFieldsMetaclass, BaseForm)):
"A collection of Fields, plus their associated data."
# This is a separate class from BaseForm in order to abstract the way
# self.fields is specified. This class (Form) is the one that does the
# fancy metaclass stuff purely for the semantic sugar -- it allows one
# to define a form using declarative syntax.
# BaseForm itself has no way of designating self.fields.
- __metaclass__ = DeclarativeFieldsMetaclass
-class BoundField(StrAndUnicode):
+@python_2_unicode_compatible
+class BoundField(object):
"A Field plus data"
def __init__(self, form, field, name):
self.form = form
@@ -404,7 +404,7 @@ class BoundField(StrAndUnicode):
self.label = self.field.label
self.help_text = field.help_text or ''
- def __unicode__(self):
+ def __str__(self):
"""Renders this field as an HTML widget."""
if self.field.show_hidden_initial:
return self.as_widget() + self.as_hidden(only_initial=True)
@@ -498,8 +498,8 @@ class BoundField(StrAndUnicode):
def label_tag(self, contents=None, attrs=None):
"""
Wraps the given contents in a