Refs #23919 -- Replaced kwargs.pop() with keyword-only arguments.

This commit is contained in:
Vytis Banaitis 2017-02-01 18:41:56 +02:00 committed by Tim Graham
parent 0ec4dc91e0
commit 8838d4dd49
41 changed files with 147 additions and 243 deletions

View File

@ -6,7 +6,7 @@ from django.urls import LocaleRegexURLResolver, get_resolver
from django.views.i18n import set_language from django.views.i18n import set_language
def i18n_patterns(*urls, **kwargs): def i18n_patterns(*urls, prefix_default_language=True):
""" """
Adds the language code prefix to every URL pattern within this Adds the language code prefix to every URL pattern within this
function. This may only be used in the root URLconf, not in an included function. This may only be used in the root URLconf, not in an included
@ -14,8 +14,6 @@ def i18n_patterns(*urls, **kwargs):
""" """
if not settings.USE_I18N: if not settings.USE_I18N:
return list(urls) return list(urls)
prefix_default_language = kwargs.pop('prefix_default_language', True)
assert not kwargs, 'Unexpected kwargs for i18n_patterns(): %s' % kwargs
return [LocaleRegexURLResolver(list(urls), prefix_default_language=prefix_default_language)] return [LocaleRegexURLResolver(list(urls), prefix_default_language=prefix_default_language)]

View File

@ -1,4 +1,4 @@
def register(*models, **kwargs): def register(*models, site=None):
""" """
Registers the given model(s) classes and wrapped ModelAdmin class with Registers the given model(s) classes and wrapped ModelAdmin class with
admin site: admin site:
@ -7,17 +7,16 @@ def register(*models, **kwargs):
class AuthorAdmin(admin.ModelAdmin): class AuthorAdmin(admin.ModelAdmin):
pass pass
A kwarg of `site` can be passed as the admin site, otherwise the default The `site` kwarg is an admin site to use instead of the default admin site.
admin site will be used.
""" """
from django.contrib.admin import ModelAdmin from django.contrib.admin import ModelAdmin
from django.contrib.admin.sites import site, AdminSite from django.contrib.admin.sites import site as default_site, AdminSite
def _model_admin_wrapper(admin_class): def _model_admin_wrapper(admin_class):
if not models: if not models:
raise ValueError('At least one model must be passed to register.') raise ValueError('At least one model must be passed to register.')
admin_site = kwargs.pop('site', site) admin_site = site or default_site
if not isinstance(admin_site, AdminSite): if not isinstance(admin_site, AdminSite):
raise ValueError('site must subclass AdminSite') raise ValueError('site must subclass AdminSite')

View File

@ -496,10 +496,8 @@ def create_generic_related_manager(superclass, rel):
self.object_id_field_name: self.pk_val, self.object_id_field_name: self.pk_val,
} }
def __call__(self, **kwargs): def __call__(self, *, manager):
# We use **kwargs rather than a kwarg argument to enforce the manager = getattr(self.model, manager)
# `manager='manager_name'` syntax.
manager = getattr(self.model, kwargs.pop('manager'))
manager_class = create_generic_related_manager(manager.__class__, rel) manager_class = create_generic_related_manager(manager.__class__, rel)
return manager_class(instance=self.instance) return manager_class(instance=self.instance)
do_not_call_in_templates = True do_not_call_in_templates = True
@ -542,8 +540,7 @@ def create_generic_related_manager(superclass, rel):
False, False,
self.prefetch_cache_name) self.prefetch_cache_name)
def add(self, *objs, **kwargs): def add(self, *objs, bulk=True):
bulk = kwargs.pop('bulk', True)
db = router.db_for_write(self.model, instance=self.instance) db = router.db_for_write(self.model, instance=self.instance)
def check_and_update_obj(obj): def check_and_update_obj(obj):
@ -576,15 +573,13 @@ def create_generic_related_manager(superclass, rel):
obj.save() obj.save()
add.alters_data = True add.alters_data = True
def remove(self, *objs, **kwargs): def remove(self, *objs, bulk=True):
if not objs: if not objs:
return return
bulk = kwargs.pop('bulk', True)
self._clear(self.filter(pk__in=[o.pk for o in objs]), bulk) self._clear(self.filter(pk__in=[o.pk for o in objs]), bulk)
remove.alters_data = True remove.alters_data = True
def clear(self, **kwargs): def clear(self, *, bulk=True):
bulk = kwargs.pop('bulk', True)
self._clear(self, bulk) self._clear(self, bulk)
clear.alters_data = True clear.alters_data = True
@ -601,14 +596,11 @@ def create_generic_related_manager(superclass, rel):
obj.delete() obj.delete()
_clear.alters_data = True _clear.alters_data = True
def set(self, objs, **kwargs): def set(self, objs, *, bulk=True, clear=False):
# Force evaluation of `objs` in case it's a queryset whose value # Force evaluation of `objs` in case it's a queryset whose value
# could be affected by `manager.clear()`. Refs #19816. # could be affected by `manager.clear()`. Refs #19816.
objs = tuple(objs) objs = tuple(objs)
bulk = kwargs.pop('bulk', True)
clear = kwargs.pop('clear', False)
db = router.db_for_write(self.model, instance=self.instance) db = router.db_for_write(self.model, instance=self.instance)
with transaction.atomic(using=db, savepoint=False): with transaction.atomic(using=db, savepoint=False):
if clear: if clear:

View File

@ -60,11 +60,10 @@ class ContentTypeManager(models.Manager):
self._add_to_cache(self.db, ct) self._add_to_cache(self.db, ct)
return ct return ct
def get_for_models(self, *models, **kwargs): def get_for_models(self, *models, for_concrete_models=True):
""" """
Given *models, returns a dictionary mapping {model: content_type}. Given *models, returns a dictionary mapping {model: content_type}.
""" """
for_concrete_models = kwargs.pop('for_concrete_models', True)
results = {} results = {}
# Models that aren't already in the cache. # Models that aren't already in the cache.
needed_app_labels = set() needed_app_labels = set()

View File

