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

Raphaël Hertzog hertzog at moszumanska.debian.org
Sun Nov 15 19:20:11 UTC 2015


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

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

commit bf9d9d34e53599542047e5129c31ea22e7151902
Author: Raphaël Hertzog <hertzog at debian.org>
Date:   Sun Nov 15 18:26:49 2015 +0100

    Import python-django_1.8.6.orig.tar.gz
---
 AUTHORS                                            |  1 +
 Django.egg-info/PKG-INFO                           |  2 +-
 Django.egg-info/SOURCES.txt                        |  2 +
 PKG-INFO                                           |  2 +-
 django/__init__.py                                 |  2 +-
 django/contrib/admin/options.py                    |  4 +-
 django/contrib/admindocs/views.py                  |  3 +-
 .../contrib/gis/db/backends/postgis/operations.py  |  2 +-
 .../contrib/gis/management/commands/ogrinspect.py  |  4 +-
 django/contrib/postgres/forms/array.py             |  2 +-
 django/core/files/storage.py                       |  5 +-
 django/core/management/__init__.py                 | 11 +--
 django/core/validators.py                          |  2 +-
 django/db/backends/sqlite3/creation.py             |  8 ++-
 django/db/migrations/loader.py                     |  6 ++
 django/db/migrations/writer.py                     | 13 ++--
 django/db/models/expressions.py                    | 11 +++
 django/db/models/fields/files.py                   |  5 +-
 django/db/models/fields/related.py                 |  7 +-
 django/db/models/functions.py                      | 19 ++---
 django/db/models/lookups.py                        |  2 +-
 django/db/models/query_utils.py                    |  9 +--
 django/db/utils.py                                 | 13 +++-
 django/dispatch/dispatcher.py                      | 18 +----
 django/forms/models.py                             |  6 +-
 django/http/multipartparser.py                     | 15 ++--
 django/template/base.py                            |  8 ++-
 django/utils/deprecation.py                        |  2 +
 django/utils/inspect.py                            | 81 ++++++++++++++++++++++
 docs/faq/install.txt                               |  4 +-
 docs/howto/custom-management-commands.txt          |  3 +
 docs/intro/tutorial05.txt                          |  4 +-
 .../ref/class-based-views/mixins-single-object.txt | 26 +++++--
 docs/ref/contrib/admin/admindocs.txt               |  2 +-
 docs/ref/contrib/admin/index.txt                   |  2 +-
 docs/ref/contrib/contenttypes.txt                  | 14 ++--
 docs/ref/contrib/gis/geoquerysets.txt              |  6 +-
 docs/ref/contrib/gis/geos.txt                      |  6 +-
 docs/ref/contrib/gis/install/index.txt             | 27 +-------
 docs/ref/contrib/gis/install/spatialite.txt        | 41 ++---------
 docs/ref/contrib/gis/tutorial.txt                  |  4 +-
 docs/ref/forms/validation.txt                      | 28 +++++---
 docs/ref/models/querysets.txt                      | 11 ++-
 docs/ref/request-response.txt                      | 64 +++++++++--------
 docs/ref/settings.txt                              |  3 +-
 docs/ref/templates/api.txt                         |  4 ++
 docs/ref/templates/builtins.txt                    |  8 +++
 docs/ref/templates/language.txt                    |  2 +
 docs/releases/1.4.22.txt                           |  3 +-
 docs/releases/1.7.10.txt                           |  3 +-
 docs/releases/1.7.txt                              | 13 +++-
 docs/releases/1.8.4.txt                            |  3 +-
 docs/releases/1.8.6.txt                            | 53 ++++++++++++++
 docs/releases/1.8.txt                              | 10 ++-
 docs/releases/index.txt                            |  1 +
 docs/topics/auth/default.txt                       |  2 +-
 docs/topics/cache.txt                              |  9 +++
 docs/topics/class-based-views/generic-display.txt  |  5 ++
 docs/topics/db/models.txt                          |  2 +-
 docs/topics/forms/formsets.txt                     | 26 ++++---
 docs/topics/forms/modelforms.txt                   | 20 +++---
 docs/topics/performance.txt                        |  4 +-
 docs/topics/testing/advanced.txt                   |  4 +-
 docs/topics/testing/tools.txt                      | 40 +++++++++--
 setup.cfg                                          |  2 +-
 tests/admin_filters/tests.py                       |  7 ++
 tests/admin_views/admin.py                         | 27 ++++----
 tests/admin_views/models.py                        | 11 +++
 tests/admin_views/tests.py                         |  8 +++
 tests/backends/tests.py                            | 24 +++++++
 tests/db_functions/tests.py                        | 18 ++++-
 tests/defer_regress/tests.py                       | 20 ++++++
 tests/expressions/tests.py                         | 12 ++++
 tests/gis_tests/geoapp/tests.py                    | 16 ++++-
 tests/gis_tests/utils.py                           | 23 +++++-
 tests/invalid_models_tests/test_relative_fields.py | 56 ++++++++-------
 tests/mail/tests.py                                |  3 +
 tests/many_to_many/models.py                       | 17 +++++
 tests/many_to_many/tests.py                        | 27 +++++++-
 tests/model_forms/tests.py                         | 23 ++++++
 tests/model_meta/results.py                        | 20 +++---
 tests/model_meta/tests.py                          |  2 +-
 tests/postgres_tests/test_array.py                 |  5 ++
 tests/runtests.py                                  |  3 +
 tests/schema/tests.py                              | 59 ++++++++--------
 tests/validators/invalid_urls.txt                  |  1 +
 86 files changed, 773 insertions(+), 333 deletions(-)

