[Python-modules-commits] [python-django] 01/07: Import python-django_1.8.9.orig.tar.gz

Raphaël Hertzog hertzog at moszumanska.debian.org
Tue Feb 2 09:07:21 UTC 2016


This is an automated email from the git hooks/post-receive script.

hertzog pushed a commit to branch debian/jessie-backports
in repository python-django.

commit 005755b3e573831af927ce66797168fa370332db
Author: Raphaël Hertzog <hertzog at debian.org>
Date:   Tue Feb 2 09:51:24 2016 +0100

    Import python-django_1.8.9.orig.tar.gz
---
 AUTHORS                                            |   2 +
 Django.egg-info/PKG-INFO                           |   2 +-
 Django.egg-info/SOURCES.txt                        |   1 +
 PKG-INFO                                           |   2 +-
 django/__init__.py                                 |   2 +-
 django/contrib/admin/helpers.py                    |   2 +-
 django/contrib/admin/sites.py                      |   8 +-
 .../static/admin/js/admin/DateTimeShortcuts.js     |   4 +-
 django/contrib/admin/static/admin/js/core.js       |   5 +-
 django/contrib/admin/utils.py                      |   2 +-
 django/contrib/auth/hashers.py                     |   2 +-
 django/contrib/gis/templates/gis/openlayers.html   |   5 +-
 django/db/backends/postgresql_psycopg2/schema.py   |   4 +-
 django/db/models/lookups.py                        |   8 ++
 django/db/models/sql/where.py                      |  16 ++-
 django/dispatch/dispatcher.py                      |   6 +-
 django/utils/functional.py                         |  20 ++++
 django/utils/translation/trans_real.py             |   3 +
 docs/howto/deployment/wsgi/modwsgi.txt             |   7 +-
 docs/intro/reusable-apps.txt                       |   1 +
 docs/ref/csrf.txt                                  |   2 +-
 docs/ref/databases.txt                             |   2 +-
 docs/releases/1.8.9.txt                            |  39 ++++++++
 docs/releases/index.txt                            |   1 +
 docs/topics/i18n/translation.txt                   |  24 ++---
 docs/topics/security.txt                           |   3 +-
 setup.cfg                                          |   2 +-
 tests/admin_scripts/tests.py                       |   1 +
 tests/admin_views/admin.py                         |  23 +++--
 tests/admin_views/models.py                        |   7 +-
 tests/admin_views/tests.py                         |  82 +++++++++++++---
 tests/expressions_case/tests.py                    |  13 ++-
 .../templates/forms_tests/article_form.html        |   2 +-
 tests/gis_tests/distapp/tests.py                   |   2 +-
 tests/gis_tests/geogapp/tests.py                   |  10 +-
 tests/gis_tests/test_geoforms.py                   |   5 +-
 tests/i18n/tests.py                                |   4 +
 tests/migrations/test_writer.py                    |   2 +
 tests/schema/tests.py                              | 108 +++++++++++++--------
 tests/templates/form_view.html                     |   2 +-
 tests/templates/login.html                         |   2 +-
 tests/utils_tests/test_dateformat.py               |   3 +
 tests/utils_tests/test_lazyobject.py               |  85 ++++++++++++++--
 43 files changed, 403 insertions(+), 123 deletions(-)

diff --git a/AUTHORS b/AUTHORS
index 06d9882..e871235 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -611,6 +611,7 @@ answer newbie questions, and generally made Django that much better:
     schwank at gmail.com
     Scot Hacker <shacker at birdhouse.org>
     Scott Barr <scott at divisionbyzero.com.au>
+    Scott Pashley <github at scottpashley.co.uk>
     scott at staplefish.com
     Sean Brant
     Sebastian Hillig <sebastian.hillig at gmail.com>
@@ -720,6 +721,7 @@ answer newbie questions, and generally made Django that much better:
     Yasushi Masuda <whosaysni at gmail.com>
     ye7cakf02 at sneakemail.com
     ymasuda at ethercube.com
+    Yoong Kang Lim <yoongkang.lim at gmail.com>
     Zachary Voase <zacharyvoase at gmail.com>
     Zach Thompson <zthompson47 at gmail.com>
     Zain Memon
diff --git a/Django.egg-info/PKG-INFO b/Django.egg-info/PKG-INFO
index a62d086..42f9052 100644
--- a/Django.egg-info/PKG-INFO
+++ b/Django.egg-info/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: Django
-Version: 1.8.8
+Version: 1.8.9
 Summary: A high-level Python Web framework that encourages rapid development and clean, pragmatic design.
 Home-page: http://www.djangoproject.com/
 Author: Django Software Foundation
diff --git a/Django.egg-info/SOURCES.txt b/Django.egg-info/SOURCES.txt
index 52865cb..4b68a10 100644
--- a/Django.egg-info/SOURCES.txt
+++ b/Django.egg-info/SOURCES.txt
@@ -3409,6 +3409,7 @@ docs/releases/1.8.5.txt
 docs/releases/1.8.6.txt
 docs/releases/1.8.7.txt
 docs/releases/1.8.8.txt
+docs/releases/1.8.9.txt
 docs/releases/1.8.txt
 docs/releases/index.txt
 docs/releases/security.txt
diff --git a/PKG-INFO b/PKG-INFO
index a62d086..42f9052 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: Django
-Version: 1.8.8
+Version: 1.8.9
 Summary: A high-level Python Web framework that encourages rapid development and clean, pragmatic design.
 Home-page: http://www.djangoproject.com/
 Author: Django Software Foundation
diff --git a/django/__init__.py b/django/__init__.py
index aa515b5..80244c4 100644
--- a/django/__init__.py
+++ b/django/__init__.py
@@ -1,6 +1,6 @@
 from django.utils.version import get_version
 