@ -263,7 +263,8 @@ class GeometryField(GeoSelectFormatMixin, BaseSpatialField):
# The OpenGIS Geometry name. # The OpenGIS Geometry name.
geom_type = 'GEOMETRY' geom_type = 'GEOMETRY'
def __init__(self, verbose_name=None, dim=2, geography=False, **kwargs): def __init__(self, verbose_name=None, dim=2, geography=False, *, extent=(-180.0, -90.0, 180.0, 90.0),
tolerance=0.05, **kwargs):
""" """
The initialization function for geometry fields. In addition to the The initialization function for geometry fields. In addition to the
parameters from BaseSpatialField, it takes the following as keyword parameters from BaseSpatialField, it takes the following as keyword
@ -289,8 +290,8 @@ class GeometryField(GeoSelectFormatMixin, BaseSpatialField):
# Oracle-specific private attributes for creating the entry in # Oracle-specific private attributes for creating the entry in
# `USER_SDO_GEOM_METADATA` # `USER_SDO_GEOM_METADATA`
self._extent = kwargs.pop('extent', (-180.0, -90.0, 180.0, 90.0)) self._extent = extent
self._tolerance = kwargs.pop('tolerance', 0.05) self._tolerance = tolerance
super().__init__(verbose_name=verbose_name, **kwargs) super().__init__(verbose_name=verbose_name, **kwargs)

View File

@ -22,11 +22,10 @@ class GeometryField(forms.Field):
'to the SRID of the geometry form field.'), 'to the SRID of the geometry form field.'),
} }
def __init__(self, **kwargs): def __init__(self, *, srid=None, geom_type=None, **kwargs):
# Pop out attributes from the database field, or use sensible self.srid = srid
# defaults (e.g., allow None). if geom_type is not None:
self.srid = kwargs.pop('srid', None) self.geom_type = geom_type
self.geom_type = kwargs.pop('geom_type', self.geom_type)
super().__init__(**kwargs) super().__init__(**kwargs)
self.widget.attrs['geom_type'] = self.geom_type self.widget.attrs['geom_type'] = self.geom_type

View File

@ -147,11 +147,14 @@ class GEOSFuncFactory:
restype = None restype = None
errcheck = None errcheck = None
def __init__(self, func_name, *args, **kwargs): def __init__(self, func_name, *args, restype=None, errcheck=None, argtypes=None, **kwargs):
self.func_name = func_name self.func_name = func_name
self.restype = kwargs.pop('restype', self.restype) if restype is not None:
self.errcheck = kwargs.pop('errcheck', self.errcheck) self.restype = restype
self.argtypes = kwargs.pop('argtypes', self.argtypes) if errcheck is not None:
self.errcheck = errcheck
if argtypes is not None:
self.argtypes = argtypes
self.args = args self.args = args
self.kwargs = kwargs self.kwargs = kwargs
self.func = None self.func = None

View File

@ -125,13 +125,11 @@ class SearchQueryCombinable:
class SearchQuery(SearchQueryCombinable, Value): class SearchQuery(SearchQueryCombinable, Value):
invert = False
_output_field = SearchQueryField() _output_field = SearchQueryField()
config = None
def __init__(self, value, output_field=None, **extra): def __init__(self, value, output_field=None, *, config=None, invert=False):
self.config = extra.pop('config', self.config) self.config = config
self.invert = extra.pop('invert', self.invert) self.invert = invert
super().__init__(value, output_field=output_field) super().__init__(value, output_field=output_field)
def resolve_expression(self, query=None, allow_joins=True, reuse=None, summarize=False, for_save=False): def resolve_expression(self, query=None, allow_joins=True, reuse=None, summarize=False, for_save=False):
@ -161,11 +159,7 @@ class SearchQuery(SearchQueryCombinable, Value):
return combined return combined
def __invert__(self): def __invert__(self):
extra = { return type(self)(self.value, config=self.config, invert=not self.invert)
'invert': not self.invert,
'config': self.config,
}
return type(self)(self.value, **extra)
class CombinedSearchQuery(SearchQueryCombinable, CombinedExpression): class CombinedSearchQuery(SearchQueryCombinable, CombinedExpression):

View File

@ -10,10 +10,10 @@ from django.core.mail.backends.console import \
class EmailBackend(ConsoleEmailBackend): class EmailBackend(ConsoleEmailBackend):
def __init__(self, *args, **kwargs): def __init__(self, *args, file_path=None, **kwargs):
self._fname = None self._fname = None
if 'file_path' in kwargs: if file_path is not None:
self.file_path = kwargs.pop('file_path') self.file_path = file_path
else: else:
self.file_path = getattr(settings, 'EMAIL_FILE_PATH', None) self.file_path = getattr(settings, 'EMAIL_FILE_PATH', None)
# Make sure self.file_path is a string. # Make sure self.file_path is a string.

View File

@ -62,19 +62,18 @@ class Serializer:
progress_class = ProgressBar progress_class = ProgressBar
stream_class = StringIO stream_class = StringIO
def serialize(self, queryset, **options): def serialize(self, queryset, *, stream=None, fields=None, use_natural_foreign_keys=False,
use_natural_primary_keys=False, progress_output=None, object_count=0, **options):
""" """
Serialize a queryset. Serialize a queryset.
""" """
self.options = options self.options = options
self.stream = options.pop("stream", self.stream_class()) self.stream = stream if stream is not None else self.stream_class()
self.selected_fields = options.pop("fields", None) self.selected_fields = fields
self.use_natural_foreign_keys = options.pop('use_natural_foreign_keys', False) self.use_natural_foreign_keys = use_natural_foreign_keys
self.use_natural_primary_keys = options.pop('use_natural_primary_keys', False) self.use_natural_primary_keys = use_natural_primary_keys
progress_bar = self.progress_class( progress_bar = self.progress_class(progress_output, object_count)
options.pop('progress_output', None), options.pop('object_count', 0)
)
self.start_serialization() self.start_serialization()
self.first = True self.first = True

View File

