Merge branch 'master' of github.com:django/django into schema-alteration

Conflicts:
	django/db/backends/postgresql_psycopg2/base.py
This commit is contained in:
Andrew Godwin 2012-07-26 18:58:10 +01:00
commit 4a2e80fff4
406 changed files with 4421 additions and 2766 deletions

View File

@ -30,6 +30,7 @@ The PRIMARY AUTHORS are (and/or have been):
* Aymeric Augustin
* Claude Paroz
* Anssi Kääriäinen
* Florian Apolloner
More information on the main contributors to Django can be found in
docs/internals/committers.txt.
@ -61,7 +62,6 @@ answer newbie questions, and generally made Django that much better:
andy@jadedplanet.net
Fabrice Aneche <akh@nobugware.com>
ant9000@netwise.it
Florian Apolloner <florian@apolloner.eu>
arien <regexbot@gmail.com>
David Ascher <http://ascher.ca/>
atlithorn <atlithorn@gmail.com>

View File

@ -15,6 +15,7 @@ from django.conf import global_settings
from django.core.exceptions import ImproperlyConfigured
from django.utils.functional import LazyObject, empty
from django.utils import importlib
from django.utils import six
ENVIRONMENT_VARIABLE = "DJANGO_SETTINGS_MODULE"
@ -73,7 +74,7 @@ class BaseSettings(object):
elif name == "ADMIN_MEDIA_PREFIX":
warnings.warn("The ADMIN_MEDIA_PREFIX setting has been removed; "
"use STATIC_URL instead.", DeprecationWarning)
elif name == "ALLOWED_INCLUDE_ROOTS" and isinstance(value, basestring):
elif name == "ALLOWED_INCLUDE_ROOTS" and isinstance(value, six.string_types):
raise ValueError("The ALLOWED_INCLUDE_ROOTS setting must be set "
"to a tuple, not a string.")
object.__setattr__(self, name, value)
@ -102,7 +103,10 @@ class Settings(BaseSettings):
if setting == setting.upper():
setting_value = getattr(mod, setting)
if setting in tuple_settings and \
isinstance(setting_value, basestring):
isinstance(setting_value, six.string_types):
warnings.warn("The %s setting must be a tuple. Please fix your "
"settings, as auto-correction is now deprecated." % setting,
PendingDeprecationWarning)
setting_value = (setting_value,) # In case the user forgot the comma.
setattr(self, setting, setting_value)

View File

@ -2,6 +2,7 @@ from django.core.urlresolvers import (RegexURLPattern,
RegexURLResolver, LocaleRegexURLResolver)
from django.core.exceptions import ImproperlyConfigured
from django.utils.importlib import import_module
from django.utils import six
__all__ = ['handler403', 'handler404', 'handler500', 'include', 'patterns', 'url']
@ -20,7 +21,7 @@ def include(arg, namespace=None, app_name=None):
# No namespace hint - use manually provided namespace
urlconf_module = arg
if isinstance(urlconf_module, basestring):
if isinstance(urlconf_module, six.string_types):
urlconf_module = import_module(urlconf_module)
patterns = getattr(urlconf_module, 'urlpatterns', urlconf_module)
@ -52,7 +53,7 @@ def url(regex, view, kwargs=None, name=None, prefix=''):
urlconf_module, app_name, namespace = view
return RegexURLResolver(regex, urlconf_module, kwargs, app_name=app_name, namespace=namespace)
else:
if isinstance(view, basestring):
if isinstance(view, six.string_types):
if not view:
raise ImproperlyConfigured('Empty URL pattern view name not permitted (for pattern %r)' % regex)
if prefix:

View File

@ -10,8 +10,9 @@ from django.db.models.fields.related import ManyToManyRel
from django.forms.util import flatatt
from django.template.defaultfilters import capfirst
from django.utils.encoding import force_unicode, smart_unicode
from django.utils.html import escape, conditional_escape
from django.utils.html import conditional_escape, format_html
from django.utils.safestring import mark_safe
from django.utils import six
from django.utils.translation import ugettext_lazy as _
from django.conf import settings
@ -49,7 +50,7 @@ class AdminForm(object):
try:
fieldset_name, fieldset_options = self.fieldsets[0]
field_name = fieldset_options['fields'][0]
if not isinstance(field_name, basestring):
if not isinstance(field_name, six.string_types):
field_name = field_name[0]
return self.form[field_name]
except (KeyError, IndexError):
@ -163,11 +164,9 @@ class AdminReadonlyField(object):
if not self.is_first:
attrs["class"] = "inline"
label = self.field['label']
contents = capfirst(force_unicode(escape(label))) + ":"
return mark_safe('<label%(attrs)s>%(contents)s</label>' % {
"attrs": flatatt(attrs),
"contents": contents,
})
return format_html('<label{0}>{1}:</label>',
flatatt(attrs),
capfirst(force_unicode(label)))
def contents(self):
from django.contrib.admin.templatetags.admin_list import _boolean_icon
@ -190,7 +189,7 @@ class AdminReadonlyField(object):
if value is None:
result_repr = EMPTY_CHANGELIST_VALUE
elif isinstance(f.rel, ManyToManyRel):
result_repr = ", ".join(map(unicode, value.all()))
result_repr = ", ".join(map(six.text_type, value.all()))
else:
result_repr = display_for_field(value, f)
return conditional_escape(result_repr)

View File

