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

Raphaël Hertzog hertzog at moszumanska.debian.org
Tue Mar 8 17:27:49 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 8fea21d6d20c57d58d53c0df77531bb93883bfee
Author: Raphaël Hertzog <hertzog at debian.org>
Date:   Tue Mar 8 17:50:36 2016 +0100

    Import python-django_1.8.11.orig.tar.gz
---
 Django.egg-info/PKG-INFO                           |   2 +-
 Django.egg-info/SOURCES.txt                        |   3 +
 PKG-INFO                                           |   2 +-
 django/__init__.py                                 |   2 +-
 django/contrib/admin/actions.py                    |   2 +-
 django/contrib/auth/context_processors.py          |   2 +-
 django/contrib/auth/hashers.py                     |  77 ++++++++++----
 django/contrib/contenttypes/models.py              |  20 ++--
 django/contrib/gis/db/backends/postgis/models.py   |   2 +-
 django/contrib/gis/db/models/query.py              |   2 +-
 django/contrib/gis/gdal/geomtype.py                |   2 +-
 django/contrib/gis/sitemaps/kml.py                 |   2 +-
 django/contrib/postgres/fields/array.py            |   7 +-
 django/contrib/postgres/fields/ranges.py           |   8 +-
 django/core/validators.py                          |   9 +-
 django/db/backends/postgresql_psycopg2/base.py     |   2 +-
 django/db/models/expressions.py                    |   2 +-
 django/db/models/fields/related.py                 |  19 ++--
 django/db/models/query_utils.py                    |   2 +-
 django/forms/forms.py                              |   2 +-
 django/template/defaultfilters.py                  |   2 +-
 django/template/defaulttags.py                     |   2 +-
 django/test/signals.py                             |   2 +-
 django/utils/http.py                               |  13 ++-
 django/utils/translation/__init__.py               |   7 ++
 docs/_theme/djangodocs/static/djangodocs.css       |   2 +-
 docs/conf.py                                       |  11 +-
 docs/howto/custom-model-fields.txt                 |   3 +-
 docs/howto/outputting-pdf.txt                      |   2 +-
 docs/internals/deprecation.txt                     |   3 +
 docs/intro/reusable-apps.txt                       |   4 +-
 docs/ref/contrib/gis/feeds.txt                     |   4 +-
 docs/ref/contrib/gis/testing.txt                   |   4 +-
 docs/ref/contrib/gis/tutorial.txt                  |   8 +-
 docs/ref/contrib/syndication.txt                   |   2 +-
 docs/ref/models/expressions.txt                    |   6 +-
 docs/ref/settings.txt                              |  27 ++---
 docs/ref/validators.txt                            |   6 +-
 docs/releases/1.6.txt                              |   4 +-
 docs/releases/1.8.10.txt                           |  80 +++++++++++++++
 docs/releases/1.8.11.txt                           |   8 ++
 docs/releases/1.8.txt                              |   7 +-
 docs/releases/index.txt                            |   2 +
 docs/releases/security.txt                         |  38 +++++++
 docs/spelling_wordlist                             |   2 +
 docs/topics/auth/customizing.txt                   |  61 +----------
 docs/topics/auth/default.txt                       |   2 +-
 docs/topics/auth/passwords.txt                     | 113 +++++++++++++++++++++
 docs/topics/db/multi-db.txt                        |   4 +-
 docs/topics/email.txt                              |   2 +
 docs/topics/testing/tools.txt                      |   1 -
 setup.cfg                                          |   2 +-
 tests/admin_changelist/tests.py                    |   2 +-
 tests/aggregation_regress/tests.py                 |   4 +-
 tests/auth_tests/test_forms.py                     |   2 +-
 tests/auth_tests/test_hashers.py                   |  58 ++++++++++-
 tests/auth_tests/test_views.py                     |  10 +-
 tests/backends/tests.py                            |   5 +
 tests/check_framework/test_security.py             |   6 +-
 tests/contenttypes_tests/test_models.py            |  14 ++-
 tests/expressions_case/tests.py                    |   2 +-
 tests/forms_tests/tests/test_fields.py             |   3 +
 tests/forms_tests/tests/test_forms.py              |  16 ++-
 tests/forms_tests/tests/tests.py                   |   2 +-
 tests/httpwrappers/tests.py                        |   2 +-
 tests/i18n/commands/__init__.py                    |   2 +-
 tests/i18n/tests.py                                |   8 ++
 tests/invalid_models_tests/test_models.py          |   2 +-
 tests/invalid_models_tests/test_relative_fields.py |  36 +++++--
 tests/m2m_through/tests.py                         |   8 +-
 tests/middleware/tests.py                          |   4 +-
 tests/migrations/test_writer.py                    |   8 +-
 tests/model_fields/models.py                       |   8 +-
 tests/model_options/test_default_related_name.py   |   2 +-
 tests/modeladmin/tests.py                          |   2 +-
 tests/null_fk_ordering/models.py                   |   4 +-
 tests/postgres_tests/test_array.py                 |   8 +-
 tests/postgres_tests/test_hstore.py                |   9 +-
 tests/postgres_tests/test_ranges.py                |  11 ++
 tests/proxy_models/tests.py                        |   2 +-
 tests/queries/models.py                            |   2 +-
 tests/queries/tests.py                             |   6 +-
 tests/queryset_pickle/tests.py                     |   2 +-
 tests/requests/tests.py                            |  14 +--
 tests/serializers_regress/tests.py                 |   2 +-
 tests/signals/tests.py                             |   2 +-
 tests/staticfiles_tests/test_liveserver.py         |   2 +-
 tests/template_tests/test_response.py              |   4 +-
 tests/template_tests/test_response_deprecations.py |  42 ++++++++
 tests/test_runner/test_discover_runner.py          |   6 +-
 tests/timezones/tests.py                           |   2 +-
 tests/unmanaged_models/models.py                   |   2 +-
 tests/utils_tests/files/strip_tags2.txt            |   2 +-
 tests/utils_tests/test_http.py                     |  28 ++++-
 tests/validators/invalid_urls.txt                  |   4 +-
 tests/validators/valid_urls.txt                    |   4 +
 96 files changed, 731 insertions(+), 236 deletions(-)