diff --git a/AUTHORS b/AUTHORS
index 0c1b017..0a1ed3e 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -434,6 +434,7 @@ answer newbie questions, and generally made Django that much better:
     Marian Andre <django at andre.sk>
     Marijn Vriens <marijn at metronomo.cl>
     Mario Gonzalez <gonzalemario at gmail.com>
+    Mariusz Felisiak <felisiak.mariusz at gmail.com>
     Mark Biggers <biggers at utsl.com>
     mark at junklight.com
     Mark Lavin <markdlavin at gmail.com>
diff --git a/Django.egg-info/PKG-INFO b/Django.egg-info/PKG-INFO
index 6a8f3a7..8af5a88 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.5
+Version: 1.8.6
 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 debb4fb..59fd088 100644
--- a/Django.egg-info/SOURCES.txt
+++ b/Django.egg-info/SOURCES.txt
@@ -3030,6 +3030,7 @@ django/utils/html.py
 django/utils/html_parser.py
 django/utils/http.py
 django/utils/importlib.py
+django/utils/inspect.py
 django/utils/ipv6.py
 django/utils/itercompat.py
 django/utils/jslex.py
@@ -3403,6 +3404,7 @@ docs/releases/1.8.2.txt
 docs/releases/1.8.3.txt
 docs/releases/1.8.4.txt
 docs/releases/1.8.5.txt
+docs/releases/1.8.6.txt
 docs/releases/1.8.txt
 docs/releases/index.txt
 docs/releases/security.txt
diff --git a/PKG-INFO b/PKG-INFO
index 6a8f3a7..8af5a88 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: Django
-Version: 1.8.5
+Version: 1.8.6
 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 1a527db..fd0591d 100644
--- a/django/__init__.py
+++ b/django/__init__.py
@@ -1,6 +1,6 @@
 from django.utils.version import get_version
 
-VERSION = (1, 8, 5, 'final', 0)
+VERSION = (1, 8, 6, 'final', 0)
 
 __version__ = get_version(VERSION)
 
diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py
index 8176926..65653a6 100644
--- a/django/contrib/admin/options.py
+++ b/django/contrib/admin/options.py
@@ -485,8 +485,10 @@ class BaseModelAdmin(six.with_metaclass(forms.MediaDefiningClass)):
         )
         for related_object in related_objects:
             related_model = related_object.related_model
+            remote_field = related_object.field.rel
             if (any(issubclass(model, related_model) for model in registered_models) and
-                    related_object.field.rel.get_related_field() == field):
+                    hasattr(remote_field, 'get_related_field') and
+                    remote_field.get_related_field() == field):
                 return True
 
         return False
diff --git a/django/contrib/admindocs/views.py b/django/contrib/admindocs/views.py
index 394c408..90d8f82 100644
--- a/django/contrib/admindocs/views.py
+++ b/django/contrib/admindocs/views.py
@@ -20,6 +20,7 @@ from django.template.engine import Engine
 from django.utils import six
 from django.utils._os import upath
 from django.utils.decorators import method_decorator
+from django.utils.inspect import func_has_no_args
 from django.utils.translation import ugettext as _
 from django.views.generic import TemplateView
 
@@ -247,7 +248,7 @@ class ModelDetailView(BaseAdminDocsView):
 
         # Gather model methods.
         for func_name, func in model.__dict__.items():
-            if (inspect.isfunction(func) and len(inspect.getargspec(func)[0]) == 1):
+            if inspect.isfunction(func) and func_has_no_args(func):
                 try:
                     for exclude in MODEL_METHODS_EXCLUDE:
                         if func_name.startswith(exclude):
diff --git a/django/contrib/gis/db/backends/postgis/operations.py b/django/contrib/gis/db/backends/postgis/operations.py
index e0af0c1..6913533 100644
--- a/django/contrib/gis/db/backends/postgis/operations.py
+++ b/django/contrib/gis/db/backends/postgis/operations.py
@@ -67,7 +67,7 @@ class PostGISOperations(BaseSpatialOperations, DatabaseOperations):
         'left': PostGISOperator(op='<<'),
         'right': PostGISOperator(op='>>'),
         'strictly_below': PostGISOperator(op='<<|'),
-        'stricly_above': PostGISOperator(op='|>>'),
+        'strictly_above': PostGISOperator(op='|>>'),
         'same_as': PostGISOperator(op='~='),
         'exact': PostGISOperator(op='~='),  # alias of same_as
         'contains_properly': PostGISOperator(func='ST_ContainsProperly'),
diff --git a/django/contrib/gis/management/commands/ogrinspect.py b/django/contrib/gis/management/commands/ogrinspect.py
index 1194cf6..f161c06 100644
--- a/django/contrib/gis/management/commands/ogrinspect.py
+++ b/django/contrib/gis/management/commands/ogrinspect.py
@@ -1,8 +1,8 @@
 import argparse
-import inspect
 
 from django.contrib.gis import gdal
 from django.core.management.base import BaseCommand, CommandError
