[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