-VERSION = (1, 8, 8, 'final', 0)
+VERSION = (1, 8, 9, 'final', 0)
 
 __version__ = get_version(VERSION)
 
diff --git a/django/contrib/admin/helpers.py b/django/contrib/admin/helpers.py
index 1b6a0ff..36886bf 100644
--- a/django/contrib/admin/helpers.py
+++ b/django/contrib/admin/helpers.py
@@ -203,7 +203,7 @@ class AdminReadonlyField(object):
                     else:
                         result_repr = linebreaksbr(result_repr)
             else:
-                if isinstance(f.rel, ManyToManyRel) and value is not None:
+                if isinstance(getattr(f, 'rel', None), ManyToManyRel) and value is not None:
                     result_repr = ", ".join(map(six.text_type, value.all()))
                 else:
                     result_repr = display_for_field(value, f)
diff --git a/django/contrib/admin/sites.py b/django/contrib/admin/sites.py
index af40880..e08b932 100644
--- a/django/contrib/admin/sites.py
+++ b/django/contrib/admin/sites.py
@@ -355,7 +355,13 @@ class AdminSite(object):
         from django.contrib.auth.views import logout
         defaults = {
             'current_app': self.name,
-            'extra_context': dict(self.each_context(request), **(extra_context or {})),
+            'extra_context': dict(
+                self.each_context(request),
+                # Since the user isn't logged out at this point, the value of
+                # has_permission must be overridden.
+                has_permission=False,
+                **(extra_context or {})
+            ),
         }
         if self.logout_template is not None:
             defaults['template_name'] = self.logout_template