@ -79,15 +79,13 @@ class Serializer(base.Serializer):
return self.objects return self.objects
def Deserializer(object_list, **options): def Deserializer(object_list, *, using=DEFAULT_DB_ALIAS, ignorenonexistent=False, **options):
""" """
Deserialize simple Python objects back into Django ORM instances. Deserialize simple Python objects back into Django ORM instances.
It's expected that you pass the Python objects themselves (instead of a It's expected that you pass the Python objects themselves (instead of a
stream or a string) to the constructor stream or a string) to the constructor
""" """
db = options.pop('using', DEFAULT_DB_ALIAS)
ignore = options.pop('ignorenonexistent', False)
field_names_cache = {} # Model: <list of field_names> field_names_cache = {} # Model: <list of field_names>
for d in object_list: for d in object_list:
@ -95,7 +93,7 @@ def Deserializer(object_list, **options):
try: try:
Model = _get_model(d["model"]) Model = _get_model(d["model"])
except base.DeserializationError: except base.DeserializationError:
if ignore: if ignorenonexistent:
continue continue
else: else:
raise raise
@ -114,7 +112,7 @@ def Deserializer(object_list, **options):
# Handle each field # Handle each field
for (field_name, field_value) in d["fields"].items(): for (field_name, field_value) in d["fields"].items():
if ignore and field_name not in field_names: if ignorenonexistent and field_name not in field_names:
# skip fields no longer on model # skip fields no longer on model
continue continue
@ -131,7 +129,7 @@ def Deserializer(object_list, **options):
if hasattr(model._default_manager, 'get_by_natural_key'): if hasattr(model._default_manager, 'get_by_natural_key'):
def m2m_convert(value): def m2m_convert(value):
if hasattr(value, '__iter__') and not isinstance(value, str): if hasattr(value, '__iter__') and not isinstance(value, str):
return model._default_manager.db_manager(db).get_by_natural_key(*value).pk return model._default_manager.db_manager(using).get_by_natural_key(*value).pk
else: else:
return force_text(model._meta.pk.to_python(value), strings_only=True) return force_text(model._meta.pk.to_python(value), strings_only=True)
else: else:
@ -154,7 +152,7 @@ def Deserializer(object_list, **options):
field_name = field.remote_field.field_name field_name = field.remote_field.field_name
if hasattr(default_manager, 'get_by_natural_key'): if hasattr(default_manager, 'get_by_natural_key'):
if hasattr(field_value, '__iter__') and not isinstance(field_value, str): if hasattr(field_value, '__iter__') and not isinstance(field_value, str):
obj = default_manager.db_manager(db).get_by_natural_key(*field_value) obj = default_manager.db_manager(using).get_by_natural_key(*field_value)
value = getattr(obj, field.remote_field.field_name) value = getattr(obj, field.remote_field.field_name)
# If this is a natural foreign key to an object that # If this is a natural foreign key to an object that
# has a FK/O2O as the foreign key, use the FK value # has a FK/O2O as the foreign key, use the FK value
@ -177,7 +175,7 @@ def Deserializer(object_list, **options):
except Exception as e: except Exception as e:
raise base.DeserializationError.WithData(e, d['model'], d.get('pk'), field_value) raise base.DeserializationError.WithData(e, d['model'], d.get('pk'), field_value)
obj = base.build_instance(Model, data, db) obj = base.build_instance(Model, data, using)
yield base.DeserializedObject(obj, m2m_data) yield base.DeserializedObject(obj, m2m_data)

View File

@ -157,11 +157,11 @@ class Deserializer(base.Deserializer):
Deserialize XML. Deserialize XML.
""" """
def __init__(self, stream_or_string, **options): def __init__(self, stream_or_string, *, using=DEFAULT_DB_ALIAS, ignorenonexistent=False, **options):
super().__init__(stream_or_string, **options) super().__init__(stream_or_string, **options)
self.event_stream = pulldom.parse(self.stream, self._make_parser()) self.event_stream = pulldom.parse(self.stream, self._make_parser())
self.db = options.pop('using', DEFAULT_DB_ALIAS) self.db = using
self.ignore = options.pop('ignorenonexistent', False) self.ignore = ignorenonexistent
def _make_parser(self): def _make_parser(self):
"""Create a hardened XML parser (no custom/external entities).""" """Create a hardened XML parser (no custom/external entities)."""

View File

@ -59,10 +59,10 @@ class WSGIServer(simple_server.WSGIServer):
request_queue_size = 10 request_queue_size = 10
def __init__(self, *args, **kwargs): def __init__(self, *args, ipv6=False, allow_reuse_address=True, **kwargs):
if kwargs.pop('ipv6', False): if ipv6:
self.address_family = socket.AF_INET6 self.address_family = socket.AF_INET6
self.allow_reuse_address = kwargs.pop('allow_reuse_address', True) self.allow_reuse_address = allow_reuse_address
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
def server_bind(self): def server_bind(self):

View File

@ -10,15 +10,13 @@ class IntervalToSeconds(Func):
EXTRACT(second from %(expressions)s) EXTRACT(second from %(expressions)s)
""" """
def __init__(self, expression, **extra): def __init__(self, expression, *, output_field=None, **extra):
output_field = extra.pop('output_field', DecimalField()) super().__init__(expression, output_field=output_field or DecimalField(), **extra)
super().__init__(expression, output_field=output_field, **extra)
class SecondsToInterval(Func): class SecondsToInterval(Func):
function = 'NUMTODSINTERVAL' function = 'NUMTODSINTERVAL'
template = "%(function)s(%(expressions)s, 'SECOND')" template = "%(function)s(%(expressions)s, 'SECOND')"
def __init__(self, expression, **extra): def __init__(self, expression, *, output_field=None, **extra):
output_field = extra.pop('output_field', DurationField()) super().__init__(expression, output_field=output_field or DurationField(), **extra)
super().__init__(expression, output_field=output_field, **extra)

View File

@ -506,7 +506,7 @@ class Func(Expression):
arg_joiner = ', ' arg_joiner = ', '
arity = None # The number of arguments the function accepts. arity = None # The number of arguments the function accepts.
def __init__(self, *expressions, **extra): def __init__(self, *expressions, output_field=None, **extra):
if self.arity is not None and len(expressions) != self.arity: if self.arity is not None and len(expressions) != self.arity:
raise TypeError( raise TypeError(
"'%s' takes exactly %s %s (%s given)" % ( "'%s' takes exactly %s %s (%s given)" % (
@ -516,7 +516,6 @@ class Func(Expression):
len(expressions), len(expressions),
) )
) )
output_field = extra.pop('output_field', None)
super().__init__(output_field=output_field) super().__init__(output_field=output_field)
self.source_expressions = self._parse_expressions(*expressions) self.source_expressions = self._parse_expressions(*expressions)
self.extra = extra self.extra = extra
@ -828,11 +827,9 @@ class Case(Expression):
template = 'CASE %(cases)s ELSE %(default)s END' template = 'CASE %(cases)s ELSE %(default)s END'
case_joiner = ' ' case_joiner = ' '
def __init__(self, *cases, **extra): def __init__(self, *cases, default=None, output_field=None, **extra):
if not all(isinstance(case, When) for case in cases): if not all(isinstance(case, When) for case in cases):
raise TypeError("Positional arguments must all be When objects.") raise TypeError("Positional arguments must all be When objects.")
default = extra.pop('default', None)
output_field = extra.pop('output_field', None)
super().__init__(output_field) super().__init__(output_field)
self.cases = list(cases) self.cases = list(cases)
self.default = self._parse_expressions(default)[0] self.default = self._parse_expressions(default)[0]
@ -983,8 +980,8 @@ class Subquery(Expression):
class Exists(Subquery): class Exists(Subquery):
template = 'EXISTS(%(subquery)s)' template = 'EXISTS(%(subquery)s)'
def __init__(self, *args, **kwargs): def __init__(self, *args, negated=False, **kwargs):
self.negated = kwargs.pop('negated', False) self.negated = negated
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
def __invert__(self): def __invert__(self):