+from django.utils.inspect import get_func_args
 
 
 class LayerOptionAction(argparse.Action):
@@ -91,7 +91,7 @@ class Command(BaseCommand):
         from django.contrib.gis.utils.ogrinspect import _ogrinspect, mapping
         # Filter options to params accepted by `_ogrinspect`
         ogr_options = {k: v for k, v in options.items()
-                       if k in inspect.getargspec(_ogrinspect).args and v is not None}
+                       if k in get_func_args(_ogrinspect) and v is not None}
         output = [s for s in _ogrinspect(ds, model_name, **ogr_options)]
 
         if options['mapping']:
diff --git a/django/contrib/postgres/forms/array.py b/django/contrib/postgres/forms/array.py
index 01c4d53..e4c8484 100644
--- a/django/contrib/postgres/forms/array.py
+++ b/django/contrib/postgres/forms/array.py
@@ -166,7 +166,7 @@ class SplitArrayField(forms.Field):
                 errors.append(None)
             except ValidationError as error:
                 errors.append(ValidationError(
-                    string_concat(self.error_messages['item_invalid'], error.message),
+                    string_concat(self.error_messages['item_invalid'], ' '.join(error.messages)),
                     code='item_invalid',
                     params={'nth': i},
                 ))
diff --git a/django/core/files/storage.py b/django/core/files/storage.py
index e611d3a..39cf5d8 100644
--- a/django/core/files/storage.py
+++ b/django/core/files/storage.py
@@ -2,7 +2,6 @@ import errno
 import os
 import warnings
 from datetime import datetime
-from inspect import getargspec
 
 from django.conf import settings
 from django.core.exceptions import SuspiciousFileOperation
@@ -14,6 +13,7 @@ from django.utils.deconstruct import deconstructible
 from django.utils.deprecation import RemovedInDjango110Warning
 from django.utils.encoding import filepath_to_uri, force_text
 from django.utils.functional import LazyObject
+from django.utils.inspect import func_supports_parameter
 from django.utils.module_loading import import_string
 from django.utils.six.moves.urllib.parse import urljoin
 from django.utils.text import get_valid_filename
@@ -49,8 +49,7 @@ class Storage(object):
         if not hasattr(content, 'chunks'):
             content = File(content)
 
-        args, varargs, varkw, defaults = getargspec(self.get_available_name)
-        if 'max_length' in args:
+        if func_supports_parameter(self.get_available_name, 'max_length'):
             name = self.get_available_name(name, max_length=max_length)
         else:
             warnings.warn(
diff --git a/django/core/management/__init__.py b/django/core/management/__init__.py
index e2885bb..4bbf57e 100644
--- a/django/core/management/__init__.py
+++ b/django/core/management/__init__.py
@@ -1,6 +1,6 @@
 from __future__ import unicode_literals
 
-import collections
+from collections import OrderedDict, defaultdict
 from importlib import import_module
 import os
 import pkgutil
@@ -145,7 +145,7 @@ class ManagementUtility(object):
                 "",
                 "Available subcommands:",
             ]
-            commands_dict = collections.defaultdict(lambda: [])
+            commands_dict = defaultdict(lambda: [])
             for name, app in six.iteritems(get_commands()):
                 if app == 'django.core':
                     app = 'django'
@@ -317,8 +317,11 @@ class ManagementUtility(object):
                     autoreload.check_errors(django.setup)()
                 except Exception:
                     # The exception will be raised later in the child process
-                    # started by the autoreloader.
-                    pass
+                    # started by the autoreloader. Pretend it didn't happen by
+                    # loading an empty list of applications.
+                    apps.all_models = defaultdict(OrderedDict)
+                    apps.app_configs = OrderedDict()
+                    apps.apps_ready = apps.models_ready = apps.ready = True
 
             # In all other cases, django.setup() is required to succeed.
             else:
diff --git a/django/core/validators.py b/django/core/validators.py
index cd5b16b..89d184f 100644
--- a/django/core/validators.py
+++ b/django/core/validators.py
@@ -73,7 +73,7 @@ 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-]*(?<!-))*'
+    domain_re = r'(?:\.(?!-)[a-z' + ul + r'0-9-]+(?<!-))*'
     tld_re = r'\.(?:[a-z' + ul + r']{2,}|xn--[a-z0-9]+)\.?'
     host_re = '(' + hostname_re + domain_re + tld_re + '|localhost)'
 
diff --git a/django/db/backends/sqlite3/creation.py b/django/db/backends/sqlite3/creation.py
index 3632e65..90670a0 100644
--- a/django/db/backends/sqlite3/creation.py
+++ b/django/db/backends/sqlite3/creation.py
@@ -18,14 +18,16 @@ class DatabaseCreation(BaseDatabaseCreation):
 
     def _get_test_db_name(self):
         test_database_name = self.connection.settings_dict['TEST']['NAME']
+        can_share_in_memory_db = self.connection.features.can_share_in_memory_db
         if test_database_name and test_database_name != ':memory:':
-            if 'mode=memory' in test_database_name:
+            if 'mode=memory' in test_database_name and not can_share_in_memory_db:
                 raise ImproperlyConfigured(
-                    "Using `mode=memory` parameter in the database name is not allowed, "
+                    "Using a shared memory database with `mode=memory` in the "
+                    "database name is not supported in your environment, "
                     "use `:memory:` instead."
                 )
             return test_database_name
