diff --git a/django/contrib/admin/actions.py b/django/contrib/admin/actions.py index 1bad81376af..34e809bebcb 100644 --- a/django/contrib/admin/actions.py +++ b/django/contrib/admin/actions.py @@ -59,19 +59,19 @@ def delete_selected(modeladmin, request, queryset): else: title = _("Are you sure?") - context = dict( - modeladmin.admin_site.each_context(request), - title=title, - objects_name=str(objects_name), - deletable_objects=[deletable_objects], - model_count=dict(model_count).items(), - queryset=queryset, - perms_lacking=perms_needed, - protected=protected, - opts=opts, - action_checkbox_name=helpers.ACTION_CHECKBOX_NAME, - media=modeladmin.media, - ) + context = { + **modeladmin.admin_site.each_context(request), + 'title': title, + 'objects_name': str(objects_name), + 'deletable_objects': [deletable_objects], + 'model_count': dict(model_count).items(), + 'queryset': queryset, + 'perms_lacking': perms_needed, + 'protected': protected, + 'opts': opts, + 'action_checkbox_name': helpers.ACTION_CHECKBOX_NAME, + 'media': modeladmin.media, + } request.current_app = modeladmin.admin_site.name diff --git a/django/contrib/admin/checks.py b/django/contrib/admin/checks.py index c8e05bde7c4..c53224499a6 100644 --- a/django/contrib/admin/checks.py +++ b/django/contrib/admin/checks.py @@ -65,21 +65,21 @@ def check_dependencies(**kwargs): class BaseModelAdminChecks: def check(self, admin_obj, **kwargs): - errors = [] - errors.extend(self._check_autocomplete_fields(admin_obj)) - errors.extend(self._check_raw_id_fields(admin_obj)) - errors.extend(self._check_fields(admin_obj)) - errors.extend(self._check_fieldsets(admin_obj)) - errors.extend(self._check_exclude(admin_obj)) - errors.extend(self._check_form(admin_obj)) - errors.extend(self._check_filter_vertical(admin_obj)) - errors.extend(self._check_filter_horizontal(admin_obj)) - errors.extend(self._check_radio_fields(admin_obj)) - errors.extend(self._check_prepopulated_fields(admin_obj)) - errors.extend(self._check_view_on_site_url(admin_obj)) - errors.extend(self._check_ordering(admin_obj)) - errors.extend(self._check_readonly_fields(admin_obj)) - return errors + return [ + *self._check_autocomplete_fields(admin_obj), + *self._check_raw_id_fields(admin_obj), + *self._check_fields(admin_obj), + *self._check_fieldsets(admin_obj), + *self._check_exclude(admin_obj), + *self._check_form(admin_obj), + *self._check_filter_vertical(admin_obj), + *self._check_filter_horizontal(admin_obj), + *self._check_radio_fields(admin_obj), + *self._check_prepopulated_fields(admin_obj), + *self._check_view_on_site_url(admin_obj), + *self._check_ordering(admin_obj), + *self._check_readonly_fields(admin_obj), + ] def _check_autocomplete_fields(self, obj): """ @@ -554,20 +554,21 @@ class BaseModelAdminChecks: class ModelAdminChecks(BaseModelAdminChecks): def check(self, admin_obj, **kwargs): - errors = super().check(admin_obj) - errors.extend(self._check_save_as(admin_obj)) - errors.extend(self._check_save_on_top(admin_obj)) - errors.extend(self._check_inlines(admin_obj)) - errors.extend(self._check_list_display(admin_obj)) - errors.extend(self._check_list_display_links(admin_obj)) - errors.extend(self._check_list_filter(admin_obj)) - errors.extend(self._check_list_select_related(admin_obj)) - errors.extend(self._check_list_per_page(admin_obj)) - errors.extend(self._check_list_max_show_all(admin_obj)) - errors.extend(self._check_list_editable(admin_obj)) - errors.extend(self._check_search_fields(admin_obj)) - errors.extend(self._check_date_hierarchy(admin_obj)) - return errors + return [ + *super().check(admin_obj), + *self._check_save_as(admin_obj), + *self._check_save_on_top(admin_obj), + *self._check_inlines(admin_obj), + *self._check_list_display(admin_obj), + *self._check_list_display_links(admin_obj), + *self._check_list_filter(admin_obj), + *self._check_list_select_related(admin_obj), + *self._check_list_per_page(admin_obj), + *self._check_list_max_show_all(admin_obj), + *self._check_list_editable(admin_obj), + *self._check_search_fields(admin_obj), + *self._check_date_hierarchy(admin_obj), + ] def _check_save_as(self, obj): """ Check save_as is a boolean. """ @@ -883,15 +884,16 @@ class ModelAdminChecks(BaseModelAdminChecks): class InlineModelAdminChecks(BaseModelAdminChecks): def check(self, inline_obj, **kwargs): - errors = super().check(inline_obj) parent_model = inline_obj.parent_model - errors.extend(self._check_relation(inline_obj, parent_model)) - errors.extend(self._check_exclude_of_parent_model(inline_obj, parent_model)) - errors.extend(self._check_extra(inline_obj)) - errors.extend(self._check_max_num(inline_obj)) - errors.extend(self._check_min_num(inline_obj)) - errors.extend(self._check_formset(inline_obj)) - return errors + return [ + *super().check(inline_obj), + *self._check_relation(inline_obj, parent_model), + *self._check_exclude_of_parent_model(inline_obj, parent_model), + *self._check_extra(inline_obj), + *self._check_max_num(inline_obj), + *self._check_min_num(inline_obj), + *self._check_formset(inline_obj), + ] def _check_exclude_of_parent_model(self, obj, parent_model): # Do not perform more specific checks if the base checks result in an diff --git a/django/contrib/admin/forms.py b/django/contrib/admin/forms.py index 6a641c96117..e973c619729 100644 --- a/django/contrib/admin/forms.py +++ b/django/contrib/admin/forms.py @@ -7,13 +7,13 @@ class AdminAuthenticationForm(AuthenticationForm): """ A custom authentication form used in the admin app. """ - error_messages = dict(AuthenticationForm.error_messages) - error_messages.update({ + error_messages = { + **AuthenticationForm.error_messages, 'invalid_login': _( "Please enter the correct %(username)s and password for a staff " "account. Note that both fields may be case-sensitive." ), - }) + } required_css_class = 'required' def confirm_login_allowed(self, user): diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py index 51cff980ef8..091e6935a80 100644 --- a/django/contrib/admin/options.py +++ b/django/contrib/admin/options.py @@ -145,7 +145,7 @@ class BaseModelAdmin(metaclass=forms.MediaDefiningClass): # formfield_overrides because **kwargs is more specific, and should # always win. if db_field.__class__ in self.formfield_overrides: - kwargs = dict(self.formfield_overrides[db_field.__class__], **kwargs) + kwargs = {**self.formfield_overrides[db_field.__class__], **kwargs} # Get the correct formfield. if isinstance(db_field, models.ForeignKey): @@ -176,7 +176,7 @@ class BaseModelAdmin(metaclass=forms.MediaDefiningClass): # passed to formfield_for_dbfield override the defaults. for klass in db_field.__class__.mro(): if klass in self.formfield_overrides: - kwargs = dict(copy.deepcopy(self.formfield_overrides[klass]), **kwargs) + kwargs = {**copy.deepcopy(self.formfield_overrides[klass]), **kwargs} return db_field.formfield(**kwargs) # For any other type of field, just call its formfield() method. @@ -653,12 +653,12 @@ class ModelAdmin(BaseModelAdmin): form = type(self.form.__name__, (self.form,), new_attrs) defaults = { - "form": form, - "fields": fields, - "exclude": exclude, - "formfield_callback": partial(self.formfield_for_dbfield, request=request), + 'form': form, + 'fields': fields, + 'exclude': exclude, + 'formfield_callback': partial(self.formfield_for_dbfield, request=request), + **kwargs, } - defaults.update(kwargs) if defaults['fields'] is None and not modelform_defines_fields(defaults['form']): defaults['fields'] = forms.ALL_FIELDS @@ -724,9 +724,9 @@ class ModelAdmin(BaseModelAdmin): Return a Form class for use in the Formset on the changelist page. """ defaults = { - "formfield_callback": partial(self.formfield_for_dbfield, request=request), + 'formfield_callback': partial(self.formfield_for_dbfield, request=request), + **kwargs, } - defaults.update(kwargs) if defaults.get('fields') is None and not modelform_defines_fields(defaults.get('form')): defaults['fields'] = forms.ALL_FIELDS @@ -738,9 +738,9 @@ class ModelAdmin(BaseModelAdmin): is used. """ defaults = { - "formfield_callback": partial(self.formfield_for_dbfield, request=request), + 'formfield_callback': partial(self.formfield_for_dbfield, request=request), + **kwargs, } - defaults.update(kwargs) return modelformset_factory( self.model, self.get_changelist_form(request), extra=0, fields=self.list_editable, **defaults @@ -1540,20 +1540,19 @@ class ModelAdmin(BaseModelAdmin): for inline_formset in inline_formsets: media = media + inline_formset.media - context = dict( - self.admin_site.each_context(request), - title=(_('Add %s') if add else _('Change %s')) % opts.verbose_name, - adminform=adminForm, - object_id=object_id, - original=obj, - is_popup=(IS_POPUP_VAR in request.POST or - IS_POPUP_VAR in request.GET), - to_field=to_field, - media=media, - inline_admin_formsets=inline_formsets, - errors=helpers.AdminErrorList(form, formsets), - preserved_filters=self.get_preserved_filters(request), - ) + context = { + **self.admin_site.each_context(request), + 'title': (_('Add %s') if add else _('Change %s')) % opts.verbose_name, + 'adminform': adminForm, + 'object_id': object_id, + 'original': obj, + 'is_popup': IS_POPUP_VAR in request.POST or IS_POPUP_VAR in request.GET, + 'to_field': to_field, + 'media': media, + 'inline_admin_formsets': inline_formsets, + 'errors': helpers.AdminErrorList(form, formsets), + 'preserved_filters': self.get_preserved_filters(request), + } # Hide the "Save" and "Save and continue" buttons if "Save as New" was # previously chosen to prevent the interface from getting confusing. @@ -1700,25 +1699,25 @@ class ModelAdmin(BaseModelAdmin): cl.result_count ) - context = dict( - self.admin_site.each_context(request), - module_name=str(opts.verbose_name_plural), - selection_note=_('0 of %(cnt)s selected') % {'cnt': len(cl.result_list)}, - selection_note_all=selection_note_all % {'total_count': cl.result_count}, - title=cl.title, - is_popup=cl.is_popup, - to_field=cl.to_field, - cl=cl, - media=media, - has_add_permission=self.has_add_permission(request), - opts=cl.opts, - action_form=action_form, - actions_on_top=self.actions_on_top, - actions_on_bottom=self.actions_on_bottom, - actions_selection_counter=self.actions_selection_counter, - preserved_filters=self.get_preserved_filters(request), - ) - context.update(extra_context or {}) + context = { + **self.admin_site.each_context(request), + 'module_name': str(opts.verbose_name_plural), + 'selection_note': _('0 of %(cnt)s selected') % {'cnt': len(cl.result_list)}, + 'selection_note_all': selection_note_all % {'total_count': cl.result_count}, + 'title': cl.title, + 'is_popup': cl.is_popup, + 'to_field': cl.to_field, + 'cl': cl, + 'media': media, + 'has_add_permission': self.has_add_permission(request), + 'opts': cl.opts, + 'action_form': action_form, + 'actions_on_top': self.actions_on_top, + 'actions_on_bottom': self.actions_on_bottom, + 'actions_selection_counter': self.actions_selection_counter, + 'preserved_filters': self.get_preserved_filters(request), + **(extra_context or {}), + } request.current_app = self.admin_site.name @@ -1775,23 +1774,22 @@ class ModelAdmin(BaseModelAdmin): else: title = _("Are you sure?") - context = dict( - self.admin_site.each_context(request), - title=title, - object_name=object_name, - object=obj, - deleted_objects=deleted_objects, - model_count=dict(model_count).items(), - perms_lacking=perms_needed, - protected=protected, - opts=opts, - app_label=app_label, - preserved_filters=self.get_preserved_filters(request), - is_popup=(IS_POPUP_VAR in request.POST or - IS_POPUP_VAR in request.GET), - to_field=to_field, - ) - context.update(extra_context or {}) + context = { + **self.admin_site.each_context(request), + 'title': title, + 'object_name': object_name, + 'object': obj, + 'deleted_objects': deleted_objects, + 'model_count': dict(model_count).items(), + 'perms_lacking': perms_needed, + 'protected': protected, + 'opts': opts, + 'app_label': app_label, + 'preserved_filters': self.get_preserved_filters(request), + 'is_popup': IS_POPUP_VAR in request.POST or IS_POPUP_VAR in request.GET, + 'to_field': to_field, + **(extra_context or {}), + } return self.render_delete_form(request, context) @@ -1815,16 +1813,16 @@ class ModelAdmin(BaseModelAdmin): content_type=get_content_type_for_model(model) ).select_related().order_by('action_time') - context = dict( - self.admin_site.each_context(request), - title=_('Change history: %s') % obj, - action_list=action_list, - module_name=str(capfirst(opts.verbose_name_plural)), - object=obj, - opts=opts, - preserved_filters=self.get_preserved_filters(request), - ) - context.update(extra_context or {}) + context = { + **self.admin_site.each_context(request), + 'title': _('Change history: %s') % obj, + 'action_list': action_list, + 'module_name': str(capfirst(opts.verbose_name_plural)), + 'object': obj, + 'opts': opts, + 'preserved_filters': self.get_preserved_filters(request), + **(extra_context or {}), + } request.current_app = self.admin_site.name @@ -1937,19 +1935,19 @@ class InlineModelAdmin(BaseModelAdmin): exclude = exclude or None can_delete = self.can_delete and self.has_delete_permission(request, obj) defaults = { - "form": self.form, - "formset": self.formset, - "fk_name": self.fk_name, - "fields": fields, - "exclude": exclude, - "formfield_callback": partial(self.formfield_for_dbfield, request=request), - "extra": self.get_extra(request, obj, **kwargs), - "min_num": self.get_min_num(request, obj, **kwargs), - "max_num": self.get_max_num(request, obj, **kwargs), - "can_delete": can_delete, + 'form': self.form, + 'formset': self.formset, + 'fk_name': self.fk_name, + 'fields': fields, + 'exclude': exclude, + 'formfield_callback': partial(self.formfield_for_dbfield, request=request), + 'extra': self.get_extra(request, obj, **kwargs), + 'min_num': self.get_min_num(request, obj, **kwargs), + 'max_num': self.get_max_num(request, obj, **kwargs), + 'can_delete': can_delete, + **kwargs, } - defaults.update(kwargs) base_model_form = defaults['form'] class DeleteProtectedModelForm(base_model_form): diff --git a/django/contrib/admin/sites.py b/django/contrib/admin/sites.py index 2e37ade62e9..1548d55ebb6 100644 --- a/django/contrib/admin/sites.py +++ b/django/contrib/admin/sites.py @@ -312,7 +312,7 @@ class AdminSite: defaults = { 'form_class': AdminPasswordChangeForm, 'success_url': url, - 'extra_context': dict(self.each_context(request), **(extra_context or {})), + 'extra_context': {**self.each_context(request), **(extra_context or {})}, } if self.password_change_template is not None: defaults['template_name'] = self.password_change_template @@ -325,7 +325,7 @@ class AdminSite: """ from django.contrib.auth.views import PasswordChangeDoneView defaults = { - 'extra_context': dict(self.each_context(request), **(extra_context or {})), + 'extra_context': {**self.each_context(request), **(extra_context or {})}, } if self.password_change_done_template is not None: defaults['template_name'] = self.password_change_done_template @@ -350,13 +350,13 @@ class AdminSite: """ from django.contrib.auth.views import LogoutView defaults = { - 'extra_context': dict( - self.each_context(request), + 'extra_context': { + **self.each_context(request), # Since the user isn't logged out at this point, the value of # has_permission must be overridden. - has_permission=False, + 'has_permission': False, **(extra_context or {}) - ), + }, } if self.logout_template is not None: defaults['template_name'] = self.logout_template @@ -378,12 +378,12 @@ class AdminSite: # it cannot import models from other applications at the module level, # and django.contrib.admin.forms eventually imports User. from django.contrib.admin.forms import AdminAuthenticationForm - context = dict( - self.each_context(request), - title=_('Log in'), - app_path=request.get_full_path(), - username=request.user.get_username(), - ) + context = { + **self.each_context(request), + 'title': _('Log in'), + 'app_path': request.get_full_path(), + 'username': request.user.get_username(), + } if (REDIRECT_FIELD_NAME not in request.GET and REDIRECT_FIELD_NAME not in request.POST): context[REDIRECT_FIELD_NAME] = reverse('admin:index', current_app=self.name) @@ -486,12 +486,12 @@ class AdminSite: """ app_list = self.get_app_list(request) - context = dict( - self.each_context(request), - title=self.index_title, - app_list=app_list, - ) - context.update(extra_context or {}) + context = { + **self.each_context(request), + 'title': self.index_title, + 'app_list': app_list, + **(extra_context or {}), + } request.current_app = self.name @@ -504,13 +504,13 @@ class AdminSite: # Sort the models alphabetically within each app. app_dict['models'].sort(key=lambda x: x['name']) app_name = apps.get_app_config(app_label).verbose_name - context = dict( - self.each_context(request), - title=_('%(app)s administration') % {'app': app_name}, - app_list=[app_dict], - app_label=app_label, - ) - context.update(extra_context or {}) + context = { + **self.each_context(request), + 'title': _('%(app)s administration') % {'app': app_name}, + 'app_list': [app_dict], + 'app_label': app_label, + **(extra_context or {}), + } request.current_app = self.name diff --git a/django/contrib/admin/templatetags/admin_list.py b/django/contrib/admin/templatetags/admin_list.py index 75b117f34e0..367a794d597 100644 --- a/django/contrib/admin/templatetags/admin_list.py +++ b/django/contrib/admin/templatetags/admin_list.py @@ -64,15 +64,17 @@ def pagination(cl): # ON_EACH_SIDE links at either end of the "current page" link. page_range = [] if page_num > (ON_EACH_SIDE + ON_ENDS): - page_range.extend(range(0, ON_ENDS)) - page_range.append(DOT) - page_range.extend(range(page_num - ON_EACH_SIDE, page_num + 1)) + page_range += [ + *range(0, ON_ENDS), DOT, + *range(page_num - ON_EACH_SIDE, page_num + 1), + ] else: page_range.extend(range(0, page_num + 1)) if page_num < (paginator.num_pages - ON_EACH_SIDE - ON_ENDS - 1): - page_range.extend(range(page_num + 1, page_num + ON_EACH_SIDE + 1)) - page_range.append(DOT) - page_range.extend(range(paginator.num_pages - ON_ENDS, paginator.num_pages)) + page_range += [ + *range(page_num + 1, page_num + ON_EACH_SIDE + 1), DOT, + *range(paginator.num_pages - ON_ENDS, paginator.num_pages) + ] else: page_range.extend(range(page_num + 1, paginator.num_pages)) diff --git a/django/contrib/admin/widgets.py b/django/contrib/admin/widgets.py index c8ead0e0aee..2e55ef65b2c 100644 --- a/django/contrib/admin/widgets.py +++ b/django/contrib/admin/widgets.py @@ -62,10 +62,8 @@ class AdminDateWidget(forms.DateInput): return forms.Media(js=["admin/js/%s" % path for path in js]) def __init__(self, attrs=None, format=None): - final_attrs = {'class': 'vDateField', 'size': '10'} - if attrs is not None: - final_attrs.update(attrs) - super().__init__(attrs=final_attrs, format=format) + attrs = {'class': 'vDateField', 'size': '10', **(attrs or {})} + super().__init__(attrs=attrs, format=format) class AdminTimeWidget(forms.TimeInput): @@ -81,10 +79,8 @@ class AdminTimeWidget(forms.TimeInput): return forms.Media(js=["admin/js/%s" % path for path in js]) def __init__(self, attrs=None, format=None): - final_attrs = {'class': 'vTimeField', 'size': '8'} - if attrs is not None: - final_attrs.update(attrs) - super().__init__(attrs=final_attrs, format=format) + attrs = {'class': 'vTimeField', 'size': '8', **(attrs or {})} + super().__init__(attrs=attrs, format=format) class AdminSplitDateTime(forms.SplitDateTimeWidget): @@ -328,36 +324,24 @@ class RelatedFieldWidgetWrapper(forms.Widget): class AdminTextareaWidget(forms.Textarea): def __init__(self, attrs=None): - final_attrs = {'class': 'vLargeTextField'} - if attrs is not None: - final_attrs.update(attrs) - super().__init__(attrs=final_attrs) + super().__init__(attrs={'class': 'vLargeTextField', **(attrs or {})}) class AdminTextInputWidget(forms.TextInput): def __init__(self, attrs=None): - final_attrs = {'class': 'vTextField'} - if attrs is not None: - final_attrs.update(attrs) - super().__init__(attrs=final_attrs) + super().__init__(attrs={'class': 'vTextField', **(attrs or {})}) class AdminEmailInputWidget(forms.EmailInput): def __init__(self, attrs=None): - final_attrs = {'class': 'vTextField'} - if attrs is not None: - final_attrs.update(attrs) - super().__init__(attrs=final_attrs) + super().__init__(attrs={'class': 'vTextField', **(attrs or {})}) class AdminURLFieldWidget(forms.URLInput): template_name = 'admin/widgets/url.html' def __init__(self, attrs=None): - final_attrs = {'class': 'vURLField'} - if attrs is not None: - final_attrs.update(attrs) - super().__init__(attrs=final_attrs) + super().__init__(attrs={'class': 'vURLField', **(attrs or {})}) def get_context(self, name, value, attrs): context = super().get_context(name, value, attrs) @@ -371,10 +355,7 @@ class AdminIntegerFieldWidget(forms.NumberInput): class_name = 'vIntegerField' def __init__(self, attrs=None): - final_attrs = {'class': self.class_name} - if attrs is not None: - final_attrs.update(attrs) - super().__init__(attrs=final_attrs) + super().__init__(attrs={'class': self.class_name, **(attrs or {})}) class AdminBigIntegerFieldWidget(AdminIntegerFieldWidget): diff --git a/django/contrib/admindocs/views.py b/django/contrib/admindocs/views.py index e45898c025b..438da150fc0 100644 --- a/django/contrib/admindocs/views.py +++ b/django/contrib/admindocs/views.py @@ -40,9 +40,11 @@ class BaseAdminDocsView(TemplateView): return super().dispatch(request, *args, **kwargs) def get_context_data(self, **kwargs): - kwargs.update({'root_path': reverse('admin:index')}) - kwargs.update(admin.site.each_context(self.request)) - return super().get_context_data(**kwargs) + return super().get_context_data(**{ + **kwargs, + 'root_path': reverse('admin:index'), + **admin.site.each_context(self.request), + }) class BookmarkletsView(BaseAdminDocsView): @@ -87,8 +89,7 @@ class TemplateTagIndexView(BaseAdminDocsView): 'meta': metadata, 'library': tag_library, }) - kwargs.update({'tags': tags}) - return super().get_context_data(**kwargs) + return super().get_context_data(**{**kwargs, 'tags': tags}) class TemplateFilterIndexView(BaseAdminDocsView): @@ -121,8 +122,7 @@ class TemplateFilterIndexView(BaseAdminDocsView): 'meta': metadata, 'library': tag_library, }) - kwargs.update({'filters': filters}) - return super().get_context_data(**kwargs) + return super().get_context_data(**{**kwargs, 'filters': filters}) class ViewIndexView(BaseAdminDocsView): @@ -145,8 +145,7 @@ class ViewIndexView(BaseAdminDocsView): 'namespace': ':'.join((namespace or [])), 'name': name, }) - kwargs.update({'views': views}) - return super().get_context_data(**kwargs) + return super().get_context_data(**{**kwargs, 'views': views}) class ViewDetailView(BaseAdminDocsView): @@ -181,13 +180,13 @@ class ViewDetailView(BaseAdminDocsView): body = utils.parse_rst(body, 'view', _('view:') + view) for key in metadata: metadata[key] = utils.parse_rst(metadata[key], 'model', _('view:') + view) - kwargs.update({ + return super().get_context_data(**{ + **kwargs, 'name': view, 'summary': title, 'body': body, 'meta': metadata, }) - return super().get_context_data(**kwargs) class ModelIndexView(BaseAdminDocsView): @@ -195,8 +194,7 @@ class ModelIndexView(BaseAdminDocsView): def get_context_data(self, **kwargs): m_list = [m._meta for m in apps.get_models()] - kwargs.update({'models': m_list}) - return super().get_context_data(**kwargs) + return super().get_context_data(**{**kwargs, 'models': m_list}) class ModelDetailView(BaseAdminDocsView): @@ -319,14 +317,14 @@ class ModelDetailView(BaseAdminDocsView): 'data_type': 'Integer', 'verbose': utils.parse_rst(_("number of %s") % verbose, 'model', _('model:') + opts.model_name), }) - kwargs.update({ + return super().get_context_data(**{ + **kwargs, 'name': '%s.%s' % (opts.app_label, opts.object_name), 'summary': title, 'description': body, 'fields': fields, 'methods': methods, }) - return super().get_context_data(**kwargs) class TemplateDetailView(BaseAdminDocsView): @@ -355,11 +353,11 @@ class TemplateDetailView(BaseAdminDocsView): 'contents': template_contents, 'order': index, }) - kwargs.update({ + return super().get_context_data(**{ + **kwargs, 'name': template, 'templates': templates, }) - return super().get_context_data(**kwargs) #################### diff --git a/django/contrib/auth/admin.py b/django/contrib/auth/admin.py index 41df65a72ee..3bfbef7c68e 100644 --- a/django/contrib/auth/admin.py +++ b/django/contrib/auth/admin.py @@ -177,8 +177,8 @@ class UserAdmin(admin.ModelAdmin): 'original': user, 'save_as': False, 'show_save': True, + **self.admin_site.each_context(request), } - context.update(self.admin_site.each_context(request)) request.current_app = self.admin_site.name diff --git a/django/contrib/auth/backends.py b/django/contrib/auth/backends.py index be02ac35424..092ad29b782 100644 --- a/django/contrib/auth/backends.py +++ b/django/contrib/auth/backends.py @@ -75,9 +75,10 @@ class ModelBackend: if not user_obj.is_active or user_obj.is_anonymous or obj is not None: return set() if not hasattr(user_obj, '_perm_cache'): - user_obj._perm_cache = set() - user_obj._perm_cache.update(self.get_user_permissions(user_obj)) - user_obj._perm_cache.update(self.get_group_permissions(user_obj)) + user_obj._perm_cache = { + *self.get_user_permissions(user_obj), + *self.get_group_permissions(user_obj), + } return user_obj._perm_cache def has_perm(self, user_obj, perm, obj=None): diff --git a/django/contrib/auth/forms.py b/django/contrib/auth/forms.py index 18fca67439b..e857f95cb26 100644 --- a/django/contrib/auth/forms.py +++ b/django/contrib/auth/forms.py @@ -299,9 +299,8 @@ class PasswordResetForm(forms.Form): 'user': user, 'token': token_generator.make_token(user), 'protocol': 'https' if use_https else 'http', + **(extra_email_context or {}), } - if extra_email_context is not None: - context.update(extra_email_context) self.send_mail( subject_template_name, email_template_name, context, from_email, email, html_email_template_name=html_email_template_name, @@ -357,9 +356,10 @@ class PasswordChangeForm(SetPasswordForm): A form that lets a user change their password by entering their old password. """ - error_messages = dict(SetPasswordForm.error_messages, **{ + error_messages = { + **SetPasswordForm.error_messages, 'password_incorrect': _("Your old password was entered incorrectly. Please enter it again."), - }) + } old_password = forms.CharField( label=_("Old password"), strip=False, diff --git a/django/contrib/auth/views.py b/django/contrib/auth/views.py index 358d386d1c7..6bd19edca45 100644 --- a/django/contrib/auth/views.py +++ b/django/contrib/auth/views.py @@ -31,9 +31,7 @@ class SuccessURLAllowedHostsMixin: success_url_allowed_hosts = set() def get_success_url_allowed_hosts(self): - allowed_hosts = {self.request.get_host()} - allowed_hosts.update(self.success_url_allowed_hosts) - return allowed_hosts + return {self.request.get_host(), *self.success_url_allowed_hosts} class LoginView(SuccessURLAllowedHostsMixin, FormView): @@ -98,9 +96,8 @@ class LoginView(SuccessURLAllowedHostsMixin, FormView): self.redirect_field_name: self.get_redirect_url(), 'site': current_site, 'site_name': current_site.name, + **(self.extra_context or {}) }) - if self.extra_context is not None: - context.update(self.extra_context) return context @@ -158,9 +155,8 @@ class LogoutView(SuccessURLAllowedHostsMixin, TemplateView): 'site': current_site, 'site_name': current_site.name, 'title': _('Logged out'), + **(self.extra_context or {}) }) - if self.extra_context is not None: - context.update(self.extra_context) return context @@ -201,9 +197,10 @@ class PasswordContextMixin: def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - context['title'] = self.title - if self.extra_context is not None: - context.update(self.extra_context) + context.update({ + 'title': self.title, + **(self.extra_context or {}) + }) return context diff --git a/django/contrib/contenttypes/admin.py b/django/contrib/contenttypes/admin.py index dd20249e622..d1790258af7 100644 --- a/django/contrib/contenttypes/admin.py +++ b/django/contrib/contenttypes/admin.py @@ -92,11 +92,7 @@ class GenericInlineModelAdmin(InlineModelAdmin): fields = kwargs.pop('fields') else: fields = flatten_fieldsets(self.get_fieldsets(request, obj)) - if self.exclude is None: - exclude = [] - else: - exclude = list(self.exclude) - exclude.extend(self.get_readonly_fields(request, obj)) + exclude = [*(self.exclude or []), *self.get_readonly_fields(request, obj)] if self.exclude is None and hasattr(self.form, '_meta') and self.form._meta.exclude: # Take the custom ModelForm's Meta.exclude into account only if the # GenericInlineModelAdmin doesn't define its own. @@ -104,20 +100,20 @@ class GenericInlineModelAdmin(InlineModelAdmin): exclude = exclude or None can_delete = self.can_delete and self.has_delete_permission(request, obj) defaults = { - "ct_field": self.ct_field, - "fk_field": self.ct_fk_field, - "form": self.form, - "formfield_callback": partial(self.formfield_for_dbfield, request=request), - "formset": self.formset, - "extra": self.get_extra(request, obj), - "can_delete": can_delete, - "can_order": False, - "fields": fields, - "min_num": self.get_min_num(request, obj), - "max_num": self.get_max_num(request, obj), - "exclude": exclude + 'ct_field': self.ct_field, + 'fk_field': self.ct_fk_field, + 'form': self.form, + 'formfield_callback': partial(self.formfield_for_dbfield, request=request), + 'formset': self.formset, + 'extra': self.get_extra(request, obj), + 'can_delete': can_delete, + 'can_order': False, + 'fields': fields, + 'min_num': self.get_min_num(request, obj), + 'max_num': self.get_max_num(request, obj), + 'exclude': exclude, + **kwargs, } - defaults.update(kwargs) if defaults['fields'] is None and not modelform_defines_fields(defaults['form']): defaults['fields'] = ALL_FIELDS diff --git a/django/contrib/contenttypes/fields.py b/django/contrib/contenttypes/fields.py index 22277072031..d186e1f39a6 100644 --- a/django/contrib/contenttypes/fields.py +++ b/django/contrib/contenttypes/fields.py @@ -72,11 +72,11 @@ class GenericForeignKey(FieldCacheMixin): return '%s.%s.%s' % (app, model._meta.object_name, self.name) def check(self, **kwargs): - errors = [] - errors.extend(self._check_field_name()) - errors.extend(self._check_object_id_field()) - errors.extend(self._check_content_type_field()) - return errors + return [ + *self._check_field_name(), + *self._check_object_id_field(), + *self._check_content_type_field(), + ] def _check_field_name(self): if self.name.endswith("_"): @@ -308,9 +308,10 @@ class GenericRelation(ForeignObject): self.for_concrete_model = for_concrete_model def check(self, **kwargs): - errors = super().check(**kwargs) - errors.extend(self._check_generic_foreign_key_existence()) - return errors + return [ + *super().check(**kwargs), + *self._check_generic_foreign_key_existence(), + ] def _is_matching_generic_foreign_key(self, field): """ diff --git a/django/contrib/contenttypes/forms.py b/django/contrib/contenttypes/forms.py index 4970ab452b2..d4c33132408 100644 --- a/django/contrib/contenttypes/forms.py +++ b/django/contrib/contenttypes/forms.py @@ -63,11 +63,7 @@ def generic_inlineformset_factory(model, form=ModelForm, if not isinstance(ct_field, models.ForeignKey) or ct_field.remote_field.model != ContentType: raise Exception("fk_name '%s' is not a ForeignKey to ContentType" % ct_field) fk_field = opts.get_field(fk_field) # let the exception propagate - if exclude is not None: - exclude = list(exclude) - exclude.extend([ct_field.name, fk_field.name]) - else: - exclude = [ct_field.name, fk_field.name] + exclude = [*(exclude or []), ct_field.name, fk_field.name] FormSet = modelformset_factory( model, form=form, formfield_callback=formfield_callback, formset=formset, extra=extra, can_delete=can_delete, diff --git a/django/contrib/gis/db/backends/spatialite/introspection.py b/django/contrib/gis/db/backends/spatialite/introspection.py index 5cd5613b69a..967448621d6 100644 --- a/django/contrib/gis/db/backends/spatialite/introspection.py +++ b/django/contrib/gis/db/backends/spatialite/introspection.py @@ -9,16 +9,16 @@ class GeoFlexibleFieldLookupDict(FlexibleFieldLookupDict): Sublcass that includes updates the `base_data_types_reverse` dict for geometry field types. """ - base_data_types_reverse = FlexibleFieldLookupDict.base_data_types_reverse.copy() - base_data_types_reverse.update( - {'point': 'GeometryField', - 'linestring': 'GeometryField', - 'polygon': 'GeometryField', - 'multipoint': 'GeometryField', - 'multilinestring': 'GeometryField', - 'multipolygon': 'GeometryField', - 'geometrycollection': 'GeometryField', - }) + base_data_types_reverse = { + **FlexibleFieldLookupDict.base_data_types_reverse, + 'point': 'GeometryField', + 'linestring': 'GeometryField', + 'polygon': 'GeometryField', + 'multipoint': 'GeometryField', + 'multilinestring': 'GeometryField', + 'multipolygon': 'GeometryField', + 'geometrycollection': 'GeometryField', + } class SpatiaLiteIntrospection(DatabaseIntrospection): diff --git a/django/contrib/gis/db/models/fields.py b/django/contrib/gis/db/models/fields.py index fea3cfc260e..5e869a82433 100644 --- a/django/contrib/gis/db/models/fields.py +++ b/django/contrib/gis/db/models/fields.py @@ -250,11 +250,12 @@ class GeometryField(BaseSpatialField): setattr(cls, self.attname, SpatialProxy(self.geom_class or GEOSGeometry, self, load_func=GEOSGeometry)) def formfield(self, **kwargs): - defaults = {'form_class': self.form_class, - 'geom_type': self.geom_type, - 'srid': self.srid, - } - defaults.update(kwargs) + defaults = { + 'form_class': self.form_class, + 'geom_type': self.geom_type, + 'srid': self.srid, + **kwargs, + } if self.dim > 2 and not getattr(defaults['form_class'].widget, 'supports_3d', False): defaults.setdefault('widget', forms.Textarea) return super().formfield(**defaults) diff --git a/django/contrib/gis/db/models/functions.py b/django/contrib/gis/db/models/functions.py index fc46823b19a..b3c8d521ca3 100644 --- a/django/contrib/gis/db/models/functions.py +++ b/django/contrib/gis/db/models/functions.py @@ -415,12 +415,10 @@ class SnapToGrid(SQLiteDecimalToFloatMixin, GeomOutputGeoFunc): ) elif nargs == 4: # Reverse origin and size param ordering - expressions.extend( - [self._handle_param(arg, '', NUMERIC_TYPES) for arg in args[2:]] - ) - expressions.extend( - [self._handle_param(arg, '', NUMERIC_TYPES) for arg in args[0:2]] - ) + expressions += [ + *(self._handle_param(arg, '', NUMERIC_TYPES) for arg in args[2:]), + *(self._handle_param(arg, '', NUMERIC_TYPES) for arg in args[0:2]), + ] else: raise ValueError('Must provide 1, 2, or 4 arguments to `SnapToGrid`.') super().__init__(*expressions, **extra) diff --git a/django/contrib/gis/db/models/lookups.py b/django/contrib/gis/db/models/lookups.py index d5318568fbb..6d5df2c10fd 100644 --- a/django/contrib/gis/db/models/lookups.py +++ b/django/contrib/gis/db/models/lookups.py @@ -78,8 +78,7 @@ class GISLookup(Lookup): rhs_sql, rhs_params = self.process_rhs(compiler, connection) sql_params.extend(rhs_params) - template_params = {'lhs': lhs_sql, 'rhs': rhs_sql, 'value': '%s'} - template_params.update(self.template_params) + template_params = {'lhs': lhs_sql, 'rhs': rhs_sql, 'value': '%s', **self.template_params} rhs_op = self.get_rhs_op(connection, rhs_sql) return rhs_op.as_sql(connection, self, template_params, sql_params) diff --git a/django/contrib/gis/forms/widgets.py b/django/contrib/gis/forms/widgets.py index e48ba96865d..0ffe2ced778 100644 --- a/django/contrib/gis/forms/widgets.py +++ b/django/contrib/gis/forms/widgets.py @@ -60,19 +60,15 @@ class BaseGeometryWidget(Widget): value.srid, self.map_srid, err ) - if attrs is None: - attrs = {} - - build_attrs_kwargs = { + context.update(self.build_attrs(self.attrs, { 'name': name, 'module': 'geodjango_%s' % name.replace('-', '_'), # JS-safe 'serialized': self.serialize(value), 'geom_type': gdal.OGRGeomType(self.attrs['geom_type']), 'STATIC_URL': settings.STATIC_URL, 'LANGUAGE_BIDI': translation.get_language_bidi(), - } - build_attrs_kwargs.update(attrs) - context.update(self.build_attrs(self.attrs, build_attrs_kwargs)) + **(attrs or {}), + })) return context diff --git a/django/contrib/gis/geos/prototypes/coordseq.py b/django/contrib/gis/geos/prototypes/coordseq.py index 75b375884c5..d1a5ed60436 100644 --- a/django/contrib/gis/geos/prototypes/coordseq.py +++ b/django/contrib/gis/geos/prototypes/coordseq.py @@ -49,7 +49,7 @@ class CsOperation(GEOSFuncFactory): else: argtypes = [CS_PTR, c_uint, dbl_param] - super().__init__(*args, **dict(kwargs, errcheck=errcheck, argtypes=argtypes)) + super().__init__(*args, **{**kwargs, 'errcheck': errcheck, 'argtypes': argtypes}) class CsOutput(GEOSFuncFactory): diff --git a/django/contrib/gis/geos/prototypes/threadsafe.py b/django/contrib/gis/geos/prototypes/threadsafe.py index 24f8f288c1e..04eb4967045 100644 --- a/django/contrib/gis/geos/prototypes/threadsafe.py +++ b/django/contrib/gis/geos/prototypes/threadsafe.py @@ -55,9 +55,7 @@ class GEOSFunc: return self.cfunc.argtypes def _set_argtypes(self, argtypes): - new_argtypes = [CONTEXT_PTR] - new_argtypes.extend(argtypes) - self.cfunc.argtypes = new_argtypes + self.cfunc.argtypes = [CONTEXT_PTR, *argtypes] argtypes = property(_get_argtypes, _set_argtypes) diff --git a/django/contrib/messages/utils.py b/django/contrib/messages/utils.py index e4a6808818e..90130449697 100644 --- a/django/contrib/messages/utils.py +++ b/django/contrib/messages/utils.py @@ -6,6 +6,7 @@ def get_level_tags(): """ Return the message level tags. """ - level_tags = constants.DEFAULT_TAGS.copy() - level_tags.update(getattr(settings, 'MESSAGE_TAGS', {})) - return level_tags + return { + **constants.DEFAULT_TAGS, + **getattr(settings, 'MESSAGE_TAGS', {}), + } diff --git a/django/contrib/postgres/fields/array.py b/django/contrib/postgres/fields/array.py index 6a8fbd0e913..bf5666e2da9 100644 --- a/django/contrib/postgres/fields/array.py +++ b/django/contrib/postgres/fields/array.py @@ -183,13 +183,12 @@ class ArrayField(CheckFieldDefaultMixin, Field): ) def formfield(self, **kwargs): - defaults = { + return super().formfield(**{ 'form_class': SimpleArrayField, 'base_field': self.base_field.formfield(), 'max_length': self.size, - } - defaults.update(kwargs) - return super().formfield(**defaults) + **kwargs, + }) @ArrayField.register_lookup diff --git a/django/contrib/postgres/fields/hstore.py b/django/contrib/postgres/fields/hstore.py index 82f731f8bfd..d47b34d4593 100644 --- a/django/contrib/postgres/fields/hstore.py +++ b/django/contrib/postgres/fields/hstore.py @@ -44,11 +44,10 @@ class HStoreField(Field): return json.dumps(self.value_from_object(obj)) def formfield(self, **kwargs): - defaults = { + return super().formfield(**{ 'form_class': forms.HStoreField, - } - defaults.update(kwargs) - return super().formfield(**defaults) + **kwargs, + }) def get_prep_value(self, value): value = super().get_prep_value(value) diff --git a/django/contrib/postgres/fields/jsonb.py b/django/contrib/postgres/fields/jsonb.py index 4ed441003b4..3c27607acd5 100644 --- a/django/contrib/postgres/fields/jsonb.py +++ b/django/contrib/postgres/fields/jsonb.py @@ -77,9 +77,10 @@ class JSONField(CheckFieldDefaultMixin, Field): return self.value_from_object(obj) def formfield(self, **kwargs): - defaults = {'form_class': forms.JSONField} - defaults.update(kwargs) - return super().formfield(**defaults) + return super().formfield(**{ + 'form_class': forms.JSONField, + **kwargs, + }) JSONField.register_lookup(lookups.DataContains) diff --git a/django/contrib/postgres/forms/array.py b/django/contrib/postgres/forms/array.py index 71c0476fa8b..f01d5836c13 100644 --- a/django/contrib/postgres/forms/array.py +++ b/django/contrib/postgres/forms/array.py @@ -135,7 +135,7 @@ class SplitArrayWidget(forms.Widget): except IndexError: widget_value = None if id_: - final_attrs = dict(final_attrs, id='%s_%s' % (id_, i)) + final_attrs = {**final_attrs, 'id': '%s_%s' % (id_, i)} context['widget']['subwidgets'].append( self.widget.get_context(name + '_%s' % i, widget_value, final_attrs)['widget'] ) diff --git a/django/contrib/postgres/utils.py b/django/contrib/postgres/utils.py index 7c3a0d5e33d..9f92f4059f4 100644 --- a/django/contrib/postgres/utils.py +++ b/django/contrib/postgres/utils.py @@ -22,7 +22,7 @@ def prefix_validation_error(error, prefix, code, params): SimpleLazyObject(lambda: error.message % error_params), ), code=code, - params=dict(error_params, **params), + params={**error_params, **params}, ) return ValidationError([ prefix_validation_error(e, prefix, code, params) for e in error.error_list diff --git a/django/contrib/postgres/validators.py b/django/contrib/postgres/validators.py index 45bf8e1e131..db6205f3565 100644 --- a/django/contrib/postgres/validators.py +++ b/django/contrib/postgres/validators.py @@ -1,5 +1,3 @@ -import copy - from django.core.exceptions import ValidationError from django.core.validators import ( MaxLengthValidator, MaxValueValidator, MinLengthValidator, @@ -37,8 +35,7 @@ class KeysValidator: self.keys = set(keys) self.strict = strict if messages is not None: - self.messages = copy.copy(self.messages) - self.messages.update(messages) + self.messages = {**self.messages, **messages} def __call__(self, value): keys = set(value) diff --git a/django/core/cache/__init__.py b/django/core/cache/__init__.py index 7aaa0572294..349ea864809 100644 --- a/django/core/cache/__init__.py +++ b/django/core/cache/__init__.py @@ -44,8 +44,7 @@ def _create_cache(backend, **kwargs): location = kwargs.pop('LOCATION', '') params = kwargs else: - params = conf.copy() - params.update(kwargs) + params = {**conf, **kwargs} backend = params.pop('BACKEND') location = params.pop('LOCATION', '') backend_cls = import_string(backend) diff --git a/django/core/handlers/exception.py b/django/core/handlers/exception.py index be2e4734ee4..e98bec262a1 100644 --- a/django/core/handlers/exception.py +++ b/django/core/handlers/exception.py @@ -96,7 +96,7 @@ def response_for_exception(request, exc): def get_exception_response(request, resolver, status_code, exception, sender=None): try: callback, param_dict = resolver.resolve_error_handler(status_code) - response = callback(request, **dict(param_dict, exception=exception)) + response = callback(request, **{**param_dict, 'exception': exception}) except Exception: signals.got_request_exception.send(sender=sender, request=request) response = handle_uncaught_exception(request, resolver, sys.exc_info()) diff --git a/django/core/management/templates.py b/django/core/management/templates.py index eb4baafd624..90ffa5be3f4 100644 --- a/django/core/management/templates.py +++ b/django/core/management/templates.py @@ -104,13 +104,14 @@ class TemplateCommand(BaseCommand): camel_case_name = 'camel_case_%s_name' % app_or_project camel_case_value = ''.join(x for x in name.title() if x != '_') - context = Context(dict(options, **{ + context = Context({ + **options, base_name: name, base_directory: top_dir, camel_case_name: camel_case_value, 'docs_version': get_docs_version(), 'django_version': django.__version__, - }), autoescape=False) + }, autoescape=False) # Setup a stub settings environment for template rendering if not settings.configured: diff --git a/django/db/backends/mysql/base.py b/django/db/backends/mysql/base.py index 6b82afc45d6..6612e109796 100644 --- a/django/db/backends/mysql/base.py +++ b/django/db/backends/mysql/base.py @@ -39,10 +39,10 @@ if version < (1, 3, 3): # MySQLdb returns TIME columns as timedelta -- they are more like timedelta in # terms of actual behavior as they are signed and include days -- and Django # expects time. -django_conversions = conversions.copy() -django_conversions.update({ - FIELD_TYPE.TIME: backend_utils.typecast_time, -}) +django_conversions = { + **conversions, + **{FIELD_TYPE.TIME: backend_utils.typecast_time}, +} # This should match the numerical portion of the version numbers (we can treat # versions like 5.0.24 and 5.0.24a as the same). diff --git a/django/db/backends/mysql/operations.py b/django/db/backends/mysql/operations.py index fff72e056cc..3ec1c2e8cea 100644 --- a/django/db/backends/mysql/operations.py +++ b/django/db/backends/mysql/operations.py @@ -10,11 +10,11 @@ class DatabaseOperations(BaseDatabaseOperations): compiler_module = "django.db.backends.mysql.compiler" # MySQL stores positive fields as UNSIGNED ints. - integer_field_ranges = dict( - BaseDatabaseOperations.integer_field_ranges, - PositiveSmallIntegerField=(0, 65535), - PositiveIntegerField=(0, 4294967295), - ) + integer_field_ranges = { + **BaseDatabaseOperations.integer_field_ranges, + 'PositiveSmallIntegerField': (0, 65535), + 'PositiveIntegerField': (0, 4294967295), + } cast_data_types = { 'CharField': 'char(%(max_length)s)', 'IntegerField': 'signed integer', diff --git a/django/db/backends/oracle/base.py b/django/db/backends/oracle/base.py index b697758a36f..74bad39214a 100644 --- a/django/db/backends/oracle/base.py +++ b/django/db/backends/oracle/base.py @@ -136,15 +136,15 @@ class DatabaseWrapper(BaseDatabaseWrapper): 'iendswith': "LIKE UPPER(TRANSLATE(%s USING NCHAR_CS)) ESCAPE TRANSLATE('\\' USING NCHAR_CS)", } - _likec_operators = _standard_operators.copy() - _likec_operators.update({ + _likec_operators = { + **_standard_operators, 'contains': "LIKEC %s ESCAPE '\\'", 'icontains': "LIKEC UPPER(%s) ESCAPE '\\'", 'startswith': "LIKEC %s ESCAPE '\\'", 'endswith': "LIKEC %s ESCAPE '\\'", 'istartswith': "LIKEC UPPER(%s) ESCAPE '\\'", 'iendswith': "LIKEC UPPER(%s) ESCAPE '\\'", - }) + } # The patterns below are used to generate SQL pattern lookup clauses when # the right-hand side of the lookup isn't a raw string (it might be an expression diff --git a/django/db/backends/oracle/creation.py b/django/db/backends/oracle/creation.py index aa57e6a6ab4..8f3d847d3ac 100644 --- a/django/db/backends/oracle/creation.py +++ b/django/db/backends/oracle/creation.py @@ -23,8 +23,7 @@ class DatabaseCreation(BaseDatabaseCreation): settings_dict = settings.DATABASES[self.connection.alias] user = settings_dict.get('SAVED_USER') or settings_dict['USER'] password = settings_dict.get('SAVED_PASSWORD') or settings_dict['PASSWORD'] - settings_dict = settings_dict.copy() - settings_dict.update(USER=user, PASSWORD=password) + settings_dict = {**settings_dict, 'USER': user, 'PASSWORD': password} DatabaseWrapper = type(self.connection) return DatabaseWrapper(settings_dict, alias=self.connection.alias) diff --git a/django/db/backends/oracle/operations.py b/django/db/backends/oracle/operations.py index fd4206d57f0..6e607190863 100644 --- a/django/db/backends/oracle/operations.py +++ b/django/db/backends/oracle/operations.py @@ -21,7 +21,7 @@ class DatabaseOperations(BaseDatabaseOperations): 'PositiveSmallIntegerField': (0, 99999999999), 'PositiveIntegerField': (0, 99999999999), } - set_operators = dict(BaseDatabaseOperations.set_operators, difference='MINUS') + set_operators = {**BaseDatabaseOperations.set_operators, 'difference': 'MINUS'} # TODO: colorize this SQL code with style.SQL_KEYWORD(), etc. _sequence_reset_sql = """ diff --git a/django/db/backends/postgresql/base.py b/django/db/backends/postgresql/base.py index fbe444988a9..1982a8aedbe 100644 --- a/django/db/backends/postgresql/base.py +++ b/django/db/backends/postgresql/base.py @@ -151,8 +151,8 @@ class DatabaseWrapper(BaseDatabaseWrapper): "Please supply the NAME value.") conn_params = { 'database': settings_dict['NAME'] or 'postgres', + **settings_dict['OPTIONS'], } - conn_params.update(settings_dict['OPTIONS']) conn_params.pop('isolation_level', None) if settings_dict['USER']: conn_params['user'] = settings_dict['USER'] diff --git a/django/db/backends/sqlite3/base.py b/django/db/backends/sqlite3/base.py index 13f9a575e2a..15f7352a934 100644 --- a/django/db/backends/sqlite3/base.py +++ b/django/db/backends/sqlite3/base.py @@ -137,8 +137,8 @@ class DatabaseWrapper(BaseDatabaseWrapper): kwargs = { 'database': settings_dict['NAME'], 'detect_types': Database.PARSE_DECLTYPES | Database.PARSE_COLNAMES, + **settings_dict['OPTIONS'], } - kwargs.update(settings_dict['OPTIONS']) # Always allow the underlying SQLite connection to be shareable # between multiple threads. The safe-guarding will be handled at a # higher level by the `BaseDatabaseWrapper.allow_thread_sharing` diff --git a/django/db/migrations/operations/models.py b/django/db/migrations/operations/models.py index a1ff5946021..24d71b17c8b 100644 --- a/django/db/migrations/operations/models.py +++ b/django/db/migrations/operations/models.py @@ -147,13 +147,11 @@ class CreateModel(ModelOperation): ), ] elif isinstance(operation, AlterModelOptions) and self.name_lower == operation.name_lower: - new_options = self.options.copy() - new_options.update(operation.options) return [ CreateModel( self.name, fields=self.fields, - options=new_options, + options={**self.options, **operation.options}, bases=self.bases, managers=self.managers, ), @@ -690,8 +688,7 @@ class AlterModelOptions(ModelOptionOperation): def state_forwards(self, app_label, state): model_state = state.models[app_label, self.name_lower] - model_state.options = dict(model_state.options) - model_state.options.update(self.options) + model_state.options = {**model_state.options, **self.options} for key in self.ALTER_OPTION_KEYS: if key not in self.options: model_state.options.pop(key, False) diff --git a/django/db/migrations/serializer.py b/django/db/migrations/serializer.py index 8c5f7269247..12fdb62cff4 100644 --- a/django/db/migrations/serializer.py +++ b/django/db/migrations/serializer.py @@ -119,9 +119,8 @@ class EnumSerializer(BaseSerializer): def serialize(self): enum_class = self.value.__class__ module = enum_class.__module__ - imports = {"import %s" % module} v_string, v_imports = serializer_factory(self.value.value).serialize() - imports.update(v_imports) + imports = {'import %s' % module, *v_imports} return "%s.%s(%s)" % (module, enum_class.__name__, v_string), imports @@ -161,15 +160,12 @@ class FunctionTypeSerializer(BaseSerializer): class FunctoolsPartialSerializer(BaseSerializer): def serialize(self): - imports = {'import functools'} # Serialize functools.partial() arguments func_string, func_imports = serializer_factory(self.value.func).serialize() args_string, args_imports = serializer_factory(self.value.args).serialize() keywords_string, keywords_imports = serializer_factory(self.value.keywords).serialize() # Add any imports needed by arguments - imports.update(func_imports) - imports.update(args_imports) - imports.update(keywords_imports) + imports = {'import functools', *func_imports, *args_imports, *keywords_imports} return ( 'functools.%s(%s, *%s, **%s)' % ( self.value.__class__.__name__, @@ -221,14 +217,12 @@ class OperationSerializer(BaseSerializer): class RegexSerializer(BaseSerializer): def serialize(self): - imports = {"import re"} regex_pattern, pattern_imports = serializer_factory(self.value.pattern).serialize() # Turn off default implicit flags (e.g. re.U) because regexes with the # same implicit and explicit flags aren't equal. flags = self.value.flags ^ re.compile('').flags regex_flags, flag_imports = serializer_factory(flags).serialize() - imports.update(pattern_imports) - imports.update(flag_imports) + imports = {'import re', *pattern_imports, *flag_imports} args = [regex_pattern] if flags: args.append(regex_flags) diff --git a/django/db/migrations/state.py b/django/db/migrations/state.py index 4dfa3dd1248..7d072175b15 100644 --- a/django/db/migrations/state.py +++ b/django/db/migrations/state.py @@ -553,8 +553,7 @@ class ModelState: def render(self, apps): """Create a Model object from our current state into the given apps.""" # First, make a Meta object - meta_contents = {'app_label': self.app_label, "apps": apps} - meta_contents.update(self.options) + meta_contents = {'app_label': self.app_label, 'apps': apps, **self.options} meta = type("Meta", (), meta_contents) # Then, work out our bases try: diff --git a/django/db/models/aggregates.py b/django/db/models/aggregates.py index ce4625c1a5d..dbb746b75dc 100644 --- a/django/db/models/aggregates.py +++ b/django/db/models/aggregates.py @@ -121,8 +121,7 @@ class Count(Aggregate): ) def _get_repr_options(self): - options = super()._get_repr_options() - return dict(options, distinct=self.extra['distinct'] != '') + return {**super()._get_repr_options(), 'distinct': self.extra['distinct'] != ''} def convert_value(self, value, expression, connection): return 0 if value is None else value @@ -147,8 +146,7 @@ class StdDev(Aggregate): super().__init__(expression, **extra) def _get_repr_options(self): - options = super()._get_repr_options() - return dict(options, sample=self.function == 'STDDEV_SAMP') + return {**super()._get_repr_options(), 'sample': self.function == 'STDDEV_SAMP'} class Sum(Aggregate): @@ -174,5 +172,4 @@ class Variance(Aggregate): super().__init__(expression, **extra) def _get_repr_options(self): - options = super()._get_repr_options() - return dict(options, sample=self.function == 'VAR_SAMP') + return {**super()._get_repr_options(), 'sample': self.function == 'VAR_SAMP'} diff --git a/django/db/models/base.py b/django/db/models/base.py index cc675c4273c..27ca63fd221 100644 --- a/django/db/models/base.py +++ b/django/db/models/base.py @@ -1186,14 +1186,13 @@ class Model(metaclass=ModelBase): @classmethod def check(cls, **kwargs): - errors = [] - errors.extend(cls._check_swappable()) - errors.extend(cls._check_model()) - errors.extend(cls._check_managers(**kwargs)) + errors = [*cls._check_swappable(), *cls._check_model(), *cls._check_managers(**kwargs)] if not cls._meta.swapped: - errors.extend(cls._check_fields(**kwargs)) - errors.extend(cls._check_m2m_through_same_relationship()) - errors.extend(cls._check_long_column_names()) + errors += [ + *cls._check_fields(**kwargs), + *cls._check_m2m_through_same_relationship(), + *cls._check_long_column_names(), + ] clash_errors = ( cls._check_id_field() + cls._check_field_name_clashes() + @@ -1204,9 +1203,11 @@ class Model(metaclass=ModelBase): # clashes. if not clash_errors: errors.extend(cls._check_column_name_clashes()) - errors.extend(cls._check_index_together()) - errors.extend(cls._check_unique_together()) - errors.extend(cls._check_ordering()) + errors += [ + *cls._check_index_together(), + *cls._check_unique_together(), + *cls._check_ordering(), + ] return errors diff --git a/django/db/models/expressions.py b/django/db/models/expressions.py index 0109c017da5..93fc7df82bb 100644 --- a/django/db/models/expressions.py +++ b/django/db/models/expressions.py @@ -565,7 +565,7 @@ class Func(SQLiteNumericMixin, Expression): def __repr__(self): args = self.arg_joiner.join(str(arg) for arg in self.source_expressions) - extra = dict(self.extra, **self._get_repr_options()) + extra = {**self.extra, **self._get_repr_options()} if extra: extra = ', '.join(str(key) + '=' + str(val) for key, val in sorted(extra.items())) return "{}({}, {})".format(self.__class__.__name__, args, extra) @@ -596,8 +596,7 @@ class Func(SQLiteNumericMixin, Expression): arg_sql, arg_params = compiler.compile(arg) sql_parts.append(arg_sql) params.extend(arg_params) - data = self.extra.copy() - data.update(**extra_context) + data = {**self.extra, **extra_context} # Use the first supplied value in this order: the parameter to this # method, a value supplied in __init__()'s **extra (the value in # `data`), or the value defined on the class. @@ -921,8 +920,7 @@ class Case(Expression): connection.ops.check_expression_support(self) if not self.cases: return compiler.compile(self.default) - template_params = self.extra.copy() - template_params.update(extra_context) + template_params = {**self.extra, **extra_context} case_parts = [] sql_params = [] for case in self.cases: @@ -1017,8 +1015,7 @@ class Subquery(Expression): def as_sql(self, compiler, connection, template=None, **extra_context): connection.ops.check_expression_support(self) - template_params = self.extra.copy() - template_params.update(extra_context) + template_params = {**self.extra, **extra_context} template_params['subquery'], sql_params = self.queryset.query.get_compiler(connection=connection).as_sql() template = template or template_params.get('template', self.template) @@ -1103,8 +1100,8 @@ class OrderBy(BaseExpression): placeholders = { 'expression': expression_sql, 'ordering': 'DESC' if self.descending else 'ASC', + **extra_context, } - placeholders.update(extra_context) template = template or self.template params *= template.count('%(expression)s') return (template % placeholders).rstrip(), params diff --git a/django/db/models/fields/__init__.py b/django/db/models/fields/__init__.py index 1e3db7e7766..999b37a4f44 100644 --- a/django/db/models/fields/__init__.py +++ b/django/db/models/fields/__init__.py @@ -2,7 +2,6 @@ import collections import copy import datetime import decimal -import itertools import operator import uuid import warnings @@ -199,15 +198,15 @@ class Field(RegisterLookupMixin): return '<%s>' % path def check(self, **kwargs): - errors = [] - errors.extend(self._check_field_name()) - errors.extend(self._check_choices()) - errors.extend(self._check_db_index()) - errors.extend(self._check_null_allowed_for_primary_keys()) - errors.extend(self._check_backend_specific_checks(**kwargs)) - errors.extend(self._check_validators()) - errors.extend(self._check_deprecation_details()) - return errors + return [ + *self._check_field_name(), + *self._check_choices(), + *self._check_db_index(), + *self._check_null_allowed_for_primary_keys(), + *self._check_backend_specific_checks(**kwargs), + *self._check_validators(), + *self._check_deprecation_details(), + ] def _check_field_name(self): """ @@ -549,7 +548,7 @@ class Field(RegisterLookupMixin): Some validators can't be created at field initialization time. This method provides a way to delay their creation until required. """ - return list(itertools.chain(self.default_validators, self._validators)) + return [*self.default_validators, *self._validators] def run_validators(self, value): if value in self.empty_values: @@ -886,9 +885,10 @@ class AutoField(Field): super().__init__(*args, **kwargs) def check(self, **kwargs): - errors = super().check(**kwargs) - errors.extend(self._check_primary_key()) - return errors + return [ + *super().check(**kwargs), + *self._check_primary_key(), + ] def _check_primary_key(self): if not self.primary_key: @@ -972,9 +972,10 @@ class BooleanField(Field): super().__init__(*args, **kwargs) def check(self, **kwargs): - errors = super().check(**kwargs) - errors.extend(self._check_null(**kwargs)) - return errors + return [ + *super().check(**kwargs), + *self._check_null(**kwargs), + ] def _check_null(self, **kwargs): if getattr(self, 'null', False): @@ -1038,9 +1039,10 @@ class CharField(Field): self.validators.append(validators.MaxLengthValidator(self.max_length)) def check(self, **kwargs): - errors = super().check(**kwargs) - errors.extend(self._check_max_length_attribute(**kwargs)) - return errors + return [ + *super().check(**kwargs), + *self._check_max_length_attribute(**kwargs), + ] def _check_max_length_attribute(self, **kwargs): if self.max_length is None: @@ -1111,10 +1113,11 @@ class CommaSeparatedIntegerField(CharField): class DateTimeCheckMixin: def check(self, **kwargs): - errors = super().check(**kwargs) - errors.extend(self._check_mutually_exclusive_options()) - errors.extend(self._check_fix_default_value()) - return errors + return [ + *super().check(**kwargs), + *self._check_mutually_exclusive_options(), + *self._check_fix_default_value(), + ] def _check_mutually_exclusive_options(self): # auto_now, auto_now_add, and default are mutually exclusive @@ -1276,9 +1279,10 @@ class DateField(DateTimeCheckMixin, Field): return '' if val is None else val.isoformat() def formfield(self, **kwargs): - defaults = {'form_class': forms.DateField} - defaults.update(kwargs) - return super().formfield(**defaults) + return super().formfield(**{ + 'form_class': forms.DateField, + **kwargs, + }) class DateTimeField(DateField): @@ -1431,9 +1435,10 @@ class DateTimeField(DateField): return '' if val is None else val.isoformat() def formfield(self, **kwargs): - defaults = {'form_class': forms.DateTimeField} - defaults.update(kwargs) - return super().formfield(**defaults) + return super().formfield(**{ + 'form_class': forms.DateTimeField, + **kwargs, + }) class DecimalField(Field): @@ -1451,8 +1456,10 @@ class DecimalField(Field): def check(self, **kwargs): errors = super().check(**kwargs) - digits_errors = self._check_decimal_places() - digits_errors.extend(self._check_max_digits()) + digits_errors = [ + *self._check_decimal_places(), + *self._check_max_digits(), + ] if not digits_errors: errors.extend(self._check_decimal_places_and_max_digits(**kwargs)) else: @@ -1575,13 +1582,12 @@ class DecimalField(Field): return self.to_python(value) def formfield(self, **kwargs): - defaults = { + return super().formfield(**{ 'max_digits': self.max_digits, 'decimal_places': self.decimal_places, 'form_class': forms.DecimalField, - } - defaults.update(kwargs) - return super().formfield(**defaults) + **kwargs, + }) class DurationField(Field): @@ -1639,11 +1645,10 @@ class DurationField(Field): return '' if val is None else duration_string(val) def formfield(self, **kwargs): - defaults = { + return super().formfield(**{ 'form_class': forms.DurationField, - } - defaults.update(kwargs) - return super().formfield(**defaults) + **kwargs, + }) class EmailField(CharField): @@ -1664,11 +1669,10 @@ class EmailField(CharField): def formfield(self, **kwargs): # As with CharField, this will cause email validation to be performed # twice. - defaults = { + return super().formfield(**{ 'form_class': forms.EmailField, - } - defaults.update(kwargs) - return super().formfield(**defaults) + **kwargs, + }) class FilePathField(Field): @@ -1682,9 +1686,10 @@ class FilePathField(Field): super().__init__(verbose_name, name, **kwargs) def check(self, **kwargs): - errors = super().check(**kwargs) - errors.extend(self._check_allowing_files_or_folders(**kwargs)) - return errors + return [ + *super().check(**kwargs), + *self._check_allowing_files_or_folders(**kwargs), + ] def _check_allowing_files_or_folders(self, **kwargs): if not self.allow_files and not self.allow_folders: @@ -1720,16 +1725,15 @@ class FilePathField(Field): return str(value) def formfield(self, **kwargs): - defaults = { + return super().formfield(**{ 'path': self.path, 'match': self.match, 'recursive': self.recursive, 'form_class': forms.FilePathField, 'allow_files': self.allow_files, 'allow_folders': self.allow_folders, - } - defaults.update(kwargs) - return super().formfield(**defaults) + **kwargs, + }) def get_internal_type(self): return "FilePathField" @@ -1764,9 +1768,10 @@ class FloatField(Field): ) def formfield(self, **kwargs): - defaults = {'form_class': forms.FloatField} - defaults.update(kwargs) - return super().formfield(**defaults) + return super().formfield(**{ + 'form_class': forms.FloatField, + **kwargs, + }) class IntegerField(Field): @@ -1777,9 +1782,10 @@ class IntegerField(Field): description = _("Integer") def check(self, **kwargs): - errors = super().check(**kwargs) - errors.extend(self._check_max_length_warning()) - return errors + return [ + *super().check(**kwargs), + *self._check_max_length_warning(), + ] def _check_max_length_warning(self): if self.max_length is not None: @@ -1836,9 +1842,10 @@ class IntegerField(Field): ) def formfield(self, **kwargs): - defaults = {'form_class': forms.IntegerField} - defaults.update(kwargs) - return super().formfield(**defaults) + return super().formfield(**{ + 'form_class': forms.IntegerField, + **kwargs, + }) class BigIntegerField(IntegerField): @@ -1850,10 +1857,11 @@ class BigIntegerField(IntegerField): return "BigIntegerField" def formfield(self, **kwargs): - defaults = {'min_value': -BigIntegerField.MAX_BIGINT - 1, - 'max_value': BigIntegerField.MAX_BIGINT} - defaults.update(kwargs) - return super().formfield(**defaults) + return super().formfield(**{ + 'min_value': -BigIntegerField.MAX_BIGINT - 1, + 'max_value': BigIntegerField.MAX_BIGINT, + **kwargs, + }) class IPAddressField(Field): @@ -1903,9 +1911,10 @@ class GenericIPAddressField(Field): super().__init__(verbose_name, name, *args, **kwargs) def check(self, **kwargs): - errors = super().check(**kwargs) - errors.extend(self._check_blank_and_null_values(**kwargs)) - return errors + return [ + *super().check(**kwargs), + *self._check_blank_and_null_values(**kwargs), + ] def _check_blank_and_null_values(self, **kwargs): if not getattr(self, 'null', False) and getattr(self, 'blank', False): @@ -1959,12 +1968,11 @@ class GenericIPAddressField(Field): return str(value) def formfield(self, **kwargs): - defaults = { + return super().formfield(**{ 'protocol': self.protocol, 'form_class': forms.GenericIPAddressField, - } - defaults.update(kwargs) - return super().formfield(**defaults) + **kwargs, + }) class NullBooleanField(Field): @@ -2012,9 +2020,10 @@ class NullBooleanField(Field): return self.to_python(value) def formfield(self, **kwargs): - defaults = {'form_class': forms.NullBooleanField} - defaults.update(kwargs) - return super().formfield(**defaults) + return super().formfield(**{ + 'form_class': forms.NullBooleanField, + **kwargs, + }) class PositiveIntegerRelDbTypeMixin: @@ -2041,9 +2050,10 @@ class PositiveIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField): return "PositiveIntegerField" def formfield(self, **kwargs): - defaults = {'min_value': 0} - defaults.update(kwargs) - return super().formfield(**defaults) + return super().formfield(**{ + 'min_value': 0, + **kwargs, + }) class PositiveSmallIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField): @@ -2053,9 +2063,10 @@ class PositiveSmallIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField): return "PositiveSmallIntegerField" def formfield(self, **kwargs): - defaults = {'min_value': 0} - defaults.update(kwargs) - return super().formfield(**defaults) + return super().formfield(**{ + 'min_value': 0, + **kwargs, + }) class SlugField(CharField): @@ -2084,9 +2095,11 @@ class SlugField(CharField): return "SlugField" def formfield(self, **kwargs): - defaults = {'form_class': forms.SlugField, 'allow_unicode': self.allow_unicode} - defaults.update(kwargs) - return super().formfield(**defaults) + return super().formfield(**{ + 'form_class': forms.SlugField, + 'allow_unicode': self.allow_unicode, + **kwargs, + }) class SmallIntegerField(IntegerField): @@ -2115,11 +2128,11 @@ class TextField(Field): # Passing max_length to forms.CharField means that the value's length # will be validated twice. This is considered acceptable since we want # the value in the form field (to pass into widget for example). - defaults = {'max_length': self.max_length} - if not self.choices: - defaults['widget'] = forms.Textarea - defaults.update(kwargs) - return super().formfield(**defaults) + return super().formfield(**{ + 'max_length': self.max_length, + **({} if self.choices else {'widget': forms.Textarea}), + **kwargs, + }) class TimeField(DateTimeCheckMixin, Field): @@ -2248,9 +2261,10 @@ class TimeField(DateTimeCheckMixin, Field): return '' if val is None else val.isoformat() def formfield(self, **kwargs): - defaults = {'form_class': forms.TimeField} - defaults.update(kwargs) - return super().formfield(**defaults) + return super().formfield(**{ + 'form_class': forms.TimeField, + **kwargs, + }) class URLField(CharField): @@ -2270,11 +2284,10 @@ class URLField(CharField): def formfield(self, **kwargs): # As with CharField, this will cause URL validation to be performed # twice. - defaults = { + return super().formfield(**{ 'form_class': forms.URLField, - } - defaults.update(kwargs) - return super().formfield(**defaults) + **kwargs, + }) class BinaryField(Field): @@ -2365,8 +2378,7 @@ class UUIDField(Field): return value def formfield(self, **kwargs): - defaults = { + return super().formfield(**{ 'form_class': forms.UUIDField, - } - defaults.update(kwargs) - return super().formfield(**defaults) + **kwargs, + }) diff --git a/django/db/models/fields/files.py b/django/db/models/fields/files.py index 00dcbc033cc..4e5ef51a092 100644 --- a/django/db/models/fields/files.py +++ b/django/db/models/fields/files.py @@ -230,10 +230,11 @@ class FileField(Field): super().__init__(verbose_name, name, **kwargs) def check(self, **kwargs): - errors = super().check(**kwargs) - errors.extend(self._check_primary_key()) - errors.extend(self._check_upload_to()) - return errors + return [ + *super().check(**kwargs), + *self._check_primary_key(), + *self._check_upload_to(), + ] def _check_primary_key(self): if self._primary_key_set_explicitly: @@ -318,9 +319,11 @@ class FileField(Field): setattr(instance, self.name, data) def formfield(self, **kwargs): - defaults = {'form_class': forms.FileField, 'max_length': self.max_length} - defaults.update(kwargs) - return super().formfield(**defaults) + return super().formfield(**{ + 'form_class': forms.FileField, + 'max_length': self.max_length, + **kwargs, + }) class ImageFileDescriptor(FileDescriptor): @@ -363,9 +366,10 @@ class ImageField(FileField): super().__init__(verbose_name, name, **kwargs) def check(self, **kwargs): - errors = super().check(**kwargs) - errors.extend(self._check_image_library_installed()) - return errors + return [ + *super().check(**kwargs), + *self._check_image_library_installed(), + ] def _check_image_library_installed(self): try: @@ -458,6 +462,7 @@ class ImageField(FileField): setattr(instance, self.height_field, height) def formfield(self, **kwargs): - defaults = {'form_class': forms.ImageField} - defaults.update(kwargs) - return super().formfield(**defaults) + return super().formfield(**{ + 'form_class': forms.ImageField, + **kwargs, + }) diff --git a/django/db/models/fields/related.py b/django/db/models/fields/related.py index cfb5ea1ef60..d07a5a879a5 100644 --- a/django/db/models/fields/related.py +++ b/django/db/models/fields/related.py @@ -95,13 +95,14 @@ class RelatedField(FieldCacheMixin, Field): return self.remote_field.model def check(self, **kwargs): - errors = super().check(**kwargs) - errors.extend(self._check_related_name_is_valid()) - errors.extend(self._check_related_query_name_is_valid()) - errors.extend(self._check_relation_model_exists()) - errors.extend(self._check_referencing_to_swapped_model()) - errors.extend(self._check_clashes()) - return errors + return [ + *super().check(**kwargs), + *self._check_related_name_is_valid(), + *self._check_related_query_name_is_valid(), + *self._check_relation_model_exists(), + *self._check_referencing_to_swapped_model(), + *self._check_clashes(), + ] def _check_related_name_is_valid(self): import keyword @@ -480,10 +481,11 @@ class ForeignObject(RelatedField): self.swappable = swappable def check(self, **kwargs): - errors = super().check(**kwargs) - errors.extend(self._check_to_fields_exist()) - errors.extend(self._check_unique_target()) - return errors + return [ + *super().check(**kwargs), + *self._check_to_fields_exist(), + *self._check_unique_target(), + ] def _check_to_fields_exist(self): # Skip nonexistent models. @@ -815,10 +817,11 @@ class ForeignKey(ForeignObject): self.db_constraint = db_constraint def check(self, **kwargs): - errors = super().check(**kwargs) - errors.extend(self._check_on_delete()) - errors.extend(self._check_unique()) - return errors + return [ + *super().check(**kwargs), + *self._check_on_delete(), + *self._check_unique(), + ] def _check_on_delete(self): on_delete = getattr(self.remote_field, 'on_delete', None) @@ -950,13 +953,12 @@ class ForeignKey(ForeignObject): raise ValueError("Cannot create form field for %r yet, because " "its related model %r has not been loaded yet" % (self.name, self.remote_field.model)) - defaults = { + return super().formfield(**{ 'form_class': forms.ModelChoiceField, 'queryset': self.remote_field.model._default_manager.using(using), 'to_field_name': self.remote_field.field_name, - } - defaults.update(kwargs) - return super().formfield(**defaults) + **kwargs, + }) def db_check(self, connection): return [] @@ -1134,12 +1136,13 @@ class ManyToManyField(RelatedField): self.swappable = swappable def check(self, **kwargs): - errors = super().check(**kwargs) - errors.extend(self._check_unique(**kwargs)) - errors.extend(self._check_relationship_model(**kwargs)) - errors.extend(self._check_ignored_options(**kwargs)) - errors.extend(self._check_table_uniqueness(**kwargs)) - return errors + return [ + *super().check(**kwargs), + *self._check_unique(**kwargs), + *self._check_relationship_model(**kwargs), + *self._check_ignored_options(**kwargs), + *self._check_table_uniqueness(**kwargs), + ] def _check_unique(self, **kwargs): if self.unique: @@ -1461,7 +1464,6 @@ class ManyToManyField(RelatedField): def _get_path_info(self, direct=False, filtered_relation=None): """Called by both direct and indirect m2m traversal.""" - pathinfos = [] int_model = self.remote_field.through linkfield1 = int_model._meta.get_field(self.m2m_field_name()) linkfield2 = int_model._meta.get_field(self.m2m_reverse_field_name()) @@ -1484,10 +1486,7 @@ class ManyToManyField(RelatedField): else: intermediate_infos = join2_initial.get_path_from_parent(join1_final.model) - pathinfos.extend(join1infos) - pathinfos.extend(intermediate_infos) - pathinfos.extend(join2infos) - return pathinfos + return [*join1infos, *intermediate_infos, *join2infos] def get_path_info(self, filtered_relation=None): return self._get_path_info(direct=True, filtered_relation=filtered_relation) @@ -1624,8 +1623,8 @@ class ManyToManyField(RelatedField): defaults = { 'form_class': forms.ModelMultipleChoiceField, 'queryset': self.remote_field.model._default_manager.using(using), + **kwargs, } - defaults.update(kwargs) # If initial is passed in, it's a list of related objects, but the # MultipleChoiceField takes a list of IDs. if defaults.get('initial') is not None: diff --git a/django/db/models/manager.py b/django/db/models/manager.py index 31f2dd37234..5f897cd3ca1 100644 --- a/django/db/models/manager.py +++ b/django/db/models/manager.py @@ -101,11 +101,10 @@ class BaseManager: def from_queryset(cls, queryset_class, class_name=None): if class_name is None: class_name = '%sFrom%s' % (cls.__name__, queryset_class.__name__) - class_dict = { + return type(class_name, (cls,), { '_queryset_class': queryset_class, - } - class_dict.update(cls._get_queryset_methods(queryset_class)) - return type(class_name, (cls,), class_dict) + **cls._get_queryset_methods(queryset_class), + }) def contribute_to_class(self, model, name): if not self.name: diff --git a/django/db/models/query.py b/django/db/models/query.py index 2997b890a04..de8ff00d2cf 100644 --- a/django/db/models/query.py +++ b/django/db/models/query.py @@ -157,9 +157,7 @@ class NamedValuesListIterable(ValuesListIterable): names = queryset._fields else: query = queryset.query - names = list(query.extra_select) - names.extend(query.values_select) - names.extend(query.annotation_select) + names = [*query.extra_select, *query.values_select, *query.annotation_select] tuple_class = self.create_namedtuple_class(*names) new = tuple.__new__ for row in super().__iter__(): diff --git a/django/db/models/sql/compiler.py b/django/db/models/sql/compiler.py index 9e381fd2697..7930d223f1c 100644 --- a/django/db/models/sql/compiler.py +++ b/django/db/models/sql/compiler.py @@ -476,10 +476,7 @@ class SQLCompiler: params.extend(s_params) out_cols.append(s_sql) - result.append(', '.join(out_cols)) - - result.append('FROM') - result.extend(from_) + result += [', '.join(out_cols), 'FROM', *from_] params.extend(f_params) if self.query.select_for_update and self.connection.features.has_select_for_update: diff --git a/django/forms/boundfield.py b/django/forms/boundfield.py index dba54e588a3..27e80c65e77 100644 --- a/django/forms/boundfield.py +++ b/django/forms/boundfield.py @@ -153,7 +153,7 @@ class BoundField: if id_: id_for_label = widget.id_for_label(id_) if id_for_label: - attrs = dict(attrs or {}, **{'for': id_for_label}) + attrs = {**(attrs or {}), 'for': id_for_label} if self.field.required and hasattr(self.form, 'required_css_class'): attrs = attrs or {} if 'class' in attrs: diff --git a/django/forms/fields.py b/django/forms/fields.py index 64124844f03..92a8f768c45 100644 --- a/django/forms/fields.py +++ b/django/forms/fields.py @@ -4,7 +4,6 @@ Field classes. import copy import datetime -import itertools import math import os import re @@ -112,7 +111,7 @@ class Field: messages.update(error_messages or {}) self.error_messages = messages - self.validators = list(itertools.chain(self.default_validators, validators)) + self.validators = [*self.default_validators, *validators] super().__init__() diff --git a/django/forms/models.py b/django/forms/models.py index 3ba7725d53c..84a07a275fc 100644 --- a/django/forms/models.py +++ b/django/forms/models.py @@ -564,9 +564,7 @@ class BaseModelFormSet(BaseFormSet): queryset=None, *, initial=None, **kwargs): self.queryset = queryset self.initial_extra = initial - defaults = {'data': data, 'files': files, 'auto_id': auto_id, 'prefix': prefix} - defaults.update(kwargs) - super().__init__(**defaults) + super().__init__(**{'data': data, 'files': files, 'auto_id': auto_id, 'prefix': prefix, **kwargs}) def initial_form_count(self): """Return the number of forms that are required in this FormSet.""" diff --git a/django/forms/widgets.py b/django/forms/widgets.py index ba8287cd976..c20c8f1b506 100644 --- a/django/forms/widgets.py +++ b/django/forms/widgets.py @@ -241,10 +241,7 @@ class Widget(metaclass=MediaDefiningClass): def build_attrs(self, base_attrs, extra_attrs=None): """Build an attribute dictionary.""" - attrs = base_attrs.copy() - if extra_attrs is not None: - attrs.update(extra_attrs) - return attrs + return {**base_attrs, **(extra_attrs or {})} def value_from_datadict(self, data, files, name): """ diff --git a/django/test/client.py b/django/test/client.py index 6406f8309e7..3a163d126f1 100644 --- a/django/test/client.py +++ b/django/test/client.py @@ -274,7 +274,7 @@ class RequestFactory: # - HTTP_COOKIE: for cookie support, # - REMOTE_ADDR: often useful, see #8551. # See http://www.python.org/dev/peps/pep-3333/#environ-variables - environ = { + return { 'HTTP_COOKIE': self.cookies.output(header='', sep='; '), 'PATH_INFO': '/', 'REMOTE_ADDR': '127.0.0.1', @@ -290,10 +290,9 @@ class RequestFactory: 'wsgi.multiprocess': True, 'wsgi.multithread': False, 'wsgi.run_once': False, + **self.defaults, + **request, } - environ.update(self.defaults) - environ.update(request) - return environ def request(self, **request): "Construct a generic request object." @@ -325,11 +324,10 @@ class RequestFactory: def get(self, path, data=None, secure=False, **extra): """Construct a GET request.""" data = {} if data is None else data - r = { + return self.generic('GET', path, secure=secure, **{ 'QUERY_STRING': urlencode(data, doseq=True), - } - r.update(extra) - return self.generic('GET', path, secure=secure, **r) + **extra, + }) def post(self, path, data=None, content_type=MULTIPART_CONTENT, secure=False, **extra): @@ -343,11 +341,10 @@ class RequestFactory: def head(self, path, data=None, secure=False, **extra): """Construct a HEAD request.""" data = {} if data is None else data - r = { + return self.generic('HEAD', path, secure=secure, **{ 'QUERY_STRING': urlencode(data, doseq=True), - } - r.update(extra) - return self.generic('HEAD', path, secure=secure, **r) + **extra, + }) def trace(self, path, secure=False, **extra): """Construct a TRACE request.""" diff --git a/django/test/testcases.py b/django/test/testcases.py index c099258befd..34961661242 100644 --- a/django/test/testcases.py +++ b/django/test/testcases.py @@ -635,7 +635,7 @@ class SimpleTestCase(unittest.TestCase): if field_kwargs is None: field_kwargs = {} required = fieldclass(*field_args, **field_kwargs) - optional = fieldclass(*field_args, **dict(field_kwargs, required=False)) + optional = fieldclass(*field_args, **{**field_kwargs, 'required': False}) # test valid inputs for input, output in valid.items(): self.assertEqual(required.clean(input), output) diff --git a/django/test/utils.py b/django/test/utils.py index 0cec1a2309a..1678bf0de4a 100644 --- a/django/test/utils.py +++ b/django/test/utils.py @@ -423,8 +423,10 @@ class override_settings(TestContextDecorator): test_func._overridden_settings = self.options else: # Duplicate dict to prevent subclasses from altering their parent. - test_func._overridden_settings = dict( - test_func._overridden_settings, **self.options) + test_func._overridden_settings = { + **test_func._overridden_settings, + **self.options, + } def decorate_class(self, cls): from django.test import SimpleTestCase diff --git a/django/urls/resolvers.py b/django/urls/resolvers.py index 55785a696fd..661525c6d1b 100644 --- a/django/urls/resolvers.py +++ b/django/urls/resolvers.py @@ -440,8 +440,8 @@ class URLResolver: ( new_matches, p_pattern + pat, - dict(defaults, **url_pattern.default_kwargs), - dict(self.pattern.converters, **converters) + {**defaults, **url_pattern.default_kwargs}, + {**self.pattern.converters, **converters} ) ) for namespace, (prefix, sub_pattern) in url_pattern.namespace_dict.items(): @@ -500,7 +500,7 @@ class URLResolver: else: if sub_match: # Merge captured arguments in match with submatch - sub_match_dict = dict(kwargs, **self.default_kwargs) + sub_match_dict = {**kwargs, **self.default_kwargs} # Update the sub_match_dict with the kwargs from the sub_match. sub_match_dict.update(sub_match.kwargs) # If there are *any* named groups, ignore all non-named groups. diff --git a/django/utils/feedgenerator.py b/django/utils/feedgenerator.py index ec01d02697e..a0f63901c7d 100644 --- a/django/utils/feedgenerator.py +++ b/django/utils/feedgenerator.py @@ -102,8 +102,8 @@ class SyndicationFeed: 'feed_copyright': to_str(feed_copyright), 'id': feed_guid or link, 'ttl': to_str(ttl), + **kwargs, } - self.feed.update(kwargs) self.items = [] def add_item(self, title, link, description, author_email=None, @@ -119,7 +119,7 @@ class SyndicationFeed: return str(s) if s is not None else s if categories: categories = [to_str(c) for c in categories] - item = { + self.items.append({ 'title': to_str(title), 'link': iri_to_uri(link), 'description': to_str(description), @@ -135,9 +135,8 @@ class SyndicationFeed: 'categories': categories or (), 'item_copyright': to_str(item_copyright), 'ttl': to_str(ttl), - } - item.update(kwargs) - self.items.append(item) + **kwargs, + }) def num_items(self): return len(self.items) diff --git a/django/utils/functional.py b/django/utils/functional.py index af493225598..dcc8e87f771 100644 --- a/django/utils/functional.py +++ b/django/utils/functional.py @@ -9,7 +9,7 @@ from functools import total_ordering, wraps # CPython) is a type and its instances don't bind. def curry(_curried_func, *args, **kwargs): def _curried(*moreargs, **morekwargs): - return _curried_func(*(args + moreargs), **dict(kwargs, **morekwargs)) + return _curried_func(*(args + moreargs), **{**kwargs, **morekwargs}) return _curried