@ -6,7 +6,6 @@ from django.contrib.auth.models import User
from django.contrib.admin.util import quote
from django.utils.translation import ugettext_lazy as _
from django.utils.encoding import smart_unicode
from django.utils.safestring import mark_safe
ADDITION = 1
CHANGE = 2
@ -66,5 +65,5 @@ class LogEntry(models.Model):
This is relative to the Django admin index page.
"""
if self.content_type and self.object_id:
return mark_safe("%s/%s/%s/" % (self.content_type.app_label, self.content_type.model, quote(self.object_id)))
return "%s/%s/%s/" % (self.content_type.app_label, self.content_type.model, quote(self.object_id))
return None

View File

@ -24,6 +24,7 @@ from django.utils.decorators import method_decorator
from django.utils.datastructures import SortedDict
from django.utils.html import escape, escapejs
from django.utils.safestring import mark_safe
from django.utils import six
from django.utils.text import capfirst, get_text_list
from django.utils.translation import ugettext as _
from django.utils.translation import ungettext
@ -57,9 +58,8 @@ FORMFIELD_FOR_DBFIELD_DEFAULTS = {
csrf_protect_m = method_decorator(csrf_protect)
class BaseModelAdmin(object):
class BaseModelAdmin(six.with_metaclass(forms.MediaDefiningClass)):
"""Functionality common to both ModelAdmin and InlineAdmin."""
__metaclass__ = forms.MediaDefiningClass
raw_id_fields = ()
fields = None
@ -745,7 +745,7 @@ class ModelAdmin(BaseModelAdmin):
'has_file_field': True, # FIXME - this should check if form or formsets have a FileField,
'has_absolute_url': hasattr(self.model, 'get_absolute_url'),
'ordered_objects': ordered_objects,
'form_url': mark_safe(form_url),
'form_url': form_url,
'opts': opts,
'content_type_id': ContentType.objects.get_for_model(self.model).id,
'save_as': self.save_as,
@ -998,7 +998,6 @@ class ModelAdmin(BaseModelAdmin):
'title': _('Add %s') % force_unicode(opts.verbose_name),
'adminform': adminForm,
'is_popup': "_popup" in request.REQUEST,
'show_delete': False,
'media': media,
'inline_admin_formsets': inline_admin_formsets,
'errors': helpers.AdminErrorList(form, formsets),
@ -1321,7 +1320,7 @@ class ModelAdmin(BaseModelAdmin):
opts = model._meta
app_label = opts.app_label
action_list = LogEntry.objects.filter(
object_id = object_id,
object_id = unquote(object_id),
content_type__id__exact = ContentType.objects.get_for_model(model).id
).select_related().order_by('action_time')
# If no history was found, see whether this object even exists.

View File

@ -231,7 +231,8 @@ class AdminSite(object):
wrap(self.i18n_javascript, cacheable=True),
name='jsi18n'),
url(r'^r/(?P<content_type_id>\d+)/(?P<object_id>.+)/$',
wrap(contenttype_views.shortcut)),
wrap(contenttype_views.shortcut),
name='view_on_site'),
url(r'^(?P<app_label>\w+)/$',
wrap(self.app_index),
name='app_list')

View File

@ -41,7 +41,8 @@
text-align: left;
}
.selector .selector-filter label {
.selector .selector-filter label,
.inline-group .aligned .selector .selector-filter label {
width: 16px;
padding: 2px;
}

View File

@ -3,8 +3,7 @@
{% load admin_urls %}
{% block extrahead %}{{ block.super }}
{% url 'admin:jsi18n' as jsi18nurl %}
<script type="text/javascript" src="{{ jsi18nurl|default:"../../../../jsi18n/" }}"></script>
<script type="text/javascript" src="{% url 'admin:jsi18n' %}"></script>
{% endblock %}
{% block extrastyle %}{{ block.super }}<link rel="stylesheet" type="text/css" href="{% static "admin/css/forms.css" %}" />{% endblock %}
{% block bodyclass %}{{ opts.app_label }}-{{ opts.object_name.lower }} change-form{% endblock %}

View File

@ -3,8 +3,7 @@
{% load admin_urls %}
{% block extrahead %}{{ block.super }}
{% url 'admin:jsi18n' as jsi18nurl %}
<script type="text/javascript" src="{{ jsi18nurl|default:"../../../jsi18n/" }}"></script>
<script type="text/javascript" src="{% url 'admin:jsi18n' %}"></script>
{{ media }}
{% endblock %}
@ -31,7 +30,7 @@
<ul class="object-tools">
{% block object-tools-items %}
<li><a href="history/" class="historylink">{% trans "History" %}</a></li>
{% if has_absolute_url %}<li><a href="../../../r/{{ content_type_id }}/{{ original.pk }}/" class="viewsitelink">{% trans "View on site" %}</a></li>{% endif%}
{% if has_absolute_url %}<li><a href="{% url 'admin:view_on_site' content_type_id original.pk %}" class="viewsitelink">{% trans "View on site" %}</a></li>{% endif%}
{% endblock %}
</ul>
{% endif %}{% endif %}

View File

@ -9,8 +9,7 @@
<link rel="stylesheet" type="text/css" href="{% static "admin/css/forms.css" %}" />
{% endif %}
{% if cl.formset or action_form %}
{% url 'admin:jsi18n' as jsi18nurl %}
<script type="text/javascript" src="{{ jsi18nurl|default:'../../jsi18n/' }}"></script>
<script type="text/javascript" src="{% url 'admin:jsi18n' %}"></script>
{% endif %}
{{ media.css }}
{% if not actions_on_top and not actions_on_bottom %}

View File

@ -7,7 +7,7 @@
<a href="{% url 'admin:index' %}">{% trans 'Home' %}</a>
&rsaquo; <a href="{% url 'admin:app_list' app_label=opts.app_label %}">{{ app_label|capfirst }}</a>
&rsaquo; <a href="{% url opts|admin_urlname:'changelist' %}">{{ opts.verbose_name_plural|capfirst|escape }}</a>
&rsaquo; <a href="{% url opts|admin_urlname:'changelist' %}{{ object.pk }}">{{ object|truncatewords:"18" }}</a>
&rsaquo; <a href="{% url opts|admin_urlname:'change' object.pk|admin_urlquote %}">{{ object|truncatewords:"18" }}</a>
&rsaquo; {% trans 'Delete' %}
</div>
{% endblock %}

View File

@ -6,7 +6,7 @@
{% for inline_admin_form in inline_admin_formset %}<div class="inline-related{% if forloop.last %} empty-form last-related{% endif %}" id="{{ inline_admin_formset.formset.prefix }}-{% if not forloop.last %}{{ forloop.counter0 }}{% else %}empty{% endif %}">
<h3><b>{{ inline_admin_formset.opts.verbose_name|title }}:</b>&nbsp;<span class="inline_label">{% if inline_admin_form.original %}{{ inline_admin_form.original }}{% else %}#{{ forloop.counter }}{% endif %}</span>
{% if inline_admin_form.show_url %}<a href="../../../r/{{ inline_admin_form.original_content_type_id }}/{{ inline_admin_form.original.pk }}/">{% trans "View on site" %}</a>{% endif %}
{% if inline_admin_form.show_url %}<a href="{% url 'admin:view_on_site' inline_admin_form.original_content_type_id inline_admin_form.original.pk %}">{% trans "View on site" %}</a>{% endif %}
{% if inline_admin_formset.formset.can_delete and inline_admin_form.original %}<span class="delete">{{ inline_admin_form.deletion_field.field }} {{ inline_admin_form.deletion_field.label_tag }}</span>{% endif %}
</h3>
{% if inline_admin_form.form.non_field_errors %}{{ inline_admin_form.form.non_field_errors }}{% endif %}

View File

@ -27,7 +27,7 @@
<td class="original">
{% if inline_admin_form.original or inline_admin_form.show_url %}<p>
{% if inline_admin_form.original %} {{ inline_admin_form.original }}{% endif %}
{% if inline_admin_form.show_url %}<a href="../../../r/{{ inline_admin_form.original_content_type_id }}/{{ inline_admin_form.original.pk }}/">{% trans "View on site" %}</a>{% endif %}
{% if inline_admin_form.show_url %}<a href="{% url 'admin:view_on_site' inline_admin_form.original_content_type_id inline_admin_form.original.pk %}">{% trans "View on site" %}</a>{% endif %}
</p>{% endif %}
{% if inline_admin_form.has_auto_field %}{{ inline_admin_form.pk_field.field }}{% endif %}
{{ inline_admin_form.fk_field.field }}

View File

@ -7,7 +7,7 @@
<a href="{% url 'admin:index' %}">{% trans 'Home' %}</a>
&rsaquo; <a href="{% url 'admin:app_list' app_label=app_label %}">{{ app_label|capfirst|escape }}</a>
&rsaquo; <a href="{% url opts|admin_urlname:'changelist' %}">{{ module_name }}</a>
&rsaquo; <a href="{% url opts|admin_urlname:'change' object.pk %}">{{ object|truncatewords:"18" }}</a>
&rsaquo; <a href="{% url opts|admin_urlname:'change' object.pk|admin_urlquote %}">{{ object|truncatewords:"18" }}</a>
&rsaquo; {% trans 'History' %}
</div>
{% endblock %}

View File

@ -10,7 +10,7 @@ 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.text import capfirst
from django.utils.translation import ugettext as _
@ -31,9 +31,12 @@ def paginator_number(cl,i):
if i == DOT:
return '... '
elif i == cl.page_num:
return mark_safe('<span class="this-page">%d</span> ' % (i+1))
return format_html('<span class="this-page">{0}</span> ', i+1)
else:
return mark_safe('<a href="%s"%s>%d</a> ' % (escape(cl.get_query_string({PAGE_VAR: i})), (i == cl.paginator.num_pages-1 and ' class="end"' or ''), i+1))
return format_html('<a href="{0}"{1}>{2}</a> ',
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):
@ -159,13 +162,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('<img src="%s" alt="%s" />' % (icon_url, field_val))
return format_html('<img src="{0}" alt="{1}" />', icon_url, field_val)
def items_for_result(cl, result, form):
"""
@ -182,7 +186,7 @@ def items_for_result(cl, result, form):
else:
if f is None:
if field_name == 'action_checkbox':
row_class = ' class="action-checkbox"'
row_class = mark_safe(' class="action-checkbox"')
allow_tags = getattr(attr, 'allow_tags', False)
boolean = getattr(attr, 'boolean', False)
if boolean:
@ -190,23 +194,21 @@ 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"'
row_class = mark_safe(' class="nowrap"')
if force_unicode(result_repr) == '':
result_repr = mark_safe('&nbsp;')
# If list_display_links not defined, add the link tag to the first field
@ -222,8 +224,14 @@ def items_for_result(cl, result, form):
attr = pk
value = result.serializable_value(attr)
result_id = repr(force_unicode(value))[1:]
yield mark_safe('<%s%s><a href="%s"%s>%s</a></%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))
yield format_html('<{0}{1}><a href="{2}"{3}>{4}</a></{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
@ -233,11 +241,9 @@ def items_for_result(cl, result, form):
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('<td%s>%s</td>' % (row_class, result_repr))
yield format_html('<td{0}>{1}</td>', row_class, result_repr)
if form and not form[cl.model._meta.pk.name].is_hidden:
yield mark_safe('<td>%s</td>' % force_unicode(form[cl.model._meta.pk.name]))
yield format_html('<td>{0}</td>', force_unicode(form[cl.model._meta.pk.name]))
class ResultList(list):
# Wrapper class used to return items in a list_editable

View File

@ -32,7 +32,7 @@ def submit_row(context):
'onclick_attrib': (opts.get_ordered_objects() and change
and 'onclick="submitOrderForm();"' or ''),
'show_delete_link': (not is_popup and context['has_delete_permission']
and (change or context['show_delete'])),
and change and context.get('show_delete', True)),
'show_save_as_new': not is_popup and change and save_as,
'show_save_and_add_another': context['has_add_permission'] and
not is_popup and (not save_as or context['add']),

View File

@ -1,8 +1,14 @@
from django.core.urlresolvers import reverse, NoReverseMatch
from django.core.urlresolvers import reverse
from django import template
from django.contrib.admin.util import quote
register = template.Library()
@register.filter
def admin_urlname(value, arg):
return 'admin:%s_%s_%s' % (value.app_label, value.module_name, arg)
@register.filter
def admin_urlquote(value):
return quote(value)

View File

@ -9,11 +9,11 @@ from django.db.models.deletion import Collector
from django.db.models.related import RelatedObject
from django.forms.forms import pretty_name
from django.utils import formats
from django.utils.html import escape
from django.utils.safestring import mark_safe
from django.utils.html import format_html
from django.utils.text import capfirst
from django.utils import timezone
from django.utils.encoding import force_unicode, smart_unicode, smart_str
from django.utils import six
from django.utils.translation import ungettext
from django.core.urlresolvers import reverse
@ -52,7 +52,7 @@ def quote(s):
quoting is slightly different so that it doesn't get automatically
unquoted by the Web browser.
"""
if not isinstance(s, basestring):
if not isinstance(s, six.string_types):
return s
res = list(s)
for i in range(len(res)):
@ -124,10 +124,10 @@ def get_deleted_objects(objs, opts, user, admin_site, using):
if not user.has_perm(p):
perms_needed.add(opts.verbose_name)
# Display a link to the admin page.
return mark_safe('%s: <a href="%s">%s</a>' %
(escape(capfirst(opts.verbose_name)),
return format_html('{0}: <a href="{1}">{2}</a>',
capfirst(opts.verbose_name),
admin_url,
escape(obj)))
obj)
else:
# Don't display link to edit, because it either has no
# admin or is edited inline.
@ -275,10 +275,10 @@ def label_for_field(name, model, model_admin=None, return_attr=False):
except models.FieldDoesNotExist:
if name == "__unicode__":
label = force_unicode(model._meta.verbose_name)
attr = unicode
attr = six.text_type
elif name == "__str__":
label = smart_str(model._meta.verbose_name)
attr = str
attr = bytes
else:
if callable(name):
attr = name
@ -350,7 +350,7 @@ def display_for_value(value, boolean=False):
return formats.localize(timezone.template_localtime(value))
elif isinstance(value, (datetime.date, datetime.time)):
return formats.localize(value)
elif isinstance(value, (decimal.Decimal, float, int, long)):
elif isinstance(value, six.integer_types + (decimal.Decimal, float)):
return formats.number_format(value)
else:
return smart_unicode(value)

View File

@ -10,11 +10,12 @@ from django.contrib.admin.templatetags.admin_static import static
from django.core.urlresolvers import reverse
from django.forms.widgets import RadioFieldRenderer
from django.forms.util import flatatt
from django.utils.html import escape
from django.utils.html import escape, format_html, format_html_join
from django.utils.text import Truncator
from django.utils.translation import ugettext as _
from django.utils.safestring import mark_safe
from django.utils.encoding import force_unicode
from django.utils import six
class FilteredSelectMultiple(forms.SelectMultiple):
@ -85,16 +86,17 @@ class AdminSplitDateTime(forms.SplitDateTimeWidget):
forms.MultiWidget.__init__(self, widgets, attrs)
def format_output(self, rendered_widgets):
return mark_safe('<p class="datetime">%s %s<br />%s %s</p>' % \
(_('Date:'), rendered_widgets[0], _('Time:'), rendered_widgets[1]))
return format_html('<p class="datetime">{0} {1}<br />{2} {3}</p>',
_('Date:'), rendered_widgets[0],
_('Time:'), rendered_widgets[1])
class AdminRadioFieldRenderer(RadioFieldRenderer):
def render(self):
"""Outputs a <ul> for this set of radio fields."""
return mark_safe('<ul%s>\n%s\n</ul>' % (
return format_html('<ul{0}>\n{1}\n</ul>',
flatatt(self.attrs),
'\n'.join(['<li>%s</li>' % force_unicode(w) for w in self]))
)
format_html_join('\n', '<li>{0}</li>',
((force_unicode(w),) for w in self)))
class AdminRadioSelect(forms.RadioSelect):
renderer = AdminRadioFieldRenderer
@ -120,7 +122,7 @@ def url_params_from_lookup_dict(lookups):
# 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

View File

@ -22,7 +22,7 @@ your computer is "internal").</p>
{% endblocktrans %}
<div id="content-main">
<h3><a href="javascript:(function(){if(typeof ActiveXObject!='undefined'){x=new ActiveXObject('Microsoft.XMLHTTP')}else if(typeof XMLHttpRequest!='undefined'){x=new XMLHttpRequest()}else{return;}x.open('HEAD',location.href,false);x.send(null);try{view=x.getResponseHeader('x-view');}catch(e){alert('No view found for this page');return;}if(view=='undefined'){alert('No view found for this page');}document.location='{{ admin_url }}doc/views/'+view+'/';})()">{% trans "Documentation for this page" %}</a></h3>
<h3><a href="javascript:(function(){if(typeof ActiveXObject!='undefined'){x=new ActiveXObject('Microsoft.XMLHTTP')}else if(typeof XMLHttpRequest!='undefined'){x=new XMLHttpRequest()}else{return;}x.open('HEAD',location.href,false);x.send(null);try{view=x.getResponseHeader('x-view');}catch(e){alert('No view found for this page');return;}if(view=='undefined'){alert('No view found for this page');}document.location='{{ admin_url|escapejs }}doc/views/'+view+'/';})()">{% trans "Documentation for this page" %}</a></h3>
<p>{% trans "Jumps you from any page to the documentation for the view that generates that page." %}</p>
<h3><a href="javascript:(function(){if(typeof ActiveXObject!='undefined'){x=new ActiveXObject('Microsoft.XMLHTTP')}else if(typeof XMLHttpRequest!='undefined'){x=new XMLHttpRequest()}else{return;}x.open('GET',location.href,false);x.send(null);try{type=x.getResponseHeader('x-object-type');id=x.getResponseHeader('x-object-id');}catch(e){type='(none)';id='(none)';}d=document;b=d.body;e=d.createElement('div');e.id='xxxhhh';s=e.style;s.position='absolute';s.left='10px';s.top='10px';s.font='10px monospace';s.border='1px black solid';s.padding='4px';s.backgroundColor='#eee';e.appendChild(d.createTextNode('Type: '+type));e.appendChild(d.createElement('br'));e.appendChild(d.createTextNode('ID: '+id));e.appendChild(d.createElement('br'));l=d.createElement('a');l.href='#';l.onclick=function(){b.removeChild(e);};l.appendChild(d.createTextNode('[close]'));l.style.textDecoration='none';e.appendChild(l);b.appendChild(e);})();">{% trans "Show object ID" %}</a></h3>

View File

@ -37,7 +37,7 @@ def bookmarklets(request):
admin_root = urlresolvers.reverse('admin:index')
return render_to_response('admin_doc/bookmarklets.html', {
'root_path': admin_root,
'admin_url': mark_safe("%s://%s%s" % (request.is_secure() and 'https' or 'http', request.get_host(), admin_root)),
'admin_url': "%s://%s%s" % (request.is_secure() and 'https' or 'http', request.get_host(), admin_root),
}, context_instance=RequestContext(request))
@staff_member_required

View File

@ -134,7 +134,7 @@ class UserAdmin(admin.ModelAdmin):
context = {
'title': _('Change password: %s') % escape(user.username),
'adminForm': adminForm,
'form_url': mark_safe(form_url),
'form_url': form_url,
'form': form,
'is_popup': '_popup' in request.REQUEST,
'add': True,

View File

@ -1,4 +1,7 @@
import urlparse
try:
from urllib.parse import urlparse
except ImportError: # Python 2
from urlparse import urlparse
from functools import wraps
from django.conf import settings
from django.contrib.auth import REDIRECT_FIELD_NAME
@ -21,9 +24,8 @@ def user_passes_test(test_func, login_url=None, redirect_field_name=REDIRECT_FIE
path = request.build_absolute_uri()
# If the login url is the same scheme and net location then just
# use the path as the "next" url.
login_scheme, login_netloc = urlparse.urlparse(login_url or
settings.LOGIN_URL)[:2]
current_scheme, current_netloc = urlparse.urlparse(path)[:2]
login_scheme, login_netloc = urlparse(login_url or settings.LOGIN_URL)[:2]
current_scheme, current_netloc = urlparse(path)[:2]
if ((not login_scheme or login_scheme == current_scheme) and
(not login_netloc or login_netloc == current_netloc)):
path = request.get_full_path()

View File

@ -1,6 +1,10 @@
from __future__ import unicode_literals
from django import forms
from django.forms.util import flatatt
from django.template import loader
from django.utils.datastructures import SortedDict
from django.utils.html import format_html, format_html_join
from django.utils.http import int_to_base36
from django.utils.safestring import mark_safe
from django.utils.translation import ugettext, ugettext_lazy as _
@ -11,6 +15,7 @@ from django.contrib.auth.hashers import UNUSABLE_PASSWORD, is_password_usable, i
from django.contrib.auth.tokens import default_token_generator
from django.contrib.sites.models import get_current_site
UNMASKED_DIGITS_TO_SHOW = 6
mask_password = lambda p: "%s%s" % (p[:UNMASKED_DIGITS_TO_SHOW], "*" * max(len(p) - UNMASKED_DIGITS_TO_SHOW, 0))
@ -28,13 +33,15 @@ class ReadOnlyPasswordHashWidget(forms.Widget):
try:
hasher = identify_hasher(encoded)
except ValueError:
summary = "<strong>Invalid password format or unknown hashing algorithm.</strong>"
summary = mark_safe("<strong>Invalid password format or unknown hashing algorithm.</strong>")
else:
summary = ""
for key, value in hasher.safe_summary(encoded).iteritems():
summary += "<strong>%(key)s</strong>: %(value)s " % {"key": ugettext(key), "value": value}
summary = format_html_join('',
"<strong>{0}</strong>: {1} ",
((ugettext(key), value)
for key, value in hasher.safe_summary(encoded).items())
)
return mark_safe("<div%(attrs)s>%(summary)s</div>" % {"attrs": flatatt(final_attrs), "summary": summary})
return format_html("<div{0}>{1}</div>", flatatt(final_attrs), summary)
class ReadOnlyPasswordHashField(forms.Field):
@ -288,8 +295,11 @@ class PasswordChangeForm(SetPasswordForm):
raise forms.ValidationError(
self.error_messages['password_incorrect'])
return old_password
PasswordChangeForm.base_fields.keyOrder = ['old_password', 'new_password1',
'new_password2']
PasswordChangeForm.base_fields = SortedDict([
(k, PasswordChangeForm.base_fields[k])
for k in ['old_password', 'new_password1', 'new_password2']
])
class AdminPasswordChangeForm(forms.Form):

View File

@ -1,13 +1,12 @@
from __future__ import unicode_literals
import urllib
from django.core.exceptions import ImproperlyConfigured
from django.core.mail import send_mail
from django.db import models
from django.db.models.manager import EmptyManager
from django.utils.crypto import get_random_string
from django.utils.encoding import smart_str
from django.utils.http import urlquote
from django.utils import six
from django.utils.translation import ugettext_lazy as _
from django.utils import timezone
@ -79,9 +78,9 @@ class Permission(models.Model):
def __unicode__(self):
return "%s | %s | %s" % (
unicode(self.content_type.app_label),
unicode(self.content_type),
unicode(self.name))
six.text_type(self.content_type.app_label),
six.text_type(self.content_type),
six.text_type(self.name))
def natural_key(self):
return (self.codename,) + self.content_type.natural_key()
@ -267,7 +266,7 @@ class User(models.Model):
return (self.username,)
def get_absolute_url(self):
return "/users/%s/" % urllib.quote(smart_str(self.username))
return "/users/%s/" % urlquote(self.username)
def is_anonymous(self):
"""
@ -300,7 +299,7 @@ class User(models.Model):
"""
def setter(raw_password):
self.set_password(raw_password)
self.save()
self.save(update_fields=["password"])
return check_password(raw_password, self.password, setter)
def set_unusable_password(self):
@ -421,7 +420,7 @@ class AnonymousUser(object):
return 'AnonymousUser'
def __str__(self):
return unicode(self).encode('utf-8')
return six.text_type(self).encode('utf-8')
def __eq__(self, other):
return isinstance(other, self.__class__)

View File

@ -1,8 +1,8 @@
from django.test import TestCase
from django.utils.unittest import skipUnless
from django.contrib.auth.models import User, AnonymousUser
from django.core.management import call_command
from StringIO import StringIO
from django.test import TestCase
from django.utils.six import StringIO
from django.utils.unittest import skipUnless
try:
import crypt as crypt_module

View File

@ -1,11 +1,10 @@
from __future__ import unicode_literals
from StringIO import StringIO
from django.contrib.auth import models, management
from django.contrib.auth.management.commands import changepassword
from django.core.management.base import CommandError
from django.test import TestCase
from django.utils.six import StringIO
class GetDefaultUsernameTestCase(TestCase):

View File

@ -5,39 +5,29 @@ from django.contrib.auth.models import (Group, User,
SiteProfileNotAvailable, UserManager)
@override_settings(USE_TZ=False)
@override_settings(USE_TZ=False, AUTH_PROFILE_MODULE='')
class ProfileTestCase(TestCase):
fixtures = ['authtestdata.json']
def setUp(self):
"""Backs up the AUTH_PROFILE_MODULE"""
self.old_AUTH_PROFILE_MODULE = getattr(settings,
'AUTH_PROFILE_MODULE', None)
def tearDown(self):
"""Restores the AUTH_PROFILE_MODULE -- if it was not set it is deleted,
otherwise the old value is restored"""
if self.old_AUTH_PROFILE_MODULE is None and \
hasattr(settings, 'AUTH_PROFILE_MODULE'):
del settings.AUTH_PROFILE_MODULE
if self.old_AUTH_PROFILE_MODULE is not None:
settings.AUTH_PROFILE_MODULE = self.old_AUTH_PROFILE_MODULE
def test_site_profile_not_available(self):
user = User.objects.create(username='testclient')
# calling get_profile without AUTH_PROFILE_MODULE set
if hasattr(settings, 'AUTH_PROFILE_MODULE'):
del settings.AUTH_PROFILE_MODULE
user = User.objects.get(username='testclient')
self.assertRaises(SiteProfileNotAvailable, user.get_profile)
with self.assertRaisesRegexp(SiteProfileNotAvailable,
"You need to set AUTH_PROFILE_MODULE in your project"):
user.get_profile()
# Bad syntax in AUTH_PROFILE_MODULE:
settings.AUTH_PROFILE_MODULE = 'foobar'
self.assertRaises(SiteProfileNotAvailable, user.get_profile)
with self.assertRaisesRegexp(SiteProfileNotAvailable,
"app_label and model_name should be separated by a dot"):
user.get_profile()
# module that doesn't exist
settings.AUTH_PROFILE_MODULE = 'foo.bar'
self.assertRaises(SiteProfileNotAvailable, user.get_profile)
with self.assertRaisesRegexp(SiteProfileNotAvailable,
"Unable to load the profile model"):
user.get_profile()
@override_settings(USE_TZ=False)

View File

@ -1,6 +1,5 @@
import os
import re
import urllib
from django.conf import settings
from django.contrib.sites.models import Site, RequestSite
@ -10,6 +9,7 @@ from django.core.urlresolvers import reverse, NoReverseMatch
from django.http import QueryDict
from django.utils.encoding import force_unicode
from django.utils.html import escape
from django.utils.http import urlquote
from django.test import TestCase
from django.test.utils import override_settings
@ -256,7 +256,7 @@ class LoginTest(AuthViewsTestCase):
nasty_url = '%(url)s?%(next)s=%(bad_url)s' % {
'url': login_url,
'next': REDIRECT_FIELD_NAME,
'bad_url': urllib.quote(bad_url),
'bad_url': urlquote(bad_url),
}
response = self.client.post(nasty_url, {
'username': 'testclient',
@ -277,7 +277,7 @@ class LoginTest(AuthViewsTestCase):
safe_url = '%(url)s?%(next)s=%(good_url)s' % {
'url': login_url,
'next': REDIRECT_FIELD_NAME,
'good_url': urllib.quote(good_url),
'good_url': urlquote(good_url),
}
response = self.client.post(safe_url, {
'username': 'testclient',
@ -412,7 +412,7 @@ class LogoutTest(AuthViewsTestCase):
nasty_url = '%(url)s?%(next)s=%(bad_url)s' % {
'url': logout_url,
'next': REDIRECT_FIELD_NAME,
'bad_url': urllib.quote(bad_url),
'bad_url': urlquote(bad_url),
}
self.login()
response = self.client.get(nasty_url)
@ -432,7 +432,7 @@ class LogoutTest(AuthViewsTestCase):
safe_url = '%(url)s?%(next)s=%(good_url)s' % {
'url': logout_url,
'next': REDIRECT_FIELD_NAME,
'good_url': urllib.quote(good_url),
'good_url': urlquote(good_url),
}
self.login()
response = self.client.get(safe_url)

View File

@ -2,6 +2,7 @@ from datetime import date
from django.conf import settings
from django.utils.http import int_to_base36, base36_to_int
from django.utils.crypto import constant_time_compare, salted_hmac
from django.utils import six
class PasswordResetTokenGenerator(object):
"""
@ -56,8 +57,8 @@ class PasswordResetTokenGenerator(object):
# Ensure results are consistent across DB backends
login_timestamp = user.last_login.replace(microsecond=0, tzinfo=None)
value = (unicode(user.id) + user.password +
unicode(login_timestamp) + unicode(timestamp))
value = (six.text_type(user.id) + user.password +
six.text_type(login_timestamp) + six.text_type(timestamp))
hash = salted_hmac(key_salt, value).hexdigest()[::2]
return "%s-%s" % (ts_b36, hash)

View File

@ -1,4 +1,7 @@
import urlparse
try:
from urllib.parse import urlparse, urlunparse
except ImportError: # Python 2
from urlparse import urlparse, urlunparse
from django.conf import settings
from django.core.urlresolvers import reverse
@ -34,7 +37,7 @@ def login(request, template_name='registration/login.html',
if request.method == "POST":
form = authentication_form(data=request.POST)
if form.is_valid():
netloc = urlparse.urlparse(redirect_to)[1]
netloc = urlparse(redirect_to)[1]
# Use default setting if redirect_to is empty
if not redirect_to:
@ -80,7 +83,7 @@ def logout(request, next_page=None,
auth_logout(request)
redirect_to = request.REQUEST.get(redirect_field_name, '')
if redirect_to:
netloc = urlparse.urlparse(redirect_to)[1]
netloc = urlparse(redirect_to)[1]
# Security check -- don't allow redirection to a different host.
if not (netloc and netloc != request.get_host()):
return HttpResponseRedirect(redirect_to)
@ -116,13 +119,13 @@ def redirect_to_login(next, login_url=None,
if not login_url:
login_url = settings.LOGIN_URL
login_url_parts = list(urlparse.urlparse(login_url))
login_url_parts = list(urlparse(login_url))
if redirect_field_name:
querystring = QueryDict(login_url_parts[4], mutable=True)
querystring[redirect_field_name] = next
login_url_parts[4] = querystring.urlencode(safe='/')
return HttpResponseRedirect(urlparse.urlunparse(login_url_parts))
return HttpResponseRedirect(urlunparse(login_url_parts))
# 4 views for password reset:
# - password_reset sends the mail

View File

@ -17,7 +17,7 @@ def flag(request, comment_id, next=None):
"""
Flags a comment. Confirmation on GET, action on POST.
Templates: `comments/flag.html`,
Templates: :template:`comments/flag.html`,
Context:
comment
the flagged `comments.comment` object
@ -43,7 +43,7 @@ def delete(request, comment_id, next=None):
Deletes a comment. Confirmation on GET, action on POST. Requires the "can
moderate comments" permission.
Templates: `comments/delete.html`,
Templates: :template:`comments/delete.html`,
Context:
comment
the flagged `comments.comment` object
@ -70,7 +70,7 @@ def approve(request, comment_id, next=None):
Approve a comment (that is, mark it as public and non-removed). Confirmation
on GET, action on POST. Requires the "can moderate comments" permission.
Templates: `comments/approve.html`,
Templates: :template:`comments/approve.html`,
Context:
comment
the `comments.comment` object for approval

View File

@ -2,8 +2,12 @@
A few bits of helper functions for comment views.
"""
import urllib
import textwrap
try:
from urllib.parse import urlencode
except ImportError: # Python 2
from urllib import urlencode
from django.http import HttpResponseRedirect
from django.core import urlresolvers
from django.shortcuts import render_to_response
@ -33,7 +37,7 @@ def next_redirect(data, default, default_view, **get_kwargs):
anchor = ''
joiner = ('?' in next) and '&' or '?'
next += joiner + urllib.urlencode(get_kwargs) + anchor
next += joiner + urlencode(get_kwargs) + anchor
return HttpResponseRedirect(next)
def confirmation_view(template, doc="Display a confirmation view."):
@ -56,7 +60,7 @@ def confirmation_view(template, doc="Display a confirmation view."):
confirmed.__doc__ = textwrap.dedent("""\
%s
Templates: `%s``
Templates: :template:`%s``
Context:
comment
The posted comment

View File

@ -1,14 +1,13 @@
from __future__ import unicode_literals
import urllib
from django.db import models
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes.views import shortcut
from django.contrib.sites.models import Site
from django.http import HttpRequest, Http404
from django.test import TestCase
from django.utils.encoding import smart_str
from django.utils.http import urlquote
from django.utils import six
class ConcreteModel(models.Model):
@ -35,7 +34,7 @@ class FooWithUrl(FooWithoutUrl):
"""
def get_absolute_url(self):
return "/users/%s/" % urllib.quote(smart_str(self.name))
return "/users/%s/" % urlquote(self.name)
class FooWithBrokenAbsoluteUrl(FooWithoutUrl):
"""
@ -271,4 +270,4 @@ class ContentTypesTests(TestCase):
app_label = 'contenttypes',
model = 'OldModel',
)
self.assertEqual(unicode(ct), 'Old model')
self.assertEqual(six.text_type(ct), 'Old model')

View File

@ -8,7 +8,6 @@ from django.db import models
from django.utils import formats
from django.utils.text import capfirst
from django.utils.encoding import smart_unicode, smart_str, iri_to_uri
from django.utils.safestring import mark_safe
from django.db.models.query import QuerySet
EMPTY_VALUE = '(None)'
@ -30,7 +29,7 @@ class EasyModel(object):
return self.site.registry[self.model]
def url(self):
return mark_safe('%s%s/%s/' % (self.site.root_url, self.model._meta.app_label, self.model._meta.module_name))
return '%s%s/%s/' % (self.site.root_url, self.model._meta.app_label, self.model._meta.module_name)
def objects(self, **kwargs):
return self.get_query_set().filter(**kwargs)
@ -70,9 +69,9 @@ class EasyField(object):
def url(self):
if self.field.choices:
return mark_safe('%s%s/%s/%s/' % (self.model.site.root_url, self.model.model._meta.app_label, self.model.model._meta.module_name, self.field.name))
return '%s%s/%s/%s/' % (self.model.site.root_url, self.model.model._meta.app_label, self.model.model._meta.module_name, self.field.name)
elif self.field.rel:
return mark_safe('%s%s/%s/' % (self.model.site.root_url, self.model.model._meta.app_label, self.model.model._meta.module_name))
return '%s%s/%s/' % (self.model.site.root_url, self.model.model._meta.app_label, self.model.model._meta.module_name)
class EasyChoice(object):
def __init__(self, easy_model, field, value, label):
@ -83,7 +82,7 @@ class EasyChoice(object):
return smart_str('<EasyChoice for %s.%s>' % (self.model.model._meta.object_name, self.field.name))
def url(self):
return mark_safe('%s%s/%s/%s/%s/' % (self.model.site.root_url, self.model.model._meta.app_label, self.model.model._meta.module_name, self.field.field.name, iri_to_uri(self.value)))
return '%s%s/%s/%s/%s/' % (self.model.site.root_url, self.model.model._meta.app_label, self.model.model._meta.module_name, self.field.field.name, iri_to_uri(self.value))
class EasyInstance(object):
def __init__(self, easy_model, instance):
@ -105,7 +104,7 @@ class EasyInstance(object):
return self.instance._get_pk_val()
def url(self):
return mark_safe('%s%s/%s/objects/%s/' % (self.model.site.root_url, self.model.model._meta.app_label, self.model.model._meta.module_name, iri_to_uri(self.pk())))
return '%s%s/%s/objects/%s/' % (self.model.site.root_url, self.model.model._meta.app_label, self.model.model._meta.module_name, iri_to_uri(self.pk()))
def fields(self):
"""
@ -187,14 +186,14 @@ class EasyInstanceField(object):
for value in self.values():
if value is None:
continue
url = mark_safe('%s%s/%s/objects/%s/' % (self.model.site.root_url, m.model._meta.app_label, m.model._meta.module_name, iri_to_uri(value._get_pk_val())))
url = '%s%s/%s/objects/%s/' % (self.model.site.root_url, m.model._meta.app_label, m.model._meta.module_name, iri_to_uri(value._get_pk_val()))
lst.append((smart_unicode(value), url))
else:
lst = [(value, None) for value in self.values()]
elif self.field.choices:
lst = []
for value in self.values():
url = mark_safe('%s%s/%s/fields/%s/%s/' % (self.model.site.root_url, self.model.model._meta.app_label, self.model.model._meta.module_name, self.field.name, iri_to_uri(self.raw_value)))
url = '%s%s/%s/fields/%s/%s/' % (self.model.site.root_url, self.model.model._meta.app_label, self.model.model._meta.module_name, self.field.name, iri_to_uri(self.raw_value))
lst.append((value, url))
elif isinstance(self.field, models.URLField):
val = self.values()[0]

View File

@ -5,9 +5,9 @@ from django.db import models
from django.contrib.databrowse.datastructures import EasyModel
from django.contrib.databrowse.sites import DatabrowsePlugin
from django.shortcuts import render_to_response
from django.utils.html import format_html, format_html_join
from django.utils.text import capfirst
from django.utils.encoding import force_unicode
from django.utils.safestring import mark_safe
from django.views.generic import dates
from django.utils import datetime_safe
@ -64,18 +64,19 @@ class CalendarPlugin(DatabrowsePlugin):
fields = self.field_dict(model)
if not fields:
return ''
return mark_safe('<p class="filter"><strong>View calendar by:</strong> %s</p>' % \
', '.join(['<a href="calendars/%s/">%s</a>' % (f.name, force_unicode(capfirst(f.verbose_name))) for f in fields.values()]))
return format_html('<p class="filter"><strong>View calendar by:</strong> {0}</p>',
format_html_join(', ', '<a href="calendars/{0}/">{1}</a>',
((f.name, force_unicode(capfirst(f.verbose_name))) for f in fields.values())))
def urls(self, plugin_name, easy_instance_field):
if isinstance(easy_instance_field.field, models.DateField):
d = easy_instance_field.raw_value
return [mark_safe('%s%s/%s/%s/%s/%s/' % (
return ['%s%s/%s/%s/%s/%s/' % (
easy_instance_field.model.url(),
plugin_name, easy_instance_field.field.name,
str(d.year),
datetime_safe.new_date(d).strftime('%b').lower(),
d.day))]
d.day)]
def model_view(self, request, model_databrowse, url):
self.model, self.site = model_databrowse.model, model_databrowse.site

View File

@ -5,10 +5,11 @@ from django.db import models
from django.contrib.databrowse.datastructures import EasyModel
from django.contrib.databrowse.sites import DatabrowsePlugin
from django.shortcuts import render_to_response
from django.utils.html import format_html, format_html_join
from django.utils.http import urlquote
from django.utils.text import capfirst
from django.utils.encoding import smart_str, force_unicode
from django.utils.safestring import mark_safe
import urllib
from django.utils.encoding import force_unicode
class FieldChoicePlugin(DatabrowsePlugin):
def __init__(self, field_filter=None):
@ -32,16 +33,16 @@ class FieldChoicePlugin(DatabrowsePlugin):
fields = self.field_dict(model)
if not fields:
return ''
return mark_safe('<p class="filter"><strong>View by:</strong> %s</p>' % \
', '.join(['<a href="fields/%s/">%s</a>' % (f.name, force_unicode(capfirst(f.verbose_name))) for f in fields.values()]))
return format_html('<p class="filter"><strong>View by:</strong> {0}</p>',
format_html_join(', ', '<a href="fields/{0}/">{1}</a>',
((f.name, force_unicode(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('%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

View File

@ -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})

View File

@ -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

View File

@ -2,6 +2,7 @@
import pickle
from django.utils.crypto import salted_hmac
from django.utils import six
def form_hmac(form):
@ -16,7 +17,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))

View File

@ -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
@ -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,10 +158,10 @@ 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():

View File

@ -1,6 +1,7 @@
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
@ -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):
@ -109,7 +110,7 @@ class OpenLayersWidget(Textarea):
""" Compare geographic value of data with its initial value. """
# Ensure we are dealing with a geographic object
if isinstance(initial, basestring):
if isinstance(initial, six.string_types):
try:
initial = GEOSGeometry(initial)
except (GEOSException, ValueError):

View File

@ -4,6 +4,7 @@ Base/mixin classes for the spatial backend database operations and the
"""
import re
from django.contrib.gis import gdal
from django.utils import six
class BaseSpatialOperations(object):
"""
@ -88,7 +89,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
@ -330,6 +331,6 @@ class SpatialRefSysMixin(object):
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)

View File

@ -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,7 +121,7 @@ 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'),
}

View File

@ -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,11 @@ class PostGISOperations(DatabaseOperations, BaseSpatialOperations):
'overlaps' : PostGISFunction(prefix, 'Overlaps'),
'contains' : PostGISFunction(prefix, 'Contains'),
'intersects' : PostGISFunction(prefix, 'Intersects'),
'relate' : (PostGISRelate, basestring),
'relate' : (PostGISRelate, six.string_types),
}
# 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),

View File

@ -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()

View File

@ -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.

View File

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

View File

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

View File

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

View File

@ -6,6 +6,9 @@ from django.contrib.gis.db.models.fields import get_srid_info, PointField, LineS
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."
@ -144,7 +147,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
@ -309,7 +312,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 +352,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 +393,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)
@ -533,7 +536,7 @@ class GeoQuerySet(QuerySet):
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']:

View File

@ -1,4 +1,4 @@
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

View File

@ -5,7 +5,7 @@ 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):
"""
@ -31,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
@ -44,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).

View File

@ -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

View File

@ -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

View File

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

View File

@ -4,6 +4,8 @@ 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
#
@ -22,7 +24,7 @@ class Driver(GDALBase):
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()

View File

@ -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
#
@ -33,7 +36,7 @@ class Feature(GDALBase):
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:

View File

@ -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+.')
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.')
@ -328,22 +328,15 @@ class OGRGeometry(GDALBase):
@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+.')
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+.')
@property
def wkb_size(self):
@ -420,7 +413,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 +688,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:

View File

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

View File

@ -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
#
@ -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.

View File

@ -15,10 +15,11 @@ 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)
@ -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

View File

@ -5,6 +5,7 @@
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.
@ -71,7 +72,7 @@ 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:
raise OGRException('Invalid geometry pointer returned from "%s".' % func.__name__)
@ -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,7 +110,7 @@ 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):
return result

View File

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

View File

@ -33,6 +33,8 @@ 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):
"""
@ -52,9 +54,9 @@ class SpatialReference(GDALBase):
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):
@ -133,7 +135,7 @@ 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)