-        if self.connection.features.can_share_in_memory_db:
+        if can_share_in_memory_db:
             return 'file:memorydb_%s?mode=memory&cache=shared' % self.connection.alias
         return ':memory:'
 
diff --git a/django/db/migrations/loader.py b/django/db/migrations/loader.py
index e824728..35266a7 100644
--- a/django/db/migrations/loader.py
+++ b/django/db/migrations/loader.py
@@ -116,6 +116,12 @@ class MigrationLoader(object):
                     break
                 self.disk_migrations[app_config.label, migration_name] = migration_module.Migration(migration_name, app_config.label)
             if south_style_migrations:
+                if app_config.label in self.migrated_apps:
+                    raise BadMigrationError(
+                        "Migrated app %r contains South migrations. Make sure "
+                        "all numbered South migrations are deleted prior to "
+                        "creating Django migrations." % app_config.label
+                    )
                 self.unmigrated_apps.add(app_config.label)
 
     def get_migration(self, app_label, name_prefix):
diff --git a/django/db/migrations/writer.py b/django/db/migrations/writer.py
index 1bed59b..779c842 100644
--- a/django/db/migrations/writer.py
+++ b/django/db/migrations/writer.py
@@ -3,7 +3,6 @@ from __future__ import unicode_literals
 import collections
 import datetime
 import decimal
-import inspect
 import math
 import os
 import re
@@ -19,6 +18,7 @@ from django.utils import datetime_safe, six
 from django.utils._os import upath
 from django.utils.encoding import force_text
 from django.utils.functional import Promise
+from django.utils.inspect import get_func_args
 from django.utils.timezone import utc
 from django.utils.version import get_docs_version
 
@@ -97,7 +97,7 @@ class OperationWriter(object):
 
         imports = set()
         name, args, kwargs = self.operation.deconstruct()
-        argspec = inspect.getargspec(self.operation.__init__)
+        operation_args = get_func_args(self.operation.__init__)
 
         # See if this operation is in django.db.migrations. If it is,
         # We can just use the fact we already have that imported,
@@ -110,16 +110,15 @@ class OperationWriter(object):
 
         self.indent()
 
-        # Start at one because argspec includes "self"
-        for i, arg in enumerate(args, 1):
+        for i, arg in enumerate(args):
             arg_value = arg
-            arg_name = argspec.args[i]
+            arg_name = operation_args[i]
             _write(arg_name, arg_value)
 
         i = len(args)
         # Only iterate over remaining arguments
-        for arg_name in argspec.args[i + 1:]:
-            if arg_name in kwargs:
+        for arg_name in operation_args[i:]:
+            if arg_name in kwargs:  # Don't sort to maintain signature order
                 arg_value = kwargs[arg_name]
                 _write(arg_name, arg_value)
 
diff --git a/django/db/models/expressions.py b/django/db/models/expressions.py
index d3769b4..5d6fab6 100644
--- a/django/db/models/expressions.py
+++ b/django/db/models/expressions.py
@@ -339,6 +339,17 @@ class BaseExpression(object):
     def reverse_ordering(self):
         return self
 