diff --git a/Django.egg-info/PKG-INFO b/Django.egg-info/PKG-INFO
index 42f9052..c536eb8 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.9
+Version: 1.8.11
 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 4b68a10..5399da9 100644
--- a/Django.egg-info/SOURCES.txt
+++ b/Django.egg-info/SOURCES.txt
@@ -3402,6 +3402,8 @@ docs/releases/1.7.8.txt
 docs/releases/1.7.9.txt
 docs/releases/1.7.txt
 docs/releases/1.8.1.txt
+docs/releases/1.8.10.txt
+docs/releases/1.8.11.txt
 docs/releases/1.8.2.txt
 docs/releases/1.8.3.txt
 docs/releases/1.8.4.txt
@@ -4794,6 +4796,7 @@ tests/template_tests/test_loaders.py
 tests/template_tests/test_nodelist.py
 tests/template_tests/test_parser.py
 tests/template_tests/test_response.py
+tests/template_tests/test_response_deprecations.py
 tests/template_tests/test_smartif.py
 tests/template_tests/test_unicode.py
 tests/template_tests/tests.py
diff --git a/PKG-INFO b/PKG-INFO
index 42f9052..c536eb8 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: Django
-Version: 1.8.9
+Version: 1.8.11
 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 80244c4..99e91ca 100644
--- a/django/__init__.py
+++ b/django/__init__.py
@@ -1,6 +1,6 @@
 from django.utils.version import get_version
 
-VERSION = (1, 8, 9, 'final', 0)
+VERSION = (1, 8, 11, 'final', 0)
 
 __version__ = get_version(VERSION)
 
diff --git a/django/contrib/admin/actions.py b/django/contrib/admin/actions.py
index 4445dd5..c4cccfd 100644
--- a/django/contrib/admin/actions.py
+++ b/django/contrib/admin/actions.py
@@ -16,7 +16,7 @@ def delete_selected(modeladmin, request, queryset):
     """
     Default action which deletes the selected objects.
 
-    This action first displays a confirmation page whichs shows all the
+    This action first displays a confirmation page which shows all the
     deleteable objects, or, if the user has no permission one of the related
     childs (foreignkeys), a "permission denied" message.
 
diff --git a/django/contrib/auth/context_processors.py b/django/contrib/auth/context_processors.py
index 474002e..ce1e42d 100644
--- a/django/contrib/auth/context_processors.py
+++ b/django/contrib/auth/context_processors.py
@@ -13,7 +13,7 @@ class PermLookupDict(object):
         return self.user.has_perm("%s.%s" % (self.app_label, perm_name))
 
     def __iter__(self):
-        # To fix 'item in perms.someapp' and __getitem__ iteraction we need to
+        # To fix 'item in perms.someapp' and __getitem__ interaction we need to
         # define __iter__. See #18979 for details.
         raise TypeError("PermLookupDict is not iterable.")
 
diff --git a/django/contrib/auth/hashers.py b/django/contrib/auth/hashers.py
index a8583f7..01f4cec 100644
--- a/django/contrib/auth/hashers.py
+++ b/django/contrib/auth/hashers.py
@@ -4,6 +4,7 @@ import base64
 import binascii
 import hashlib
 import importlib
+import warnings
 from collections import OrderedDict
 
 from django.conf import settings
@@ -46,10 +47,17 @@ def check_password(password, encoded, setter=None, preferred='default'):
     preferred = get_hasher(preferred)
     hasher = identify_hasher(encoded)
 
-    must_update = hasher.algorithm != preferred.algorithm
-    if not must_update:
-        must_update = preferred.must_update(encoded)
+    hasher_changed = hasher.algorithm != preferred.algorithm
+    must_update = hasher_changed or preferred.must_update(encoded)
     is_correct = hasher.verify(password, encoded)
+
+    # If the hasher didn't change (we don't protect against enumeration if it
+    # does) and the password should get updated, try to close the timing gap
+    # between the work factor of the current encoded password and the default
+    # work factor.
+    if not is_correct and not hasher_changed and must_update:
+        hasher.harden_runtime(password, encoded)
+
     if setter and is_correct and must_update:
         setter(password)
     return is_correct
@@ -216,6 +224,19 @@ class BasePasswordHasher(object):
     def must_update(self, encoded):
         return False
 
+    def harden_runtime(self, password, encoded):
+        """
+        Bridge the runtime gap between the work factor supplied in `encoded`
+        and the work factor suggested by this hasher.
+
+        Taking PBKDF2 as an example, if `encoded` contains 20000 iterations and
+        `self.iterations` is 30000, this method should run password through
+        another 10000 iterations of PBKDF2. Similar approaches should exist
+        for any hasher that has a work factor. If not, this method should be
+        defined as a no-op to silence the warning.
+        """
+        warnings.warn('subclasses of BasePasswordHasher should provide a harden_runtime() method')
+
 
 class PBKDF2PasswordHasher(BasePasswordHasher):
     """