View File

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

View File

@ -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.

View File

@ -6,6 +6,8 @@ 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
@ -35,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

View File

@ -10,7 +10,6 @@ except ImportError:
# A 'dummy' gdal module.
class GDALInfo(object):
HAS_GDAL = False
GEOJSON = False
gdal = GDALInfo()
# NumPy supported?

View File

@ -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

View File

@ -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."

View File

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

View File

@ -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

View File

@ -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

View File

@ -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]

View File

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

View File

@ -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
@ -56,7 +58,7 @@ class Polygon(GEOSGeometry):
"Constructs a Polygon from a bounding box (4-tuple)."
x0, y0, x1, y1 = bbox
for z in bbox:
if not isinstance(z, (int, long, float)):
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)))

View File

@ -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

View File

@ -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']

View File

@ -8,6 +8,8 @@ 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
@ -196,7 +198,7 @@ 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 and gdal.GEOJSON, "gdal >= 1.5 is required")
@unittest.skipUnless(gdal.HAS_GDAL, "gdal is required")
def test_json(self):
"Testing GeoJSON input/output (via GDAL)."
for g in self.geometries.json_geoms:
@ -951,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.
@ -1004,7 +1007,7 @@ class GEOSTest(unittest.TestCase, TestDataMixin):
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")
@ -1012,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")