View File

@ -2045,15 +2045,11 @@ class SlugField(CharField):
default_validators = [validators.validate_slug] default_validators = [validators.validate_slug]
description = _("Slug (up to %(max_length)s)") description = _("Slug (up to %(max_length)s)")
def __init__(self, *args, **kwargs): def __init__(self, *args, max_length=50, db_index=True, allow_unicode=False, **kwargs):
kwargs['max_length'] = kwargs.get('max_length', 50) self.allow_unicode = allow_unicode
# Set db_index=True unless it's been set manually.
if 'db_index' not in kwargs:
kwargs['db_index'] = True
self.allow_unicode = kwargs.pop('allow_unicode', False)
if self.allow_unicode: if self.allow_unicode:
self.default_validators = [validators.validate_unicode_slug] self.default_validators = [validators.validate_unicode_slug]
super().__init__(*args, **kwargs) super().__init__(*args, max_length=max_length, db_index=db_index, **kwargs)
def deconstruct(self): def deconstruct(self):
name, path, args, kwargs = super().deconstruct() name, path, args, kwargs = super().deconstruct()

View File

@ -922,15 +922,14 @@ class ForeignKey(ForeignObject):
if self.remote_field.field_name is None: if self.remote_field.field_name is None:
self.remote_field.field_name = cls._meta.pk.name self.remote_field.field_name = cls._meta.pk.name
def formfield(self, **kwargs): def formfield(self, *, using=None, **kwargs):
db = kwargs.pop('using', None)
if isinstance(self.remote_field.model, str): if isinstance(self.remote_field.model, str):
raise ValueError("Cannot create form field for %r yet, because " raise ValueError("Cannot create form field for %r yet, because "
"its related model %r has not been loaded yet" % "its related model %r has not been loaded yet" %
(self.name, self.remote_field.model)) (self.name, self.remote_field.model))
defaults = { defaults = {
'form_class': forms.ModelChoiceField, 'form_class': forms.ModelChoiceField,
'queryset': self.remote_field.model._default_manager.using(db), 'queryset': self.remote_field.model._default_manager.using(using),
'to_field_name': self.remote_field.field_name, 'to_field_name': self.remote_field.field_name,
} }
defaults.update(kwargs) defaults.update(kwargs)
@ -1609,11 +1608,10 @@ class ManyToManyField(RelatedField):
def save_form_data(self, instance, data): def save_form_data(self, instance, data):
getattr(instance, self.attname).set(data) getattr(instance, self.attname).set(data)
def formfield(self, **kwargs): def formfield(self, *, using=None, **kwargs):
db = kwargs.pop('using', None)
defaults = { defaults = {
'form_class': forms.ModelMultipleChoiceField, 'form_class': forms.ModelMultipleChoiceField,
'queryset': self.remote_field.model._default_manager.using(db), 'queryset': self.remote_field.model._default_manager.using(using),
} }
defaults.update(kwargs) defaults.update(kwargs)
# If initial is passed in, it's a list of related objects, but the # If initial is passed in, it's a list of related objects, but the

View File