+    def flatten(self):
+        """
+        Recursively yield this expression and all subexpressions, in
+        depth-first order.
+        """
+        yield self
+        for expr in self.get_source_expressions():
+            if expr:
+                for inner_expr in expr.flatten():
+                    yield inner_expr
+
 
 class Expression(BaseExpression, Combinable):
     """
diff --git a/django/db/models/fields/files.py b/django/db/models/fields/files.py
index 73c67be..d6c1eaf 100644
--- a/django/db/models/fields/files.py
+++ b/django/db/models/fields/files.py
@@ -1,7 +1,6 @@
 import datetime
 import os
 import warnings
-from inspect import getargspec
 
 from django import forms
 from django.core import checks
@@ -13,6 +12,7 @@ from django.db.models.fields import Field
 from django.utils import six
 from django.utils.deprecation import RemovedInDjango110Warning
 from django.utils.encoding import force_str, force_text
+from django.utils.inspect import func_supports_parameter
 from django.utils.translation import ugettext_lazy as _
 
 
@@ -89,8 +89,7 @@ class FieldFile(File):
     def save(self, name, content, save=True):
         name = self.field.generate_filename(self.instance, name)
 
-        args, varargs, varkw, defaults = getargspec(self.storage.save)
-        if 'max_length' in args:
+        if func_supports_parameter(self.storage.save, 'max_length'):
             self.name = self.storage.save(name, content, max_length=self.field.max_length)
         else:
             warnings.warn(
diff --git a/django/db/models/fields/related.py b/django/db/models/fields/related.py
index 83e2a0a..47b479c 100644
--- a/django/db/models/fields/related.py
+++ b/django/db/models/fields/related.py
@@ -1523,6 +1523,9 @@ class ForeignObject(RelatedField):
         except AttributeError:
             return []
 
+        if not self.foreign_related_fields:
+            return []
+
         has_unique_field = any(rel_field.unique
             for rel_field in self.foreign_related_fields)
         if not has_unique_field and len(self.foreign_related_fields) > 1:
@@ -1622,7 +1625,7 @@ class ForeignObject(RelatedField):
 
     @property
     def foreign_related_fields(self):
-        return tuple(rhs_field for lhs_field, rhs_field in self.related_fields)
+        return tuple(rhs_field for lhs_field, rhs_field in self.related_fields if rhs_field)
 
     def get_local_related_value(self, instance):
         return self.get_instance_value_for_fields(instance, self.local_related_fields)
@@ -2537,7 +2540,7 @@ class ManyToManyField(RelatedField):
             # related_name with one generated from the m2m field name. Django
             # still uses backwards relations internally and we need to avoid
             # clashes between multiple m2m fields with related_name == '+'.
-            self.rel.related_name = "_%s_+" % name
+            self.rel.related_name = "_%s_%s_+" % (cls.__name__.lower(), name)
 
         super(ManyToManyField, self).contribute_to_class(cls, name, **kwargs)
 
diff --git a/django/db/models/functions.py b/django/db/models/functions.py
index 610ecb6..92665a6 100644
--- a/django/db/models/functions.py
+++ b/django/db/models/functions.py
@@ -41,20 +41,23 @@ class ConcatPair(Func):
         super(ConcatPair, self).__init__(left, right, **extra)
 
     def as_sqlite(self, compiler, connection):
-        self.arg_joiner = ' || '
-        self.template = '%(expressions)s'
-        self.coalesce()
-        return super(ConcatPair, self).as_sql(compiler, connection)
+        coalesced = self.coalesce()
+        coalesced.arg_joiner = ' || '
+        coalesced.template = '%(expressions)s'
+        return super(ConcatPair, coalesced).as_sql(compiler, connection)
 
     def as_mysql(self, compiler, connection):
-        self.coalesce()
-        return super(ConcatPair, self).as_sql(compiler, connection)
+        coalesced = self.coalesce()
+        return super(ConcatPair, coalesced).as_sql(compiler, connection)
 
     def coalesce(self):
         # null on either side results in null for expression, wrap with coalesce
+        c = self.copy()
         expressions = [
-            Coalesce(expression, Value('')) for expression in self.get_source_expressions()]
-        self.set_source_expressions(expressions)
+            Coalesce(expression, Value('')) for expression in c.get_source_expressions()
+        ]
+        c.set_source_expressions(expressions)
+        return c
 
 
 class Concat(Func):
diff --git a/django/db/models/lookups.py b/django/db/models/lookups.py
index d6fb607..d0b30ac 100644
--- a/django/db/models/lookups.py
+++ b/django/db/models/lookups.py
@@ -204,7 +204,7 @@ class BuiltinLookup(Lookup):
         lhs_sql = connection.ops.field_cast_sql(
             db_type, field_internal_type) % lhs_sql
         lhs_sql = connection.ops.lookup_cast(self.lookup_name, field_internal_type) % lhs_sql
-        return lhs_sql, params
+        return lhs_sql, list(params)
 
     def as_sql(self, compiler, connection):
         lhs_sql, params = self.process_lhs(compiler, connection)
diff --git a/django/db/models/query_utils.py b/django/db/models/query_utils.py
index 3f24ab8..4eca2c9 100644
--- a/django/db/models/query_utils.py
+++ b/django/db/models/query_utils.py
@@ -9,7 +9,6 @@ from __future__ import unicode_literals
 
 from collections import namedtuple
 
-from django.apps import apps
 from django.core.exceptions import FieldDoesNotExist
 from django.db.backends import utils
 from django.db.models.constants import LOOKUP_SEP
@@ -215,12 +214,13 @@ def deferred_class_factory(model, attrs):
     """
     if not attrs:
         return model
+    opts = model._meta
     # Never create deferred models based on deferred model
     if model._deferred:
         # Deferred models are proxies for the non-deferred model. We never
         # create chains of defers => proxy_for_model is the non-deferred
         # model.
-        model = model._meta.proxy_for_model
+        model = opts.proxy_for_model
     # The app registry wants a unique name for each model, otherwise the new
     # class won't be created (we get an exception). Therefore, we generate
     # the name using the passed in attrs. It's OK to reuse an existing class
@@ -229,13 +229,14 @@ def deferred_class_factory(model, attrs):
     name = utils.truncate_name(name, 80, 32)
 
     try:
-        return apps.get_model(model._meta.app_label, name)
+        return opts.apps.get_model(model._meta.app_label, name)
 
     except LookupError:
 
         class Meta:
             proxy = True
-            app_label = model._meta.app_label
+            apps = opts.apps
+            app_label = opts.app_label
 
         overrides = {attr: DeferredAttribute(attr, model) for attr in attrs}
         overrides["Meta"] = Meta
diff --git a/django/db/utils.py b/django/db/utils.py
index 2261a69..e442ac1 100644
--- a/django/db/utils.py
+++ b/django/db/utils.py
@@ -13,6 +13,7 @@ from django.utils.deprecation import (
     RemovedInDjango19Warning, RemovedInDjango110Warning,
 )
 from django.utils.functional import cached_property
+from django.utils.inspect import HAS_INSPECT_SIGNATURE
 from django.utils.module_loading import import_string
 
 DEFAULT_DB_ALIAS = 'default'
@@ -333,8 +334,16 @@ class ConnectionRouter(object):
                 # If the router doesn't have a method, skip to the next one.
                 continue
 