View File

@ -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'))

View File

@ -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

View File

@ -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&amp;v=%s&amp;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('<body %s %s>' % (self.onload, self.onunload))
return format_html('<body {0} {1}>', self.onload, self.onunload)
@property
def onload(self):
"Returns the `onload` HTML <body> 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 <script> tag for the Google Maps API javascript."
return mark_safe('<script src="%s%s" type="text/javascript"></script>' % (self.api_url, self.key))
return format_html('<script src="{0}{1}" type="text/javascript"></script>',
self.api_url, self.key)
@property
def js(self):
@ -131,17 +134,17 @@ class GoogleMap(object):
@property
def scripts(self):
"Returns all <script></script> tags required with Google Maps JavaScript."
return mark_safe('%s\n <script type="text/javascript">\n//<![CDATA[\n%s//]]>\n </script>' % (self.api_script, self.js))
return format_html('%s\n <script type="text/javascript">\n//<![CDATA[\n%s//]]>\n </script>', self.api_script, mark_safe(self.js))
@property
def style(self):
"Returns additional CSS styling needed for Google Maps on IE."
return mark_safe('<style type="text/css">%s</style>' % self.vml_css)
return format_html('<style type="text/css">{0}</style>', self.vml_css)
@property
def xhtml(self):
"Returns XHTML information needed for IE VML overlays."
return mark_safe('<html xmlns="http://www.w3.org/1999/xhtml" %s>' % self.xmlns)
return format_html('<html xmlns="http://www.w3.org/1999/xhtml" {0}>', self.xmlns)
@property
def icons(self):