@ -510,10 +510,8 @@ def create_reverse_many_to_one_manager(superclass, rel):
self.core_filters = {self.field.name: instance} self.core_filters = {self.field.name: instance}
def __call__(self, **kwargs): def __call__(self, *, manager):
# We use **kwargs rather than a kwarg argument to enforce the manager = getattr(self.model, manager)
# `manager='manager_name'` syntax.
manager = getattr(self.model, kwargs.pop('manager'))
manager_class = create_reverse_many_to_one_manager(manager.__class__, rel) manager_class = create_reverse_many_to_one_manager(manager.__class__, rel)
return manager_class(self.instance) return manager_class(self.instance)
do_not_call_in_templates = True do_not_call_in_templates = True
@ -569,9 +567,8 @@ def create_reverse_many_to_one_manager(superclass, rel):
cache_name = self.field.related_query_name() cache_name = self.field.related_query_name()
return queryset, rel_obj_attr, instance_attr, False, cache_name return queryset, rel_obj_attr, instance_attr, False, cache_name
def add(self, *objs, **kwargs): def add(self, *objs, bulk=True):
self._remove_prefetched_objects() self._remove_prefetched_objects()
bulk = kwargs.pop('bulk', True)
objs = list(objs) objs = list(objs)
db = router.db_for_write(self.model, instance=self.instance) db = router.db_for_write(self.model, instance=self.instance)
@ -622,10 +619,9 @@ def create_reverse_many_to_one_manager(superclass, rel):
# remove() and clear() are only provided if the ForeignKey can have a value of null. # remove() and clear() are only provided if the ForeignKey can have a value of null.
if rel.field.null: if rel.field.null:
def remove(self, *objs, **kwargs): def remove(self, *objs, bulk=True):
if not objs: if not objs:
return return
bulk = kwargs.pop('bulk', True)
val = self.field.get_foreign_related_value(self.instance) val = self.field.get_foreign_related_value(self.instance)
old_ids = set() old_ids = set()
for obj in objs: for obj in objs:
@ -639,8 +635,7 @@ def create_reverse_many_to_one_manager(superclass, rel):
self._clear(self.filter(pk__in=old_ids), bulk) self._clear(self.filter(pk__in=old_ids), bulk)
remove.alters_data = True remove.alters_data = True
def clear(self, **kwargs): def clear(self, *, bulk=True):
bulk = kwargs.pop('bulk', True)
self._clear(self, bulk) self._clear(self, bulk)
clear.alters_data = True clear.alters_data = True
@ -658,14 +653,11 @@ def create_reverse_many_to_one_manager(superclass, rel):
obj.save(update_fields=[self.field.name]) obj.save(update_fields=[self.field.name])
_clear.alters_data = True _clear.alters_data = True
def set(self, objs, **kwargs): def set(self, objs, *, bulk=True, clear=False):
# Force evaluation of `objs` in case it's a queryset whose value # Force evaluation of `objs` in case it's a queryset whose value
# could be affected by `manager.clear()`. Refs #19816. # could be affected by `manager.clear()`. Refs #19816.
objs = tuple(objs) objs = tuple(objs)
bulk = kwargs.pop('bulk', True)
clear = kwargs.pop('clear', False)
if self.field.null: if self.field.null:
db = router.db_for_write(self.model, instance=self.instance) db = router.db_for_write(self.model, instance=self.instance)
with transaction.atomic(using=db, savepoint=False): with transaction.atomic(using=db, savepoint=False):
@ -791,10 +783,8 @@ def create_forward_many_to_many_manager(superclass, rel, reverse):
"a many-to-many relationship can be used." % "a many-to-many relationship can be used." %
instance.__class__.__name__) instance.__class__.__name__)
def __call__(self, **kwargs): def __call__(self, *, manager):
# We use **kwargs rather than a kwarg argument to enforce the manager = getattr(self.model, manager)
# `manager='manager_name'` syntax.
manager = getattr(self.model, kwargs.pop('manager'))
manager_class = create_forward_many_to_many_manager(manager.__class__, rel, reverse) manager_class = create_forward_many_to_many_manager(manager.__class__, rel, reverse)
return manager_class(instance=self.instance) return manager_class(instance=self.instance)
do_not_call_in_templates = True do_not_call_in_templates = True
@ -924,7 +914,7 @@ def create_forward_many_to_many_manager(superclass, rel, reverse):
) )
clear.alters_data = True clear.alters_data = True
def set(self, objs, **kwargs): def set(self, objs, *, clear=False):
if not rel.through._meta.auto_created: if not rel.through._meta.auto_created:
opts = self.through._meta opts = self.through._meta
raise AttributeError( raise AttributeError(
@ -937,8 +927,6 @@ def create_forward_many_to_many_manager(superclass, rel, reverse):
# could be affected by `manager.clear()`. Refs #19816. # could be affected by `manager.clear()`. Refs #19816.
objs = tuple(objs) objs = tuple(objs)
clear = kwargs.pop('clear', False)
db = router.db_for_write(self.through, instance=self.instance) db = router.db_for_write(self.through, instance=self.instance)
with transaction.atomic(using=db, savepoint=False): with transaction.atomic(using=db, savepoint=False):
if clear: if clear:

View File

@ -165,9 +165,8 @@ class Length(Transform):
function = 'LENGTH' function = 'LENGTH'
lookup_name = 'length' lookup_name = 'length'
def __init__(self, expression, **extra): def __init__(self, expression, *, output_field=None, **extra):
output_field = extra.pop('output_field', fields.IntegerField()) super().__init__(expression, output_field=output_field or fields.IntegerField(), **extra)
super().__init__(expression, output_field=output_field, **extra)
def as_mysql(self, compiler, connection): def as_mysql(self, compiler, connection):
return super().as_sql(compiler, connection, function='CHAR_LENGTH') return super().as_sql(compiler, connection, function='CHAR_LENGTH')

View File

@ -691,11 +691,7 @@ class QuerySet:
clone._iterable_class = ValuesIterable clone._iterable_class = ValuesIterable
return clone return clone
def values_list(self, *fields, **kwargs): def values_list(self, *fields, flat=False):
flat = kwargs.pop('flat', False)
if kwargs:
raise TypeError('Unexpected keyword arguments to values_list: %s' % (list(kwargs),))
if flat and len(fields) > 1: if flat and len(fields) > 1:
raise TypeError("'flat' is not valid when values_list is called with more than one field.") raise TypeError("'flat' is not valid when values_list is called with more than one field.")
@ -812,7 +808,7 @@ class QuerySet:
else: else:
return self._filter_or_exclude(None, **filter_obj) return self._filter_or_exclude(None, **filter_obj)
def _combinator_query(self, combinator, *other_qs, **kwargs): def _combinator_query(self, combinator, *other_qs, all=False):
# Clone the query to inherit the select list and everything # Clone the query to inherit the select list and everything
clone = self._clone() clone = self._clone()
# Clear limits and ordering so they can be reapplied # Clear limits and ordering so they can be reapplied
@ -820,18 +816,11 @@ class QuerySet:
clone.query.clear_limits() clone.query.clear_limits()
clone.query.combined_queries = (self.query,) + tuple(qs.query for qs in other_qs) clone.query.combined_queries = (self.query,) + tuple(qs.query for qs in other_qs)
clone.query.combinator = combinator clone.query.combinator = combinator
clone.query.combinator_all = kwargs.pop('all', False) clone.query.combinator_all = all
return clone return clone
def union(self, *other_qs, **kwargs): def union(self, *other_qs, all=False):
if kwargs: return self._combinator_query('union', *other_qs, all=all)
unexpected_kwarg = next((k for k in kwargs.keys() if k != 'all'), None)
if unexpected_kwarg:
raise TypeError(
"union() received an unexpected keyword argument '%s'" %
(unexpected_kwarg,)
)
return self._combinator_query('union', *other_qs, **kwargs)
def intersection(self, *other_qs): def intersection(self, *other_qs):
return self._combinator_query('intersection', *other_qs) return self._combinator_query('intersection', *other_qs)

View File

@ -541,9 +541,9 @@ class FileField(Field):
'contradiction': _('Please either submit a file or check the clear checkbox, not both.') 'contradiction': _('Please either submit a file or check the clear checkbox, not both.')
} }
def __init__(self, *args, **kwargs): def __init__(self, *args, max_length=None, allow_empty_file=False, **kwargs):
self.max_length = kwargs.pop('max_length', None) self.max_length = max_length
self.allow_empty_file = kwargs.pop('allow_empty_file', False) self.allow_empty_file = allow_empty_file
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
def to_python(self, data): def to_python(self, data):
@ -821,9 +821,9 @@ class ChoiceField(Field):
class TypedChoiceField(ChoiceField): class TypedChoiceField(ChoiceField):
def __init__(self, *args, **kwargs): def __init__(self, *args, coerce=lambda val: val, empty_value='', **kwargs):
self.coerce = kwargs.pop('coerce', lambda val: val) self.coerce = coerce
self.empty_value = kwargs.pop('empty_value', '') self.empty_value = empty_value
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
def _coerce(self, value): def _coerce(self, value):
@ -890,8 +890,8 @@ class MultipleChoiceField(ChoiceField):
class TypedMultipleChoiceField(MultipleChoiceField): class TypedMultipleChoiceField(MultipleChoiceField):
def __init__(self, *args, **kwargs): def __init__(self, *args, coerce=lambda val: val, **kwargs):
self.coerce = kwargs.pop('coerce', lambda val: val) self.coerce = coerce
self.empty_value = kwargs.pop('empty_value', []) self.empty_value = kwargs.pop('empty_value', [])
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
@ -971,8 +971,8 @@ class MultiValueField(Field):
'incomplete': _('Enter a complete value.'), 'incomplete': _('Enter a complete value.'),
} }
def __init__(self, fields=(), *args, **kwargs): def __init__(self, fields=(), *args, require_all_fields=True, **kwargs):
self.require_all_fields = kwargs.pop('require_all_fields', True) self.require_all_fields = require_all_fields
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
for f in fields: for f in fields:
f.error_messages.setdefault('incomplete', f.error_messages.setdefault('incomplete',
@ -1174,8 +1174,8 @@ class GenericIPAddressField(CharField):
class SlugField(CharField): class SlugField(CharField):
default_validators = [validators.validate_slug] default_validators = [validators.validate_slug]
def __init__(self, *args, **kwargs): def __init__(self, *args, allow_unicode=False, **kwargs):
self.allow_unicode = kwargs.pop('allow_unicode', False) self.allow_unicode = allow_unicode
if self.allow_unicode: if self.allow_unicode:
self.default_validators = [validators.validate_unicode_slug] self.default_validators = [validators.validate_unicode_slug]
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)

View File

@ -553,9 +553,9 @@ class BaseModelFormSet(BaseFormSet):
unique_fields = set() unique_fields = set()
def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None, def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None,
queryset=None, **kwargs): queryset=None, *, initial=None, **kwargs):
self.queryset = queryset self.queryset = queryset
self.initial_extra = kwargs.pop('initial', None) self.initial_extra = initial
defaults = {'data': data, 'files': files, 'auto_id': auto_id, 'prefix': prefix} defaults = {'data': data, 'files': files, 'auto_id': auto_id, 'prefix': prefix}
defaults.update(kwargs) defaults.update(kwargs)
super().__init__(**defaults) super().__init__(**defaults)
@ -1065,10 +1065,10 @@ class InlineForeignKeyField(Field):
'invalid_choice': _('The inline foreign key did not match the parent instance primary key.'), 'invalid_choice': _('The inline foreign key did not match the parent instance primary key.'),
} }
def __init__(self, parent_instance, *args, **kwargs): def __init__(self, parent_instance, *args, pk_field=False, to_field=None, **kwargs):
self.parent_instance = parent_instance self.parent_instance = parent_instance
self.pk_field = kwargs.pop("pk_field", False) self.pk_field = pk_field
self.to_field = kwargs.pop("to_field", None) self.to_field = to_field
if self.parent_instance is not None: if self.parent_instance is not None:
if self.to_field: if self.to_field:
kwargs["initial"] = getattr(self.parent_instance, self.to_field) kwargs["initial"] = getattr(self.parent_instance, self.to_field)