-            argspec = inspect.getargspec(method)
-            if len(argspec.args) == 3 and not argspec.keywords:
+            if HAS_INSPECT_SIGNATURE:
+                sig = inspect.signature(router.allow_migrate)
+                has_deprecated_signature = not any(
+                    p.kind == inspect.Parameter.VAR_KEYWORD for p in sig.parameters.values()
+                )
+            else:
+                argspec = inspect.getargspec(router.allow_migrate)
+                has_deprecated_signature = len(argspec.args) == 3 and not argspec.keywords
+
+            if has_deprecated_signature:
                 warnings.warn(
                     "The signature of allow_migrate has changed from "
                     "allow_migrate(self, db, model) to "
diff --git a/django/dispatch/dispatcher.py b/django/dispatch/dispatcher.py
index b02adb8..5d7f24c 100644
--- a/django/dispatch/dispatcher.py
+++ b/django/dispatch/dispatcher.py
@@ -2,6 +2,7 @@ import sys
 import threading
 import weakref
 
+from django.utils.inspect import func_accepts_kwargs
 from django.utils.six.moves import range
 
 if sys.version_info < (3, 4):
@@ -87,24 +88,11 @@ class Signal(object):
 
         # If DEBUG is on, check that we got a good receiver
         if settings.configured and settings.DEBUG:
-            import inspect
             assert callable(receiver), "Signal receivers must be callable."
 
             # Check for **kwargs
-            # Not all callables are inspectable with getargspec, so we'll
-            # try a couple different ways but in the end fall back on assuming
-            # it is -- we don't want to prevent registration of valid but weird
-            # callables.
-            try:
-                argspec = inspect.getargspec(receiver)
-            except TypeError:
-                try:
-                    argspec = inspect.getargspec(receiver.__call__)
-                except (TypeError, AttributeError):
-                    argspec = None
-            if argspec:
-                assert argspec[2] is not None, \
-                    "Signal receivers must accept keyword arguments (**kwargs)."
+            if not func_accepts_kwargs(receiver):
+                raise ValueError("Signal receivers must accept keyword arguments (**kwargs).")
 
         if dispatch_uid:
             lookup_key = (dispatch_uid, _make_id(sender))
diff --git a/django/forms/models.py b/django/forms/models.py
index 2137e9f..1036e9b 100644
--- a/django/forms/models.py
+++ b/django/forms/models.py
@@ -1092,15 +1092,17 @@ class ModelChoiceIterator(object):
     def __iter__(self):
         if self.field.empty_label is not None:
             yield ("", self.field.empty_label)
+        method = 'all' if self.queryset._prefetch_related_lookups else 'iterator'
+        queryset = getattr(self.queryset, method)
         if self.field.cache_choices:
             if self.field.choice_cache is None:
                 self.field.choice_cache = [
-                    self.choice(obj) for obj in self.queryset.iterator()
+                    self.choice(obj) for obj in queryset()
                 ]
             for choice in self.field.choice_cache:
                 yield choice
         else:
-            for obj in self.queryset.iterator():
+            for obj in queryset():
                 yield self.choice(obj)
 
     def __len__(self):
diff --git a/django/http/multipartparser.py b/django/http/multipartparser.py
index 53e4149..375584e 100644
--- a/django/http/multipartparser.py
+++ b/django/http/multipartparser.py
@@ -327,12 +327,15 @@ class LazyStream(six.Iterator):
             while remaining != 0:
                 assert remaining > 0, 'remaining bytes to read should never go negative'
 
-                chunk = next(self)
-
-                emitting = chunk[:remaining]
-                self.unget(chunk[remaining:])
-                remaining -= len(emitting)
-                yield emitting
+                try:
+                    chunk = next(self)
+                except StopIteration:
+                    return
+                else:
+                    emitting = chunk[:remaining]
+                    self.unget(chunk[remaining:])
+                    remaining -= len(emitting)
+                    yield emitting
 
         out = b''.join(parts())
         return out
diff --git a/django/template/base.py b/django/template/base.py
index 5661bdc..79c8a48 100644
--- a/django/template/base.py
+++ b/django/template/base.py
@@ -51,11 +51,11 @@ u'<html></html>'
 
 from __future__ import unicode_literals
 
+import inspect
 import re
 import warnings
 from functools import partial
 from importlib import import_module
-from inspect import getargspec, getcallargs
 
 from django.apps import apps
 from django.template.context import (  # NOQA: imported for backwards compatibility
@@ -68,6 +68,7 @@ from django.utils.encoding import (
 )
 from django.utils.formats import localize
 from django.utils.html import conditional_escape
+from django.utils.inspect import getargspec
 from django.utils.itercompat import is_iterable
 from django.utils.module_loading import module_has_submodule
 from django.utils.safestring import (
@@ -686,7 +687,8 @@ class FilterExpression(object):
         plen = len(provided) + 1
         # Check to see if a decorator is providing the real function.
         func = getattr(func, '_decorated_function', func)
-        args, varargs, varkw, defaults = getargspec(func)
+
+        args, _, _, defaults = getargspec(func)
         alen = len(args)
         dlen = len(defaults or [])
         # Not enough OR Too many
@@ -847,7 +849,7 @@ class Variable(object):
                             current = current()
                         except TypeError:
                             try:
-                                getcallargs(current)
+                                inspect.getcallargs(current)
                             except TypeError:  # arguments *were* required
                                 current = context.template.engine.string_if_invalid  # invalid method call
                             else:
diff --git a/django/utils/deprecation.py b/django/utils/deprecation.py
index 6a0c91d..8a24764 100644
--- a/django/utils/deprecation.py
+++ b/django/utils/deprecation.py
@@ -1,3 +1,5 @@
+from __future__ import absolute_import
+
 import inspect
 import warnings
 
diff --git a/django/utils/inspect.py b/django/utils/inspect.py
new file mode 100644
index 0000000..ab584c5
--- /dev/null
+++ b/django/utils/inspect.py
@@ -0,0 +1,81 @@
+from __future__ import absolute_import
+
+import inspect
+import sys
+
+HAS_INSPECT_SIGNATURE = sys.version_info >= (3, 3)
+
+
+def getargspec(func):
+    if not HAS_INSPECT_SIGNATURE:
+        return inspect.getargspec(func)
+
+    sig = inspect.signature(func)
+    args = [
+        p.name for p in sig.parameters.values()
+        if p.kind == inspect.Parameter.POSITIONAL_OR_KEYWORD
+    ]
+    varargs = [
+        p.name for p in sig.parameters.values()
+        if p.kind == inspect.Parameter.VAR_POSITIONAL
+    ]
+    varargs = varargs[0] if varargs else None
+    varkw = [
+        p.name for p in sig.parameters.values()
+        if p.kind == inspect.Parameter.VAR_KEYWORD
+    ]
+    varkw = varkw[0] if varkw else None
+    defaults = [
+        p.default for p in sig.parameters.values()
+        if p.kind == inspect.Parameter.POSITIONAL_OR_KEYWORD and p.default is not p.empty
+    ] or None
+    return args, varargs, varkw, defaults
+
+
+def get_func_args(func):
+    if not HAS_INSPECT_SIGNATURE:
+        argspec = inspect.getargspec(func)
+        return argspec.args[1:]  # ignore 'self'
+
+    sig = inspect.signature(func)
+    return [
+        arg_name for arg_name, param in sig.parameters.items()
+        if param.kind == inspect.Parameter.POSITIONAL_OR_KEYWORD
+    ]
+
+
+def func_accepts_kwargs(func):
+    if not HAS_INSPECT_SIGNATURE:
+        # Not all callables are inspectable with getargspec, so we'll
+        # try a couple different ways but in the end fall back on assuming
+        # it is -- we don't want to prevent registration of valid but weird
+        # callables.
+        try:
+            argspec = inspect.getargspec(func)
+        except TypeError:
+            try:
+                argspec = inspect.getargspec(func.__call__)
+            except (TypeError, AttributeError):
+                argspec = None
+        return not argspec or argspec[2] is not None
+
+    return any(
+        p for p in inspect.signature(func).parameters.values()
+        if p.kind == p.VAR_KEYWORD
+    )
+
+
+def func_has_no_args(func):
+    args = inspect.getargspec(func)[0] if not HAS_INSPECT_SIGNATURE else [
+        p for p in inspect.signature(func).parameters.values()
+        if p.kind == p.POSITIONAL_OR_KEYWORD and p.default is p.empty
+    ]
+    return len(args) == 1
+
+
+def func_supports_parameter(func, parameter):
+    if HAS_INSPECT_SIGNATURE:
+        return parameter in inspect.signature(func).parameters
+    else:
+        args, varargs, varkw, defaults = inspect.getargspec(func)
+        return parameter in args
diff --git a/docs/faq/install.txt b/docs/faq/install.txt
index ac4fac2..84acb55 100644
--- a/docs/faq/install.txt
+++ b/docs/faq/install.txt
@@ -45,8 +45,8 @@ What Python version can I use with Django?
 ============== ===============
 Django version Python versions
 ============== ===============
-1.4            2.5, 2.6, 2.7
-**1.7, 1.8**   **2.7** and **3.2, 3.3, 3.4**
+1.7            2.7 and 3.2, 3.3, 3.4
+**1.8**        **2.7** and **3.2, 3.3, 3.4, 3.5**
 1.9            2.7, 3.4, 3.5
 ============== ===============
 
diff --git a/docs/howto/custom-management-commands.txt b/docs/howto/custom-management-commands.txt
index 6547bf5..4e55111 100644
--- a/docs/howto/custom-management-commands.txt
+++ b/docs/howto/custom-management-commands.txt
@@ -366,6 +366,9 @@ the :meth:`~BaseCommand.handle` method must be implemented.
 
     The actual logic of the command. Subclasses must implement this method.
 
+    It may return a Unicode string which will be printed to ``stdout`` (wrapped
+    by ``BEGIN;`` and ``COMMIT;`` if :attr:`output_transaction` is ``True``).
+
 .. method:: BaseCommand.check(app_configs=None, tags=None, display_num_errors=False)
 
     .. versionadded:: 1.7
diff --git a/docs/intro/tutorial05.txt b/docs/intro/tutorial05.txt
index eaa6133..5e7bf73 100644
--- a/docs/intro/tutorial05.txt
+++ b/docs/intro/tutorial05.txt
@@ -369,7 +369,7 @@ With that ready, we can ask the client to do some work for us::
     >>> response.status_code
     200
     >>> response.content
-    '\n\n\n    <p>No polls are available.</p>\n\n'
+    b'\n\n\n    <p>No polls are available.</p>\n\n'
     >>> # note - you might get unexpected results if your ``TIME_ZONE``
     >>> # in ``settings.py`` is not correct. If you need to change it,
     >>> # you will also need to restart your shell session
@@ -381,7 +381,7 @@ With that ready, we can ask the client to do some work for us::
     >>> # check the response once again
     >>> response = client.get('/polls/')
     >>> response.content
-    '\n\n\n    <ul>\n    \n        <li><a href="/polls/1/">Who is your favorite Beatle?</a></li>\n    \n    </ul>\n\n'
+    b'\n\n\n    <ul>\n    \n        <li><a href="/polls/1/">Who is your favorite Beatle?</a></li>\n    \n    </ul>\n\n'
     >>> # If the following doesn't work, you probably omitted the call to
     >>> # setup_test_environment() described above
     >>> response.context['latest_question_list']
diff --git a/docs/ref/class-based-views/mixins-single-object.txt b/docs/ref/class-based-views/mixins-single-object.txt
index 8296064..af9acbf 100644
--- a/docs/ref/class-based-views/mixins-single-object.txt
+++ b/docs/ref/class-based-views/mixins-single-object.txt
@@ -106,20 +106,34 @@ SingleObjectMixin
 
         Returns context data for displaying the list of objects.
 
-        The base implementation of this method requires that the ``object``
+        The base implementation of this method requires that the ``self.object``
         attribute be set by the view (even if ``None``). Be sure to do this if
         you are using this mixin without one of the built-in views that does so.
 
+        It returns a dictionary with these contents:
+
+        * ``object``: The object that this view is displaying
+          (``self.object``).
+        * ``context_object_name``: ``self.object`` will also be stored under
+          the name returned by :meth:`get_context_object_name`, which defaults
+          to the lowercased version of the model name.
+
+        .. admonition:: Context variables override values from template context processors
+
+            Any variables from :meth:`get_context_data` take precedence over
+            context variables from :ref:`context processors
+            <subclassing-context-requestcontext>`. For example, if your view
+            sets the :attr:`model` attribute to
+            :class:`~django.contrib.auth.models.User`, the default context
+            object name of ``user`` would override the ``user`` variable from
+            the :func:`django.contrib.auth.context_processors.auth` context
+            processor. Use :meth:`get_context_object_name` to avoid a clash.
+
     .. method:: get_slug_field()
 
         Returns the name of a slug field to be used to look up by slug. By
         default this simply returns the value of :attr:`slug_field`.
 
-    **Context**
-
-    * ``object``: The object that this view is displaying. If
-      ``context_object_name`` is specified, that variable will also be
-      set in the context, with the same value as ``object``.
 
 SingleObjectTemplateResponseMixin
 ---------------------------------
diff --git a/docs/ref/contrib/admin/admindocs.txt b/docs/ref/contrib/admin/admindocs.txt
index 040dc25..6be06d4 100644
--- a/docs/ref/contrib/admin/admindocs.txt
+++ b/docs/ref/contrib/admin/admindocs.txt
@@ -28,7 +28,7 @@ To activate the :mod:`~django.contrib.admindocs`, you will need to do
 the following:
 
 * Add :mod:`django.contrib.admindocs` to your :setting:`INSTALLED_APPS`.
-* Add ``(r'^admin/doc/', include('django.contrib.admindocs.urls'))`` to
+* Add ``url(r'^admin/doc/', include('django.contrib.admindocs.urls'))`` to
   your ``urlpatterns``. Make sure it's included *before* the
   ``r'^admin/'`` entry, so that requests to ``/admin/doc/`` don't get
   handled by the latter entry.
diff --git a/docs/ref/contrib/admin/index.txt b/docs/ref/contrib/admin/index.txt
index 9e69138..8656229 100644
--- a/docs/ref/contrib/admin/index.txt
+++ b/docs/ref/contrib/admin/index.txt
@@ -1671,7 +1671,7 @@ templates used by the :class:`ModelAdmin` views:
     changelist page if :attr:`~ModelAdmin.list_editable` is used. To use a
     custom formset, for example::
 
-        from django.forms.models import BaseModelFormSet
+        from django.forms import BaseModelFormSet
 
         class MyAdminFormSet(BaseModelFormSet):
             pass
diff --git a/docs/ref/contrib/contenttypes.txt b/docs/ref/contrib/contenttypes.txt
index 16f1e9a..298606e 100644
--- a/docs/ref/contrib/contenttypes.txt
+++ b/docs/ref/contrib/contenttypes.txt
@@ -475,18 +475,12 @@ signal.
 Generic relations and aggregation
 ---------------------------------
 
-:doc:`Django's database aggregation API </topics/db/aggregation>`
-doesn't work with a
+:doc:`Django's database aggregation API </topics/db/aggregation>` works with a
 :class:`~django.contrib.contenttypes.fields.GenericRelation`. For example, you
-might be tempted to try something like::
+can find out how many tags all the bookmarks have::
 
-    Bookmark.objects.aggregate(Count('tags'))
-
-This will not work correctly, however. The generic relation adds extra filters
-to the queryset to ensure the correct content type, but the
-:meth:`~django.db.models.query.QuerySet.aggregate` method doesn't take them
-into account. For now, if you need aggregates on generic relations, you'll
-need to calculate them without using the aggregation API.
+    >>> Bookmark.objects.aggregate(Count('tags'))
... 1734 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