Code

Ticket #17627: 0002.patch

File 0002.patch, 120.5 KB (added by lukegb, 2 years ago)

Same as original patch, rebased against master and also including all util.py -> utils.py changes apart from utils/unittests/util.py

  • AUTHORS

    diff --git a/AUTHORS b/AUTHORS
    index 5fa21d3..faa6126 100644
    a b answer newbie questions, and generally made Django that much better: 
    218218    David Gouldin <dgouldin@gmail.com> 
    219219    pradeep.gowda@gmail.com 
    220220    Collin Grady <collin@collingrady.com> 
     221    Luke Granger-Brown <django@lukegb.com> 
    221222    Gabriel Grant <g@briel.ca> 
    222223    Simon Greenhill <dev@simon.net.nz> 
    223224    Owen Griffiths 
    answer newbie questions, and generally made Django that much better: 
    295296    Cameron Knight (ckknight) 
    296297    Nena Kojadin <nena@kiberpipa.org> 
    297298    Igor Kolar <ike@email.si> 
     299    Wiktor Kołodziej 
    298300    Tomáš Kopeček <permonik@m6.cz> 
    299301    Gasper Koren 
    300302    Mikhail Korobov <kmike84@googlemail.com> 
  • django/conf/locale/en/LC_MESSAGES/django.po

    diff --git a/django/conf/locale/en/LC_MESSAGES/django.po b/django/conf/locale/en/LC_MESSAGES/django.po
    index abb52ae..1f3317b 100644
    a b msgstr "" 
    655655msgid "\"%s\" is not a valid value for a primary key." 
    656656msgstr "" 
    657657 
    658 #: forms/util.py:70 
     658#: forms/utils.py:70 
    659659#, python-format 
    660660msgid "" 
    661661"%(datetime)s couldn't be interpreted in time zone %(current_timezone)s; it " 
  • django/contrib/admin/actions.py

    diff --git a/django/contrib/admin/actions.py b/django/contrib/admin/actions.py
    index 5b56402..4a03a97 100644
    a b Built-in, globally-available admin actions. 
    44 
    55from django.core.exceptions import PermissionDenied 
    66from django.contrib.admin import helpers 
    7 from django.contrib.admin.util import get_deleted_objects, model_ngettext 
     7from django.contrib.admin.utils import get_deleted_objects, model_ngettext 
    88from django.db import router 
    99from django.template.response import TemplateResponse 
    1010from django.utils.encoding import force_unicode 
  • django/contrib/admin/filters.py

    diff --git a/django/contrib/admin/filters.py b/django/contrib/admin/filters.py
    index 550683b..dc4434b 100644
    a b from django.core.exceptions import ImproperlyConfigured 
    1212from django.utils.encoding import smart_unicode 
    1313from django.utils.translation import ugettext_lazy as _ 
    1414 
    15 from django.contrib.admin.util import (get_model_from_relation, 
     15from django.contrib.admin.utils import (get_model_from_relation, 
    1616    reverse_field_path, get_limit_choices_to_from_path, prepare_lookup_value) 
    1717 
    1818class ListFilter(object): 
  • django/contrib/admin/helpers.py

    diff --git a/django/contrib/admin/helpers.py b/django/contrib/admin/helpers.py
    index b08d1c8..ae46be4 100644
    a b  
    11from django import forms 
    2 from django.contrib.admin.util import (flatten_fieldsets, lookup_field, 
     2from django.contrib.admin.utils import (flatten_fieldsets, lookup_field, 
    33    display_for_field, label_for_field, help_text_for_field) 
    44from django.contrib.admin.templatetags.admin_static import static 
    55from django.contrib.contenttypes.models import ContentType 
    66from django.core.exceptions import ObjectDoesNotExist 
    77from django.db.models.fields.related import ManyToManyRel 
    8 from django.forms.util import flatatt 
     8from django.forms.utils import flatatt 
    99from django.template.defaultfilters import capfirst 
    1010from django.utils.encoding import force_unicode, smart_unicode 
    1111from django.utils.html import escape, conditional_escape 
    class InlineFieldset(Fieldset): 
    318318            yield Fieldline(self.form, field, self.readonly_fields, 
    319319                model_admin=self.model_admin) 
    320320 
    321 class AdminErrorList(forms.util.ErrorList): 
     321class AdminErrorList(forms.utils.ErrorList): 
    322322    """ 
    323323    Stores all errors for the form/formsets in an add/change stage view. 
    324324    """ 
  • django/contrib/admin/models.py

    diff --git a/django/contrib/admin/models.py b/django/contrib/admin/models.py
    index 0e5b8a7..013ae44 100644
    a b  
    11from django.db import models 
    22from django.contrib.contenttypes.models import ContentType 
    33from django.contrib.auth.models import User 
    4 from django.contrib.admin.util import quote 
     4from django.contrib.admin.utils import quote 
    55from django.utils.translation import ugettext_lazy as _ 
    66from django.utils.encoding import smart_unicode 
    77from django.utils.safestring import mark_safe 
  • django/contrib/admin/options.py

    diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py
    index f5f6256..0dcb4e6 100644
    a b from django.forms.models import (modelform_factory, modelformset_factory, 
    66    inlineformset_factory, BaseInlineFormSet) 
    77from django.contrib.contenttypes.models import ContentType 
    88from django.contrib.admin import widgets, helpers 
    9 from django.contrib.admin.util import unquote, flatten_fieldsets, get_deleted_objects, model_format_dict 
     9from django.contrib.admin.utils import unquote, flatten_fieldsets, get_deleted_objects, model_format_dict 
    1010from django.contrib.admin.templatetags.admin_static import static 
    1111from django.contrib import messages 
    1212from django.views.decorators.csrf import csrf_protect 
  • django/contrib/admin/templatetags/admin_list.py

    diff --git a/django/contrib/admin/templatetags/admin_list.py b/django/contrib/admin/templatetags/admin_list.py
    index e778429..23ba3ea 100644
    a b  
    11import datetime 
    22 
    3 from django.contrib.admin.util import lookup_field, display_for_field, label_for_field 
     3from django.contrib.admin.utils import lookup_field, display_for_field, label_for_field 
    44from django.contrib.admin.views.main import (ALL_VAR, EMPTY_CHANGELIST_VALUE, 
    55    ORDER_VAR, PAGE_VAR, SEARCH_VAR) 
    66from django.contrib.admin.templatetags.admin_static import static 
  • django/contrib/admin/util.py

    diff --git a/django/contrib/admin/util.py b/django/contrib/admin/util.py
    index 61182a6..fc8b3dd 100644
    a b  
    1 from django.db import models 
    2 from django.db.models.sql.constants import LOOKUP_SEP 
    3 from django.db.models.deletion import Collector 
    4 from django.db.models.related import RelatedObject 
    5 from django.forms.forms import pretty_name 
    6 from django.utils import formats 
    7 from django.utils.html import escape 
    8 from django.utils.safestring import mark_safe 
    9 from django.utils.text import capfirst 
    10 from django.utils import timezone 
    11 from django.utils.encoding import force_unicode, smart_unicode, smart_str 
    12 from django.utils.translation import ungettext 
    13 from django.core.urlresolvers import reverse 
     1import warnings 
    142 
    15 def lookup_needs_distinct(opts, lookup_path): 
    16     """ 
    17     Returns True if 'distinct()' should be used to query the given lookup path. 
    18     """ 
    19     field_name = lookup_path.split('__', 1)[0] 
    20     field = opts.get_field_by_name(field_name)[0] 
    21     if ((hasattr(field, 'rel') and 
    22          isinstance(field.rel, models.ManyToManyRel)) or 
    23         (isinstance(field, models.related.RelatedObject) and 
    24          not field.field.unique)): 
    25          return True 
    26     return False 
     3warnings.warn("The django.contrib.admin.util module has been renamed " 
     4              "(https://code.djangoproject.com/ticket/17627/). " 
     5              "Use django.contrib.admin.utils instead.", PendingDeprecationWarning) 
    276 
    28 def prepare_lookup_value(key, value): 
    29     """ 
    30     Returns a lookup value prepared to be used in queryset filtering. 
    31     """ 
    32     # if key ends with __in, split parameter into separate values 
    33     if key.endswith('__in'): 
    34         value = value.split(',') 
    35     # if key ends with __isnull, special case '' and false 
    36     if key.endswith('__isnull'): 
    37         if value.lower() in ('', 'false'): 
    38             value = False 
    39         else: 
    40             value = True 
    41     return value 
    42  
    43 def quote(s): 
    44     """ 
    45     Ensure that primary key values do not confuse the admin URLs by escaping 
    46     any '/', '_' and ':' characters. Similar to urllib.quote, except that the 
    47     quoting is slightly different so that it doesn't get automatically 
    48     unquoted by the Web browser. 
    49     """ 
    50     if not isinstance(s, basestring): 
    51         return s 
    52     res = list(s) 
    53     for i in range(len(res)): 
    54         c = res[i] 
    55         if c in """:/_#?;@&=+$,"<>%\\""": 
    56             res[i] = '_%02X' % ord(c) 
    57     return ''.join(res) 
    58  
    59  
    60 def unquote(s): 
    61     """ 
    62     Undo the effects of quote(). Based heavily on urllib.unquote(). 
    63     """ 
    64     mychr = chr 
    65     myatoi = int 
    66     list = s.split('_') 
    67     res = [list[0]] 
    68     myappend = res.append 
    69     del list[0] 
    70     for item in list: 
    71         if item[1:2]: 
    72             try: 
    73                 myappend(mychr(myatoi(item[:2], 16)) + item[2:]) 
    74             except ValueError: 
    75                 myappend('_' + item) 
    76         else: 
    77             myappend('_' + item) 
    78     return "".join(res) 
    79  
    80  
    81 def flatten_fieldsets(fieldsets): 
    82     """Returns a list of field names from an admin fieldsets structure.""" 
    83     field_names = [] 
    84     for name, opts in fieldsets: 
    85         for field in opts['fields']: 
    86             # type checking feels dirty, but it seems like the best way here 
    87             if type(field) == tuple: 
    88                 field_names.extend(field) 
    89             else: 
    90                 field_names.append(field) 
    91     return field_names 
    92  
    93  
    94 def get_deleted_objects(objs, opts, user, admin_site, using): 
    95     """ 
    96     Find all objects related to ``objs`` that should also be deleted. ``objs`` 
    97     must be a homogenous iterable of objects (e.g. a QuerySet). 
    98  
    99     Returns a nested list of strings suitable for display in the 
    100     template with the ``unordered_list`` filter. 
    101  
    102     """ 
    103     collector = NestedObjects(using=using) 
    104     collector.collect(objs) 
    105     perms_needed = set() 
    106  
    107     def format_callback(obj): 
    108         has_admin = obj.__class__ in admin_site._registry 
    109         opts = obj._meta 
    110  
    111         if has_admin: 
    112             admin_url = reverse('%s:%s_%s_change' 
    113                                 % (admin_site.name, 
    114                                    opts.app_label, 
    115                                    opts.object_name.lower()), 
    116                                 None, (quote(obj._get_pk_val()),)) 
    117             p = '%s.%s' % (opts.app_label, 
    118                            opts.get_delete_permission()) 
    119             if not user.has_perm(p): 
    120                 perms_needed.add(opts.verbose_name) 
    121             # Display a link to the admin page. 
    122             return mark_safe(u'%s: <a href="%s">%s</a>' % 
    123                              (escape(capfirst(opts.verbose_name)), 
    124                               admin_url, 
    125                               escape(obj))) 
    126         else: 
    127             # Don't display link to edit, because it either has no 
    128             # admin or is edited inline. 
    129             return u'%s: %s' % (capfirst(opts.verbose_name), 
    130                                 force_unicode(obj)) 
    131  
    132     to_delete = collector.nested(format_callback) 
    133  
    134     protected = [format_callback(obj) for obj in collector.protected] 
    135  
    136     return to_delete, perms_needed, protected 
    137  
    138  
    139 class NestedObjects(Collector): 
    140     def __init__(self, *args, **kwargs): 
    141         super(NestedObjects, self).__init__(*args, **kwargs) 
    142         self.edges = {} # {from_instance: [to_instances]} 
    143         self.protected = set() 
    144  
    145     def add_edge(self, source, target): 
    146         self.edges.setdefault(source, []).append(target) 
    147  
    148     def collect(self, objs, source_attr=None, **kwargs): 
    149         for obj in objs: 
    150             if source_attr: 
    151                 self.add_edge(getattr(obj, source_attr), obj) 
    152             else: 
    153                 self.add_edge(None, obj) 
    154         try: 
    155             return super(NestedObjects, self).collect(objs, source_attr=source_attr, **kwargs) 
    156         except models.ProtectedError, e: 
    157             self.protected.update(e.protected_objects) 
    158  
    159     def related_objects(self, related, objs): 
    160         qs = super(NestedObjects, self).related_objects(related, objs) 
    161         return qs.select_related(related.field.name) 
    162  
    163     def _nested(self, obj, seen, format_callback): 
    164         if obj in seen: 
    165             return [] 
    166         seen.add(obj) 
    167         children = [] 
    168         for child in self.edges.get(obj, ()): 
    169             children.extend(self._nested(child, seen, format_callback)) 
    170         if format_callback: 
    171             ret = [format_callback(obj)] 
    172         else: 
    173             ret = [obj] 
    174         if children: 
    175             ret.append(children) 
    176         return ret 
    177  
    178     def nested(self, format_callback=None): 
    179         """ 
    180         Return the graph as a nested list. 
    181  
    182         """ 
    183         seen = set() 
    184         roots = [] 
    185         for root in self.edges.get(None, ()): 
    186             roots.extend(self._nested(root, seen, format_callback)) 
    187         return roots 
    188  
    189  
    190 def model_format_dict(obj): 
    191     """ 
    192     Return a `dict` with keys 'verbose_name' and 'verbose_name_plural', 
    193     typically for use with string formatting. 
    194  
    195     `obj` may be a `Model` instance, `Model` subclass, or `QuerySet` instance. 
    196  
    197     """ 
    198     if isinstance(obj, (models.Model, models.base.ModelBase)): 
    199         opts = obj._meta 
    200     elif isinstance(obj, models.query.QuerySet): 
    201         opts = obj.model._meta 
    202     else: 
    203         opts = obj 
    204     return { 
    205         'verbose_name': force_unicode(opts.verbose_name), 
    206         'verbose_name_plural': force_unicode(opts.verbose_name_plural) 
    207     } 
    208  
    209  
    210 def model_ngettext(obj, n=None): 
    211     """ 
    212     Return the appropriate `verbose_name` or `verbose_name_plural` value for 
    213     `obj` depending on the count `n`. 
    214  
    215     `obj` may be a `Model` instance, `Model` subclass, or `QuerySet` instance. 
    216     If `obj` is a `QuerySet` instance, `n` is optional and the length of the 
    217     `QuerySet` is used. 
    218  
    219     """ 
    220     if isinstance(obj, models.query.QuerySet): 
    221         if n is None: 
    222             n = obj.count() 
    223         obj = obj.model 
    224     d = model_format_dict(obj) 
    225     singular, plural = d["verbose_name"], d["verbose_name_plural"] 
    226     return ungettext(singular, plural, n or 0) 
    227  
    228  
    229 def lookup_field(name, obj, model_admin=None): 
    230     opts = obj._meta 
    231     try: 
    232         f = opts.get_field(name) 
    233     except models.FieldDoesNotExist: 
    234         # For non-field values, the value is either a method, property or 
    235         # returned via a callable. 
    236         if callable(name): 
    237             attr = name 
    238             value = attr(obj) 
    239         elif (model_admin is not None and hasattr(model_admin, name) and 
    240           not name == '__str__' and not name == '__unicode__'): 
    241             attr = getattr(model_admin, name) 
    242             value = attr(obj) 
    243         else: 
    244             attr = getattr(obj, name) 
    245             if callable(attr): 
    246                 value = attr() 
    247             else: 
    248                 value = attr 
    249         f = None 
    250     else: 
    251         attr = None 
    252         value = getattr(obj, name) 
    253     return f, attr, value 
    254  
    255  
    256 def label_for_field(name, model, model_admin=None, return_attr=False): 
    257     """ 
    258     Returns a sensible label for a field name. The name can be a callable or the 
    259     name of an object attributes, as well as a genuine fields. If return_attr is 
    260     True, the resolved attribute (which could be a callable) is also returned. 
    261     This will be None if (and only if) the name refers to a field. 
    262     """ 
    263     attr = None 
    264     try: 
    265         field = model._meta.get_field_by_name(name)[0] 
    266         if isinstance(field, RelatedObject): 
    267             label = field.opts.verbose_name 
    268         else: 
    269             label = field.verbose_name 
    270     except models.FieldDoesNotExist: 
    271         if name == "__unicode__": 
    272             label = force_unicode(model._meta.verbose_name) 
    273             attr = unicode 
    274         elif name == "__str__": 
    275             label = smart_str(model._meta.verbose_name) 
    276             attr = str 
    277         else: 
    278             if callable(name): 
    279                 attr = name 
    280             elif model_admin is not None and hasattr(model_admin, name): 
    281                 attr = getattr(model_admin, name) 
    282             elif hasattr(model, name): 
    283                 attr = getattr(model, name) 
    284             else: 
    285                 message = "Unable to lookup '%s' on %s" % (name, model._meta.object_name) 
    286                 if model_admin: 
    287                     message += " or %s" % (model_admin.__class__.__name__,) 
    288                 raise AttributeError(message) 
    289  
    290             if hasattr(attr, "short_description"): 
    291                 label = attr.short_description 
    292             elif callable(attr): 
    293                 if attr.__name__ == "<lambda>": 
    294                     label = "--" 
    295                 else: 
    296                     label = pretty_name(attr.__name__) 
    297             else: 
    298                 label = pretty_name(name) 
    299     if return_attr: 
    300         return (label, attr) 
    301     else: 
    302         return label 
    303  
    304 def help_text_for_field(name, model): 
    305     try: 
    306         help_text = model._meta.get_field_by_name(name)[0].help_text 
    307     except models.FieldDoesNotExist: 
    308         help_text = "" 
    309     return smart_unicode(help_text) 
    310  
    311  
    312 def display_for_field(value, field): 
    313     from django.contrib.admin.templatetags.admin_list import _boolean_icon 
    314     from django.contrib.admin.views.main import EMPTY_CHANGELIST_VALUE 
    315  
    316     if field.flatchoices: 
    317         return dict(field.flatchoices).get(value, EMPTY_CHANGELIST_VALUE) 
    318     # NullBooleanField needs special-case null-handling, so it comes 
    319     # before the general null test. 
    320     elif isinstance(field, models.BooleanField) or isinstance(field, models.NullBooleanField): 
    321         return _boolean_icon(value) 
    322     elif value is None: 
    323         return EMPTY_CHANGELIST_VALUE 
    324     elif isinstance(field, models.DateTimeField): 
    325         return formats.localize(timezone.localtime(value)) 
    326     elif isinstance(field, models.DateField) or isinstance(field, models.TimeField): 
    327         return formats.localize(value) 
    328     elif isinstance(field, models.DecimalField): 
    329         return formats.number_format(value, field.decimal_places) 
    330     elif isinstance(field, models.FloatField): 
    331         return formats.number_format(value) 
    332     else: 
    333         return smart_unicode(value) 
    334  
    335  
    336 class NotRelationField(Exception): 
    337     pass 
    338  
    339  
    340 def get_model_from_relation(field): 
    341     if isinstance(field, models.related.RelatedObject): 
    342         return field.model 
    343     elif getattr(field, 'rel'): # or isinstance? 
    344         return field.rel.to 
    345     else: 
    346         raise NotRelationField 
    347  
    348  
    349 def reverse_field_path(model, path): 
    350     """ Create a reversed field path. 
    351  
    352     E.g. Given (Order, "user__groups"), 
    353     return (Group, "user__order"). 
    354  
    355     Final field must be a related model, not a data field. 
    356  
    357     """ 
    358     reversed_path = [] 
    359     parent = model 
    360     pieces = path.split(LOOKUP_SEP) 
    361     for piece in pieces: 
    362         field, model, direct, m2m = parent._meta.get_field_by_name(piece) 
    363         # skip trailing data field if extant: 
    364         if len(reversed_path) == len(pieces)-1: # final iteration 
    365             try: 
    366                 get_model_from_relation(field) 
    367             except NotRelationField: 
    368                 break 
    369         if direct: 
    370             related_name = field.related_query_name() 
    371             parent = field.rel.to 
    372         else: 
    373             related_name = field.field.name 
    374             parent = field.model 
    375         reversed_path.insert(0, related_name) 
    376     return (parent, LOOKUP_SEP.join(reversed_path)) 
    377  
    378  
    379 def get_fields_from_path(model, path): 
    380     """ Return list of Fields given path relative to model. 
    381  
    382     e.g. (ModelX, "user__groups__name") -> [ 
    383         <django.db.models.fields.related.ForeignKey object at 0x...>, 
    384         <django.db.models.fields.related.ManyToManyField object at 0x...>, 
    385         <django.db.models.fields.CharField object at 0x...>, 
    386     ] 
    387     """ 
    388     pieces = path.split(LOOKUP_SEP) 
    389     fields = [] 
    390     for piece in pieces: 
    391         if fields: 
    392             parent = get_model_from_relation(fields[-1]) 
    393         else: 
    394             parent = model 
    395         fields.append(parent._meta.get_field_by_name(piece)[0]) 
    396     return fields 
    397  
    398  
    399 def remove_trailing_data_field(fields): 
    400     """ Discard trailing non-relation field if extant. """ 
    401     try: 
    402         get_model_from_relation(fields[-1]) 
    403     except NotRelationField: 
    404         fields = fields[:-1] 
    405     return fields 
    406  
    407  
    408 def get_limit_choices_to_from_path(model, path): 
    409     """ Return Q object for limiting choices if applicable. 
    410  
    411     If final model in path is linked via a ForeignKey or ManyToManyField which 
    412     has a `limit_choices_to` attribute, return it as a Q object. 
    413     """ 
    414  
    415     fields = get_fields_from_path(model, path) 
    416     fields = remove_trailing_data_field(fields) 
    417     limit_choices_to = ( 
    418         fields and hasattr(fields[-1], 'rel') and 
    419         getattr(fields[-1].rel, 'limit_choices_to', None)) 
    420     if not limit_choices_to: 
    421         return models.Q() # empty Q 
    422     elif isinstance(limit_choices_to, models.Q): 
    423         return limit_choices_to # already a Q 
    424     else: 
    425         return models.Q(**limit_choices_to) # convert dict to Q 
     7from django.contrib.admin.utils import * 
  • new file django/contrib/admin/utils.py

    diff --git a/django/contrib/admin/utils.py b/django/contrib/admin/utils.py
    new file mode 100644
    index 0000000..61182a6
    - +  
     1from django.db import models 
     2from django.db.models.sql.constants import LOOKUP_SEP 
     3from django.db.models.deletion import Collector 
     4from django.db.models.related import RelatedObject 
     5from django.forms.forms import pretty_name 
     6from django.utils import formats 
     7from django.utils.html import escape 
     8from django.utils.safestring import mark_safe 
     9from django.utils.text import capfirst 
     10from django.utils import timezone 
     11from django.utils.encoding import force_unicode, smart_unicode, smart_str 
     12from django.utils.translation import ungettext 
     13from django.core.urlresolvers import reverse 
     14 
     15def lookup_needs_distinct(opts, lookup_path): 
     16    """ 
     17    Returns True if 'distinct()' should be used to query the given lookup path. 
     18    """ 
     19    field_name = lookup_path.split('__', 1)[0] 
     20    field = opts.get_field_by_name(field_name)[0] 
     21    if ((hasattr(field, 'rel') and 
     22         isinstance(field.rel, models.ManyToManyRel)) or 
     23        (isinstance(field, models.related.RelatedObject) and 
     24         not field.field.unique)): 
     25         return True 
     26    return False 
     27 
     28def prepare_lookup_value(key, value): 
     29    """ 
     30    Returns a lookup value prepared to be used in queryset filtering. 
     31    """ 
     32    # if key ends with __in, split parameter into separate values 
     33    if key.endswith('__in'): 
     34        value = value.split(',') 
     35    # if key ends with __isnull, special case '' and false 
     36    if key.endswith('__isnull'): 
     37        if value.lower() in ('', 'false'): 
     38            value = False 
     39        else: 
     40            value = True 
     41    return value 
     42 
     43def quote(s): 
     44    """ 
     45    Ensure that primary key values do not confuse the admin URLs by escaping 
     46    any '/', '_' and ':' characters. Similar to urllib.quote, except that the 
     47    quoting is slightly different so that it doesn't get automatically 
     48    unquoted by the Web browser. 
     49    """ 
     50    if not isinstance(s, basestring): 
     51        return s 
     52    res = list(s) 
     53    for i in range(len(res)): 
     54        c = res[i] 
     55        if c in """:/_#?;@&=+$,"<>%\\""": 
     56            res[i] = '_%02X' % ord(c) 
     57    return ''.join(res) 
     58 
     59 
     60def unquote(s): 
     61    """ 
     62    Undo the effects of quote(). Based heavily on urllib.unquote(). 
     63    """ 
     64    mychr = chr 
     65    myatoi = int 
     66    list = s.split('_') 
     67    res = [list[0]] 
     68    myappend = res.append 
     69    del list[0] 
     70    for item in list: 
     71        if item[1:2]: 
     72            try: 
     73                myappend(mychr(myatoi(item[:2], 16)) + item[2:]) 
     74            except ValueError: 
     75                myappend('_' + item) 
     76        else: 
     77            myappend('_' + item) 
     78    return "".join(res) 
     79 
     80 
     81def flatten_fieldsets(fieldsets): 
     82    """Returns a list of field names from an admin fieldsets structure.""" 
     83    field_names = [] 
     84    for name, opts in fieldsets: 
     85        for field in opts['fields']: 
     86            # type checking feels dirty, but it seems like the best way here 
     87            if type(field) == tuple: 
     88                field_names.extend(field) 
     89            else: 
     90                field_names.append(field) 
     91    return field_names 
     92 
     93 
     94def get_deleted_objects(objs, opts, user, admin_site, using): 
     95    """ 
     96    Find all objects related to ``objs`` that should also be deleted. ``objs`` 
     97    must be a homogenous iterable of objects (e.g. a QuerySet). 
     98 
     99    Returns a nested list of strings suitable for display in the 
     100    template with the ``unordered_list`` filter. 
     101 
     102    """ 
     103    collector = NestedObjects(using=using) 
     104    collector.collect(objs) 
     105    perms_needed = set() 
     106 
     107    def format_callback(obj): 
     108        has_admin = obj.__class__ in admin_site._registry 
     109        opts = obj._meta 
     110 
     111        if has_admin: 
     112            admin_url = reverse('%s:%s_%s_change' 
     113                                % (admin_site.name, 
     114                                   opts.app_label, 
     115                                   opts.object_name.lower()), 
     116                                None, (quote(obj._get_pk_val()),)) 
     117            p = '%s.%s' % (opts.app_label, 
     118                           opts.get_delete_permission()) 
     119            if not user.has_perm(p): 
     120                perms_needed.add(opts.verbose_name) 
     121            # Display a link to the admin page. 
     122            return mark_safe(u'%s: <a href="%s">%s</a>' % 
     123                             (escape(capfirst(opts.verbose_name)), 
     124                              admin_url, 
     125                              escape(obj))) 
     126        else: 
     127            # Don't display link to edit, because it either has no 
     128            # admin or is edited inline. 
     129            return u'%s: %s' % (capfirst(opts.verbose_name), 
     130                                force_unicode(obj)) 
     131 
     132    to_delete = collector.nested(format_callback) 
     133 
     134    protected = [format_callback(obj) for obj in collector.protected] 
     135 
     136    return to_delete, perms_needed, protected 
     137 
     138 
     139class NestedObjects(Collector): 
     140    def __init__(self, *args, **kwargs): 
     141        super(NestedObjects, self).__init__(*args, **kwargs) 
     142        self.edges = {} # {from_instance: [to_instances]} 
     143        self.protected = set() 
     144 
     145    def add_edge(self, source, target): 
     146        self.edges.setdefault(source, []).append(target) 
     147 
     148    def collect(self, objs, source_attr=None, **kwargs): 
     149        for obj in objs: 
     150            if source_attr: 
     151                self.add_edge(getattr(obj, source_attr), obj) 
     152            else: 
     153                self.add_edge(None, obj) 
     154        try: 
     155            return super(NestedObjects, self).collect(objs, source_attr=source_attr, **kwargs) 
     156        except models.ProtectedError, e: 
     157            self.protected.update(e.protected_objects) 
     158 
     159    def related_objects(self, related, objs): 
     160        qs = super(NestedObjects, self).related_objects(related, objs) 
     161        return qs.select_related(related.field.name) 
     162 
     163    def _nested(self, obj, seen, format_callback): 
     164        if obj in seen: 
     165            return [] 
     166        seen.add(obj) 
     167        children = [] 
     168        for child in self.edges.get(obj, ()): 
     169            children.extend(self._nested(child, seen, format_callback)) 
     170        if format_callback: 
     171            ret = [format_callback(obj)] 
     172        else: 
     173            ret = [obj] 
     174        if children: 
     175            ret.append(children) 
     176        return ret 
     177 
     178    def nested(self, format_callback=None): 
     179        """ 
     180        Return the graph as a nested list. 
     181 
     182        """ 
     183        seen = set() 
     184        roots = [] 
     185        for root in self.edges.get(None, ()): 
     186            roots.extend(self._nested(root, seen, format_callback)) 
     187        return roots 
     188 
     189 
     190def model_format_dict(obj): 
     191    """ 
     192    Return a `dict` with keys 'verbose_name' and 'verbose_name_plural', 
     193    typically for use with string formatting. 
     194 
     195    `obj` may be a `Model` instance, `Model` subclass, or `QuerySet` instance. 
     196 
     197    """ 
     198    if isinstance(obj, (models.Model, models.base.ModelBase)): 
     199        opts = obj._meta 
     200    elif isinstance(obj, models.query.QuerySet): 
     201        opts = obj.model._meta 
     202    else: 
     203        opts = obj 
     204    return { 
     205        'verbose_name': force_unicode(opts.verbose_name), 
     206        'verbose_name_plural': force_unicode(opts.verbose_name_plural) 
     207    } 
     208 
     209 
     210def model_ngettext(obj, n=None): 
     211    """ 
     212    Return the appropriate `verbose_name` or `verbose_name_plural` value for 
     213    `obj` depending on the count `n`. 
     214 
     215    `obj` may be a `Model` instance, `Model` subclass, or `QuerySet` instance. 
     216    If `obj` is a `QuerySet` instance, `n` is optional and the length of the 
     217    `QuerySet` is used. 
     218 
     219    """ 
     220    if isinstance(obj, models.query.QuerySet): 
     221        if n is None: 
     222            n = obj.count() 
     223        obj = obj.model 
     224    d = model_format_dict(obj) 
     225    singular, plural = d["verbose_name"], d["verbose_name_plural"] 
     226    return ungettext(singular, plural, n or 0) 
     227 
     228 
     229def lookup_field(name, obj, model_admin=None): 
     230    opts = obj._meta 
     231    try: 
     232        f = opts.get_field(name) 
     233    except models.FieldDoesNotExist: 
     234        # For non-field values, the value is either a method, property or 
     235        # returned via a callable. 
     236        if callable(name): 
     237            attr = name 
     238            value = attr(obj) 
     239        elif (model_admin is not None and hasattr(model_admin, name) and 
     240          not name == '__str__' and not name == '__unicode__'): 
     241            attr = getattr(model_admin, name) 
     242            value = attr(obj) 
     243        else: 
     244            attr = getattr(obj, name) 
     245            if callable(attr): 
     246                value = attr() 
     247            else: 
     248                value = attr 
     249        f = None 
     250    else: 
     251        attr = None 
     252        value = getattr(obj, name) 
     253    return f, attr, value 
     254 
     255 
     256def label_for_field(name, model, model_admin=None, return_attr=False): 
     257    """ 
     258    Returns a sensible label for a field name. The name can be a callable or the 
     259    name of an object attributes, as well as a genuine fields. If return_attr is 
     260    True, the resolved attribute (which could be a callable) is also returned. 
     261    This will be None if (and only if) the name refers to a field. 
     262    """ 
     263    attr = None 
     264    try: 
     265        field = model._meta.get_field_by_name(name)[0] 
     266        if isinstance(field, RelatedObject): 
     267            label = field.opts.verbose_name 
     268        else: 
     269            label = field.verbose_name 
     270    except models.FieldDoesNotExist: 
     271        if name == "__unicode__": 
     272            label = force_unicode(model._meta.verbose_name) 
     273            attr = unicode 
     274        elif name == "__str__": 
     275            label = smart_str(model._meta.verbose_name) 
     276            attr = str 
     277        else: 
     278            if callable(name): 
     279                attr = name 
     280            elif model_admin is not None and hasattr(model_admin, name): 
     281                attr = getattr(model_admin, name) 
     282            elif hasattr(model, name): 
     283                attr = getattr(model, name) 
     284            else: 
     285                message = "Unable to lookup '%s' on %s" % (name, model._meta.object_name) 
     286                if model_admin: 
     287                    message += " or %s" % (model_admin.__class__.__name__,) 
     288                raise AttributeError(message) 
     289 
     290            if hasattr(attr, "short_description"): 
     291                label = attr.short_description 
     292            elif callable(attr): 
     293                if attr.__name__ == "<lambda>": 
     294                    label = "--" 
     295                else: 
     296                    label = pretty_name(attr.__name__) 
     297            else: 
     298                label = pretty_name(name) 
     299    if return_attr: 
     300        return (label, attr) 
     301    else: 
     302        return label 
     303 
     304def help_text_for_field(name, model): 
     305    try: 
     306        help_text = model._meta.get_field_by_name(name)[0].help_text 
     307    except models.FieldDoesNotExist: 
     308        help_text = "" 
     309    return smart_unicode(help_text) 
     310 
     311 
     312def display_for_field(value, field): 
     313    from django.contrib.admin.templatetags.admin_list import _boolean_icon 
     314    from django.contrib.admin.views.main import EMPTY_CHANGELIST_VALUE 
     315 
     316    if field.flatchoices: 
     317        return dict(field.flatchoices).get(value, EMPTY_CHANGELIST_VALUE) 
     318    # NullBooleanField needs special-case null-handling, so it comes 
     319    # before the general null test. 
     320    elif isinstance(field, models.BooleanField) or isinstance(field, models.NullBooleanField): 
     321        return _boolean_icon(value) 
     322    elif value is None: 
     323        return EMPTY_CHANGELIST_VALUE 
     324    elif isinstance(field, models.DateTimeField): 
     325        return formats.localize(timezone.localtime(value)) 
     326    elif isinstance(field, models.DateField) or isinstance(field, models.TimeField): 
     327        return formats.localize(value) 
     328    elif isinstance(field, models.DecimalField): 
     329        return formats.number_format(value, field.decimal_places) 
     330    elif isinstance(field, models.FloatField): 
     331        return formats.number_format(value) 
     332    else: 
     333        return smart_unicode(value) 
     334 
     335 
     336class NotRelationField(Exception): 
     337    pass 
     338 
     339 
     340def get_model_from_relation(field): 
     341    if isinstance(field, models.related.RelatedObject): 
     342        return field.model 
     343    elif getattr(field, 'rel'): # or isinstance? 
     344        return field.rel.to 
     345    else: 
     346        raise NotRelationField 
     347 
     348 
     349def reverse_field_path(model, path): 
     350    """ Create a reversed field path. 
     351 
     352    E.g. Given (Order, "user__groups"), 
     353    return (Group, "user__order"). 
     354 
     355    Final field must be a related model, not a data field. 
     356 
     357    """ 
     358    reversed_path = [] 
     359    parent = model 
     360    pieces = path.split(LOOKUP_SEP) 
     361    for piece in pieces: 
     362        field, model, direct, m2m = parent._meta.get_field_by_name(piece) 
     363        # skip trailing data field if extant: 
     364        if len(reversed_path) == len(pieces)-1: # final iteration 
     365            try: 
     366                get_model_from_relation(field) 
     367            except NotRelationField: 
     368                break 
     369        if direct: 
     370            related_name = field.related_query_name() 
     371            parent = field.rel.to 
     372        else: 
     373            related_name = field.field.name 
     374            parent = field.model 
     375        reversed_path.insert(0, related_name) 
     376    return (parent, LOOKUP_SEP.join(reversed_path)) 
     377 
     378 
     379def get_fields_from_path(model, path): 
     380    """ Return list of Fields given path relative to model. 
     381 
     382    e.g. (ModelX, "user__groups__name") -> [ 
     383        <django.db.models.fields.related.ForeignKey object at 0x...>, 
     384        <django.db.models.fields.related.ManyToManyField object at 0x...>, 
     385        <django.db.models.fields.CharField object at 0x...>, 
     386    ] 
     387    """ 
     388    pieces = path.split(LOOKUP_SEP) 
     389    fields = [] 
     390    for piece in pieces: 
     391        if fields: 
     392            parent = get_model_from_relation(fields[-1]) 
     393        else: 
     394            parent = model 
     395        fields.append(parent._meta.get_field_by_name(piece)[0]) 
     396    return fields 
     397 
     398 
     399def remove_trailing_data_field(fields): 
     400    """ Discard trailing non-relation field if extant. """ 
     401    try: 
     402        get_model_from_relation(fields[-1]) 
     403    except NotRelationField: 
     404        fields = fields[:-1] 
     405    return fields 
     406 
     407 
     408def get_limit_choices_to_from_path(model, path): 
     409    """ Return Q object for limiting choices if applicable. 
     410 
     411    If final model in path is linked via a ForeignKey or ManyToManyField which 
     412    has a `limit_choices_to` attribute, return it as a Q object. 
     413    """ 
     414 
     415    fields = get_fields_from_path(model, path) 
     416    fields = remove_trailing_data_field(fields) 
     417    limit_choices_to = ( 
     418        fields and hasattr(fields[-1], 'rel') and 
     419        getattr(fields[-1].rel, 'limit_choices_to', None)) 
     420    if not limit_choices_to: 
     421        return models.Q() # empty Q 
     422    elif isinstance(limit_choices_to, models.Q): 
     423        return limit_choices_to # already a Q 
     424    else: 
     425        return models.Q(**limit_choices_to) # convert dict to Q 
  • django/contrib/admin/validation.py

    diff --git a/django/contrib/admin/validation.py b/django/contrib/admin/validation.py
    index 733f89d..bd99b84 100644
    a b from django.db.models.fields import FieldDoesNotExist 
    44from django.forms.models import (BaseModelForm, BaseModelFormSet, fields_for_model, 
    55    _get_foreign_key) 
    66from django.contrib.admin import ListFilter, FieldListFilter 
    7 from django.contrib.admin.util import get_fields_from_path, NotRelationField 
     7from django.contrib.admin.utils import get_fields_from_path, NotRelationField 
    88from django.contrib.admin.options import (flatten_fieldsets, BaseModelAdmin, 
    99    HORIZONTAL, VERTICAL) 
    1010 
  • django/contrib/admin/views/main.py

    diff --git a/django/contrib/admin/views/main.py b/django/contrib/admin/views/main.py
    index 56f13f8..e12cca5 100644
    a b from django.utils.http import urlencode 
    1010 
    1111from django.contrib.admin import FieldListFilter 
    1212from django.contrib.admin.options import IncorrectLookupParameters 
    13 from django.contrib.admin.util import (quote, get_fields_from_path, 
     13from django.contrib.admin.utils import (quote, get_fields_from_path, 
    1414    lookup_needs_distinct, prepare_lookup_value) 
    1515 
    1616# Changelist settings 
  • django/contrib/admin/widgets.py

    diff --git a/django/contrib/admin/widgets.py b/django/contrib/admin/widgets.py
    index 29958b2..148ce1c 100644
    a b from django import forms 
    77from django.contrib.admin.templatetags.admin_static import static 
    88from django.core.urlresolvers import reverse 
    99from django.forms.widgets import RadioFieldRenderer 
    10 from django.forms.util import flatatt 
     10from django.forms.utils import flatatt 
    1111from django.utils.html import escape 
    1212from django.utils.text import Truncator 
    1313from django.utils.translation import ugettext as _ 
  • django/contrib/auth/admin.py

    diff --git a/django/contrib/auth/admin.py b/django/contrib/auth/admin.py
    index f14b3d2..973bdb8 100644
    a b class UserAdmin(admin.ModelAdmin): 
    7171        if obj is None: 
    7272            defaults.update({ 
    7373                'form': self.add_form, 
    74                 'fields': admin.util.flatten_fieldsets(self.add_fieldsets), 
     74                'fields': admin.utils.flatten_fieldsets(self.add_fieldsets), 
    7575            }) 
    7676        defaults.update(kwargs) 
    7777        return super(UserAdmin, self).get_form(request, obj, **defaults) 
  • django/contrib/auth/forms.py

    diff --git a/django/contrib/auth/forms.py b/django/contrib/auth/forms.py
    index badd760..d988ce3 100644
    a b  
    11from django import forms 
    2 from django.forms.util import flatatt 
     2from django.forms.utils import flatatt 
    33from django.template import loader 
    44from django.utils.encoding import smart_str 
    55from django.utils.http import int_to_base36 
  • django/contrib/comments/forms.py

    diff --git a/django/contrib/comments/forms.py b/django/contrib/comments/forms.py
    index 830e24b..88c2e5e 100644
    a b  
    11import time 
    22from django import forms 
    3 from django.forms.util import ErrorDict 
     3from django.forms.utils import ErrorDict 
    44from django.conf import settings 
    55from django.contrib.contenttypes.models import ContentType 
    66from django.contrib.comments.models import Comment 
  • django/contrib/gis/db/backends/oracle/creation.py

    diff --git a/django/contrib/gis/db/backends/oracle/creation.py b/django/contrib/gis/db/backends/oracle/creation.py
    index 043da91..14f8d4d 100644
    a b  
    11from django.db.backends.oracle.creation import DatabaseCreation 
    2 from django.db.backends.util import truncate_name 
     2from django.db.backends.utils import truncate_name 
    33 
    44class OracleCreation(DatabaseCreation): 
    55 
  • django/contrib/gis/db/backends/oracle/operations.py

    diff --git a/django/contrib/gis/db/backends/oracle/operations.py b/django/contrib/gis/db/backends/oracle/operations.py
    index a2374bb..97380a3 100644
    a b from decimal import Decimal 
    1313from django.db.backends.oracle.base import DatabaseOperations 
    1414from django.contrib.gis.db.backends.base import BaseSpatialOperations 
    1515from django.contrib.gis.db.backends.oracle.adapter import OracleSpatialAdapter 
    16 from django.contrib.gis.db.backends.util import SpatialFunction 
     16from django.contrib.gis.db.backends.utils import SpatialFunction 
    1717from django.contrib.gis.geometry.backend import Geometry 
    1818from django.contrib.gis.measure import Distance 
    1919 
  • django/contrib/gis/db/backends/postgis/operations.py

    diff --git a/django/contrib/gis/db/backends/postgis/operations.py b/django/contrib/gis/db/backends/postgis/operations.py
    index 3286748..31e659c 100644
    a b from decimal import Decimal 
    33 
    44from django.conf import settings 
    55from django.contrib.gis.db.backends.base import BaseSpatialOperations 
    6 from django.contrib.gis.db.backends.util import SpatialOperation, SpatialFunction 
     6from django.contrib.gis.db.backends.utils import SpatialOperation, SpatialFunction 
    77from django.contrib.gis.db.backends.postgis.adapter import PostGISAdapter 
    88from django.contrib.gis.geometry.backend import Geometry 
    99from django.contrib.gis.measure import Distance 
  • django/contrib/gis/db/backends/spatialite/operations.py

    diff --git a/django/contrib/gis/db/backends/spatialite/operations.py b/django/contrib/gis/db/backends/spatialite/operations.py
    index a0efb99..6dacff0 100644
    a b import re 
    22from decimal import Decimal 
    33 
    44from django.contrib.gis.db.backends.base import BaseSpatialOperations 
    5 from django.contrib.gis.db.backends.util import SpatialOperation, SpatialFunction 
     5from django.contrib.gis.db.backends.utils import SpatialOperation, SpatialFunction 
    66from django.contrib.gis.db.backends.spatialite.adapter import SpatiaLiteAdapter 
    77from django.contrib.gis.geometry.backend import Geometry 
    88from django.contrib.gis.measure import Distance 
  • django/contrib/gis/db/backends/util.py

    diff --git a/django/contrib/gis/db/backends/util.py b/django/contrib/gis/db/backends/util.py
    index b50c8e2..3b52c38 100644
    a b  
    1 """ 
    2 A collection of utility routines and classes used by the spatial 
    3 backends. 
    4 """ 
     1import warnings 
    52 
    6 def gqn(val): 
    7     """ 
    8     The geographic quote name function; used for quoting tables and 
    9     geometries (they use single rather than the double quotes of the 
    10     backend quotename function). 
    11     """ 
    12     if isinstance(val, basestring): 
    13         if isinstance(val, unicode): val = val.encode('ascii') 
    14         return "'%s'" % val 
    15     else: 
    16         return str(val) 
     3warnings.warn("The django.contrib.gis.db.util module has been renamed " 
     4              "(https://code.djangoproject.com/ticket/17627/). " 
     5              "Use django.contrib.gis.db.utils instead.", PendingDeprecationWarning) 
    176 
    18 class SpatialOperation(object): 
    19     """ 
    20     Base class for generating spatial SQL. 
    21     """ 
    22     sql_template = '%(geo_col)s %(operator)s %(geometry)s' 
    23  
    24     def __init__(self, function='', operator='', result='', **kwargs): 
    25         self.function = function 
    26         self.operator = operator 
    27         self.result = result 
    28         self.extra = kwargs 
    29  
    30     def as_sql(self, geo_col, geometry='%s'): 
    31         return self.sql_template % self.params(geo_col, geometry) 
    32  
    33     def params(self, geo_col, geometry): 
    34         params = {'function' : self.function, 
    35                   'geo_col' : geo_col, 
    36                   'geometry' : geometry, 
    37                   'operator' : self.operator, 
    38                   'result' : self.result, 
    39                   } 
    40         params.update(self.extra) 
    41         return params 
    42  
    43 class SpatialFunction(SpatialOperation): 
    44     """ 
    45     Base class for generating spatial SQL related to a function. 
    46     """ 
    47     sql_template = '%(function)s(%(geo_col)s, %(geometry)s)' 
    48  
    49     def __init__(self, func, result='', operator='', **kwargs): 
    50         # Getting the function prefix. 
    51         default = {'function' : func, 
    52                    'operator' : operator, 
    53                    'result' : result 
    54                    } 
    55         kwargs.update(default) 
    56         super(SpatialFunction, self).__init__(**kwargs) 
     7from django.contrib.gis.db.utils import * 
  • new file django/contrib/gis/db/backends/utils.py

    diff --git a/django/contrib/gis/db/backends/utils.py b/django/contrib/gis/db/backends/utils.py
    new file mode 100644
    index 0000000..b50c8e2
    - +  
     1""" 
     2A collection of utility routines and classes used by the spatial 
     3backends. 
     4""" 
     5 
     6def gqn(val): 
     7    """ 
     8    The geographic quote name function; used for quoting tables and 
     9    geometries (they use single rather than the double quotes of the 
     10    backend quotename function). 
     11    """ 
     12    if isinstance(val, basestring): 
     13        if isinstance(val, unicode): val = val.encode('ascii') 
     14        return "'%s'" % val 
     15    else: 
     16        return str(val) 
     17 
     18class SpatialOperation(object): 
     19    """ 
     20    Base class for generating spatial SQL. 
     21    """ 
     22    sql_template = '%(geo_col)s %(operator)s %(geometry)s' 
     23 
     24    def __init__(self, function='', operator='', result='', **kwargs): 
     25        self.function = function 
     26        self.operator = operator 
     27        self.result = result 
     28        self.extra = kwargs 
     29 
     30    def as_sql(self, geo_col, geometry='%s'): 
     31        return self.sql_template % self.params(geo_col, geometry) 
     32 
     33    def params(self, geo_col, geometry): 
     34        params = {'function' : self.function, 
     35                  'geo_col' : geo_col, 
     36                  'geometry' : geometry, 
     37                  'operator' : self.operator, 
     38                  'result' : self.result, 
     39                  } 
     40        params.update(self.extra) 
     41        return params 
     42 
     43class SpatialFunction(SpatialOperation): 
     44    """ 
     45    Base class for generating spatial SQL related to a function. 
     46    """ 
     47    sql_template = '%(function)s(%(geo_col)s, %(geometry)s)' 
     48 
     49    def __init__(self, func, result='', operator='', **kwargs): 
     50        # Getting the function prefix. 
     51        default = {'function' : func, 
     52                   'operator' : operator, 
     53                   'result' : result 
     54                   } 
     55        kwargs.update(default) 
     56        super(SpatialFunction, self).__init__(**kwargs) 
  • django/contrib/gis/db/models/sql/compiler.py

    diff --git a/django/contrib/gis/db/models/sql/compiler.py b/django/contrib/gis/db/models/sql/compiler.py
    index 07eea32..a387fb6 100644
    a b  
    11from itertools import izip 
    2 from django.db.backends.util import truncate_name, typecast_timestamp 
     2from django.db.backends.utils import truncate_name, typecast_timestamp 
    33from django.db.models.sql import compiler 
    44from django.db.models.sql.constants import TABLE_NAME, MULTI 
    55 
  • django/contrib/localflavor/it/forms.py

    diff --git a/django/contrib/localflavor/it/forms.py b/django/contrib/localflavor/it/forms.py
    index 0060b48..a7dd5cd 100644
    a b import re 
    88 
    99from django.contrib.localflavor.it.it_province import PROVINCE_CHOICES 
    1010from django.contrib.localflavor.it.it_region import REGION_CHOICES 
    11 from django.contrib.localflavor.it.util import ssn_check_digit, vat_number_check_digit 
     11from django.contrib.localflavor.it.utils import ssn_check_digit, vat_number_check_digit 
    1212from django.core.validators import EMPTY_VALUES 
    1313from django.forms import ValidationError 
    1414from django.forms.fields import Field, RegexField, Select 
  • django/contrib/localflavor/it/util.py

    diff --git a/django/contrib/localflavor/it/util.py b/django/contrib/localflavor/it/util.py
    index c162ff7..8abd1bd 100644
    a b  
    1 from django.utils.encoding import smart_str, smart_unicode 
     1import warnings 
    22 
    3 def ssn_check_digit(value): 
    4     "Calculate Italian social security number check digit." 
    5     ssn_even_chars = { 
    6         '0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, 
    7         '9': 9, 'A': 0, 'B': 1, 'C': 2, 'D': 3, 'E': 4, 'F': 5, 'G': 6, 'H': 7, 
    8         'I': 8, 'J': 9, 'K': 10, 'L': 11, 'M': 12, 'N': 13, 'O': 14, 'P': 15, 
    9         'Q': 16, 'R': 17, 'S': 18, 'T': 19, 'U': 20, 'V': 21, 'W': 22, 'X': 23, 
    10         'Y': 24, 'Z': 25 
    11     } 
    12     ssn_odd_chars = { 
    13         '0': 1, '1': 0, '2': 5, '3': 7, '4': 9, '5': 13, '6': 15, '7': 17, '8': 
    14         19, '9': 21, 'A': 1, 'B': 0, 'C': 5, 'D': 7, 'E': 9, 'F': 13, 'G': 15, 
    15         'H': 17, 'I': 19, 'J': 21, 'K': 2, 'L': 4, 'M': 18, 'N': 20, 'O': 11, 
    16         'P': 3, 'Q': 6, 'R': 8, 'S': 12, 'T': 14, 'U': 16, 'V': 10, 'W': 22, 
    17         'X': 25, 'Y': 24, 'Z': 23 
    18     } 
    19     # Chars from 'A' to 'Z' 
    20     ssn_check_digits = [chr(x) for x in range(65, 91)] 
     3warnings.warn("The django.contrib.localflavor.it.util module has been renamed " 
     4              "(https://code.djangoproject.com/ticket/17627/). " 
     5              "Use django.contrib.localflavor.it.utils instead.", PendingDeprecationWarning) 
    216 
    22     ssn = value.upper() 
    23     total = 0 
    24     for i in range(0, 15): 
    25         try: 
    26             if i % 2 == 0: 
    27                 total += ssn_odd_chars[ssn[i]] 
    28             else: 
    29                 total += ssn_even_chars[ssn[i]] 
    30         except KeyError: 
    31             msg = "Character '%(char)s' is not allowed." % {'char': ssn[i]} 
    32             raise ValueError(msg) 
    33     return ssn_check_digits[total % 26] 
    34  
    35 def vat_number_check_digit(vat_number): 
    36     "Calculate Italian VAT number check digit." 
    37     normalized_vat_number = smart_str(vat_number).zfill(10) 
    38     total = 0 
    39     for i in range(0, 10, 2): 
    40         total += int(normalized_vat_number[i]) 
    41     for i in range(1, 11, 2): 
    42         quotient , remainder = divmod(int(normalized_vat_number[i]) * 2, 10) 
    43         total += quotient + remainder 
    44     return smart_unicode((10 - total % 10) % 10) 
     7from django.contrib.localflavor.it.utils import * 
  • new file django/contrib/localflavor/it/utils.py

    diff --git a/django/contrib/localflavor/it/utils.py b/django/contrib/localflavor/it/utils.py
    new file mode 100644
    index 0000000..c162ff7
    - +  
     1from django.utils.encoding import smart_str, smart_unicode 
     2 
     3def ssn_check_digit(value): 
     4    "Calculate Italian social security number check digit." 
     5    ssn_even_chars = { 
     6        '0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, 
     7        '9': 9, 'A': 0, 'B': 1, 'C': 2, 'D': 3, 'E': 4, 'F': 5, 'G': 6, 'H': 7, 
     8        'I': 8, 'J': 9, 'K': 10, 'L': 11, 'M': 12, 'N': 13, 'O': 14, 'P': 15, 
     9        'Q': 16, 'R': 17, 'S': 18, 'T': 19, 'U': 20, 'V': 21, 'W': 22, 'X': 23, 
     10        'Y': 24, 'Z': 25 
     11    } 
     12    ssn_odd_chars = { 
     13        '0': 1, '1': 0, '2': 5, '3': 7, '4': 9, '5': 13, '6': 15, '7': 17, '8': 
     14        19, '9': 21, 'A': 1, 'B': 0, 'C': 5, 'D': 7, 'E': 9, 'F': 13, 'G': 15, 
     15        'H': 17, 'I': 19, 'J': 21, 'K': 2, 'L': 4, 'M': 18, 'N': 20, 'O': 11, 
     16        'P': 3, 'Q': 6, 'R': 8, 'S': 12, 'T': 14, 'U': 16, 'V': 10, 'W': 22, 
     17        'X': 25, 'Y': 24, 'Z': 23 
     18    } 
     19    # Chars from 'A' to 'Z' 
     20    ssn_check_digits = [chr(x) for x in range(65, 91)] 
     21 
     22    ssn = value.upper() 
     23    total = 0 
     24    for i in range(0, 15): 
     25        try: 
     26            if i % 2 == 0: 
     27                total += ssn_odd_chars[ssn[i]] 
     28            else: 
     29                total += ssn_even_chars[ssn[i]] 
     30        except KeyError: 
     31            msg = "Character '%(char)s' is not allowed." % {'char': ssn[i]} 
     32            raise ValueError(msg) 
     33    return ssn_check_digits[total % 26] 
     34 
     35def vat_number_check_digit(vat_number): 
     36    "Calculate Italian VAT number check digit." 
     37    normalized_vat_number = smart_str(vat_number).zfill(10) 
     38    total = 0 
     39    for i in range(0, 10, 2): 
     40        total += int(normalized_vat_number[i]) 
     41    for i in range(1, 11, 2): 
     42        quotient , remainder = divmod(int(normalized_vat_number[i]) * 2, 10) 
     43        total += quotient + remainder 
     44    return smart_unicode((10 - total % 10) % 10) 
  • django/contrib/localflavor/uy/forms.py

    diff --git a/django/contrib/localflavor/uy/forms.py b/django/contrib/localflavor/uy/forms.py
    index 2112162..6107667 100644
    a b from django.core.validators import EMPTY_VALUES 
    99from django.forms.fields import Select, RegexField 
    1010from django.forms import ValidationError 
    1111from django.utils.translation import ugettext_lazy as _ 
    12 from django.contrib.localflavor.uy.util import get_validation_digit 
     12from django.contrib.localflavor.uy.utils import get_validation_digit 
    1313 
    1414 
    1515class UYDepartamentSelect(Select): 
  • django/contrib/localflavor/uy/util.py

    diff --git a/django/contrib/localflavor/uy/util.py b/django/contrib/localflavor/uy/util.py
    index 0c1a8f8..95598ad 100644
    a b  
    1 # -*- coding: utf-8 -*- 
     1import warnings 
    22 
    3 def get_validation_digit(number): 
    4     """ Calculates the validation digit for the given number. """ 
    5     sum = 0 
    6     dvs = [4, 3, 6, 7, 8, 9, 2] 
    7     number = str(number) 
     3warnings.warn("The django.contrib.localflavor.uy.util module has been renamed " 
     4              "(https://code.djangoproject.com/ticket/17627/). " 
     5              "Use django.contrib.localflavor.uy.utils instead.", PendingDeprecationWarning) 
    86 
    9     for i in range(0, len(number)): 
    10         sum = (int(number[-1 - i]) * dvs[i] + sum) % 10 
    11  
    12     return (10-sum) % 10 
     7from django.contrib.localflavor.uy.utils import * 
  • new file django/contrib/localflavor/uy/utils.py

    diff --git a/django/contrib/localflavor/uy/utils.py b/django/contrib/localflavor/uy/utils.py
    new file mode 100644
    index 0000000..0c1a8f8
    - +  
     1# -*- coding: utf-8 -*- 
     2 
     3def get_validation_digit(number): 
     4    """ Calculates the validation digit for the given number. """ 
     5    sum = 0 
     6    dvs = [4, 3, 6, 7, 8, 9, 2] 
     7    number = str(number) 
     8 
     9    for i in range(0, len(number)): 
     10        sum = (int(number[-1 - i]) * dvs[i] + sum) % 10 
     11 
     12    return (10-sum) % 10 
  • django/db/backends/__init__.py

    diff --git a/django/db/backends/__init__.py b/django/db/backends/__init__.py
    index 7674f5c..37985e8 100644
    a b from contextlib import contextmanager 
    88 
    99from django.conf import settings 
    1010from django.db import DEFAULT_DB_ALIAS 
    11 from django.db.backends import util 
     11from django.db.backends import utils 
    1212from django.db.transaction import TransactionManagementError 
    1313from django.utils.importlib import import_module 
    1414from django.utils.timezone import is_aware 
    class BaseDatabaseWrapper(object): 
    305305            (self.use_debug_cursor is None and settings.DEBUG)): 
    306306            cursor = self.make_debug_cursor(self._cursor()) 
    307307        else: 
    308             cursor = util.CursorWrapper(self._cursor(), self) 
     308            cursor = utils.CursorWrapper(self._cursor(), self) 
    309309        return cursor 
    310310 
    311311    def make_debug_cursor(self, cursor): 
    312         return util.CursorDebugWrapper(cursor, self) 
     312        return utils.CursorDebugWrapper(cursor, self) 
    313313 
    314314class BaseDatabaseFeatures(object): 
    315315    allows_group_by_pk = False 
    class BaseDatabaseOperations(object): 
    798798        """ 
    799799        if value is None: 
    800800            return None 
    801         return util.format_number(value, max_digits, decimal_places) 
     801        return utils.format_number(value, max_digits, decimal_places) 
    802802 
    803803    def year_lookup_bounds(self, value): 
    804804        """ 
  • django/db/backends/creation.py

    diff --git a/django/db/backends/creation.py b/django/db/backends/creation.py
    index 0cd0558..e845abd 100644
    a b class BaseDatabaseCreation(object): 
    129129        """ 
    130130        Returns any ALTER TABLE statements to add constraints after the fact. 
    131131        """ 
    132         from django.db.backends.util import truncate_name 
     132        from django.db.backends.utils import truncate_name 
    133133 
    134134        if not model._meta.managed or model._meta.proxy: 
    135135            return [] 
    class BaseDatabaseCreation(object): 
    171171        """ 
    172172        Return the CREATE INDEX SQL statements for a single model field. 
    173173        """ 
    174         from django.db.backends.util import truncate_name 
     174        from django.db.backends.utils import truncate_name 
    175175 
    176176        if f.db_index and not f.unique: 
    177177            qn = self.connection.ops.quote_name 
    class BaseDatabaseCreation(object): 
    215215        return output 
    216216 
    217217    def sql_remove_table_constraints(self, model, references_to_delete, style): 
    218         from django.db.backends.util import truncate_name 
     218        from django.db.backends.utils import truncate_name 
    219219        if not model._meta.managed or model._meta.proxy: 
    220220            return [] 
    221221        output = [] 
  • django/db/backends/mysql/base.py

    diff --git a/django/db/backends/mysql/base.py b/django/db/backends/mysql/base.py
    index e30cb90..009cb50 100644
    a b if (version < (1,2,1) or (version[:3] == (1, 2, 1) and 
    2626from MySQLdb.converters import conversions, Thing2Literal 
    2727from MySQLdb.constants import FIELD_TYPE, CLIENT 
    2828 
    29 from django.db import utils 
    3029from django.db.backends import * 
     30from django.db.backends import utils as util 
     31from django.db import utils 
    3132from django.db.backends.signals import connection_created 
    3233from django.db.backends.mysql.client import DatabaseClient 
    3334from django.db.backends.mysql.creation import DatabaseCreation 
  • django/db/backends/oracle/base.py

    diff --git a/django/db/backends/oracle/base.py b/django/db/backends/oracle/base.py
    index 6bc6e1d..30e16f8 100644
    a b except ImportError, e: 
    4545    raise ImproperlyConfigured("Error loading cx_Oracle module: %s" % e) 
    4646 
    4747from django.conf import settings 
    48 from django.db import utils 
    4948from django.db.backends import * 
     49from django.db.backends import utils as util 
     50from django.db import utils 
    5051from django.db.backends.signals import connection_created 
    5152from django.db.backends.oracle.client import DatabaseClient 
    5253from django.db.backends.oracle.creation import DatabaseCreation 
  • django/db/backends/postgresql_psycopg2/base.py

    diff --git a/django/db/backends/postgresql_psycopg2/base.py b/django/db/backends/postgresql_psycopg2/base.py
    index 802ebf2..0bb8738 100644
    a b Requires psycopg 2: http://initd.org/projects/psycopg2 
    55""" 
    66import sys 
    77 
    8 from django.db import utils 
    98from django.db.backends import * 
     9from django.db.backends import utils as util 
     10from django.db import utils 
    1011from django.db.backends.signals import connection_created 
    1112from django.db.backends.postgresql_psycopg2.operations import DatabaseOperations 
    1213from django.db.backends.postgresql_psycopg2.client import DatabaseClient 
  • django/db/backends/postgresql_psycopg2/creation.py

    diff --git a/django/db/backends/postgresql_psycopg2/creation.py b/django/db/backends/postgresql_psycopg2/creation.py
    index ca389b9..75db89a 100644
    a b  
    11import psycopg2.extensions 
    22 
    33from django.db.backends.creation import BaseDatabaseCreation 
    4 from django.db.backends.util import truncate_name 
     4from django.db.backends.utils import truncate_name 
    55 
    66 
    77class DatabaseCreation(BaseDatabaseCreation): 
  • django/db/backends/sqlite3/base.py

    diff --git a/django/db/backends/sqlite3/base.py b/django/db/backends/sqlite3/base.py
    index 0b19442..5a05dbb 100644
    a b import warnings 
    1111import re 
    1212import sys 
    1313 
    14 from django.db import utils 
    1514from django.db.backends import * 
     15from django.db.backends import utils as util 
    1616from django.db.backends.signals import connection_created 
    1717from django.db.backends.sqlite3.client import DatabaseClient 
    1818from django.db.backends.sqlite3.creation import DatabaseCreation 
    1919from django.db.backends.sqlite3.introspection import DatabaseIntrospection 
     20from django.db import utils 
    2021from django.utils.dateparse import parse_date, parse_datetime, parse_time 
    2122from django.utils.safestring import SafeString 
    2223from django.utils import timezone 
  • django/db/backends/util.py

    diff --git a/django/db/backends/util.py b/django/db/backends/util.py
    index 32e0f4f..c6f3785 100644
    a b  
    1 import datetime 
    2 import decimal 
    3 import hashlib 
    4 from time import time 
     1import warnings 
    52 
    6 from django.conf import settings 
    7 from django.utils.log import getLogger 
    8 from django.utils.timezone import utc 
     3warnings.warn("The django.db.backends.util module has been renamed " 
     4              "(https://code.djangoproject.com/ticket/17627/). " 
     5              "Use django.db.backends.utils instead.", PendingDeprecationWarning) 
    96 
    10  
    11 logger = getLogger('django.db.backends') 
    12  
    13  
    14 class CursorWrapper(object): 
    15     def __init__(self, cursor, db): 
    16         self.cursor = cursor 
    17         self.db = db 
    18  
    19     def set_dirty(self): 
    20         if self.db.is_managed(): 
    21             self.db.set_dirty() 
    22  
    23     def __getattr__(self, attr): 
    24         self.set_dirty() 
    25         if attr in self.__dict__: 
    26             return self.__dict__[attr] 
    27         else: 
    28             return getattr(self.cursor, attr) 
    29  
    30     def __iter__(self): 
    31         return iter(self.cursor) 
    32  
    33  
    34 class CursorDebugWrapper(CursorWrapper): 
    35  
    36     def execute(self, sql, params=()): 
    37         self.set_dirty() 
    38         start = time() 
    39         try: 
    40             return self.cursor.execute(sql, params) 
    41         finally: 
    42             stop = time() 
    43             duration = stop - start 
    44             sql = self.db.ops.last_executed_query(self.cursor, sql, params) 
    45             self.db.queries.append({ 
    46                 'sql': sql, 
    47                 'time': "%.3f" % duration, 
    48             }) 
    49             logger.debug('(%.3f) %s; args=%s' % (duration, sql, params), 
    50                 extra={'duration': duration, 'sql': sql, 'params': params} 
    51             ) 
    52  
    53     def executemany(self, sql, param_list): 
    54         self.set_dirty() 
    55         start = time() 
    56         try: 
    57             return self.cursor.executemany(sql, param_list) 
    58         finally: 
    59             stop = time() 
    60             duration = stop - start 
    61             try: 
    62                 times = len(param_list) 
    63             except TypeError:           # param_list could be an iterator 
    64                 times = '?' 
    65             self.db.queries.append({ 
    66                 'sql': '%s times: %s' % (times, sql), 
    67                 'time': "%.3f" % duration, 
    68             }) 
    69             logger.debug('(%.3f) %s; args=%s' % (duration, sql, param_list), 
    70                 extra={'duration': duration, 'sql': sql, 'params': param_list} 
    71             ) 
    72  
    73  
    74 ############################################### 
    75 # Converters from database (string) to Python # 
    76 ############################################### 
    77  
    78 def typecast_date(s): 
    79     return s and datetime.date(*map(int, s.split('-'))) or None # returns None if s is null 
    80  
    81 def typecast_time(s): # does NOT store time zone information 
    82     if not s: return None 
    83     hour, minutes, seconds = s.split(':') 
    84     if '.' in seconds: # check whether seconds have a fractional part 
    85         seconds, microseconds = seconds.split('.') 
    86     else: 
    87         microseconds = '0' 
    88     return datetime.time(int(hour), int(minutes), int(seconds), int(float('.'+microseconds) * 1000000)) 
    89  
    90 def typecast_timestamp(s): # does NOT store time zone information 
    91     # "2005-07-29 15:48:00.590358-05" 
    92     # "2005-07-29 09:56:00-05" 
    93     if not s: return None 
    94     if not ' ' in s: return typecast_date(s) 
    95     d, t = s.split() 
    96     # Extract timezone information, if it exists. Currently we just throw 
    97     # it away, but in the future we may make use of it. 
    98     if '-' in t: 
    99         t, tz = t.split('-', 1) 
    100         tz = '-' + tz 
    101     elif '+' in t: 
    102         t, tz = t.split('+', 1) 
    103         tz = '+' + tz 
    104     else: 
    105         tz = '' 
    106     dates = d.split('-') 
    107     times = t.split(':') 
    108     seconds = times[2] 
    109     if '.' in seconds: # check whether seconds have a fractional part 
    110         seconds, microseconds = seconds.split('.') 
    111     else: 
    112         microseconds = '0' 
    113     tzinfo = utc if settings.USE_TZ else None 
    114     return datetime.datetime(int(dates[0]), int(dates[1]), int(dates[2]), 
    115         int(times[0]), int(times[1]), int(seconds), 
    116         int((microseconds + '000000')[:6]), tzinfo) 
    117  
    118 def typecast_decimal(s): 
    119     if s is None or s == '': 
    120         return None 
    121     return decimal.Decimal(s) 
    122  
    123 ############################################### 
    124 # Converters from Python to database (string) # 
    125 ############################################### 
    126  
    127 def rev_typecast_decimal(d): 
    128     if d is None: 
    129         return None 
    130     return str(d) 
    131  
    132 def truncate_name(name, length=None, hash_len=4): 
    133     """Shortens a string to a repeatable mangled version with the given length. 
    134     """ 
    135     if length is None or len(name) <= length: 
    136         return name 
    137  
    138     hsh = hashlib.md5(name).hexdigest()[:hash_len] 
    139     return '%s%s' % (name[:length-hash_len], hsh) 
    140  
    141 def format_number(value, max_digits, decimal_places): 
    142     """ 
    143     Formats a number into a string with the requisite number of digits and 
    144     decimal places. 
    145     """ 
    146     if isinstance(value, decimal.Decimal): 
    147         context = decimal.getcontext().copy() 
    148         context.prec = max_digits 
    149         return u'%s' % str(value.quantize(decimal.Decimal(".1") ** decimal_places, context=context)) 
    150     else: 
    151         return u"%.*f" % (decimal_places, value) 
     7from django.db.backends.utils import * 
  • new file django/db/backends/utils.py

    diff --git a/django/db/backends/utils.py b/django/db/backends/utils.py
    new file mode 100644
    index 0000000..32e0f4f
    - +  
     1import datetime 
     2import decimal 
     3import hashlib 
     4from time import time 
     5 
     6from django.conf import settings 
     7from django.utils.log import getLogger 
     8from django.utils.timezone import utc 
     9 
     10 
     11logger = getLogger('django.db.backends') 
     12 
     13 
     14class CursorWrapper(object): 
     15    def __init__(self, cursor, db): 
     16        self.cursor = cursor 
     17        self.db = db 
     18 
     19    def set_dirty(self): 
     20        if self.db.is_managed(): 
     21            self.db.set_dirty() 
     22 
     23    def __getattr__(self, attr): 
     24        self.set_dirty() 
     25        if attr in self.__dict__: 
     26            return self.__dict__[attr] 
     27        else: 
     28            return getattr(self.cursor, attr) 
     29 
     30    def __iter__(self): 
     31        return iter(self.cursor) 
     32 
     33 
     34class CursorDebugWrapper(CursorWrapper): 
     35 
     36    def execute(self, sql, params=()): 
     37        self.set_dirty() 
     38        start = time() 
     39        try: 
     40            return self.cursor.execute(sql, params) 
     41        finally: 
     42            stop = time() 
     43            duration = stop - start 
     44            sql = self.db.ops.last_executed_query(self.cursor, sql, params) 
     45            self.db.queries.append({ 
     46                'sql': sql, 
     47                'time': "%.3f" % duration, 
     48            }) 
     49            logger.debug('(%.3f) %s; args=%s' % (duration, sql, params), 
     50                extra={'duration': duration, 'sql': sql, 'params': params} 
     51            ) 
     52 
     53    def executemany(self, sql, param_list): 
     54        self.set_dirty() 
     55        start = time() 
     56        try: 
     57            return self.cursor.executemany(sql, param_list) 
     58        finally: 
     59            stop = time() 
     60            duration = stop - start 
     61            try: 
     62                times = len(param_list) 
     63            except TypeError:           # param_list could be an iterator 
     64                times = '?' 
     65            self.db.queries.append({ 
     66                'sql': '%s times: %s' % (times, sql), 
     67                'time': "%.3f" % duration, 
     68            }) 
     69            logger.debug('(%.3f) %s; args=%s' % (duration, sql, param_list), 
     70                extra={'duration': duration, 'sql': sql, 'params': param_list} 
     71            ) 
     72 
     73 
     74############################################### 
     75# Converters from database (string) to Python # 
     76############################################### 
     77 
     78def typecast_date(s): 
     79    return s and datetime.date(*map(int, s.split('-'))) or None # returns None if s is null 
     80 
     81def typecast_time(s): # does NOT store time zone information 
     82    if not s: return None 
     83    hour, minutes, seconds = s.split(':') 
     84    if '.' in seconds: # check whether seconds have a fractional part 
     85        seconds, microseconds = seconds.split('.') 
     86    else: 
     87        microseconds = '0' 
     88    return datetime.time(int(hour), int(minutes), int(seconds), int(float('.'+microseconds) * 1000000)) 
     89 
     90def typecast_timestamp(s): # does NOT store time zone information 
     91    # "2005-07-29 15:48:00.590358-05" 
     92    # "2005-07-29 09:56:00-05" 
     93    if not s: return None 
     94    if not ' ' in s: return typecast_date(s) 
     95    d, t = s.split() 
     96    # Extract timezone information, if it exists. Currently we just throw 
     97    # it away, but in the future we may make use of it. 
     98    if '-' in t: 
     99        t, tz = t.split('-', 1) 
     100        tz = '-' + tz 
     101    elif '+' in t: 
     102        t, tz = t.split('+', 1) 
     103        tz = '+' + tz 
     104    else: 
     105        tz = '' 
     106    dates = d.split('-') 
     107    times = t.split(':') 
     108    seconds = times[2] 
     109    if '.' in seconds: # check whether seconds have a fractional part 
     110        seconds, microseconds = seconds.split('.') 
     111    else: 
     112        microseconds = '0' 
     113    tzinfo = utc if settings.USE_TZ else None 
     114    return datetime.datetime(int(dates[0]), int(dates[1]), int(dates[2]), 
     115        int(times[0]), int(times[1]), int(seconds), 
     116        int((microseconds + '000000')[:6]), tzinfo) 
     117 
     118def typecast_decimal(s): 
     119    if s is None or s == '': 
     120        return None 
     121    return decimal.Decimal(s) 
     122 
     123############################################### 
     124# Converters from Python to database (string) # 
     125############################################### 
     126 
     127def rev_typecast_decimal(d): 
     128    if d is None: 
     129        return None 
     130    return str(d) 
     131 
     132def truncate_name(name, length=None, hash_len=4): 
     133    """Shortens a string to a repeatable mangled version with the given length. 
     134    """ 
     135    if length is None or len(name) <= length: 
     136        return name 
     137 
     138    hsh = hashlib.md5(name).hexdigest()[:hash_len] 
     139    return '%s%s' % (name[:length-hash_len], hsh) 
     140 
     141def format_number(value, max_digits, decimal_places): 
     142    """ 
     143    Formats a number into a string with the requisite number of digits and 
     144    decimal places. 
     145    """ 
     146    if isinstance(value, decimal.Decimal): 
     147        context = decimal.getcontext().copy() 
     148        context.prec = max_digits 
     149        return u'%s' % str(value.quantize(decimal.Decimal(".1") ** decimal_places, context=context)) 
     150    else: 
     151        return u"%.*f" % (decimal_places, value) 
  • django/db/models/fields/__init__.py

    diff --git a/django/db/models/fields/__init__.py b/django/db/models/fields/__init__.py
    index 22546c2..debdacf 100644
    a b class DecimalField(Field): 
    860860        Formats a number into a string with the requisite number of digits and 
    861861        decimal places. 
    862862        """ 
    863         # Method moved to django.db.backends.util. 
     863        # Method moved to django.db.backends.utils. 
    864864        # 
    865865        # It is preserved because it is used by the oracle backend 
    866866        # (django.db.backends.oracle.query), and also for 
    867867        # backwards-compatibility with any external code which may have used 
    868868        # this method. 
    869         from django.db.backends import util 
    870         return util.format_number(value, self.max_digits, self.decimal_places) 
     869        from django.db.backends import utils 
     870        return utils.format_number(value, self.max_digits, self.decimal_places) 
    871871 
    872872    def get_db_prep_save(self, value, connection): 
    873873        return connection.ops.value_to_db_decimal(self.to_python(value), 
  • django/db/models/fields/related.py

    diff --git a/django/db/models/fields/related.py b/django/db/models/fields/related.py
    index e23c7dc..ab0c74e 100644
    a b  
    11from operator import attrgetter 
    22 
    33from django.db import connection, router 
    4 from django.db.backends import util 
     4from django.db.backends import utils 
    55from django.db.models import signals, get_model 
    66from django.db.models.fields import (AutoField, Field, IntegerField, 
    77    PositiveIntegerField, PositiveSmallIntegerField, FieldDoesNotExist) 
    class ManyToManyField(RelatedField, Field): 
    11301130        elif self.db_table: 
    11311131            return self.db_table 
    11321132        else: 
    1133             return util.truncate_name('%s_%s' % (opts.db_table, self.name), 
     1133            return utils.truncate_name('%s_%s' % (opts.db_table, self.name), 
    11341134                                      connection.ops.max_name_length()) 
    11351135 
    11361136    def _get_m2m_attr(self, related, attr): 
  • django/db/models/options.py

    diff --git a/django/db/models/options.py b/django/db/models/options.py
    index e13a496..4bf45d7 100644
    a b class Options(object): 
    6565 
    6666    def contribute_to_class(self, cls, name): 
    6767        from django.db import connection 
    68         from django.db.backends.util import truncate_name 
     68        from django.db.backends.utils import truncate_name 
    6969 
    7070        cls._meta = self 
    7171        self.installed = re.sub('\.models$', '', cls.__module__) in settings.INSTALLED_APPS 
  • django/db/models/query_utils.py

    diff --git a/django/db/models/query_utils.py b/django/db/models/query_utils.py
    index a56ab5c..8e9d770 100644
    a b circular import difficulties. 
    88 
    99import weakref 
    1010 
    11 from django.db.backends import util 
     11from django.db.backends import utils 
    1212from django.utils import tree 
    1313 
    1414 
    def deferred_class_factory(model, attrs): 
    155155    # name using the passed in attrs. It's OK to reuse an existing class 
    156156    # object if the attrs are identical. 
    157157    name = "%s_Deferred_%s" % (model.__name__, '_'.join(sorted(list(attrs)))) 
    158     name = util.truncate_name(name, 80, 32) 
     158    name = utils.truncate_name(name, 80, 32) 
    159159 
    160160    overrides = dict([(attr, DeferredAttribute(attr, model)) 
    161161            for attr in attrs]) 
  • django/db/models/sql/compiler.py

    diff --git a/django/db/models/sql/compiler.py b/django/db/models/sql/compiler.py
    index 6c516e2..95841cd 100644
    a b from itertools import izip 
    22 
    33from django.core.exceptions import FieldError 
    44from django.db import transaction 
    5 from django.db.backends.util import truncate_name 
     5from django.db.backends.utils import truncate_name 
    66from django.db.models.query_utils import select_related_descend 
    77from django.db.models.sql.constants import * 
    88from django.db.models.sql.datastructures import EmptyResultSet 
    class SQLDateCompiler(SQLCompiler): 
    10671067            from django.db.models.fields import DateTimeField 
    10681068            fields = [DateTimeField()] 
    10691069        else: 
    1070             from django.db.backends.util import typecast_timestamp 
     1070            from django.db.backends.utils import typecast_timestamp 
    10711071            needs_string_cast = self.connection.features.needs_datetime_string_cast 
    10721072 
    10731073        offset = len(self.query.extra_select) 
  • django/forms/fields.py

    diff --git a/django/forms/fields.py b/django/forms/fields.py
    index 96ecabf..61f57e0 100644
    a b except ImportError: 
    1717 
    1818from django.core import validators 
    1919from django.core.exceptions import ValidationError 
    20 from django.forms.util import ErrorList, from_current_timezone, to_current_timezone 
     20from django.forms.utils import ErrorList, from_current_timezone, to_current_timezone 
    2121from django.forms.widgets import (TextInput, PasswordInput, HiddenInput, 
    2222    MultipleHiddenInput, ClearableFileInput, CheckboxInput, Select, 
    2323    NullBooleanSelect, SelectMultiple, DateInput, DateTimeInput, TimeInput, 
  • django/forms/forms.py

    diff --git a/django/forms/forms.py b/django/forms/forms.py
    index 94eb22d..155ee90 100644
    a b import copy 
    88 
    99from django.core.exceptions import ValidationError 
    1010from django.forms.fields import Field, FileField 
    11 from django.forms.util import flatatt, ErrorDict, ErrorList 
     11from django.forms.utils import flatatt, ErrorDict, ErrorList 
    1212from django.forms.widgets import Media, media_property, TextInput, Textarea 
    1313from django.utils.datastructures import SortedDict 
    1414from django.utils.html import conditional_escape 
  • django/forms/formsets.py

    diff --git a/django/forms/formsets.py b/django/forms/formsets.py
    index dcd2f01..2736ed8 100644
    a b from __future__ import absolute_import 
    33from django.core.exceptions import ValidationError 
    44from django.forms import Form 
    55from django.forms.fields import IntegerField, BooleanField 
    6 from django.forms.util import ErrorList 
     6from django.forms.utils import ErrorList 
    77from django.forms.widgets import Media, HiddenInput 
    88from django.utils.encoding import StrAndUnicode 
    99from django.utils.safestring import mark_safe 
  • django/forms/models.py

    diff --git a/django/forms/models.py b/django/forms/models.py
    index cd8f027..730f3ee 100644
    a b from django.core.validators import EMPTY_VALUES 
    1010from django.forms.fields import Field, ChoiceField 
    1111from django.forms.forms import BaseForm, get_declared_fields 
    1212from django.forms.formsets import BaseFormSet, formset_factory 
    13 from django.forms.util import ErrorList 
     13from django.forms.utils import ErrorList 
    1414from django.forms.widgets import (SelectMultiple, HiddenInput, 
    1515    MultipleHiddenInput, media_property) 
    1616from django.utils.encoding import smart_unicode, force_unicode 
  • django/forms/util.py

    diff --git a/django/forms/util.py b/django/forms/util.py
    index 886f08e..6b14b92 100644
    a b  
    1 from django.conf import settings 
    2 from django.utils.html import conditional_escape 
    3 from django.utils.encoding import StrAndUnicode, force_unicode 
    4 from django.utils.safestring import mark_safe 
    5 from django.utils import timezone 
    6 from django.utils.translation import ugettext_lazy as _ 
     1import warnings 
    72 
    8 # Import ValidationError so that it can be imported from this 
    9 # module to maintain backwards compatibility. 
    10 from django.core.exceptions import ValidationError 
     3warnings.warn("The django.forms.util module has been renamed " 
     4              "(https://code.djangoproject.com/ticket/17627/). " 
     5              "Use django.forms.utils instead.", PendingDeprecationWarning) 
    116 
    12 def flatatt(attrs): 
    13     """ 
    14     Convert a dictionary of attributes to a single string. 
    15     The returned string will contain a leading space followed by key="value", 
    16     XML-style pairs.  It is assumed that the keys do not need to be XML-escaped. 
    17     If the passed dictionary is empty, then return an empty string. 
    18     """ 
    19     return u''.join([u' %s="%s"' % (k, conditional_escape(v)) for k, v in attrs.items()]) 
    20  
    21 class ErrorDict(dict, StrAndUnicode): 
    22     """ 
    23     A collection of errors that knows how to display itself in various formats. 
    24  
    25     The dictionary keys are the field names, and the values are the errors. 
    26     """ 
    27     def __unicode__(self): 
    28         return self.as_ul() 
    29  
    30     def as_ul(self): 
    31         if not self: return u'' 
    32         return mark_safe(u'<ul class="errorlist">%s</ul>' 
    33                 % ''.join([u'<li>%s%s</li>' % (k, conditional_escape(force_unicode(v))) 
    34                     for k, v in self.items()])) 
    35  
    36     def as_text(self): 
    37         return u'\n'.join([u'* %s\n%s' % (k, u'\n'.join([u'  * %s' % force_unicode(i) for i in v])) for k, v in self.items()]) 
    38  
    39 class ErrorList(list, StrAndUnicode): 
    40     """ 
    41     A collection of errors that knows how to display itself in various formats. 
    42     """ 
    43     def __unicode__(self): 
    44         return self.as_ul() 
    45  
    46     def as_ul(self): 
    47         if not self: return u'' 
    48         return mark_safe(u'<ul class="errorlist">%s</ul>' 
    49                 % ''.join([u'<li>%s</li>' % conditional_escape(force_unicode(e)) for e in self])) 
    50  
    51     def as_text(self): 
    52         if not self: return u'' 
    53         return u'\n'.join([u'* %s' % force_unicode(e) for e in self]) 
    54  
    55     def __repr__(self): 
    56         return repr([force_unicode(e) for e in self]) 
    57  
    58 # Utilities for time zone support in DateTimeField et al. 
    59  
    60 def from_current_timezone(value): 
    61     """ 
    62     When time zone support is enabled, convert naive datetimes 
    63     entered in the current time zone to aware datetimes. 
    64     """ 
    65     if settings.USE_TZ and value is not None and timezone.is_naive(value): 
    66         current_timezone = timezone.get_current_timezone() 
    67         try: 
    68             return timezone.make_aware(value, current_timezone) 
    69         except Exception, e: 
    70             raise ValidationError(_('%(datetime)s couldn\'t be interpreted ' 
    71                                     'in time zone %(current_timezone)s; it ' 
    72                                     'may be ambiguous or it may not exist.') 
    73                                   % {'datetime': value, 
    74                                      'current_timezone': current_timezone}) 
    75     return value 
    76  
    77 def to_current_timezone(value): 
    78     """ 
    79     When time zone support is enabled, convert aware datetimes 
    80     to naive dateimes in the current time zone for display. 
    81     """ 
    82     if settings.USE_TZ and value is not None and timezone.is_aware(value): 
    83         current_timezone = timezone.get_current_timezone() 
    84         return timezone.make_naive(value, current_timezone) 
    85     return value 
     7from django.forms.utils import * 
  • new file django/forms/utils.py

    diff --git a/django/forms/utils.py b/django/forms/utils.py
    new file mode 100644
    index 0000000..886f08e
    - +  
     1from django.conf import settings 
     2from django.utils.html import conditional_escape 
     3from django.utils.encoding import StrAndUnicode, force_unicode 
     4from django.utils.safestring import mark_safe 
     5from django.utils import timezone 
     6from django.utils.translation import ugettext_lazy as _ 
     7 
     8# Import ValidationError so that it can be imported from this 
     9# module to maintain backwards compatibility. 
     10from django.core.exceptions import ValidationError 
     11 
     12def flatatt(attrs): 
     13    """ 
     14    Convert a dictionary of attributes to a single string. 
     15    The returned string will contain a leading space followed by key="value", 
     16    XML-style pairs.  It is assumed that the keys do not need to be XML-escaped. 
     17    If the passed dictionary is empty, then return an empty string. 
     18    """ 
     19    return u''.join([u' %s="%s"' % (k, conditional_escape(v)) for k, v in attrs.items()]) 
     20 
     21class ErrorDict(dict, StrAndUnicode): 
     22    """ 
     23    A collection of errors that knows how to display itself in various formats. 
     24 
     25    The dictionary keys are the field names, and the values are the errors. 
     26    """ 
     27    def __unicode__(self): 
     28        return self.as_ul() 
     29 
     30    def as_ul(self): 
     31        if not self: return u'' 
     32        return mark_safe(u'<ul class="errorlist">%s</ul>' 
     33                % ''.join([u'<li>%s%s</li>' % (k, conditional_escape(force_unicode(v))) 
     34                    for k, v in self.items()])) 
     35 
     36    def as_text(self): 
     37        return u'\n'.join([u'* %s\n%s' % (k, u'\n'.join([u'  * %s' % force_unicode(i) for i in v])) for k, v in self.items()]) 
     38 
     39class ErrorList(list, StrAndUnicode): 
     40    """ 
     41    A collection of errors that knows how to display itself in various formats. 
     42    """ 
     43    def __unicode__(self): 
     44        return self.as_ul() 
     45 
     46    def as_ul(self): 
     47        if not self: return u'' 
     48        return mark_safe(u'<ul class="errorlist">%s</ul>' 
     49                % ''.join([u'<li>%s</li>' % conditional_escape(force_unicode(e)) for e in self])) 
     50 
     51    def as_text(self): 
     52        if not self: return u'' 
     53        return u'\n'.join([u'* %s' % force_unicode(e) for e in self]) 
     54 
     55    def __repr__(self): 
     56        return repr([force_unicode(e) for e in self]) 
     57 
     58# Utilities for time zone support in DateTimeField et al. 
     59 
     60def from_current_timezone(value): 
     61    """ 
     62    When time zone support is enabled, convert naive datetimes 
     63    entered in the current time zone to aware datetimes. 
     64    """ 
     65    if settings.USE_TZ and value is not None and timezone.is_naive(value): 
     66        current_timezone = timezone.get_current_timezone() 
     67        try: 
     68            return timezone.make_aware(value, current_timezone) 
     69        except Exception, e: 
     70            raise ValidationError(_('%(datetime)s couldn\'t be interpreted ' 
     71                                    'in time zone %(current_timezone)s; it ' 
     72                                    'may be ambiguous or it may not exist.') 
     73                                  % {'datetime': value, 
     74                                     'current_timezone': current_timezone}) 
     75    return value 
     76 
     77def to_current_timezone(value): 
     78    """ 
     79    When time zone support is enabled, convert aware datetimes 
     80    to naive dateimes in the current time zone for display. 
     81    """ 
     82    if settings.USE_TZ and value is not None and timezone.is_aware(value): 
     83        current_timezone = timezone.get_current_timezone() 
     84        return timezone.make_naive(value, current_timezone) 
     85    return value 
  • django/forms/widgets.py

    diff --git a/django/forms/widgets.py b/django/forms/widgets.py
    index 1fbef98..74e3043 100644
    a b from itertools import chain 
    1010from urlparse import urljoin 
    1111 
    1212from django.conf import settings 
    13 from django.forms.util import flatatt, to_current_timezone 
     13from django.forms.utils import flatatt, to_current_timezone 
    1414from django.utils.datastructures import MultiValueDict, MergeDict 
    1515from django.utils.html import escape, conditional_escape 
    1616from django.utils.translation import ugettext, ugettext_lazy 
  • docs/internals/deprecation.txt

    diff --git a/docs/internals/deprecation.txt b/docs/internals/deprecation.txt
    index cb91a1c..dfc4cf4 100644
    a b these changes. 
    271271  in 1.4. The backward compatibility will be removed -- 
    272272  ``HttpRequest.raw_post_data`` will no longer work. 
    273273 
     2741.7 
     275--- 
     276 
     277* Instances of ``util.py`` in the Django codebase have been renamed to ``utils.py`` in 
     278  an effort to unify all util and utils references across Django. Compatibility modules 
     279  for ``django.contrib.admin.util`` (now :mod:`django.contrib.admin.utils`), 
     280  ``django.contrib.gis.db.backends.util`` (now :mod:`django.contrib.gis.db.backends.utils``), 
     281  ``django.contrib.localflavor.it.util`` (now :mod:`django.contrib.localflavor.it.utils``), 
     282  ``django.contrib.localflavor.uy.util`` (now :mod:`django.contrib.localflavor.uy.utils``), 
     283  ``django.db.backends.util`` (now :mod:`django.db.backends.utils`), 
     284  and ``django.forms.util`` (now :mod:`django.forms.utils`) will be removed in the 1.8 
     285  release. 
     286 
    2742872.0 
    275288--- 
    276289 
  • deleted file tests/regressiontests/admin_util/models.py

    diff --git a/tests/regressiontests/admin_util/__init__.py b/tests/regressiontests/admin_util/__init__.py
    deleted file mode 100644
    index e69de29..0000000
    diff --git a/tests/regressiontests/admin_util/models.py b/tests/regressiontests/admin_util/models.py
    deleted file mode 100644
    index 0e81df3..0000000
    + -  
    1 from django.db import models 
    2  
    3  
    4 class Article(models.Model): 
    5     """ 
    6     A simple Article model for testing 
    7     """ 
    8     site = models.ForeignKey('sites.Site', related_name="admin_articles") 
    9     title = models.CharField(max_length=100) 
    10     title2 = models.CharField(max_length=100, verbose_name="another name") 
    11     created = models.DateTimeField() 
    12  
    13     def test_from_model(self): 
    14         return "nothing" 
    15  
    16     def test_from_model_with_override(self): 
    17         return "nothing" 
    18     test_from_model_with_override.short_description = "not What you Expect" 
    19  
    20 class Count(models.Model): 
    21     num = models.PositiveSmallIntegerField() 
    22     parent = models.ForeignKey('self', null=True) 
    23  
    24     def __unicode__(self): 
    25         return unicode(self.num) 
    26  
    27 class Event(models.Model): 
    28     date = models.DateTimeField(auto_now_add=True) 
    29  
    30 class Location(models.Model): 
    31     event = models.OneToOneField(Event, verbose_name='awesome event') 
    32  
    33 class Guest(models.Model): 
    34     event = models.OneToOneField(Event) 
    35     name = models.CharField(max_length=255) 
    36  
    37     class Meta: 
    38         verbose_name = "awesome guest" 
  • deleted file tests/regressiontests/admin_util/tests.py

    diff --git a/tests/regressiontests/admin_util/tests.py b/tests/regressiontests/admin_util/tests.py
    deleted file mode 100644
    index 8113f2e..0000000
    + -  
    1 from __future__ import absolute_import 
    2  
    3 from datetime import datetime 
    4  
    5 from django.conf import settings 
    6 from django.contrib import admin 
    7 from django.contrib.admin import helpers 
    8 from django.contrib.admin.util import (display_for_field, label_for_field, 
    9     lookup_field, NestedObjects) 
    10 from django.contrib.admin.views.main import EMPTY_CHANGELIST_VALUE 
    11 from django.contrib.sites.models import Site 
    12 from django.db import models, DEFAULT_DB_ALIAS 
    13 from django import forms 
    14 from django.test import TestCase 
    15 from django.utils import unittest 
    16 from django.utils.formats import localize 
    17 from django.utils.safestring import mark_safe 
    18  
    19 from .models import Article, Count, Event, Location 
    20  
    21  
    22 class NestedObjectsTests(TestCase): 
    23     """ 
    24     Tests for ``NestedObject`` utility collection. 
    25  
    26     """ 
    27     def setUp(self): 
    28         self.n = NestedObjects(using=DEFAULT_DB_ALIAS) 
    29         self.objs = [Count.objects.create(num=i) for i in range(5)] 
    30  
    31     def _check(self, target): 
    32         self.assertEqual(self.n.nested(lambda obj: obj.num), target) 
    33  
    34     def _connect(self, i, j): 
    35         self.objs[i].parent = self.objs[j] 
    36         self.objs[i].save() 
    37  
    38     def _collect(self, *indices): 
    39         self.n.collect([self.objs[i] for i in indices]) 
    40  
    41     def test_unrelated_roots(self): 
    42         self._connect(2, 1) 
    43         self._collect(0) 
    44         self._collect(1) 
    45         self._check([0, 1, [2]]) 
    46  
    47     def test_siblings(self): 
    48         self._connect(1, 0) 
    49         self._connect(2, 0) 
    50         self._collect(0) 
    51         self._check([0, [1, 2]]) 
    52  
    53     def test_non_added_parent(self): 
    54         self._connect(0, 1) 
    55         self._collect(0) 
    56         self._check([0]) 
    57  
    58     def test_cyclic(self): 
    59         self._connect(0, 2) 
    60         self._connect(1, 0) 
    61         self._connect(2, 1) 
    62         self._collect(0) 
    63         self._check([0, [1, [2]]]) 
    64  
    65     def test_queries(self): 
    66         self._connect(1, 0) 
    67         self._connect(2, 0) 
    68         # 1 query to fetch all children of 0 (1 and 2) 
    69         # 1 query to fetch all children of 1 and 2 (none) 
    70         # Should not require additional queries to populate the nested graph. 
    71         self.assertNumQueries(2, self._collect, 0) 
    72  
    73 class UtilTests(unittest.TestCase): 
    74     def test_values_from_lookup_field(self): 
    75         """ 
    76         Regression test for #12654: lookup_field 
    77         """ 
    78         SITE_NAME = 'example.com' 
    79         TITLE_TEXT = 'Some title' 
    80         CREATED_DATE = datetime.min 
    81         ADMIN_METHOD = 'admin method' 
    82         SIMPLE_FUNCTION = 'function' 
    83         INSTANCE_ATTRIBUTE = 'attr' 
    84  
    85         class MockModelAdmin(object): 
    86             def get_admin_value(self, obj): 
    87                 return ADMIN_METHOD 
    88  
    89         simple_function = lambda obj: SIMPLE_FUNCTION 
    90  
    91         article = Article( 
    92             site=Site(domain=SITE_NAME), 
    93             title=TITLE_TEXT, 
    94             created=CREATED_DATE, 
    95         ) 
    96         article.non_field = INSTANCE_ATTRIBUTE 
    97  
    98         verifications = ( 
    99             ('site', SITE_NAME), 
    100             ('created', localize(CREATED_DATE)), 
    101             ('title', TITLE_TEXT), 
    102             ('get_admin_value', ADMIN_METHOD), 
    103             (simple_function, SIMPLE_FUNCTION), 
    104             ('test_from_model', article.test_from_model()), 
    105             ('non_field', INSTANCE_ATTRIBUTE) 
    106         ) 
    107  
    108         mock_admin = MockModelAdmin() 
    109         for name, value in verifications: 
    110             field, attr, resolved_value = lookup_field(name, article, mock_admin) 
    111  
    112             if field is not None: 
    113                 resolved_value = display_for_field(resolved_value, field) 
    114  
    115             self.assertEqual(value, resolved_value) 
    116  
    117     def test_null_display_for_field(self): 
    118         """ 
    119         Regression test for #12550: display_for_field should handle None 
    120         value. 
    121         """ 
    122         display_value = display_for_field(None, models.CharField()) 
    123         self.assertEqual(display_value, EMPTY_CHANGELIST_VALUE) 
    124  
    125         display_value = display_for_field(None, models.CharField( 
    126             choices=( 
    127                 (None, "test_none"), 
    128             ) 
    129         )) 
    130         self.assertEqual(display_value, "test_none") 
    131  
    132         display_value = display_for_field(None, models.DateField()) 
    133         self.assertEqual(display_value, EMPTY_CHANGELIST_VALUE) 
    134  
    135         display_value = display_for_field(None, models.TimeField()) 
    136         self.assertEqual(display_value, EMPTY_CHANGELIST_VALUE) 
    137  
    138         # Regression test for #13071: NullBooleanField has special 
    139         # handling. 
    140         display_value = display_for_field(None, models.NullBooleanField()) 
    141         expected = u'<img src="%sadmin/img/icon-unknown.gif" alt="None" />' % settings.STATIC_URL 
    142         self.assertEqual(display_value, expected) 
    143  
    144         display_value = display_for_field(None, models.DecimalField()) 
    145         self.assertEqual(display_value, EMPTY_CHANGELIST_VALUE) 
    146  
    147         display_value = display_for_field(None, models.FloatField()) 
    148         self.assertEqual(display_value, EMPTY_CHANGELIST_VALUE) 
    149  
    150     def test_label_for_field(self): 
    151         """ 
    152         Tests for label_for_field 
    153         """ 
    154         self.assertEqual( 
    155             label_for_field("title", Article), 
    156             "title" 
    157         ) 
    158         self.assertEqual( 
    159             label_for_field("title2", Article), 
    160             "another name" 
    161         ) 
    162         self.assertEqual( 
    163             label_for_field("title2", Article, return_attr=True), 
    164             ("another name", None) 
    165         ) 
    166  
    167         self.assertEqual( 
    168             label_for_field("__unicode__", Article), 
    169             "article" 
    170         ) 
    171         self.assertEqual( 
    172             label_for_field("__str__", Article), 
    173             "article" 
    174         ) 
    175  
    176         self.assertRaises( 
    177             AttributeError, 
    178             lambda: label_for_field("unknown", Article) 
    179         ) 
    180  
    181         def test_callable(obj): 
    182             return "nothing" 
    183         self.assertEqual( 
    184             label_for_field(test_callable, Article), 
    185             "Test callable" 
    186         ) 
    187         self.assertEqual( 
    188             label_for_field(test_callable, Article, return_attr=True), 
    189             ("Test callable", test_callable) 
    190         ) 
    191  
    192         self.assertEqual( 
    193             label_for_field("test_from_model", Article), 
    194             "Test from model" 
    195         ) 
    196         self.assertEqual( 
    197             label_for_field("test_from_model", Article, return_attr=True), 
    198             ("Test from model", Article.test_from_model) 
    199         ) 
    200         self.assertEqual( 
    201             label_for_field("test_from_model_with_override", Article), 
    202             "not What you Expect" 
    203         ) 
    204  
    205         self.assertEqual( 
    206             label_for_field(lambda x: "nothing", Article), 
    207             "--" 
    208         ) 
    209  
    210         class MockModelAdmin(object): 
    211             def test_from_model(self, obj): 
    212                 return "nothing" 
    213             test_from_model.short_description = "not Really the Model" 
    214  
    215         self.assertEqual( 
    216             label_for_field("test_from_model", Article, model_admin=MockModelAdmin), 
    217             "not Really the Model" 
    218         ) 
    219         self.assertEqual( 
    220             label_for_field("test_from_model", Article, 
    221                 model_admin = MockModelAdmin, 
    222                 return_attr = True 
    223             ), 
    224             ("not Really the Model", MockModelAdmin.test_from_model) 
    225         ) 
    226  
    227     def test_related_name(self): 
    228         """ 
    229         Regression test for #13963 
    230         """ 
    231         self.assertEqual( 
    232             label_for_field('location', Event, return_attr=True), 
    233             ('location', None), 
    234         ) 
    235         self.assertEqual( 
    236             label_for_field('event', Location, return_attr=True), 
    237             ('awesome event', None), 
    238         ) 
    239         self.assertEqual( 
    240             label_for_field('guest', Event, return_attr=True), 
    241             ('awesome guest', None), 
    242         ) 
    243  
    244     def test_logentry_unicode(self): 
    245         """ 
    246         Regression test for #15661 
    247         """ 
    248         log_entry = admin.models.LogEntry() 
    249  
    250         log_entry.action_flag = admin.models.ADDITION 
    251         self.assertTrue( 
    252             unicode(log_entry).startswith('Added ') 
    253         ) 
    254  
    255         log_entry.action_flag = admin.models.CHANGE 
    256         self.assertTrue( 
    257             unicode(log_entry).startswith('Changed ') 
    258         ) 
    259  
    260         log_entry.action_flag = admin.models.DELETION 
    261         self.assertTrue( 
    262             unicode(log_entry).startswith('Deleted ') 
    263         ) 
    264  
    265     def test_safestring_in_field_label(self): 
    266         # safestring should not be escaped 
    267         class MyForm(forms.Form): 
    268             text = forms.CharField(label=mark_safe('<i>text</i>')) 
    269             cb   = forms.BooleanField(label=mark_safe('<i>cb</i>')) 
    270  
    271         form = MyForm() 
    272         self.assertEqual(helpers.AdminField(form, 'text', is_first=False).label_tag(), 
    273                          '<label for="id_text" class="required inline"><i>text</i>:</label>') 
    274         self.assertEqual(helpers.AdminField(form, 'cb', is_first=False).label_tag(), 
    275                          '<label for="id_cb" class="vCheckboxLabel required inline"><i>cb</i></label>') 
    276  
    277         # normal strings needs to be escaped 
    278         class MyForm(forms.Form): 
    279             text = forms.CharField(label='&text') 
    280             cb   = forms.BooleanField(label='&cb') 
    281  
    282         form = MyForm() 
    283         self.assertEqual(helpers.AdminField(form, 'text', is_first=False).label_tag(), 
    284                          '<label for="id_text" class="required inline">&amp;text:</label>') 
    285         self.assertEqual(helpers.AdminField(form, 'cb', is_first=False).label_tag(), 
    286                          '<label for="id_cb" class="vCheckboxLabel required inline">&amp;cb</label>') 
  • new file tests/regressiontests/admin_utils/models.py

    diff --git a/tests/regressiontests/admin_utils/__init__.py b/tests/regressiontests/admin_utils/__init__.py
    new file mode 100644
    index 0000000..e69de29
    diff --git a/tests/regressiontests/admin_utils/models.py b/tests/regressiontests/admin_utils/models.py
    new file mode 100644
    index 0000000..0e81df3
    - +  
     1from django.db import models 
     2 
     3 
     4class Article(models.Model): 
     5    """ 
     6    A simple Article model for testing 
     7    """ 
     8    site = models.ForeignKey('sites.Site', related_name="admin_articles") 
     9    title = models.CharField(max_length=100) 
     10    title2 = models.CharField(max_length=100, verbose_name="another name") 
     11    created = models.DateTimeField() 
     12 
     13    def test_from_model(self): 
     14        return "nothing" 
     15 
     16    def test_from_model_with_override(self): 
     17        return "nothing" 
     18    test_from_model_with_override.short_description = "not What you Expect" 
     19 
     20class Count(models.Model): 
     21    num = models.PositiveSmallIntegerField() 
     22    parent = models.ForeignKey('self', null=True) 
     23 
     24    def __unicode__(self): 
     25        return unicode(self.num) 
     26 
     27class Event(models.Model): 
     28    date = models.DateTimeField(auto_now_add=True) 
     29 
     30class Location(models.Model): 
     31    event = models.OneToOneField(Event, verbose_name='awesome event') 
     32 
     33class Guest(models.Model): 
     34    event = models.OneToOneField(Event) 
     35    name = models.CharField(max_length=255) 
     36 
     37    class Meta: 
     38        verbose_name = "awesome guest" 
  • new file tests/regressiontests/admin_utils/tests.py

    diff --git a/tests/regressiontests/admin_utils/tests.py b/tests/regressiontests/admin_utils/tests.py
    new file mode 100644
    index 0000000..d7eaabe
    - +  
     1from __future__ import absolute_import 
     2 
     3from datetime import datetime 
     4 
     5from django.conf import settings 
     6from django.contrib import admin 
     7from django.contrib.admin import helpers 
     8from django.contrib.admin.utils import (display_for_field, label_for_field, 
     9    lookup_field, NestedObjects) 
     10from django.contrib.admin.views.main import EMPTY_CHANGELIST_VALUE 
     11from django.contrib.sites.models import Site 
     12from django.db import models, DEFAULT_DB_ALIAS 
     13from django import forms 
     14from django.test import TestCase 
     15from django.utils import unittest 
     16from django.utils.formats import localize 
     17from django.utils.safestring import mark_safe 
     18 
     19from .models import Article, Count, Event, Location 
     20 
     21 
     22class NestedObjectsTests(TestCase): 
     23    """ 
     24    Tests for ``NestedObject`` utility collection. 
     25 
     26    """ 
     27    def setUp(self): 
     28        self.n = NestedObjects(using=DEFAULT_DB_ALIAS) 
     29        self.objs = [Count.objects.create(num=i) for i in range(5)] 
     30 
     31    def _check(self, target): 
     32        self.assertEqual(self.n.nested(lambda obj: obj.num), target) 
     33 
     34    def _connect(self, i, j): 
     35        self.objs[i].parent = self.objs[j] 
     36        self.objs[i].save() 
     37 
     38    def _collect(self, *indices): 
     39        self.n.collect([self.objs[i] for i in indices]) 
     40 
     41    def test_unrelated_roots(self): 
     42        self._connect(2, 1) 
     43        self._collect(0) 
     44        self._collect(1) 
     45        self._check([0, 1, [2]]) 
     46 
     47    def test_siblings(self): 
     48        self._connect(1, 0) 
     49        self._connect(2, 0) 
     50        self._collect(0) 
     51        self._check([0, [1, 2]]) 
     52 
     53    def test_non_added_parent(self): 
     54        self._connect(0, 1) 
     55        self._collect(0) 
     56        self._check([0]) 
     57 
     58    def test_cyclic(self): 
     59        self._connect(0, 2) 
     60        self._connect(1, 0) 
     61        self._connect(2, 1) 
     62        self._collect(0) 
     63        self._check([0, [1, [2]]]) 
     64 
     65    def test_queries(self): 
     66        self._connect(1, 0) 
     67        self._connect(2, 0) 
     68        # 1 query to fetch all children of 0 (1 and 2) 
     69        # 1 query to fetch all children of 1 and 2 (none) 
     70        # Should not require additional queries to populate the nested graph. 
     71        self.assertNumQueries(2, self._collect, 0) 
     72 
     73class UtilTests(unittest.TestCase): 
     74    def test_values_from_lookup_field(self): 
     75        """ 
     76        Regression test for #12654: lookup_field 
     77        """ 
     78        SITE_NAME = 'example.com' 
     79        TITLE_TEXT = 'Some title' 
     80        CREATED_DATE = datetime.min 
     81        ADMIN_METHOD = 'admin method' 
     82        SIMPLE_FUNCTION = 'function' 
     83        INSTANCE_ATTRIBUTE = 'attr' 
     84 
     85        class MockModelAdmin(object): 
     86            def get_admin_value(self, obj): 
     87                return ADMIN_METHOD 
     88 
     89        simple_function = lambda obj: SIMPLE_FUNCTION 
     90 
     91        article = Article( 
     92            site=Site(domain=SITE_NAME), 
     93            title=TITLE_TEXT, 
     94            created=CREATED_DATE, 
     95        ) 
     96        article.non_field = INSTANCE_ATTRIBUTE 
     97 
     98        verifications = ( 
     99            ('site', SITE_NAME), 
     100            ('created', localize(CREATED_DATE)), 
     101            ('title', TITLE_TEXT), 
     102            ('get_admin_value', ADMIN_METHOD), 
     103            (simple_function, SIMPLE_FUNCTION), 
     104            ('test_from_model', article.test_from_model()), 
     105            ('non_field', INSTANCE_ATTRIBUTE) 
     106        ) 
     107 
     108        mock_admin = MockModelAdmin() 
     109        for name, value in verifications: 
     110            field, attr, resolved_value = lookup_field(name, article, mock_admin) 
     111 
     112            if field is not None: 
     113                resolved_value = display_for_field(resolved_value, field) 
     114 
     115            self.assertEqual(value, resolved_value) 
     116 
     117    def test_null_display_for_field(self): 
     118        """ 
     119        Regression test for #12550: display_for_field should handle None 
     120        value. 
     121        """ 
     122        display_value = display_for_field(None, models.CharField()) 
     123        self.assertEqual(display_value, EMPTY_CHANGELIST_VALUE) 
     124 
     125        display_value = display_for_field(None, models.CharField( 
     126            choices=( 
     127                (None, "test_none"), 
     128            ) 
     129        )) 
     130        self.assertEqual(display_value, "test_none") 
     131 
     132        display_value = display_for_field(None, models.DateField()) 
     133        self.assertEqual(display_value, EMPTY_CHANGELIST_VALUE) 
     134 
     135        display_value = display_for_field(None, models.TimeField()) 
     136        self.assertEqual(display_value, EMPTY_CHANGELIST_VALUE) 
     137 
     138        # Regression test for #13071: NullBooleanField has special 
     139        # handling. 
     140        display_value = display_for_field(None, models.NullBooleanField()) 
     141        expected = u'<img src="%sadmin/img/icon-unknown.gif" alt="None" />' % settings.STATIC_URL 
     142        self.assertEqual(display_value, expected) 
     143 
     144        display_value = display_for_field(None, models.DecimalField()) 
     145        self.assertEqual(display_value, EMPTY_CHANGELIST_VALUE) 
     146 
     147        display_value = display_for_field(None, models.FloatField()) 
     148        self.assertEqual(display_value, EMPTY_CHANGELIST_VALUE) 
     149 
     150    def test_label_for_field(self): 
     151        """ 
     152        Tests for label_for_field 
     153        """ 
     154        self.assertEqual( 
     155            label_for_field("title", Article), 
     156            "title" 
     157        ) 
     158        self.assertEqual( 
     159            label_for_field("title2", Article), 
     160            "another name" 
     161        ) 
     162        self.assertEqual( 
     163            label_for_field("title2", Article, return_attr=True), 
     164            ("another name", None) 
     165        ) 
     166 
     167        self.assertEqual( 
     168            label_for_field("__unicode__", Article), 
     169            "article" 
     170        ) 
     171        self.assertEqual( 
     172            label_for_field("__str__", Article), 
     173            "article" 
     174        ) 
     175 
     176        self.assertRaises( 
     177            AttributeError, 
     178            lambda: label_for_field("unknown", Article) 
     179        ) 
     180 
     181        def test_callable(obj): 
     182            return "nothing" 
     183        self.assertEqual( 
     184            label_for_field(test_callable, Article), 
     185            "Test callable" 
     186        ) 
     187        self.assertEqual( 
     188            label_for_field(test_callable, Article, return_attr=True), 
     189            ("Test callable", test_callable) 
     190        ) 
     191 
     192        self.assertEqual( 
     193            label_for_field("test_from_model", Article), 
     194            "Test from model" 
     195        ) 
     196        self.assertEqual( 
     197            label_for_field("test_from_model", Article, return_attr=True), 
     198            ("Test from model", Article.test_from_model) 
     199        ) 
     200        self.assertEqual( 
     201            label_for_field("test_from_model_with_override", Article), 
     202            "not What you Expect" 
     203        ) 
     204 
     205        self.assertEqual( 
     206            label_for_field(lambda x: "nothing", Article), 
     207            "--" 
     208        ) 
     209 
     210        class MockModelAdmin(object): 
     211            def test_from_model(self, obj): 
     212                return "nothing" 
     213            test_from_model.short_description = "not Really the Model" 
     214 
     215        self.assertEqual( 
     216            label_for_field("test_from_model", Article, model_admin=MockModelAdmin), 
     217            "not Really the Model" 
     218        ) 
     219        self.assertEqual( 
     220            label_for_field("test_from_model", Article, 
     221                model_admin = MockModelAdmin, 
     222                return_attr = True 
     223            ), 
     224            ("not Really the Model", MockModelAdmin.test_from_model) 
     225        ) 
     226 
     227    def test_related_name(self): 
     228        """ 
     229        Regression test for #13963 
     230        """ 
     231        self.assertEqual( 
     232            label_for_field('location', Event, return_attr=True), 
     233            ('location', None), 
     234        ) 
     235        self.assertEqual( 
     236            label_for_field('event', Location, return_attr=True), 
     237            ('awesome event', None), 
     238        ) 
     239        self.assertEqual( 
     240            label_for_field('guest', Event, return_attr=True), 
     241            ('awesome guest', None), 
     242        ) 
     243 
     244    def test_logentry_unicode(self): 
     245        """ 
     246        Regression test for #15661 
     247        """ 
     248        log_entry = admin.models.LogEntry() 
     249 
     250        log_entry.action_flag = admin.models.ADDITION 
     251        self.assertTrue( 
     252            unicode(log_entry).startswith('Added ') 
     253        ) 
     254 
     255        log_entry.action_flag = admin.models.CHANGE 
     256        self.assertTrue( 
     257            unicode(log_entry).startswith('Changed ') 
     258        ) 
     259 
     260        log_entry.action_flag = admin.models.DELETION 
     261        self.assertTrue( 
     262            unicode(log_entry).startswith('Deleted ') 
     263        ) 
     264 
     265    def test_safestring_in_field_label(self): 
     266        # safestring should not be escaped 
     267        class MyForm(forms.Form): 
     268            text = forms.CharField(label=mark_safe('<i>text</i>')) 
     269            cb   = forms.BooleanField(label=mark_safe('<i>cb</i>')) 
     270 
     271        form = MyForm() 
     272        self.assertEqual(helpers.AdminField(form, 'text', is_first=False).label_tag(), 
     273                         '<label for="id_text" class="required inline"><i>text</i>:</label>') 
     274        self.assertEqual(helpers.AdminField(form, 'cb', is_first=False).label_tag(), 
     275                         '<label for="id_cb" class="vCheckboxLabel required inline"><i>cb</i></label>') 
     276 
     277        # normal strings needs to be escaped 
     278        class MyForm(forms.Form): 
     279            text = forms.CharField(label='&text') 
     280            cb   = forms.BooleanField(label='&cb') 
     281 
     282        form = MyForm() 
     283        self.assertEqual(helpers.AdminField(form, 'text', is_first=False).label_tag(), 
     284                         '<label for="id_text" class="required inline">&amp;text:</label>') 
     285        self.assertEqual(helpers.AdminField(form, 'cb', is_first=False).label_tag(), 
     286                         '<label for="id_cb" class="vCheckboxLabel required inline">&amp;cb</label>') 
  • tests/regressiontests/admin_views/admin.py

    diff --git a/tests/regressiontests/admin_views/admin.py b/tests/regressiontests/admin_views/admin.py
    index d960749..86cd039 100644
    a b site.register(UnorderedObject, UnorderedObjectAdmin) 
    625625#     related OneToOne object not registered in admin 
    626626# when deleting Book so as exercise all four troublesome (w.r.t escaping 
    627627# and calling force_unicode to avoid problems on Python 2.3) paths through 
    628 # contrib.admin.util's get_deleted_objects function. 
     628# contrib.admin.utils's get_deleted_objects function. 
    629629site.register(Book, inlines=[ChapterInline]) 
    630630site.register(Promo) 
    631631site.register(ChapterXtra1, ChapterXtra1Admin) 
  • tests/regressiontests/admin_views/tests.py

    diff --git a/tests/regressiontests/admin_views/tests.py b/tests/regressiontests/admin_views/tests.py
    index 5241d26..0652e81 100755
    a b from django.contrib import admin 
    1616from django.contrib.admin.helpers import ACTION_CHECKBOX_NAME 
    1717from django.contrib.admin.models import LogEntry, DELETION 
    1818from django.contrib.admin.sites import LOGIN_FORM_KEY 
    19 from django.contrib.admin.util import quote 
     19from django.contrib.admin.utils import quote 
    2020from django.contrib.admin.views.main import IS_POPUP_VAR 
    2121from django.contrib.admin.tests import AdminSeleniumWebDriverTestCase 
    2222from django.contrib.auth import REDIRECT_FIELD_NAME 
    2323from django.contrib.auth.models import Group, User, Permission, UNUSABLE_PASSWORD 
    2424from django.contrib.contenttypes.models import ContentType 
    25 from django.forms.util import ErrorList 
     25from django.forms.utils import ErrorList 
    2626from django.template import context as context_module 
    2727from django.template.response import TemplateResponse 
    2828from django.test import TestCase 
  • tests/regressiontests/db_typecasts/tests.py

    diff --git a/tests/regressiontests/db_typecasts/tests.py b/tests/regressiontests/db_typecasts/tests.py
    index 83bd1e6..c905a6d 100644
    a b  
    22 
    33import datetime 
    44 
    5 from django.db.backends import util as typecasts 
     5from django.db.backends import utils as typecasts 
    66from django.utils import unittest 
    77 
    88 
  • tests/regressiontests/forms/tests/__init__.py

    diff --git a/tests/regressiontests/forms/tests/__init__.py b/tests/regressiontests/forms/tests/__init__.py
    index 8e2150c..a94b2a0 100644
    a b from .media import FormsMediaTestCase, StaticFormsMediaTestCase 
    1515from .models import (TestTicket12510, ModelFormCallableModelDefault, 
    1616    FormsModelTestCase, RelatedModelFormTests) 
    1717from .regressions import FormsRegressionsTestCase 
    18 from .util import FormsUtilTestCase 
     18from .utils import FormsUtilTestCase 
    1919from .validators import TestFieldWithValidators 
    2020from .widgets import (FormsWidgetTestCase, FormsI18NWidgetsTestCase, 
    2121    WidgetTests, ClearableFileInputTests) 
  • tests/regressiontests/forms/tests/error_messages.py

    diff --git a/tests/regressiontests/forms/tests/error_messages.py b/tests/regressiontests/forms/tests/error_messages.py
    index b7b4e98..e8c8999 100644
    a b class FormsErrorMessagesTestCase(TestCase, AssertFormErrorsMixin): 
    219219            def clean(self): 
    220220                raise ValidationError("I like to be awkward.") 
    221221 
    222         class CustomErrorList(util.ErrorList): 
     222        class CustomErrorList(utils.ErrorList): 
    223223            def __unicode__(self): 
    224224                return self.as_divs() 
    225225 
  • tests/regressiontests/forms/tests/extra.py

    diff --git a/tests/regressiontests/forms/tests/extra.py b/tests/regressiontests/forms/tests/extra.py
    index c873af7..87d2c0d 100644
    a b import datetime 
    77from django.conf import settings 
    88from django.forms import * 
    99from django.forms.extras import SelectDateWidget 
    10 from django.forms.util import ErrorList 
     10from django.forms.utils import ErrorList 
    1111from django.test import TestCase 
    1212from django.utils import translation 
    1313from django.utils.encoding import force_unicode, smart_unicode 
  • tests/regressiontests/forms/tests/fields.py

    diff --git a/tests/regressiontests/forms/tests/fields.py b/tests/regressiontests/forms/tests/fields.py
    index 03e0ff6..a1aa199 100644
    a b class FieldsTests(SimpleTestCase): 
    999999                ('/django/forms/formsets.py', 'formsets.py'), 
    10001000                ('/django/forms/models.py', 'models.py'), 
    10011001                ('/django/forms/util.py', 'util.py'), 
     1002                ('/django/forms/utils.py', 'utils.py'), 
    10021003                ('/django/forms/widgets.py', 'widgets.py') 
    10031004            ] 
    10041005        for exp, got in zip(expected, fix_os_paths(f.choices)): 
    class FieldsTests(SimpleTestCase): 
    10191020                ('/django/forms/formsets.py', 'formsets.py'), 
    10201021                ('/django/forms/models.py', 'models.py'), 
    10211022                ('/django/forms/util.py', 'util.py'), 
     1023                ('/django/forms/utils.py', 'utils.py'), 
    10221024                ('/django/forms/widgets.py', 'widgets.py') 
    10231025            ] 
    10241026        for exp, got in zip(expected, fix_os_paths(f.choices)): 
    class FieldsTests(SimpleTestCase): 
    10391041                ('/django/forms/formsets.py', 'formsets.py'), 
    10401042                ('/django/forms/models.py', 'models.py'), 
    10411043                ('/django/forms/util.py', 'util.py'), 
     1044                ('/django/forms/utils.py', 'utils.py'), 
    10421045                ('/django/forms/widgets.py', 'widgets.py') 
    10431046            ] 
    10441047        for exp, got in zip(expected, fix_os_paths(f.choices)): 
  • deleted file tests/regressiontests/forms/tests/util.py

    diff --git a/tests/regressiontests/forms/tests/util.py b/tests/regressiontests/forms/tests/util.py
    deleted file mode 100644
    index dddb8c7..0000000
    + -  
    1 # -*- coding: utf-8 -*- 
    2 from django.core.exceptions import ValidationError 
    3 from django.forms.util import flatatt, ErrorDict, ErrorList 
    4 from django.test import TestCase 
    5 from django.utils.safestring import mark_safe 
    6 from django.utils.translation import ugettext_lazy 
    7  
    8  
    9 class FormsUtilTestCase(TestCase): 
    10         # Tests for forms/util.py module. 
    11  
    12     def test_flatatt(self): 
    13         ########### 
    14         # flatatt # 
    15         ########### 
    16  
    17         self.assertEqual(flatatt({'id': "header"}), u' id="header"') 
    18         self.assertEqual(flatatt({'class': "news", 'title': "Read this"}), u' class="news" title="Read this"') 
    19         self.assertEqual(flatatt({}), u'') 
    20  
    21     def test_validation_error(self): 
    22         ################### 
    23         # ValidationError # 
    24         ################### 
    25  
    26         # Can take a string. 
    27         self.assertHTMLEqual(str(ErrorList(ValidationError("There was an error.").messages)), 
    28                          '<ul class="errorlist"><li>There was an error.</li></ul>') 
    29  
    30         # Can take a unicode string. 
    31         self.assertHTMLEqual(unicode(ErrorList(ValidationError(u"Not \u03C0.").messages)), 
    32                          u'<ul class="errorlist"><li>Not π.</li></ul>') 
    33  
    34         # Can take a lazy string. 
    35         self.assertHTMLEqual(str(ErrorList(ValidationError(ugettext_lazy("Error.")).messages)), 
    36                          '<ul class="errorlist"><li>Error.</li></ul>') 
    37  
    38         # Can take a list. 
    39         self.assertHTMLEqual(str(ErrorList(ValidationError(["Error one.", "Error two."]).messages)), 
    40                          '<ul class="errorlist"><li>Error one.</li><li>Error two.</li></ul>') 
    41  
    42         # Can take a mixture in a list. 
    43         self.assertHTMLEqual(str(ErrorList(ValidationError(["First error.", u"Not \u03C0.", ugettext_lazy("Error.")]).messages)), 
    44                          '<ul class="errorlist"><li>First error.</li><li>Not π.</li><li>Error.</li></ul>') 
    45  
    46         class VeryBadError: 
    47             def __unicode__(self): return u"A very bad error." 
    48  
    49         # Can take a non-string. 
    50         self.assertHTMLEqual(str(ErrorList(ValidationError(VeryBadError()).messages)), 
    51                          '<ul class="errorlist"><li>A very bad error.</li></ul>') 
    52  
    53         # Escapes non-safe input but not input marked safe. 
    54         example = 'Example of link: <a href="http://www.example.com/">example</a>' 
    55         self.assertHTMLEqual(str(ErrorList([example])), 
    56                          '<ul class="errorlist"><li>Example of link: &lt;a href=&quot;http://www.example.com/&quot;&gt;example&lt;/a&gt;</li></ul>') 
    57         self.assertHTMLEqual(str(ErrorList([mark_safe(example)])), 
    58                          '<ul class="errorlist"><li>Example of link: <a href="http://www.example.com/">example</a></li></ul>') 
    59         self.assertHTMLEqual(str(ErrorDict({'name': example})), 
    60                          '<ul class="errorlist"><li>nameExample of link: &lt;a href=&quot;http://www.example.com/&quot;&gt;example&lt;/a&gt;</li></ul>') 
    61         self.assertHTMLEqual(str(ErrorDict({'name': mark_safe(example)})), 
    62                          '<ul class="errorlist"><li>nameExample of link: <a href="http://www.example.com/">example</a></li></ul>') 
  • new file tests/regressiontests/forms/tests/utils.py

    diff --git a/tests/regressiontests/forms/tests/utils.py b/tests/regressiontests/forms/tests/utils.py
    new file mode 100644
    index 0000000..ab827e6
    - +  
     1# -*- coding: utf-8 -*- 
     2from django.core.exceptions import ValidationError 
     3from django.forms.utils import flatatt, ErrorDict, ErrorList 
     4from django.test import TestCase 
     5from django.utils.safestring import mark_safe 
     6from django.utils.translation import ugettext_lazy 
     7 
     8 
     9class FormsUtilTestCase(TestCase): 
     10        # Tests for forms/util.py module. 
     11 
     12    def test_flatatt(self): 
     13        ########### 
     14        # flatatt # 
     15        ########### 
     16 
     17        self.assertEqual(flatatt({'id': "header"}), u' id="header"') 
     18        self.assertEqual(flatatt({'class': "news", 'title': "Read this"}), u' class="news" title="Read this"') 
     19        self.assertEqual(flatatt({}), u'') 
     20 
     21    def test_validation_error(self): 
     22        ################### 
     23        # ValidationError # 
     24        ################### 
     25 
     26        # Can take a string. 
     27        self.assertHTMLEqual(str(ErrorList(ValidationError("There was an error.").messages)), 
     28                         '<ul class="errorlist"><li>There was an error.</li></ul>') 
     29 
     30        # Can take a unicode string. 
     31        self.assertHTMLEqual(unicode(ErrorList(ValidationError(u"Not \u03C0.").messages)), 
     32                         u'<ul class="errorlist"><li>Not π.</li></ul>') 
     33 
     34        # Can take a lazy string. 
     35        self.assertHTMLEqual(str(ErrorList(ValidationError(ugettext_lazy("Error.")).messages)), 
     36                         '<ul class="errorlist"><li>Error.</li></ul>') 
     37 
     38        # Can take a list. 
     39        self.assertHTMLEqual(str(ErrorList(ValidationError(["Error one.", "Error two."]).messages)), 
     40                         '<ul class="errorlist"><li>Error one.</li><li>Error two.</li></ul>') 
     41 
     42        # Can take a mixture in a list. 
     43        self.assertHTMLEqual(str(ErrorList(ValidationError(["First error.", u"Not \u03C0.", ugettext_lazy("Error.")]).messages)), 
     44                         '<ul class="errorlist"><li>First error.</li><li>Not π.</li><li>Error.</li></ul>') 
     45 
     46        class VeryBadError: 
     47            def __unicode__(self): return u"A very bad error." 
     48 
     49        # Can take a non-string. 
     50        self.assertHTMLEqual(str(ErrorList(ValidationError(VeryBadError()).messages)), 
     51                         '<ul class="errorlist"><li>A very bad error.</li></ul>') 
     52 
     53        # Escapes non-safe input but not input marked safe. 
     54        example = 'Example of link: <a href="http://www.example.com/">example</a>' 
     55        self.assertHTMLEqual(str(ErrorList([example])), 
     56                         '<ul class="errorlist"><li>Example of link: &lt;a href=&quot;http://www.example.com/&quot;&gt;example&lt;/a&gt;</li></ul>') 
     57        self.assertHTMLEqual(str(ErrorList([mark_safe(example)])), 
     58                         '<ul class="errorlist"><li>Example of link: <a href="http://www.example.com/">example</a></li></ul>') 
     59        self.assertHTMLEqual(str(ErrorDict({'name': example})), 
     60                         '<ul class="errorlist"><li>nameExample of link: &lt;a href=&quot;http://www.example.com/&quot;&gt;example&lt;/a&gt;</li></ul>') 
     61        self.assertHTMLEqual(str(ErrorDict({'name': mark_safe(example)})), 
     62                         '<ul class="errorlist"><li>nameExample of link: <a href="http://www.example.com/">example</a></li></ul>') 
  • tests/regressiontests/localflavor/uy/tests.py

    diff --git a/tests/regressiontests/localflavor/uy/tests.py b/tests/regressiontests/localflavor/uy/tests.py
    index eda0068..b1fdc19 100644
    a b  
    11from django.contrib.localflavor.uy.forms import UYDepartamentSelect, UYCIField 
    2 from django.contrib.localflavor.uy.util import get_validation_digit 
     2from django.contrib.localflavor.uy.utils import get_validation_digit 
    33 
    44from django.test import SimpleTestCase 
    55 
  • tests/regressiontests/model_formsets_regress/tests.py

    diff --git a/tests/regressiontests/model_formsets_regress/tests.py b/tests/regressiontests/model_formsets_regress/tests.py
    index d058f1d..ecdf72e 100644
    a b from __future__ import absolute_import, with_statement 
    22 
    33from django import forms 
    44from django.forms.formsets import BaseFormSet, DELETION_FIELD_NAME 
    5 from django.forms.util import ErrorDict, ErrorList 
     5from django.forms.utils import ErrorDict, ErrorList 
    66from django.forms.models import modelform_factory, inlineformset_factory, modelformset_factory, BaseModelFormSet 
    77from django.test import TestCase 
    88