View File

@ -30,7 +30,7 @@ def render(request, template_name, context=None, content_type=None, status=None,
return HttpResponse(content, content_type, status) return HttpResponse(content, content_type, status)
def redirect(to, *args, **kwargs): def redirect(to, *args, permanent=False, **kwargs):
""" """
Returns an HttpResponseRedirect to the appropriate URL for the arguments Returns an HttpResponseRedirect to the appropriate URL for the arguments
passed. passed.
@ -47,11 +47,7 @@ def redirect(to, *args, **kwargs):
By default issues a temporary redirect; pass permanent=True to issue a By default issues a temporary redirect; pass permanent=True to issue a
permanent redirect permanent redirect
""" """
if kwargs.pop('permanent', False): redirect_class = HttpResponsePermanentRedirect if permanent else HttpResponseRedirect
redirect_class = HttpResponsePermanentRedirect
else:
redirect_class = HttpResponseRedirect
return redirect_class(resolve_url(to, *args, **kwargs)) return redirect_class(resolve_url(to, *args, **kwargs))

View File

@ -157,10 +157,10 @@ class ExtendsNode(Node):
class IncludeNode(Node): class IncludeNode(Node):
context_key = '__include_context' context_key = '__include_context'
def __init__(self, template, *args, **kwargs): def __init__(self, template, *args, extra_context=None, isolated_context=False, **kwargs):
self.template = template self.template = template
self.extra_context = kwargs.pop('extra_context', {}) self.extra_context = extra_context or {}
self.isolated_context = kwargs.pop('isolated_context', False) self.isolated_context = isolated_context
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
def render(self, context): def render(self, context):

View File

@ -929,8 +929,7 @@ class TransactionTestCase(SimpleTestCase):
"against more than one ordered values") "against more than one ordered values")
return self.assertEqual(list(items), values, msg=msg) return self.assertEqual(list(items), values, msg=msg)
def assertNumQueries(self, num, func=None, *args, **kwargs): def assertNumQueries(self, num, func=None, *args, using=DEFAULT_DB_ALIAS, **kwargs):
using = kwargs.pop("using", DEFAULT_DB_ALIAS)
conn = connections[using] conn = connections[using]
context = _AssertNumQueriesContext(self, num, conn) context = _AssertNumQueriesContext(self, num, conn)

View File

@ -235,12 +235,7 @@ class ImmutableList(tuple):
AttributeError: You cannot mutate this. AttributeError: You cannot mutate this.
""" """
def __new__(cls, *args, **kwargs): def __new__(cls, *args, warning='ImmutableList object is immutable.', **kwargs):
if 'warning' in kwargs:
warning = kwargs['warning']
del kwargs['warning']
else:
warning = 'ImmutableList object is immutable.'
self = tuple.__new__(cls, *args, **kwargs) self = tuple.__new__(cls, *args, **kwargs)
self.warning = warning self.warning = warning
return self return self

View File

@ -3,15 +3,13 @@ from importlib import import_module
from django.utils.version import get_docs_version from django.utils.version import get_docs_version
def deconstructible(*args, **kwargs): def deconstructible(*args, path=None):
""" """
Class decorator that allow the decorated class to be serialized Class decorator that allow the decorated class to be serialized
by the migrations subsystem. by the migrations subsystem.
Accepts an optional kwarg `path` to specify the import path. Accepts an optional kwarg `path` to specify the import path.
""" """
path = kwargs.pop('path', None)
def decorator(klass): def decorator(klass):
def __new__(cls, *args, **kwargs): def __new__(cls, *args, **kwargs):
# We capture the arguments to make returning them trivial # We capture the arguments to make returning them trivial
@ -54,4 +52,4 @@ def deconstructible(*args, **kwargs):
if not args: if not args:
return decorator return decorator
return decorator(*args, **kwargs) return decorator(*args)

View File