@@ -258,6 +279,12 @@ class PBKDF2PasswordHasher(BasePasswordHasher):
         algorithm, iterations, salt, hash = encoded.split('$', 3)
         return int(iterations) != self.iterations
 
+    def harden_runtime(self, password, encoded):
+        algorithm, iterations, salt, hash = encoded.split('$', 3)
+        extra_iterations = self.iterations - int(iterations)
+        if extra_iterations > 0:
+            self.encode(password, salt, extra_iterations)
+
 
 class PBKDF2SHA1PasswordHasher(PBKDF2PasswordHasher):
     """
@@ -308,23 +335,8 @@ class BCryptSHA256PasswordHasher(BasePasswordHasher):
     def verify(self, password, encoded):
         algorithm, data = encoded.split('$', 1)
         assert algorithm == self.algorithm
-        bcrypt = self._load_library()
-
-        # Hash the password prior to using bcrypt to prevent password truncation
-        #   See: https://code.djangoproject.com/ticket/20138
-        if self.digest is not None:
-            # We use binascii.hexlify here because Python3 decided that a hex encoded
-            #   bytestring is somehow a unicode.
-            password = binascii.hexlify(self.digest(force_bytes(password)).digest())
-        else:
-            password = force_bytes(password)
-
-        # Ensure that our data is a bytestring
-        data = force_bytes(data)
-        # force_bytes() necessary for py-bcrypt compatibility
-        hashpw = force_bytes(bcrypt.hashpw(password, data))
-
-        return constant_time_compare(data, hashpw)
+        encoded_2 = self.encode(password, force_bytes(data))
+        return constant_time_compare(encoded, encoded_2)
 
     def safe_summary(self, encoded):
         algorithm, empty, algostr, work_factor, data = encoded.split('$', 4)
@@ -337,6 +349,16 @@ class BCryptSHA256PasswordHasher(BasePasswordHasher):
             (_('checksum'), mask_hash(checksum)),
         ])
 
+    def harden_runtime(self, password, encoded):
+        _, data = encoded.split('$', 1)
+        salt = data[:29]  # Length of the salt in bcrypt.
+        rounds = data.split('$')[2]
+        # work factor is logarithmic, adding one doubles the load.
+        diff = 2**(self.rounds - int(rounds)) - 1
+        while diff > 0:
+            self.encode(password, force_bytes(salt))
+            diff -= 1
+
 
 class BCryptPasswordHasher(BCryptSHA256PasswordHasher):
     """
@@ -384,6 +406,9 @@ class SHA1PasswordHasher(BasePasswordHasher):
             (_('hash'), mask_hash(hash)),
         ])
 
+    def harden_runtime(self, password, encoded):
+        pass
+
 
 class MD5PasswordHasher(BasePasswordHasher):
     """
@@ -412,6 +437,9 @@ class MD5PasswordHasher(BasePasswordHasher):
             (_('hash'), mask_hash(hash)),
         ])
 
+    def harden_runtime(self, password, encoded):
+        pass
+
 
 class UnsaltedSHA1PasswordHasher(BasePasswordHasher):
     """
@@ -444,6 +472,9 @@ class UnsaltedSHA1PasswordHasher(BasePasswordHasher):
             (_('hash'), mask_hash(hash)),
         ])
 
+    def harden_runtime(self, password, encoded):
+        pass
+
 
 class UnsaltedMD5PasswordHasher(BasePasswordHasher):
     """
@@ -477,6 +508,9 @@ class UnsaltedMD5PasswordHasher(BasePasswordHasher):
             (_('hash'), mask_hash(encoded, show=3)),
         ])
 
+    def harden_runtime(self, password, encoded):
+        pass
+
 
 class CryptPasswordHasher(BasePasswordHasher):
     """
@@ -511,3 +545,6 @@ class CryptPasswordHasher(BasePasswordHasher):
             (_('salt'), salt),
             (_('hash'), mask_hash(data, show=3)),
         ])
+
+    def harden_runtime(self, password, encoded):
+        pass
diff --git a/django/contrib/contenttypes/models.py b/django/contrib/contenttypes/models.py
index 27a5388..8d459f6 100644
--- a/django/contrib/contenttypes/models.py
+++ b/django/contrib/contenttypes/models.py
@@ -13,13 +13,15 @@ from django.utils.translation import ugettext_lazy as _
 class ContentTypeManager(models.Manager):
     use_in_migrations = True
 
-    # Cache to avoid re-looking up ContentType objects all over the place.
-    # This cache is shared by all the get_for_* methods.
-    _cache = {}
+    def __init__(self, *args, **kwargs):
+        super(ContentTypeManager, self).__init__(*args, **kwargs)
+        # Cache shared by all the get_for_* methods to speed up
+        # ContentType retrieval.
+        self._cache = {}
 
     def get_by_natural_key(self, app_label, model):
         try:
-            ct = self.__class__._cache[self.db][(app_label, model)]
+            ct = self._cache[self.db][(app_label, model)]
         except KeyError:
             ct = self.get(app_label=app_label, model=model)
             self._add_to_cache(self.db, ct)
@@ -34,7 +36,7 @@ class ContentTypeManager(models.Manager):
 
     def _get_from_cache(self, opts):
         key = (opts.app_label, opts.model_name)
-        return self.__class__._cache[self.db][key]
+        return self._cache[self.db][key]
 
     def create(self, **kwargs):
         if 'name' in kwargs:
@@ -129,7 +131,7 @@ class ContentTypeManager(models.Manager):
         (though ContentTypes are obviously not created on-the-fly by get_by_id).
         """
         try:
-            ct = self.__class__._cache[self.db][id]
+            ct = self._cache[self.db][id]
         except KeyError:
             # This could raise a DoesNotExist; that's correct behavior and will
             # make sure that only correct ctypes get stored in the cache dict.
@@ -144,15 +146,15 @@ class ContentTypeManager(models.Manager):
         django.contrib.contenttypes.management.update_contenttypes for where
         this gets called).
         """
-        self.__class__._cache.clear()
+        self._cache.clear()
 
     def _add_to_cache(self, using, ct):
         """Insert a ContentType into the cache."""
         # Note it's possible for ContentType objects to be stale; model_class() will return None.
         # Hence, there is no reliance on model._meta.app_label here, just using the model fields instead.
         key = (ct.app_label, ct.model)
-        self.__class__._cache.setdefault(using, {})[key] = ct
-        self.__class__._cache.setdefault(using, {})[ct.id] = ct
+        self._cache.setdefault(using, {})[key] = ct
+        self._cache.setdefault(using, {})[ct.id] = ct
 
 
 @python_2_unicode_compatible
diff --git a/django/contrib/gis/db/backends/postgis/models.py b/django/contrib/gis/db/backends/postgis/models.py
index 83b254c..68d4c18 100644
--- a/django/contrib/gis/db/backends/postgis/models.py
+++ b/django/contrib/gis/db/backends/postgis/models.py
@@ -51,7 +51,7 @@ class PostGISGeometryColumns(models.Model):
 class PostGISSpatialRefSys(models.Model, SpatialRefSysMixin):
     """
     The 'spatial_ref_sys' table from PostGIS. See the PostGIS
-    documentaiton at Ch. 4.2.1.
+    documentation at Ch. 4.2.1.
     """
     srid = models.IntegerField(primary_key=True)
     auth_name = models.CharField(max_length=256)
diff --git a/django/contrib/gis/db/models/query.py b/django/contrib/gis/db/models/query.py
index 343610c..c60750a 100644
--- a/django/contrib/gis/db/models/query.py
+++ b/django/contrib/gis/db/models/query.py
@@ -500,7 +500,7 @@ class GeoQuerySet(QuerySet):
           SQL function to call.
 
          settings:
-          Dictonary of internal settings to customize for the spatial procedure.
+          Dictionary of internal settings to customize for the spatial procedure.
 
         Public Keyword Arguments:
 
diff --git a/django/contrib/gis/gdal/geomtype.py b/django/contrib/gis/gdal/geomtype.py
index abb184e..d0dc1c0 100644
--- a/django/contrib/gis/gdal/geomtype.py
+++ b/django/contrib/gis/gdal/geomtype.py
@@ -3,7 +3,7 @@ from django.utils import six
 
 
 class OGRGeomType(object):
-    "Encapulates OGR Geometry Types."
+    "Encapsulates OGR Geometry Types."
 
     wkb25bit = -2147483648
 
diff --git a/django/contrib/gis/sitemaps/kml.py b/django/contrib/gis/sitemaps/kml.py
index 4dcaa8f..83e1edc 100644
--- a/django/contrib/gis/sitemaps/kml.py
+++ b/django/contrib/gis/sitemaps/kml.py
@@ -44,7 +44,7 @@ class KMLSitemap(Sitemap):
 
     def get_urls(self, page=1, site=None, protocol=None):
         """
-        This method is overrridden so the appropriate `geo_format` attribute
+        This method is overridden so the appropriate `geo_format` attribute
         is placed on each URL element.
         """
         urls = Sitemap.get_urls(self, page=page, site=site, protocol=protocol)
diff --git a/django/contrib/postgres/fields/array.py b/django/contrib/postgres/fields/array.py
index ceac798..a2953af 100644
--- a/django/contrib/postgres/fields/array.py
+++ b/django/contrib/postgres/fields/array.py
@@ -95,8 +95,11 @@ class ArrayField(Field):
         base_field = self.base_field
 
         for val in vals:
-            obj = AttributeSetter(base_field.attname, val)
-            values.append(base_field.value_to_string(obj))
+            if val is None:
+                values.append(None)
+            else:
+                obj = AttributeSetter(base_field.attname, val)
+                values.append(base_field.value_to_string(obj))
         return json.dumps(values)
 
     def get_transform(self, name):
diff --git a/django/contrib/postgres/fields/ranges.py b/django/contrib/postgres/fields/ranges.py
index fe69b08..83319b2 100644
--- a/django/contrib/postgres/fields/ranges.py
+++ b/django/contrib/postgres/fields/ranges.py
@@ -51,8 +51,12 @@ class RangeField(models.Field):
         base_field = self.base_field
         result = {"bounds": value._bounds}
         for end in ('lower', 'upper'):
-            obj = AttributeSetter(base_field.attname, getattr(value, end))
-            result[end] = base_field.value_to_string(obj)
+            val = getattr(value, end)
+            if val is None:
+                result[end] = None
+            else:
+                obj = AttributeSetter(base_field.attname, val)
+                result[end] = base_field.value_to_string(obj)
         return json.dumps(result)
 
     def formfield(self, **kwargs):
diff --git a/django/core/validators.py b/django/core/validators.py
index 89d184f..de25f57 100644
--- a/django/core/validators.py
+++ b/django/core/validators.py
@@ -74,7 +74,14 @@ class URLValidator(RegexValidator):
     # Host patterns
     hostname_re = r'[a-z' + ul + r'0-9](?:[a-z' + ul + r'0-9-]*[a-z' + ul + r'0-9])?'
     domain_re = r'(?:\.(?!-)[a-z' + ul + r'0-9-]+(?<!-))*'