diff --git a/django/contrib/admin/static/admin/js/admin/DateTimeShortcuts.js b/django/contrib/admin/static/admin/js/admin/DateTimeShortcuts.js
index faec5a4..8d50046 100644
--- a/django/contrib/admin/static/admin/js/admin/DateTimeShortcuts.js
+++ b/django/contrib/admin/static/admin/js/admin/DateTimeShortcuts.js
@@ -292,8 +292,8 @@ var DateTimeShortcuts = {
         if (inp.value) {
             var format = get_format('DATE_INPUT_FORMATS')[0];
             var selected = inp.value.strptime(format);
-            var year = selected.getFullYear();
-            var month = selected.getMonth() + 1;
+            var year = selected.getUTCFullYear();
+            var month = selected.getUTCMonth() + 1;
             var re = /\d{4}/
             if (re.test(year.toString()) && month >= 1 && month <= 12) {
                 DateTimeShortcuts.calendars[num].drawDate(month, year, selected);
diff --git a/django/contrib/admin/static/admin/js/core.js b/django/contrib/admin/static/admin/js/core.js
index 2c096aa..7526bd3 100644
--- a/django/contrib/admin/static/admin/js/core.js
+++ b/django/contrib/admin/static/admin/js/core.js
@@ -225,7 +225,10 @@ String.prototype.strptime = function(format) {
         }
         ++i;
     };
-    return new Date(year, month, day);
+    // Create Date object from UTC since the parsed value is supposed to be in
+    // UTC, not local time. Also, the calendar uses UTC functions for date
+    // extraction.
+    return new Date(Date.UTC(year, month, day));
 }
 
 // ----------------------------------------------------------------------------
diff --git a/django/contrib/admin/utils.py b/django/contrib/admin/utils.py
index 8ddba50..1ea73d6 100644
--- a/django/contrib/admin/utils.py
+++ b/django/contrib/admin/utils.py
@@ -376,7 +376,7 @@ def display_for_field(value, field):
     from django.contrib.admin.templatetags.admin_list import _boolean_icon
     from django.contrib.admin.views.main import EMPTY_CHANGELIST_VALUE
 
-    if field.flatchoices:
+    if getattr(field, 'flatchoices', None):
         return dict(field.flatchoices).get(value, EMPTY_CHANGELIST_VALUE)
     # NullBooleanField needs special-case null-handling, so it comes
     # before the general null test.
diff --git a/django/contrib/auth/hashers.py b/django/contrib/auth/hashers.py
index f7f143b..a8583f7 100644
--- a/django/contrib/auth/hashers.py
+++ b/django/contrib/auth/hashers.py
@@ -349,7 +349,7 @@ class BCryptPasswordHasher(BCryptSHA256PasswordHasher):
 
     This hasher does not first hash the password which means it is subject to
     the 72 character bcrypt password truncation, most use cases should prefer
-    the BCryptSha512PasswordHasher.
+    the BCryptSHA256PasswordHasher.
 
     See: https://code.djangoproject.com/ticket/20138
     """
diff --git a/django/contrib/gis/templates/gis/openlayers.html b/django/contrib/gis/templates/gis/openlayers.html
index cbefb3a..0356a9d 100644
--- a/django/contrib/gis/templates/gis/openlayers.html
+++ b/django/contrib/gis/templates/gis/openlayers.html
@@ -1,4 +1,5 @@
-<style type="text/css">{% block map_css %}{% load i18n static %}{% get_current_language_bidi as LANGUAGE_BIDI %}
+{% load i18n l10n static %}
+<style type="text/css">{% block map_css %}{% get_current_language_bidi as LANGUAGE_BIDI %}
     #{{ id }}_map { width: {{ map_width }}px; height: {{ map_height }}px; }
     #{{ id }}_map .aligned label { float: inherit; }
     #{{ id }}_div_map { position: relative; vertical-align: top; float: {{ LANGUAGE_BIDI|yesno:"right,left" }}; }
@@ -25,7 +26,7 @@
             id: '{{ id }}',
             map_id: '{{ id }}_map',
             map_options: map_options,
-            map_srid: {{ map_srid }},
+            map_srid: {{ map_srid|unlocalize }},
             name: '{{ name }}'
         };
         {% endblock %}
diff --git a/django/db/backends/postgresql_psycopg2/schema.py b/django/db/backends/postgresql_psycopg2/schema.py
index e425154..884ac44 100644
--- a/django/db/backends/postgresql_psycopg2/schema.py
+++ b/django/db/backends/postgresql_psycopg2/schema.py
@@ -107,13 +107,13 @@ class DatabaseSchemaEditor(BaseDatabaseSchemaEditor):
             new_db_params, strict,
         )
         # Added an index? Create any PostgreSQL-specific indexes.
-        if ((not old_field.db_index and new_field.db_index) or (not old_field.unique and new_field.unique)):
+        if not old_field.db_index and not old_field.unique and (new_field.db_index or new_field.unique):
             like_index_statement = self._create_like_index_sql(model, new_field)
             if like_index_statement is not None:
                 self.execute(like_index_statement)
 
         # Removed an index? Drop any PostgreSQL-specific indexes.
-        if ((not new_field.db_index and old_field.db_index) or (not new_field.unique and old_field.unique)):
+        if (old_field.db_index or old_field.unique) and not (new_field.db_index or new_field.unique):
             index_to_remove = self._create_index_name(model, [old_field.column], suffix='_like')
             index_names = self._constraint_names(model, [old_field.column], index=True)
             for index_name in index_names:
diff --git a/django/db/models/lookups.py b/django/db/models/lookups.py
index d0b30ac..8428d38 100644
--- a/django/db/models/lookups.py
+++ b/django/db/models/lookups.py
@@ -92,6 +92,10 @@ class Transform(RegisterLookupMixin):
             bilateral_transforms.append((self.__class__, self.init_lookups))
         return bilateral_transforms
 
+    @cached_property
+    def contains_aggregate(self):
+        return self.lhs.contains_aggregate
+
 
 class Lookup(RegisterLookupMixin):
     lookup_name = None
@@ -194,6 +198,10 @@ class Lookup(RegisterLookupMixin):
     def as_sql(self, compiler, connection):
         raise NotImplementedError
 
+    @cached_property
+    def contains_aggregate(self):
+        return self.lhs.contains_aggregate or getattr(self.rhs, 'contains_aggregate', False)
+
 
 class BuiltinLookup(Lookup):
     def process_lhs(self, compiler, connection, lhs=None):
diff --git a/django/db/models/sql/where.py b/django/db/models/sql/where.py
index 2ba6cea..8cad3df 100644
--- a/django/db/models/sql/where.py
+++ b/django/db/models/sql/where.py
@@ -315,9 +315,9 @@ class WhereNode(tree.Node):
 
     @classmethod
     def _contains_aggregate(cls, obj):
-        if not isinstance(obj, tree.Node):
-            return getattr(obj.lhs, 'contains_aggregate', False) or getattr(obj.rhs, 'contains_aggregate', False)
-        return any(cls._contains_aggregate(c) for c in obj.children)
+        if isinstance(obj, tree.Node):
+            return any(cls._contains_aggregate(c) for c in obj.children)
+        return obj.contains_aggregate
 
     @cached_property
     def contains_aggregate(self):
@@ -336,6 +336,7 @@ class EverythingNode(object):
     """
     A node that matches everything.
     """
+    contains_aggregate = False
 
     def as_sql(self, compiler=None, connection=None):
         return '', []
@@ -345,11 +346,16 @@ class NothingNode(object):
     """
     A node that matches nothing.
     """
+    contains_aggregate = False
+
     def as_sql(self, compiler=None, connection=None):
         raise EmptyResultSet
 
 
 class ExtraWhere(object):
+    # The contents are a black box - assume no aggregates are used.
+    contains_aggregate = False
+
     def __init__(self, sqls, params):
         self.sqls = sqls
         self.params = params
@@ -410,6 +416,10 @@ class Constraint(object):
 
 
 class SubqueryConstraint(object):
+    # Even if aggregates would be used in a subquery, the outer query isn't
+    # interested about those.
+    contains_aggregate = False
+
     def __init__(self, alias, columns, targets, query_object):
         self.alias = alias
         self.columns = columns
diff --git a/django/dispatch/dispatcher.py b/django/dispatch/dispatcher.py
index 5d7f24c..ec59666 100644
--- a/django/dispatch/dispatcher.py
+++ b/django/dispatch/dispatcher.py
@@ -168,13 +168,13 @@ class Signal(object):
         Send signal from sender to all connected receivers.
 
         If any receiver raises an error, the error propagates back through send,
-        terminating the dispatch loop, so it is quite possible to not have all
-        receivers called if a raises an error.
+        terminating the dispatch loop. So it's possible that all receivers
+        won't be called if an error is raised.
 
         Arguments:
 
             sender
-                The sender of the signal Either a specific object or None.
+                The sender of the signal. Either a specific object or None.
 
             named
                 Named arguments which will be passed to receivers.
diff --git a/django/utils/functional.py b/django/utils/functional.py
index a3c0b88..b230273 100644
--- a/django/utils/functional.py
+++ b/django/utils/functional.py
@@ -240,6 +240,8 @@ class LazyObject(object):
     _wrapped = None
 
     def __init__(self):
+        # Note: if a subclass overrides __init__(), it will likely need to
+        # override __copy__() and __deepcopy__() as well.
         self._wrapped = empty
 
     __getattr__ = new_method_proxy(getattr)
@@ -292,6 +294,15 @@ class LazyObject(object):
     def __getstate__(self):
         return {}
 
+    def __copy__(self):
+        if self._wrapped is empty:
+            # If uninitialized, copy the wrapper. Use type(self), not
+            # self.__class__, because the latter is proxied.
+            return type(self)()
+        else:
+            # If initialized, return a copy of the wrapped object.
+            return copy.copy(self._wrapped)
+
     def __deepcopy__(self, memo):
         if self._wrapped is empty:
             # We have to use type(self), not self.__class__, because the
@@ -373,6 +384,15 @@ class SimpleLazyObject(LazyObject):
             repr_attr = self._wrapped
         return '<%s: %r>' % (type(self).__name__, repr_attr)
 
+    def __copy__(self):
+        if self._wrapped is empty:
+            # If uninitialized, copy the wrapper. Use SimpleLazyObject, not
+            # self.__class__, because the latter is proxied.
+            return SimpleLazyObject(self._setupfunc)
+        else:
+            # If initialized, return a copy of the wrapped object.
+            return copy.copy(self._wrapped)
+
     def __deepcopy__(self, memo):
         if self._wrapped is empty:
             # We have to use SimpleLazyObject, not self.__class__, because the
diff --git a/django/utils/translation/trans_real.py b/django/utils/translation/trans_real.py
index aa50c02..8aa8f4e 100644
--- a/django/utils/translation/trans_real.py
+++ b/django/utils/translation/trans_real.py
@@ -121,6 +121,9 @@ class DjangoTranslation(gettext_module.GNUTranslations):
             # default lang should have at least one translation file available.
             raise IOError("No translation files found for default language %s." % settings.LANGUAGE_CODE)
         self._add_fallback()
+        if self._catalog is None:
+            # No catalogs found for this language, set an empty catalog.
+            self._catalog = {}
 
     def __repr__(self):
         return "<DjangoTranslation lang:%s>" % self.__language
diff --git a/docs/howto/deployment/wsgi/modwsgi.txt b/docs/howto/deployment/wsgi/modwsgi.txt
index 90ca1c0..985926c 100644
--- a/docs/howto/deployment/wsgi/modwsgi.txt
+++ b/docs/howto/deployment/wsgi/modwsgi.txt
@@ -157,10 +157,9 @@ If, however, you have no option but to serve media files on the same Apache
 ``VirtualHost`` as Django, you can set up Apache to serve some URLs as
 static media, and others using the mod_wsgi interface to Django.
 
-This example sets up Django at the site root, but explicitly serves
-``robots.txt``, ``favicon.ico``, any CSS file, and anything in the
-``/static/`` and ``/media/`` URL space as a static file. All other URLs
-will be served using mod_wsgi:
+This example sets up Django at the site root, but serves ``robots.txt``,
+``favicon.ico``, and anything in the ``/static/`` and ``/media/`` URL space as
+a static file. All other URLs will be served using mod_wsgi:
 
 .. code-block:: apache
 
diff --git a/docs/intro/reusable-apps.txt b/docs/intro/reusable-apps.txt
index 3c8041e..245a88b 100644
--- a/docs/intro/reusable-apps.txt
+++ b/docs/intro/reusable-apps.txt
@@ -215,6 +215,7 @@ this. For a small app like polls, this process isn't too difficult.
            classifiers=[
                'Environment :: Web Environment',
                'Framework :: Django',
+               'Framework :: Django :: X.Y',  # replace "X.Y" as appropriate
                'Intended Audience :: Developers',
                'License :: OSI Approved :: BSD License', # example license
                'Operating System :: OS Independent',
diff --git a/docs/ref/csrf.txt b/docs/ref/csrf.txt
index 85810b9..dbc05b6 100644
--- a/docs/ref/csrf.txt
+++ b/docs/ref/csrf.txt
@@ -40,7 +40,7 @@ To take advantage of CSRF protection in your views, follow these steps:
 2. In any template that uses a POST form, use the :ttag:`csrf_token` tag inside
    the ``<form>`` element if the form is for an internal URL, e.g.::
 
-       <form action="." method="post">{% csrf_token %}
+       <form action="" method="post">{% csrf_token %}
 
    This should not be done for POST forms that target external URLs, since
    that would cause the CSRF token to be leaked, leading to a vulnerability.
diff --git a/docs/ref/databases.txt b/docs/ref/databases.txt
index dd3ea36..ed15390 100644
--- a/docs/ref/databases.txt
+++ b/docs/ref/databases.txt
@@ -448,7 +448,7 @@ storage engine, you have a couple of options.
   creating your tables::
 
       'OPTIONS': {
-         'init_command': 'SET storage_engine=INNODB',
+         'init_command': 'SET default_storage_engine=INNODB',
       }
 
   This sets the default storage engine upon connecting to the database.
diff --git a/docs/releases/1.8.9.txt b/docs/releases/1.8.9.txt
new file mode 100644
index 0000000..92f35ec
--- /dev/null
+++ b/docs/releases/1.8.9.txt
@@ -0,0 +1,39 @@
+==========================
+Django 1.8.9 release notes
+==========================
+
+*February 1, 2016*
+
+Django 1.8.9 fixes several bugs in 1.8.8.
+
+Bugfixes
+========
+
+* Fixed a regression that caused the "user-tools" items to display on the
+  admin's logout page (:ticket:`26035`).
+
+* Fixed a crash in the translations system when the current language has no
+  translations (:ticket:`26046`).
+
+* Fixed a regression that caused the incorrect day to be selected when opening
+  the admin calendar widget for timezones from GMT+0100 to GMT+1200
+  (:ticket:`24980`).
+
+* Fixed a regression in 1.8.8 causing incorrect index handling in migrations on
+  PostgreSQL when adding ``db_index=True`` or ``unique=True`` to a
+  ``CharField`` or ``TextField`` that already had the other specified, or when
+  removing one of them from a field that had both, or when adding
+  ``unique=True`` to a field already listed in ``unique_together``
+  (:ticket:`26034`).
+
+* Fixed a crash when using an ``__in`` lookup inside a ``Case`` expression
+  (:ticket:`26071`).
+
+* Fixed a crash when using a reverse ``OneToOneField`` in
+  ``ModelAdmin.readonly_fields`` (:ticket:`26060`).
+
+* Fixed a regression in Django 1.8.5 that broke copying a ``SimpleLazyObject``
+  with ``copy.copy()`` (:ticket:`26122`).
+
+* Fixed the ``contrib.gis`` map widgets when using
+  ``USE_THOUSAND_SEPARATOR=True`` (:ticket:`20415`).
diff --git a/docs/releases/index.txt b/docs/releases/index.txt
index ec4f0cc..9e6257b 100644
--- a/docs/releases/index.txt
+++ b/docs/releases/index.txt
@@ -25,6 +25,7 @@ versions of the documentation contain the release notes for any later releases.
 .. toctree::
    :maxdepth: 1
 
+   1.8.9
    1.8.8
    1.8.7
    1.8.6
diff --git a/docs/topics/i18n/translation.txt b/docs/topics/i18n/translation.txt
index 7f6de9e..db33e65 100644
--- a/docs/topics/i18n/translation.txt
+++ b/docs/topics/i18n/translation.txt
@@ -70,8 +70,6 @@ as a shorter alias, ``_``, to save typing.
        global ``_()`` function causes interference. Explicitly importing
        ``ugettext()`` as ``_()`` avoids this problem.
 
-.. highlightlang:: python
-
 In this example, the text ``"Welcome to my site."`` is marked as a translation
 string::
 
@@ -960,7 +958,7 @@ You hook it up like this::
     }
 
     urlpatterns = [
-        url(r'^jsi18n/$', javascript_catalog, js_info_dict),
+        url(r'^jsi18n/$', javascript_catalog, js_info_dict, name='javascript-catalog'),
     ]
 
 Each string in ``packages`` should be in Python dotted-package syntax (the
@@ -980,7 +978,7 @@ changed by altering the ``domain`` argument.
 You can make the view dynamic by putting the packages into the URL pattern::
 
     urlpatterns = [
-        url(r'^jsi18n/(?P<packages>\S+?)/$', javascript_catalog),
+        url(r'^jsi18n/(?P<packages>\S+?)/$', javascript_catalog, name='javascript-catalog'),
     ]
 
 With this, you specify the packages as a list of package names delimited by '+'
@@ -1005,7 +1003,7 @@ To use the catalog, just pull in the dynamically generated script like this:
 
 .. code-block:: html+django
 
-    <script type="text/javascript" src="{% url 'django.views.i18n.javascript_catalog' %}"></script>
+    <script type="text/javascript" src="{% url 'javascript-catalog' %}"></script>
 
 This uses reverse URL lookup to find the URL of the JavaScript catalog view.
 When the catalog is loaded, your JavaScript code can use the following methods:
@@ -1158,6 +1156,8 @@ Additionally, if there are complex rules around pluralization, the catalog view
 will render a conditional expression. This will evaluate to either a ``true``
 (should pluralize) or ``false`` (should **not** pluralize) value.
 
+.. highlightlang:: python
+
 Note on performance
 -------------------
 
@@ -1269,8 +1269,8 @@ After defining these URL patterns, Django will automatically add the
 language prefix to the URL patterns that were added by the ``i18n_patterns``
 function. Example::
 
-    from django.core.urlresolvers import reverse
-    from django.utils.translation import activate
+    >>> from django.core.urlresolvers import reverse
+    >>> from django.utils.translation import activate
 
     >>> activate('en')
     >>> reverse('sitemap-xml')
@@ -1327,8 +1327,8 @@ After you've created the translations, the
 :func:`~django.core.urlresolvers.reverse` function will return the URL in the
 active language. Example::
 
-    from django.core.urlresolvers import reverse
-    from django.utils.translation import activate
+    >>> from django.core.urlresolvers import reverse
+    >>> from django.utils.translation import activate
 
     >>> activate('en')
     >>> reverse('news:category', kwargs={'slug': 'recent'})
@@ -1624,8 +1624,6 @@ translation utilities with a ``gettext`` package if the command ``xgettext
 Customizing the ``makemessages`` command
 ----------------------------------------
 
-.. highlightlang:: python
-
 If you want to pass additional parameters to ``xgettext``, you need to create a
 custom :djadmin:`makemessages` command and override its ``xgettext_options``
 attribute::
@@ -1664,8 +1662,6 @@ Miscellaneous
 The ``set_language`` redirect view
 ----------------------------------
 
-.. highlightlang:: python
-
 .. currentmodule:: django.views.i18n
 
 .. function:: set_language(request)
@@ -1728,8 +1724,6 @@ redirected in the ``redirect_to`` context variable.
 Explicitly setting the active language
 --------------------------------------
 
-.. highlightlang:: python
-
 You may want to set the active language for the current session explicitly. Perhaps
 a user's language preference is retrieved from another system, for example.
 You've already been introduced to :func:`django.utils.translation.activate()`. That
diff --git a/docs/topics/security.txt b/docs/topics/security.txt
index 62be131..b3639ba 100644
--- a/docs/topics/security.txt
+++ b/docs/topics/security.txt
@@ -29,7 +29,8 @@ which are particularly dangerous to HTML. While this protects users from most
 malicious input, it is not entirely foolproof. For example, it will not
 protect the following:
 
-.. code-block:: html+django
+.. code-block:: text
+..   highlighting as html+django fails due to intentionally missing quotes.
 
     <style class={{ var }}>...</style>
 
diff --git a/setup.cfg b/setup.cfg
index fac4f6b..e4cafa8 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -22,6 +22,6 @@ universal = 1
 
 [egg_info]
 tag_build = 
-tag_date = 0
 tag_svn_revision = 0
+tag_date = 0
 
diff --git a/tests/admin_scripts/tests.py b/tests/admin_scripts/tests.py
index 7b2617e..a8617fb 100644
--- a/tests/admin_scripts/tests.py
+++ b/tests/admin_scripts/tests.py
@@ -61,6 +61,7 @@ class AdminScriptTestCase(unittest.TestCase):
                 'SECRET_KEY',
                 'TEST_RUNNER',  # We need to include TEST_RUNNER, otherwise we get a compatibility warning.
                 'MIDDLEWARE_CLASSES',  # We need to include MIDDLEWARE_CLASSES, otherwise we get a compatibility warning.
+                'SPATIALITE_LIBRARY_PATH',
             ]
             for s in exports:
                 if hasattr(settings, s):
diff --git a/tests/admin_views/admin.py b/tests/admin_views/admin.py
index 7a6b25b..68960df 100644
--- a/tests/admin_views/admin.py
+++ b/tests/admin_views/admin.py
@@ -34,15 +34,15 @@ from .models import (
     InlineReference, InlineReferer, Inquisition, Language, Link,
     MainPrepopulated, ModelWithStringPrimaryKey, NotReferenced, OldSubscriber,
     OtherStory, Paper, Parent, ParentWithDependentChildren, Person, Persona,
-    Picture, Pizza, Plot, PlotDetails, PluggableSearchPerson, Podcast, Post,
-    PrePopulatedPost, PrePopulatedPostLargeSlug, PrePopulatedSubPost, Promo,
-    Question, Recipe, Recommendation, Recommender, ReferencedByGenRel,
-    ReferencedByInline, ReferencedByParent, RelatedPrepopulated, Report,
-    Reservation, Restaurant, RowLevelChangePermissionModel, Section,
-    ShortMessage, Simple, Sketch, State, Story, StumpJoke, Subscriber,
-    SuperVillain, Telegram, Thing, Topping, UnchangeableObject,
-    UndeletableObject, UnorderedObject, UserMessenger, Villain, Vodcast,
-    Whatsit, Widget, Worker, WorkHour,
+    Picture, Pizza, Plot, PlotDetails, PlotProxy, PluggableSearchPerson,
+    Podcast, Post, PrePopulatedPost, PrePopulatedPostLargeSlug,
+    PrePopulatedSubPost, Promo, Question, Recipe, Recommendation, Recommender,
+    ReferencedByGenRel, ReferencedByInline, ReferencedByParent,
+    RelatedPrepopulated, Report, Reservation, Restaurant,
+    RowLevelChangePermissionModel, Section, ShortMessage, Simple, Sketch,
+    State, Story, StumpJoke, Subscriber, SuperVillain, Telegram, Thing,
+    Topping, UnchangeableObject, UndeletableObject, UnorderedObject,
+    UserMessenger, Villain, Vodcast, Whatsit, Widget, Worker, WorkHour,
 )
 
 
@@ -853,6 +853,10 @@ class InlineRefererAdmin(admin.ModelAdmin):
     inlines = [InlineReferenceInline]
 
 
+class PlotReadonlyAdmin(admin.ModelAdmin):
+    readonly_fields = ('plotdetails',)
+
+
 class GetFormsetsArgumentCheckingAdmin(admin.ModelAdmin):
     fields = ['name']
 
@@ -907,6 +911,7 @@ site.register(Villain)
 site.register(SuperVillain)
 site.register(Plot)
 site.register(PlotDetails)
+site.register(PlotProxy, PlotReadonlyAdmin)
 site.register(CyclicOne)
 site.register(CyclicTwo)
 site.register(WorkHour, WorkHourAdmin)
diff --git a/tests/admin_views/models.py b/tests/admin_views/models.py
index d68c44f..9218241 100644
--- a/tests/admin_views/models.py
+++ b/tests/admin_views/models.py
@@ -501,12 +501,17 @@ class Plot(models.Model):
 @python_2_unicode_compatible
 class PlotDetails(models.Model):
     details = models.CharField(max_length=100)
-    plot = models.OneToOneField(Plot)
+    plot = models.OneToOneField(Plot, null=True, blank=True)
 
     def __str__(self):
         return self.details
 
 
+class PlotProxy(Plot):
+    class Meta:
+        proxy = True
+
+
 @python_2_unicode_compatible
 class SecretHideout(models.Model):
     """ Secret! Not registered with the admin! """
diff --git a/tests/admin_views/tests.py b/tests/admin_views/tests.py
index a64e4d7..cb804dc 100644
--- a/tests/admin_views/tests.py
+++ b/tests/admin_views/tests.py
@@ -52,11 +52,11 @@ from .models import (
     FoodDelivery, FunkyTag, Gallery, Grommet, Inquisition, Language, Link,
     MainPrepopulated, ModelWithStringPrimaryKey, OtherStory, Paper, Parent,
     ParentWithDependentChildren, Person, Persona, Picture, Pizza, Plot,
-    PluggableSearchPerson, Podcast, Post, Promo, Question, RelatedPrepopulated,
-    Report, Restaurant, RowLevelChangePermissionModel, Section, ShortMessage,
-    Simple, Story, Subscriber, Telegram, Topping, UnchangeableObject,
-    UndeletableObject, UnorderedObject, Vodcast, Whatsit, Widget, Worker,
-    WorkHour,
+    PlotDetails, PluggableSearchPerson, Podcast, Post, Promo, Question,
+    RelatedPrepopulated, Report, Restaurant, RowLevelChangePermissionModel,
+    Section, ShortMessage, Simple, Story, Subscriber, Telegram, Topping,
+    UnchangeableObject, UndeletableObject, UnorderedObject, Villain, Vodcast,
+    Whatsit, Widget, Worker, WorkHour,
 )
 
 
@@ -64,6 +64,44 @@ ERROR_MESSAGE = "Please enter the correct username and password \
 for a staff account. Note that both fields may be case-sensitive."
 
 
+class AdminFieldExtractionMixin(object):
+    """
+    Helper methods for extracting data from AdminForm.
+    """
+    def get_admin_form_fields(self, response):
+        """
+        Return a list of AdminFields for the AdminForm in the response.
+        """
+        admin_form = response.context['adminform']
+        fieldsets = list(admin_form)
+
+        field_lines = []
+        for fieldset in fieldsets:
+            field_lines += list(fieldset)
+
+        fields = []
+        for field_line in field_lines:
+            fields += list(field_line)
+
+        return fields
+
+    def get_admin_fields(self, response):
+        """
+        Return the fields for the response's AdminForm.
+        """
+        return [f for f in self.get_admin_form_fields(response)]
+
+    def get_admin_field(self, response, field_name):
+        """
+        Return the field for the given field_name.
+        """
+        fields = self.get_admin_fields(response)
+        for field in fields:
+            name = field.field['name'] if isinstance(field.field, dict) else field.field.name
+            if name == field_name:
+                return field
+
+
 @override_settings(PASSWORD_HASHERS=('django.contrib.auth.hashers.SHA1PasswordHasher',),
                    ROOT_URLCONF="admin_views.urls",
                    USE_I18N=True, USE_L10N=False, LANGUAGE_CODE='en')
@@ -4029,7 +4067,7 @@ class SeleniumAdminViewsIETests(SeleniumAdminViewsFirefoxTests):
 
 @override_settings(PASSWORD_HASHERS=('django.contrib.auth.hashers.SHA1PasswordHasher',),
     ROOT_URLCONF="admin_views.urls")
-class ReadonlyTest(TestCase):
+class ReadonlyTest(AdminFieldExtractionMixin, TestCase):
     fixtures = ['admin-views-users.xml']
 
     def setUp(self):
@@ -4126,7 +4164,7 @@ class ReadonlyTest(TestCase):
         self.assertContains(response, '<p>No opinion</p>', html=True)
         self.assertNotContains(response, '<p>(None)</p>')
 
-    def test_readonly_backwards_ref(self):
+    def test_readonly_manytomany_backwards_ref(self):
         """
         Regression test for #16433 - backwards references for related objects
         broke if the related field is read-only due to the help_text attribute
@@ -4137,6 +4175,26 @@ class ReadonlyTest(TestCase):
         response = self.client.get(reverse('admin:admin_views_topping_add'))
         self.assertEqual(response.status_code, 200)
 
+    def test_readonly_onetoone_backwards_ref(self):
+        """
+        Can reference a reverse OneToOneField in ModelAdmin.readonly_fields.
+        """
+        v1 = Villain.objects.create(name='Adam')
+        pl = Plot.objects.create(name='Test Plot', team_leader=v1, contact=v1)
+        pd = PlotDetails.objects.create(details='Brand New Plot', plot=pl)
+
+        response = self.client.get(reverse('admin:admin_views_plotproxy_change', args=(pl.pk,)))
+        field = self.get_admin_field(response, 'plotdetails')
+        self.assertEqual(field.contents(), 'Brand New Plot')
+
+        # The reverse relation also works if the OneToOneField is null.
+        pd.plot = None
+        pd.save()
+
+        response = self.client.get(reverse('admin:admin_views_plotproxy_change', args=(pl.pk,)))
+        field = self.get_admin_field(response, 'plotdetails')
+        self.assertEqual(force_text(field.contents()), '(None)')
+
     def test_readonly_field_overrides(self):
         """
         Regression test for #22087 - ModelForm Meta overrides are ignored by
@@ -4832,19 +4890,19 @@ class AdminCustomSaveRelatedTests(TestCase):
 
 @override_settings(PASSWORD_HASHERS=('django.contrib.auth.hashers.SHA1PasswordHasher',),
     ROOT_URLCONF="admin_views.urls")
-class AdminViewLogoutTest(TestCase):
+class AdminViewLogoutTests(TestCase):
     fixtures = ['admin-views-users.xml']
 
-    def setUp(self):
+    def test_logout(self):
         self.client.login(username='super', password='secret')
-
-    def test_client_logout_url_can_be_used_to_login(self):
         response = self.client.get(reverse('admin:logout'))
         self.assertEqual(response.status_code, 200)
         self.assertTemplateUsed(response, 'registration/logged_out.html')
         self.assertEqual(response.request['PATH_INFO'], reverse('admin:logout'))
+        self.assertFalse(response.context['has_permission'])
+        self.assertNotContains(response, 'user-tools')  # user-tools div shouldn't visible.
 
-        # we are now logged out
+    def test_client_logout_url_can_be_used_to_login(self):
         response = self.client.get(reverse('admin:logout'))
         self.assertEqual(response.status_code, 302)  # we should be redirected to the login page.
 
diff --git a/tests/expressions_case/tests.py b/tests/expressions_case/tests.py
index 27aef93..de1859b 100644
--- a/tests/expressions_case/tests.py
+++ b/tests/expressions_case/tests.py
@@ -8,7 +8,7 @@ from uuid import UUID
 
 from django.core.exceptions import FieldError
 from django.db import connection, models
-from django.db.models import F, Q, Max, Min, Value
+from django.db.models import F, Q, Max, Min, Sum, Value
 from django.db.models.expressions import Case, When
 from django.test import TestCase
 from django.utils import six
@@ -119,6 +119,17 @@ class CaseExpressionTests(TestCase):
             transform=attrgetter('integer', 'join_test')
         )
 
+    def test_annotate_with_in_clause(self):
+        fk_rels = FKCaseTestModel.objects.filter(integer__in=[5])
+        self.assertQuerysetEqual(
+            CaseTestModel.objects.only('pk', 'integer').annotate(in_test=Sum(Case(
+                When(fk_rel__in=fk_rels, then=F('fk_rel__integer')),
+                default=Value(0),
+            ))).order_by('pk'),
+            [(1, 0), (2, 0), (3, 0), (2, 0), (3, 0), (3, 0), (4, 5)],
+            transform=attrgetter('integer', 'in_test')
+        )
+
     def test_annotate_with_join_in_condition(self):
         self.assertQuerysetEqual(
             CaseTestModel.objects.annotate(join_test=Case(
diff --git a/tests/forms_tests/templates/forms_tests/article_form.html b/tests/forms_tests/templates/forms_tests/article_form.html
index de38466..8ab7a85 100644
--- a/tests/forms_tests/templates/forms_tests/article_form.html
+++ b/tests/forms_tests/templates/forms_tests/article_form.html
@@ -1,6 +1,6 @@
 <html>
 <body>
-  <form method="post" action=".">{% csrf_token %}
+  <form method="post" action="">{% csrf_token %}
     {{ form.as_p }}<br>
     <input id="submit" type="submit">
   </form>
diff --git a/tests/gis_tests/distapp/tests.py b/tests/gis_tests/distapp/tests.py
index bde78a8..a047980 100644
--- a/tests/gis_tests/distapp/tests.py
+++ b/tests/gis_tests/distapp/tests.py
@@ -142,7 +142,7 @@ class DistanceTest(TestCase):
         """
         Test the `distance` GeoQuerySet method on geodetic coordinate systems.
         """
-        tol = 2 if oracle else 5
+        tol = 2 if oracle else 4
 
         # Testing geodetic distance calculation with a non-point geometry
         # (a LineString of Wollongong and Shellharbour coords).
diff --git a/tests/gis_tests/geogapp/tests.py b/tests/gis_tests/geogapp/tests.py
index e3e97f4..e2f7dc2 100644
--- a/tests/gis_tests/geogapp/tests.py
+++ b/tests/gis_tests/geogapp/tests.py
@@ -12,7 +12,7 @@ from django.contrib.gis.measure import D
 from django.test import TestCase, skipUnlessDBFeature
 from django.utils._os import upath
 
-from ..utils import oracle, postgis
+from ..utils import postgis
 
 if HAS_GEOS:
     from .models import City, County, Zipcode
@@ -97,7 +97,9 @@ class GeographyTest(TestCase):
     def test06_geography_area(self):
         "Testing that Area calculations work on geography columns."
         # SELECT ST_Area(poly) FROM geogapp_zipcode WHERE code='77002';
-        ref_area = 5439100.95415646 if oracle else 5439084.70637573
-        tol = 5
         z = Zipcode.objects.area().get(code='77002')
-        self.assertAlmostEqual(z.area.sq_m, ref_area, tol)
+        # Round to the nearest thousand as possible values (depending on
+        # the database and geolib) include 5439084, 5439100, 5439101.
+        rounded_value = z.area.sq_m
+        rounded_value -= z.area.sq_m % 1000
+        self.assertEqual(rounded_value, 5439000)
diff --git a/tests/gis_tests/test_geoforms.py b/tests/gis_tests/test_geoforms.py
index bcbb5f0..d7fb631 100644
--- a/tests/gis_tests/test_geoforms.py
+++ b/tests/gis_tests/test_geoforms.py
@@ -2,7 +2,7 @@ from unittest import skipUnless
 
 from django.contrib.gis.gdal import HAS_GDAL
 from django.forms import ValidationError
-from django.test import SimpleTestCase, skipUnlessDBFeature
+from django.test import SimpleTestCase, override_settings, skipUnlessDBFeature
 from django.utils import six
 from django.utils.html import escape
 
@@ -154,6 +154,7 @@ class SpecializedFieldTest(SimpleTestCase):
         self.assertTrue(form_instance.is_valid())
         rendered = form_instance.as_p()
         self.assertIn('new MapWidget(options);', rendered)
+        self.assertIn('map_srid: 4326,', rendered)
         self.assertIn('gis/js/OLMapWidget.js', str(form_instance.media))
 
     def assertTextarea(self, geom, rendered):
@@ -163,6 +164,8 @@ class SpecializedFieldTest(SimpleTestCase):
         self.assertIn('required', rendered)
         self.assertIn(geom.wkt, rendered)
 
+    # map_srid in operlayers.html template must not be localized.
+    @override_settings(USE_L10N=True, USE_THOUSAND_SEPARATOR=True)
     def test_pointfield(self):
         class PointForm(forms.Form):
             p = forms.PointField()
diff --git a/tests/i18n/tests.py b/tests/i18n/tests.py
index 9a20ba5..7150578 100644
--- a/tests/i18n/tests.py
+++ b/tests/i18n/tests.py
@@ -1273,6 +1273,10 @@ class TestLanguageInfo(TestCase):
 
     def test_unknown_language_code(self):
         six.assertRaisesRegex(self, KeyError, r"Unknown language code xx\.", get_language_info, 'xx')
+        with translation.override('xx'):
+            # A language with no translation catalogs should fallback to the
+            # untranslated string.
+            self.assertEqual(ugettext("Title"), "Title")
 
     def test_unknown_only_country_code(self):
         li = get_language_info('de-xx')
diff --git a/tests/migrations/test_writer.py b/tests/migrations/test_writer.py
index a6527ca..f03e84c 100644
--- a/tests/migrations/test_writer.py
+++ b/tests/migrations/test_writer.py
@@ -281,6 +281,8 @@ class WriterTests(TestCase):
             SettingsReference("someapp.model", "AUTH_USER_MODEL"),
             ("settings.AUTH_USER_MODEL", {"from django.conf import settings"})
         )
+
+    def test_serialize_iterators(self):
... 323 lines suppressed ...

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/python-django.git



More information about the Python-modules-commits mailing list