@ -5,7 +5,7 @@ from django.utils.cache import add_never_cache_headers, patch_cache_control
from django.utils.decorators import decorator_from_middleware_with_args from django.utils.decorators import decorator_from_middleware_with_args
def cache_page(*args, **kwargs): def cache_page(timeout, *, cache=None, key_prefix=None):
""" """
Decorator for views that tries getting the page from the cache and Decorator for views that tries getting the page from the cache and
populates the cache if the page isn't in the cache yet. populates the cache if the page isn't in the cache yet.
@ -19,18 +19,8 @@ def cache_page(*args, **kwargs):
Additionally, all headers from the response's Vary header will be taken Additionally, all headers from the response's Vary header will be taken
into account on caching -- just like the middleware does. into account on caching -- just like the middleware does.
""" """
# We also add some asserts to give better error messages in case people are
# using other ways to call cache_page that no longer work.
if len(args) != 1 or callable(args[0]):
raise TypeError("cache_page has a single mandatory positional argument: timeout")
cache_timeout = args[0]
cache_alias = kwargs.pop('cache', None)
key_prefix = kwargs.pop('key_prefix', None)
if kwargs:
raise TypeError("cache_page has two optional keyword arguments: cache and key_prefix")
return decorator_from_middleware_with_args(CacheMiddleware)( return decorator_from_middleware_with_args(CacheMiddleware)(
cache_timeout=cache_timeout, cache_alias=cache_alias, key_prefix=key_prefix cache_timeout=timeout, cache_alias=cache, key_prefix=key_prefix
) )

View File

@ -120,11 +120,11 @@ class MultipleObjectMixin(ContextMixin):
else: else:
return None return None
def get_context_data(self, **kwargs): def get_context_data(self, *, object_list=None, **kwargs):
""" """
Get the context for this view. Get the context for this view.
""" """
queryset = kwargs.pop('object_list', self.object_list) queryset = object_list if object_list is not None else self.object_list
page_size = self.get_paginate_by(queryset) page_size = self.get_paginate_by(queryset)
context_object_name = self.get_context_object_name(queryset) context_object_name = self.get_context_object_name(queryset)
if page_size: if page_size:

View File

@ -557,8 +557,8 @@ You can pass this parameter when instantiating the formset::
>>> from myapp.forms import ArticleForm >>> from myapp.forms import ArticleForm
>>> class MyArticleForm(ArticleForm): >>> class MyArticleForm(ArticleForm):
... def __init__(self, *args, **kwargs): ... def __init__(self, *args, user, **kwargs):
... self.user = kwargs.pop('user') ... self.user = user
... super().__init__(*args, **kwargs) ... super().__init__(*args, **kwargs)
>>> ArticleFormSet = formset_factory(MyArticleForm) >>> ArticleFormSet = formset_factory(MyArticleForm)

View File

@ -13,12 +13,10 @@ class RevisionableModel(models.Model):
def __str__(self): def __str__(self):
return "%s (%s, %s)" % (self.title, self.id, self.base.id) return "%s (%s, %s)" % (self.title, self.id, self.base.id)
def save(self, *args, **kwargs): def save(self, *args, force_insert=None, force_update=None, **kwargs):
super().save(*args, **kwargs) super().save(*args, force_insert=force_insert, force_update=force_update, **kwargs)
if not self.base: if not self.base:
self.base = self self.base = self
kwargs.pop('force_insert', None)
kwargs.pop('force_update', None)
super().save(*args, **kwargs) super().save(*args, **kwargs)
def new_revision(self): def new_revision(self):

View File

@ -56,8 +56,8 @@ SplitDateTimeFormSet = formset_factory(SplitDateTimeForm)
class CustomKwargForm(Form): class CustomKwargForm(Form):
def __init__(self, *args, **kwargs): def __init__(self, *args, custom_kwarg, **kwargs):
self.custom_kwarg = kwargs.pop('custom_kwarg') self.custom_kwarg = custom_kwarg
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)

View File

@ -1258,8 +1258,7 @@ class GEOSTest(SimpleTestCase, TestDataMixin):
to the parent class during `__init__`. to the parent class during `__init__`.
""" """
class ExtendedPolygon(Polygon): class ExtendedPolygon(Polygon):
def __init__(self, *args, **kwargs): def __init__(self, *args, data=0, **kwargs):
data = kwargs.pop('data', 0)
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
self._data = data self._data = data

View File

@ -43,9 +43,8 @@ class TestDS(TestObj):
""" """
Object for testing GDAL data sources. Object for testing GDAL data sources.
""" """
def __init__(self, name, **kwargs): def __init__(self, name, *, ext='shp', **kwargs):
# Shapefile is default extension, unless specified otherwise. # Shapefile is default extension, unless specified otherwise.
ext = kwargs.pop('ext', 'shp')
self.ds = get_ds_file(name, ext) self.ds = get_ds_file(name, ext)
super().__init__(**kwargs) super().__init__(**kwargs)
@ -55,19 +54,14 @@ class TestGeom(TestObj):
Testing object used for wrapping reference geometry data Testing object used for wrapping reference geometry data
in GEOS/GDAL tests. in GEOS/GDAL tests.
""" """
def __init__(self, **kwargs): def __init__(self, *, coords=None, centroid=None, ext_ring_cs=None, **kwargs):
# Converting lists to tuples of certain keyword args # Converting lists to tuples of certain keyword args
# so coordinate test cases will match (JSON has no # so coordinate test cases will match (JSON has no
# concept of tuple). # concept of tuple).
coords = kwargs.pop('coords', None)
if coords: if coords:
self.coords = tuplize(coords) self.coords = tuplize(coords)
centroid = kwargs.pop('centroid', None)
if centroid: if centroid:
self.centroid = tuple(centroid) self.centroid = tuple(centroid)
ext_ring_cs = kwargs.pop('ext_ring_cs', None)
if ext_ring_cs: if ext_ring_cs:
ext_ring_cs = tuplize(ext_ring_cs) ext_ring_cs = tuplize(ext_ring_cs)
self.ext_ring_cs = ext_ring_cs self.ext_ring_cs = ext_ring_cs

View File

@ -1388,10 +1388,6 @@ class UnprefixedDefaultLanguageTests(SimpleTestCase):
response = self.client.get('/simple/', HTTP_ACCEPT_LANGUAGE='fr') response = self.client.get('/simple/', HTTP_ACCEPT_LANGUAGE='fr')
self.assertEqual(response.content, b'Yes') self.assertEqual(response.content, b'Yes')
def test_unexpected_kwarg_to_i18n_patterns(self):
with self.assertRaisesMessage(AssertionError, "Unexpected kwargs for i18n_patterns(): {'foo':"):
i18n_patterns(object(), foo='bar')
def test_page_with_dash(self): def test_page_with_dash(self):
# A page starting with /de* shouldn't match the 'de' langauge code. # A page starting with /de* shouldn't match the 'de' langauge code.
response = self.client.get('/de-simple-page/') response = self.client.get('/de-simple-page/')