-    tld_re = r'\.(?:[a-z' + ul + r']{2,}|xn--[a-z0-9]+)\.?'
+    tld_re = (
+        '\.'                                # dot
+        '(?!-)'                             # can't start with a dash
+        '(?:[a-z' + ul + '-]{2,}'           # domain label
+        '|xn--[a-z0-9]+)'                   # or punycode label
+        '(?<!-)'                            # can't end with a dash
+        '\.?'                               # may have a trailing dot
+    )
     host_re = '(' + hostname_re + domain_re + tld_re + '|localhost)'
 
     regex = re.compile(
diff --git a/django/db/backends/postgresql_psycopg2/base.py b/django/db/backends/postgresql_psycopg2/base.py
index a76ca3c..e625c28 100644
--- a/django/db/backends/postgresql_psycopg2/base.py
+++ b/django/db/backends/postgresql_psycopg2/base.py
@@ -198,7 +198,7 @@ class DatabaseWrapper(BaseDatabaseWrapper):
         tz = self.settings_dict['TIME_ZONE']
         conn_tz = self.connection.get_parameter_status('TimeZone')
 
-        if conn_tz != tz:
+        if tz and conn_tz != tz:
             cursor = self.connection.cursor()
             try:
                 cursor.execute(self.ops.set_time_zone_sql(), [tz])
diff --git a/django/db/models/expressions.py b/django/db/models/expressions.py
index 83121a9..931a9d8 100644
--- a/django/db/models/expressions.py
+++ b/django/db/models/expressions.py
@@ -302,7 +302,7 @@ class BaseExpression(object):
         Does this expression contain a reference to some of the
         existing aggregates? If so, returns the aggregate and also
         the lookup parts that *weren't* found. So, if
-            exsiting_aggregates = {'max_id': Max('id')}
+            existing_aggregates = {'max_id': Max('id')}
             self.name = 'max_id'
             queryset.filter(max_id__range=[10,100])
         then this method will return Max('id') and those parts of the
diff --git a/django/db/models/fields/related.py b/django/db/models/fields/related.py
index f64ca22..93a0879 100644
--- a/django/db/models/fields/related.py
+++ b/django/db/models/fields/related.py
@@ -194,12 +194,6 @@ class RelatedField(Field):
         if not isinstance(self.rel.to, ModelBase):
             return []
 
-        # If the field doesn't install backward relation on the target model (so
-        # `is_hidden` returns True), then there are no clashes to check and we
-        # can skip these fields.
-        if self.rel.is_hidden():
-            return []
-
         try:
             self.rel
         except AttributeError:
@@ -216,12 +210,15 @@ class RelatedField(Field):
         #         foreign = models.ForeignKey(Target)
         #         m2m = models.ManyToManyField(Target)
 
-        rel_opts = self.rel.to._meta
         # rel_opts.object_name == "Target"
+        rel_opts = self.rel.to._meta
+        # If the field doesn't install a backward relation on the target model
+        # (so `is_hidden` returns True), then there are no clashes to check
+        # and we can skip these fields.
+        rel_is_hidden = self.rel.is_hidden()
         rel_name = self.rel.get_accessor_name()  # i. e. "model_set"
         rel_query_name = self.related_query_name()  # i. e. "model"
-        field_name = "%s.%s" % (opts.object_name,
-            self.name)  # i. e. "Model.field"
+        field_name = "%s.%s" % (opts.object_name, self.name)  # i. e. "Model.field"
 
         # Check clashes between accessor or reverse query name of `field`
         # and any other field name -- i.e. accessor for Model.foreign is
@@ -230,7 +227,7 @@ class RelatedField(Field):
         for clash_field in potential_clashes:
             clash_name = "%s.%s" % (rel_opts.object_name,
                 clash_field.name)  # i. e. "Target.model_set"
-            if clash_field.name == rel_name:
+            if not rel_is_hidden and clash_field.name == rel_name:
                 errors.append(
                     checks.Error(
                         "Reverse accessor for '%s' clashes with field name '%s'." % (field_name, clash_name),
@@ -260,7 +257,7 @@ class RelatedField(Field):
             clash_name = "%s.%s" % (  # i. e. "Model.m2m"
                 clash_field.related_model._meta.object_name,
                 clash_field.field.name)
-            if clash_field.get_accessor_name() == rel_name:
+            if not rel_is_hidden and clash_field.get_accessor_name() == rel_name:
                 errors.append(
                     checks.Error(
                         "Reverse accessor for '%s' clashes with reverse accessor for '%s'." % (field_name, clash_name),
diff --git a/django/db/models/query_utils.py b/django/db/models/query_utils.py
index 4eca2c9..90c294d 100644
--- a/django/db/models/query_utils.py
+++ b/django/db/models/query_utils.py
@@ -42,7 +42,7 @@ class QueryWrapper(object):
 class Q(tree.Node):
     """
     Encapsulates filters as objects that can then be combined logically (using
-    & and |).
+    `&` and `|`).
     """
     # Connection types
     AND = 'AND'
diff --git a/django/forms/forms.py b/django/forms/forms.py
index 80ba830..3f9d789 100644
--- a/django/forms/forms.py
+++ b/django/forms/forms.py
@@ -554,7 +554,7 @@ class BoundField(object):
     def __getitem__(self, idx):
         # Prevent unnecessary reevaluation when accessing BoundField's attrs
         # from templates.
-        if not isinstance(idx, six.integer_types):
+        if not isinstance(idx, six.integer_types + (slice,)):
             raise TypeError
         return list(self.__iter__())[idx]
 
diff --git a/django/template/defaultfilters.py b/django/template/defaultfilters.py
index 9324b7f..cd2457d 100644
--- a/django/template/defaultfilters.py
+++ b/django/template/defaultfilters.py
@@ -841,7 +841,7 @@ def default_if_none(value, arg):
 
 @register.filter(is_safe=False)
 def divisibleby(value, arg):
-    """Returns True if the value is devisible by the argument."""
+    """Returns True if the value is divisible by the argument."""
     return int(value) % int(arg) == 0
 
 
diff --git a/django/template/defaulttags.py b/django/template/defaulttags.py
index 09c0e72..4526737 100644
--- a/django/template/defaulttags.py
+++ b/django/template/defaulttags.py
@@ -824,7 +824,7 @@ def do_for(parser, token):
     than -- the following::
 
         <ul>
-          {% if althete_list %}
+          {% if athlete_list %}
             {% for athlete in athlete_list %}
               <li>{{ athlete.name }}</li>
             {% endfor %}
diff --git a/django/test/signals.py b/django/test/signals.py
index 0c2bf52..fd3de51 100644
--- a/django/test/signals.py
+++ b/django/test/signals.py
@@ -73,7 +73,7 @@ def update_connections_time_zone(**kwargs):
     for conn in connections.all():
         conn.settings_dict['TIME_ZONE'] = tz
         tz_sql = conn.ops.set_time_zone_sql()
-        if tz_sql:
+        if tz_sql and tz:
             conn.cursor().execute(tz_sql, [tz])
 
 
diff --git a/django/utils/http.py b/django/utils/http.py
index 34c1742..b70720d 100644
--- a/django/utils/http.py
+++ b/django/utils/http.py
@@ -277,8 +277,17 @@ def is_safe_url(url, host=None):
         url = url.strip()
     if not url:
         return False
-    # Chrome treats \ completely as /
-    url = url.replace('\\', '/')
+    if six.PY2:
+        try:
+            url = force_text(url)
+        except UnicodeDecodeError:
+            return False
+    # Chrome treats \ completely as / in paths but it could be part of some
+    # basic auth credentials so we need to check both URLs.
+    return _is_safe_url(url, host) and _is_safe_url(url.replace('\\', '/'), host)
+
+
+def _is_safe_url(url, host):
     # Chrome considers any URL with more than two slashes to be absolute, but
     # urlparse is not so flexible. Treat any url with three slashes as unsafe.
     if url.startswith('///'):
diff --git a/django/utils/translation/__init__.py b/django/utils/translation/__init__.py
index a4c6963..ed45250 100644
--- a/django/utils/translation/__init__.py
+++ b/django/utils/translation/__init__.py
@@ -105,6 +105,8 @@ def lazy_number(func, resultclass, number=None, **kwargs):
         kwargs['number'] = number
         proxy = lazy(func, resultclass)(**kwargs)
     else:
+        original_kwargs = kwargs.copy()
+
         class NumberAwareString(resultclass):
             def __mod__(self, rhs):
                 if isinstance(rhs, dict) and number:
@@ -127,9 +129,14 @@ def lazy_number(func, resultclass, number=None, **kwargs):
                 return translated
 
         proxy = lazy(lambda **kwargs: NumberAwareString(), NumberAwareString)(**kwargs)
+        proxy.__reduce__ = lambda: (_lazy_number_unpickle, (func, resultclass, number, original_kwargs))
     return proxy
 
 
+def _lazy_number_unpickle(func, resultclass, number, kwargs):
+    return lazy_number(func, resultclass, number=number, **kwargs)
+
+
 def ngettext_lazy(singular, plural, number=None):
     return lazy_number(ngettext, str, singular=singular, plural=plural, number=number)
 
diff --git a/docs/_theme/djangodocs/static/djangodocs.css b/docs/_theme/djangodocs/static/djangodocs.css
index 9cf2384..a05f747 100644
--- a/docs/_theme/djangodocs/static/djangodocs.css
+++ b/docs/_theme/djangodocs/static/djangodocs.css
@@ -118,7 +118,7 @@ div.admonition-philosophy { padding-left:65px; background:url(docicons-philosoph
 div.admonition-behind-the-scenes { padding-left:65px; background:url(docicons-behindscenes.png) .8em .8em no-repeat;}
 .admonition.warning { background:url(docicons-warning.png) .8em .8em no-repeat; border:1px solid #ffc83c;}
 
-/*** versoinadded/changes ***/
+/*** versionadded/changes ***/
 div.versionadded, div.versionchanged {  }
 div.versionadded span.title, div.versionchanged span.title, span.versionmodified { font-weight: bold; }
 div.versionadded, div.versionchanged, div.deprecated { color:#555; }
diff --git a/docs/conf.py b/docs/conf.py
index 55d13f0..1176f8d 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -6,7 +6,7 @@
 # This file is execfile()d with the current directory set to its containing dir.
 #
 # The contents of this file are pickled, so don't put values in the namespace
-# that aren't pickleable (module imports are okay, they're removed automatically).
+# that aren't picklable (module imports are okay, they're removed automatically).
 #
 # All configuration values have a default; values that are commented out
 # serve to show the default.
@@ -16,6 +16,15 @@ from __future__ import unicode_literals
 import sys
 from os.path import abspath, dirname, join
 
+# Workaround for sphinx-build recursion limit overflow:
+# pickle.dump(doctree, f, pickle.HIGHEST_PROTOCOL)
+#  RuntimeError: maximum recursion depth exceeded while pickling an object
+#
+# Python's default allowed recursion depth is 1000 but this isn't enough for
+# building docs/ref/settings.txt sometimes.
+# https://groups.google.com/d/topic/sphinx-dev/MtRf64eGtv4/discussion
+sys.setrecursionlimit(2000)
+
 # Make sure we get the version of this copy of Django
 sys.path.insert(1, dirname(dirname(abspath(__file__))))
 
diff --git a/docs/howto/custom-model-fields.txt b/docs/howto/custom-model-fields.txt
index f41e950..9848f2c 100644
--- a/docs/howto/custom-model-fields.txt
+++ b/docs/howto/custom-model-fields.txt
@@ -470,6 +470,7 @@ instances::
 
     from django.core.exceptions import ValidationError
     from django.db import models
+    from django.utils.translation import ugettext_lazy as _
 
     def parse_hand(hand_string):
         """Takes a string of cards and splits into a full hand."""
@@ -477,7 +478,7 @@ instances::
         p2 = re.compile('..')
         args = [p2.findall(x) for x in p1.findall(hand_string)]
         if len(args) != 4:
-            raise ValidationError("Invalid input for a Hand instance")
+            raise ValidationError(_("Invalid input for a Hand instance"))
         return Hand(*args)
 
     class HandField(models.Field):
diff --git a/docs/howto/outputting-pdf.txt b/docs/howto/outputting-pdf.txt
index 5b070c6..0e82ecc 100644
--- a/docs/howto/outputting-pdf.txt
+++ b/docs/howto/outputting-pdf.txt
@@ -153,7 +153,7 @@ Further resources
   using ``system`` or ``popen`` and retrieve the output in Python.
 
 .. _PDFlib: http://www.pdflib.org/
-.. _`Pisa XHTML2PDF`: http://www.xhtml2pdf.com/
+.. _`Pisa XHTML2PDF`: https://github.com/xhtml2pdf/xhtml2pdf
 .. _HTMLdoc: https://www.msweet.org/projects.php?Z1
 
 Other formats
diff --git a/docs/internals/deprecation.txt b/docs/internals/deprecation.txt
index 2fca895..ed82ad2 100644
--- a/docs/internals/deprecation.txt
+++ b/docs/internals/deprecation.txt
@@ -34,6 +34,9 @@ details on these changes.
 * The ability to :func:`~django.core.urlresolvers.reverse` URLs using a dotted
   Python path will be removed.
 
+* The ability to use a dotted Python path for the ``LOGIN_URL`` and
+  ``LOGIN_REDIRECT_URL`` settings will be removed.
+
 * Support for :py:mod:`optparse` will be dropped for custom management commands
   (replaced by :py:mod:`argparse`).
 
diff --git a/docs/intro/reusable-apps.txt b/docs/intro/reusable-apps.txt
index 245a88b..ffe1295 100644
--- a/docs/intro/reusable-apps.txt
+++ b/docs/intro/reusable-apps.txt
@@ -193,7 +193,7 @@ this. For a small app like polls, this process isn't too difficult.
        :filename: django-polls/setup.py
 
        import os
-       from setuptools import setup
+       from setuptools import find_packages, setup
 
        with open(os.path.join(os.path.dirname(__file__), 'README.rst')) as readme:
            README = readme.read()
@@ -204,7 +204,7 @@ this. For a small app like polls, this process isn't too difficult.
        setup(
            name='django-polls',
            version='0.1',
-           packages=['polls'],
+           packages=find_packages(),
            include_package_data=True,
            license='BSD License',  # example license
            description='A simple Django app to conduct Web-based polls.',
diff --git a/docs/ref/contrib/gis/feeds.txt b/docs/ref/contrib/gis/feeds.txt
index 72c51b5..49c8f97 100644
--- a/docs/ref/contrib/gis/feeds.txt
+++ b/docs/ref/contrib/gis/feeds.txt
@@ -31,9 +31,9 @@ API Reference
    base class, GeoDjango's ``Feed`` class provides
    the following overrides.  Note that these overrides may be done in multiple ways::
 
-       from django.contrib.gis.feeds import Feed
+        from django.contrib.gis.feeds import Feed
 
-       class MyFeed(Feed):
+        class MyFeed(Feed):
 
             # First, as a class attribute.
             geometry = ...
diff --git a/docs/ref/contrib/gis/testing.txt b/docs/ref/contrib/gis/testing.txt
index bdd46e9..17eeeac 100644
--- a/docs/ref/contrib/gis/testing.txt
+++ b/docs/ref/contrib/gis/testing.txt
@@ -132,11 +132,11 @@ in :mod:`django.contrib.gis`::
             'NAME': 'geodjango',
             'USER': 'geodjango',
         },
-       'other': {
+        'other': {
             'ENGINE': 'django.contrib.gis.db.backends.postgis',
             'NAME': 'other',
             'USER': 'geodjango',
-       }
+        },
     }
 
     SECRET_KEY = 'django_tests_secret_key'
diff --git a/docs/ref/contrib/gis/tutorial.txt b/docs/ref/contrib/gis/tutorial.txt
index 6ea5dd3..5b0a0f3 100644
--- a/docs/ref/contrib/gis/tutorial.txt
+++ b/docs/ref/contrib/gis/tutorial.txt
@@ -107,7 +107,7 @@ file. Edit the database connection settings to match your setup::
              'ENGINE': 'django.contrib.gis.db.backends.postgis',
              'NAME': 'geodjango',
              'USER': 'geo',
-         }
+        },
     }
 
 In addition, modify the :setting:`INSTALLED_APPS` setting to include
@@ -122,7 +122,7 @@ and ``world`` (your newly created application)::
         'django.contrib.messages',
         'django.contrib.staticfiles',
         'django.contrib.gis',
-        'world'
+        'world',
     )
 
 Geographic Data
@@ -470,7 +470,7 @@ with the following code::
 
     import os
     from django.contrib.gis.utils import LayerMapping
-    from models import WorldBorder
+    from .models import WorldBorder
 
     world_mapping = {
         'fips' : 'FIPS',
@@ -738,7 +738,7 @@ Let's dive right in.  Create a file called ``admin.py`` inside the
 ``world`` application with the following code::
 
     from django.contrib.gis import admin
-    from models import WorldBorder
+    from .models import WorldBorder
 
     admin.site.register(WorldBorder, admin.GeoModelAdmin)
 
diff --git a/docs/ref/contrib/syndication.txt b/docs/ref/contrib/syndication.txt
index 002cafe..bf1e3f6 100644
--- a/docs/ref/contrib/syndication.txt
+++ b/docs/ref/contrib/syndication.txt
@@ -823,7 +823,7 @@ This example illustrates all possible attributes and methods for a
 
         def item_updateddate(self):
             """
-            Returns the updateddated for every item in the feed.
+            Returns the updateddate for every item in the feed.
             """
 
         item_updateddate = datetime.datetime(2005, 5, 3) # Hard-coded updateddate.
diff --git a/docs/ref/models/expressions.txt b/docs/ref/models/expressions.txt
index 2f780e4..67c2f39 100644
--- a/docs/ref/models/expressions.txt
+++ b/docs/ref/models/expressions.txt
@@ -448,7 +448,7 @@ calling the appropriate methods on the wrapped expression.
         Tells Django that this expression contains an aggregate and that a
         ``GROUP BY`` clause needs to be added to the query.
 
-    .. method:: resolve_expression(query=None, allow_joins=True, reuse=None, summarize=False)
+    .. method:: resolve_expression(query=None, allow_joins=True, reuse=None, summarize=False, for_save=False)
 
         Provides the chance to do any pre-processing or validation of
         the expression before it's added to the query. ``resolve_expression()``
@@ -579,11 +579,11 @@ Now we implement the pre-processing and validation. Since we do not have
 any of our own validation at this point, we just delegate to the nested
 expressions::
 
-    def resolve_expression(self, query=None, allow_joins=True, reuse=None, summarize=False):
+    def resolve_expression(self, query=None, allow_joins=True, reuse=None, summarize=False, for_save=False):
         c = self.copy()
         c.is_summary = summarize
         for pos, expression in enumerate(self.expressions):
-            c.expressions[pos] = expression.resolve_expression(query, allow_joins, reuse, summarize)
+            c.expressions[pos] = expression.resolve_expression(query, allow_joins, reuse, summarize, for_save)
         return c
 
 Next, we write the method responsible for generating the SQL::
diff --git a/docs/ref/settings.txt b/docs/ref/settings.txt
index 426cae5..30a2c7d 100644
--- a/docs/ref/settings.txt
+++ b/docs/ref/settings.txt
@@ -2866,9 +2866,14 @@ The URL where requests are redirected after login when the
 This is used by the :func:`~django.contrib.auth.decorators.login_required`
 decorator, for example.
 
-This setting also accepts view function names and :ref:`named URL patterns
-<naming-url-patterns>` which can be used to reduce configuration duplication
-since you don't have to define the URL in two places (``settings`` and URLconf).
+This setting also accepts :ref:`named URL patterns <naming-url-patterns>` which
+can be used to reduce configuration duplication since you don't have to define
+the URL in two places (``settings`` and URLconf).
+
+.. deprecated:: 1.8
+
+    The setting may also be a dotted Python path to a view function. Support
+    for this will be removed in Django 1.10.
 
 .. setting:: LOGIN_URL
 
@@ -2880,18 +2885,14 @@ Default: ``'/accounts/login/'``
 The URL where requests are redirected for login, especially when using the
 :func:`~django.contrib.auth.decorators.login_required` decorator.
 
-This setting also accepts view function names and :ref:`named URL patterns
-<naming-url-patterns>` which can be used to reduce configuration duplication
-since you don't have to define the URL in two places (``settings`` and URLconf).
-
-.. setting:: LOGOUT_URL
+This setting also accepts :ref:`named URL patterns <naming-url-patterns>` which
+can be used to reduce configuration duplication since you don't have to define
+the URL in two places (``settings`` and URLconf).
 
-LOGOUT_URL
-----------
-
-Default: ``'/accounts/logout/'``
+.. deprecated:: 1.8
 
-LOGIN_URL counterpart.
+    The setting may also be a dotted Python path to a view function. Support
+    for this will be removed in Django 1.10.
 
 .. setting:: PASSWORD_RESET_TIMEOUT_DAYS
 
diff --git a/docs/ref/validators.txt b/docs/ref/validators.txt
index 0ae1ba5..5119f53 100644
--- a/docs/ref/validators.txt
+++ b/docs/ref/validators.txt
@@ -16,10 +16,14 @@ different types of fields.
 For example, here's a validator that only allows even numbers::
 
     from django.core.exceptions import ValidationError
+    from django.utils.translation import ugettext_lazy as _
 
     def validate_even(value):
         if value % 2 != 0:
-            raise ValidationError('%s is not an even number' % value)
+            raise ValidationError(
+                _('%(value)s is not an even number'),
+                params={'value': value},
+            )
... 1596 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