View File

@ -1,6 +1,7 @@
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
class GEvent(object):
@ -98,7 +99,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 +149,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)):
@ -278,7 +279,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)

View File

@ -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.

View File

@ -39,8 +39,9 @@ __all__ = ['A', 'Area', 'D', 'Distance']
from decimal import Decimal
from django.utils.functional import total_ordering
from django.utils import six
NUMERIC_TYPES = (int, float, long, Decimal)
NUMERIC_TYPES = six.integer_types + (float, Decimal)
AREA_PREFIX = "sq_"
def pretty_name(obj):
@ -57,7 +58,7 @@ class MeasureBase(object):
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, basestring):
if default_unit and isinstance(default_unit, six.string_types):
self._default_unit = default_unit
def _get_standard(self):

View File

@ -11,6 +11,7 @@ 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
@ -663,7 +664,7 @@ class GeoModelTest(TestCase):
# 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

View File

@ -56,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))

View File

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

View File

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

View File

@ -2,6 +2,8 @@
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
@ -19,7 +21,7 @@ def precision_wkt(geom, prec):
"""
if isinstance(prec, int):
num_fmt = '%%.%df' % prec
elif isinstance(prec, basestring):
elif isinstance(prec, six.string_types):
num_fmt = prec
else:
raise TypeError

View File

@ -1,6 +1,6 @@
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
@ -143,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
@ -169,6 +171,8 @@ def naturalday(value, arg=None):
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):
"""
@ -184,7 +188,7 @@ 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 _('now')
elif delta.seconds < 60:
@ -206,7 +210,7 @@ def naturaltime(value):
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 _('now')
elif delta.seconds < 60:

View File

@ -1,13 +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):
@ -109,28 +127,36 @@ class HumanizeTests(TestCase):
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),
@ -148,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),
@ -169,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

View File

@ -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):
@ -96,6 +97,8 @@ class ARCUITField(RegexField):
if value in EMPTY_VALUES:
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,9 +108,16 @@ 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:

View File

@ -8,7 +8,7 @@ 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.forms.fields import CharField, RegexField, Select
from django.utils.encoding import smart_unicode
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,6 +35,10 @@ 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:
@ -51,4 +55,3 @@ class FRDepartmentSelect(Select):
"""
def __init__(self, attrs=None):
super(FRDepartmentSelect, self).__init__(attrs, choices=DEPARTMENT_CHOICES)

View File

@ -7,6 +7,7 @@ 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
@ -147,7 +148,7 @@ class MXRFCField(RegexField):
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:
@ -155,7 +156,7 @@ class MXRFCField(RegexField):
elif checksum == 11:
return '0'
return unicode(checksum)
return six.text_type(checksum)
def _has_inconvenient_word(self, rfc):
first_four = rfc[:4]
@ -214,12 +215,12 @@ class MXCURPField(RegexField):
def _checksum(self, value):
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 '0'
return unicode(checksum)
return six.text_type(checksum)
def _has_inconvenient_word(self, curp):
first_four = curp[:4]

View File

@ -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 \

View File

@ -80,10 +80,10 @@ class TRIdentificationNumberField(Field):
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

View File

@ -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')

Some files were not shown because too many files have changed in this diff Show More