View File

@ -13,19 +13,19 @@ class SecurityMiddlewareTest(SimpleTestCase):
def secure_request_kwargs(self): def secure_request_kwargs(self):
return {"wsgi.url_scheme": "https"} return {"wsgi.url_scheme": "https"}
def response(self, *args, **kwargs): def response(self, *args, headers=None, **kwargs):
headers = kwargs.pop("headers", {})
response = HttpResponse(*args, **kwargs) response = HttpResponse(*args, **kwargs)
for k, v in headers.items(): if headers:
response[k] = v for k, v in headers.items():
response[k] = v
return response return response
def process_response(self, *args, **kwargs): def process_response(self, *args, secure=False, request=None, **kwargs):
request_kwargs = {} request_kwargs = {}
if kwargs.pop("secure", False): if secure:
request_kwargs.update(self.secure_request_kwargs) request_kwargs.update(self.secure_request_kwargs)
request = (kwargs.pop("request", None) or if request is None:
self.request.get("/some/url", **request_kwargs)) request = self.request.get("/some/url", **request_kwargs)
ret = self.middleware.process_request(request) ret = self.middleware.process_request(request)
if ret: if ret:
return ret return ret
@ -34,8 +34,8 @@ class SecurityMiddlewareTest(SimpleTestCase):
request = RequestFactory() request = RequestFactory()
def process_request(self, method, *args, **kwargs): def process_request(self, method, *args, secure=False, **kwargs):
if kwargs.pop("secure", False): if secure:
kwargs.update(self.secure_request_kwargs) kwargs.update(self.secure_request_kwargs)
req = getattr(self.request, method.lower())(*args, **kwargs) req = getattr(self.request, method.lower())(*args, **kwargs)
return self.middleware.process_request(req) return self.middleware.process_request(req)

View File

@ -40,12 +40,10 @@ class Person(models.Model):
# calls. This argument is used to establish that the BookManager # calls. This argument is used to establish that the BookManager
# is actually getting used when it should be. # is actually getting used when it should be.
class BookManager(models.Manager): class BookManager(models.Manager):
def create(self, *args, **kwargs): def create(self, *args, extra_arg=None, **kwargs):
kwargs.pop('extra_arg', None)
return super().create(*args, **kwargs) return super().create(*args, **kwargs)
def get_or_create(self, *args, **kwargs): def get_or_create(self, *args, extra_arg=None, **kwargs):
kwargs.pop('extra_arg', None)
return super().get_or_create(*args, **kwargs) return super().get_or_create(*args, **kwargs)

View File

@ -42,12 +42,6 @@ class QuerySetSetOperationTests(TestCase):
self.assertEqual(len(list(qs1.union(qs2, all=True))), 20) self.assertEqual(len(list(qs1.union(qs2, all=True))), 20)
self.assertEqual(len(list(qs1.union(qs2))), 10) self.assertEqual(len(list(qs1.union(qs2))), 10)
def test_union_bad_kwarg(self):
qs1 = Number.objects.all()
msg = "union() received an unexpected keyword argument 'bad'"
with self.assertRaisesMessage(TypeError, msg):
self.assertEqual(len(list(qs1.union(qs1, bad=True))), 20)
def test_limits(self): def test_limits(self):
qs1 = Number.objects.all() qs1 = Number.objects.all()
qs2 = Number.objects.all() qs2 = Number.objects.all()

View File

@ -13,23 +13,24 @@ class CustomManyToManyField(RelatedField):
""" """
many_to_many = True many_to_many = True
def __init__(self, to, db_constraint=True, swappable=True, **kwargs): def __init__(self, to, db_constraint=True, swappable=True, related_name=None, related_query_name=None,
limit_choices_to=None, symmetrical=None, through=None, through_fields=None, db_table=None, **kwargs):
try: try:
to._meta to._meta
except AttributeError: except AttributeError:
to = str(to) to = str(to)
kwargs['rel'] = ManyToManyRel( kwargs['rel'] = ManyToManyRel(
self, to, self, to,
related_name=kwargs.pop('related_name', None), related_name=related_name,
related_query_name=kwargs.pop('related_query_name', None), related_query_name=related_query_name,
limit_choices_to=kwargs.pop('limit_choices_to', None), limit_choices_to=limit_choices_to,
symmetrical=kwargs.pop('symmetrical', to == RECURSIVE_RELATIONSHIP_CONSTANT), symmetrical=symmetrical if symmetrical is not None else (to == RECURSIVE_RELATIONSHIP_CONSTANT),
through=kwargs.pop('through', None), through=through,
through_fields=kwargs.pop('through_fields', None), through_fields=through_fields,
db_constraint=db_constraint, db_constraint=db_constraint,
) )
self.swappable = swappable self.swappable = swappable
self.db_table = kwargs.pop('db_table', None) self.db_table = db_table
if kwargs['rel'].through is not None: if kwargs['rel'].through is not None:
assert self.db_table is None, "Cannot specify a db_table if an intermediary model is used." assert self.db_table is None, "Cannot specify a db_table if an intermediary model is used."
super().__init__(**kwargs) super().__init__(**kwargs)

View File

@ -1819,9 +1819,9 @@ class SchemaTests(TransactionTestCase):
""" """
#23065 - Constraint names must be quoted if they contain capital letters. #23065 - Constraint names must be quoted if they contain capital letters.
""" """
def get_field(*args, **kwargs): def get_field(*args, field_class=IntegerField, **kwargs):
kwargs['db_column'] = "CamelCase" kwargs['db_column'] = "CamelCase"
field = kwargs.pop('field_class', IntegerField)(*args, **kwargs) field = field_class(*args, **kwargs)
field.set_attributes_from_name("CamelCase") field.set_attributes_from_name("CamelCase")
return field return field

View File

@ -76,8 +76,7 @@ class CollectionTestCase(BaseStaticFilesMixin, SimpleTestCase):
self.patched_settings.disable() self.patched_settings.disable()
super().tearDown() super().tearDown()
def run_collectstatic(self, **kwargs): def run_collectstatic(self, *, verbosity=0, **kwargs):
verbosity = kwargs.pop('verbosity', 0)
call_command('collectstatic', interactive=False, verbosity=verbosity, call_command('collectstatic', interactive=False, verbosity=verbosity,
ignore_patterns=['*.ignoreme'], **kwargs) ignore_patterns=['*.ignoreme'], **kwargs)