Browse Source

Refs #28909 -- Simplifed code using unpacking generalizations.

Sergey Fedoseev 6 years ago
parent
commit
8ef8bc0f64

+ 1 - 1
django/apps/registry.py

@@ -389,7 +389,7 @@ class Apps:
         # to lazy_model_operation() along with the remaining model args and
         # repeat until all models are loaded and all arguments are applied.
         else:
-            next_model, more_models = model_keys[0], model_keys[1:]
+            next_model, *more_models = model_keys
 
             # This will be executed after the class corresponding to next_model
             # has been imported and registered. The `func` attribute provides

+ 1 - 1
django/conf/__init__.py

@@ -182,7 +182,7 @@ class UserSettingsHolder:
 
     def __dir__(self):
         return sorted(
-            s for s in list(self.__dict__) + dir(self.default_settings)
+            s for s in [*self.__dict__, *dir(self.default_settings)]
             if s not in self._deleted
         )
 

+ 3 - 3
django/contrib/admin/options.py

@@ -256,7 +256,7 @@ class BaseModelAdmin(metaclass=forms.MediaDefiningClass):
             kwargs['widget'] = AutocompleteSelectMultiple(db_field.remote_field, self.admin_site, using=db)
         elif db_field.name in self.raw_id_fields:
             kwargs['widget'] = widgets.ManyToManyRawIdWidget(db_field.remote_field, self.admin_site, using=db)
-        elif db_field.name in list(self.filter_vertical) + list(self.filter_horizontal):
+        elif db_field.name in [*self.filter_vertical, *self.filter_horizontal]:
             kwargs['widget'] = widgets.FilteredSelectMultiple(
                 db_field.verbose_name,
                 db_field.name in self.filter_vertical
@@ -318,7 +318,7 @@ class BaseModelAdmin(metaclass=forms.MediaDefiningClass):
             return self.fields
         # _get_form_for_get_fields() is implemented in subclasses.
         form = self._get_form_for_get_fields(request, obj)
-        return list(form.base_fields) + list(self.get_readonly_fields(request, obj))
+        return [*form.base_fields, *self.get_readonly_fields(request, obj)]
 
     def get_fieldsets(self, request, obj=None):
         """
@@ -724,7 +724,7 @@ class ModelAdmin(BaseModelAdmin):
         list_display_links = self.get_list_display_links(request, list_display)
         # Add the action checkboxes if any actions are available.
         if self.get_actions(request):
-            list_display = ['action_checkbox'] + list(list_display)
+            list_display = ['action_checkbox', *list_display]
         sortable_by = self.get_sortable_by(request)
         ChangeList = self.get_changelist(request)
         return ChangeList(

+ 1 - 1
django/contrib/admindocs/views.py

@@ -278,7 +278,7 @@ class ModelDetailView(BaseAdminDocsView):
                     # join it with '='. Use repr() so that strings will be
                     # correctly displayed.
                     print_arguments = ', '.join([
-                        '='.join(list(arg_el[:1]) + [repr(el) for el in arg_el[1:]])
+                        '='.join([arg_el[0], *map(repr, arg_el[1:])])
                         for arg_el in arguments
                     ])
                     methods.append({

+ 1 - 3
django/contrib/auth/management/__init__.py

@@ -15,9 +15,7 @@ def _get_all_permissions(opts):
     """
     Return (codename, name) for all permissions in the given opts.
     """
-    builtin = _get_builtin_permissions(opts)
-    custom = list(opts.permissions)
-    return builtin + custom
+    return [*_get_builtin_permissions(opts), *opts.permissions]
 
 
 def _get_builtin_permissions(opts):

+ 2 - 2
django/contrib/gis/geos/mutable_list.py

@@ -109,11 +109,11 @@ class ListMixin:
     # ### Special methods for arithmetic operations ###
     def __add__(self, other):
         'add another list-like object'
-        return self.__class__(list(self) + list(other))
+        return self.__class__([*self, *other])
 
     def __radd__(self, other):
         'add to another list-like object'
-        return other.__class__(list(other) + list(self))
+        return other.__class__([*other, *self])
 
     def __iadd__(self, other):
         'add another list-like object to self'

+ 2 - 3
django/contrib/gis/geos/polygon.py

@@ -31,8 +31,7 @@ class Polygon(GEOSGeometry):
             return
 
         # Getting the ext_ring and init_holes parameters from the argument list
-        ext_ring = args[0]
-        init_holes = args[1:]
+        ext_ring, *init_holes = args
         n_holes = len(init_holes)
 
         # If initialized as Polygon(shell, (LinearRing, LinearRing)) [for backward-compatibility]
@@ -44,7 +43,7 @@ class Polygon(GEOSGeometry):
                 init_holes = init_holes[0]
                 n_holes = len(init_holes)
 
-        polygon = self._create_polygon(n_holes + 1, (ext_ring,) + init_holes)
+        polygon = self._create_polygon(n_holes + 1, [ext_ring, *init_holes])
         super().__init__(polygon, **kwargs)
 
     def __iter__(self):

+ 1 - 1
django/contrib/gis/serializers/geojson.py

@@ -13,7 +13,7 @@ class Serializer(JSONSerializer):
         self.srid = self.json_kwargs.pop('srid', 4326)
         if (self.selected_fields is not None and self.geometry_field is not None and
                 self.geometry_field not in self.selected_fields):
-            self.selected_fields = list(self.selected_fields) + [self.geometry_field]
+            self.selected_fields = [*self.selected_fields, self.geometry_field]
 
     def start_serialization(self):
         self._init_options()

+ 1 - 2
django/contrib/postgres/fields/array.py

@@ -28,8 +28,7 @@ class ArrayField(CheckFieldDefaultMixin, Field):
         self.base_field = base_field
         self.size = size
         if self.size:
-            self.default_validators = self.default_validators[:]
-            self.default_validators.append(ArrayMaxLengthValidator(self.size))
+            self.default_validators = [*self.default_validators, ArrayMaxLengthValidator(self.size)]
         # For performance, only add a from_db_value() method if the base field
         # implements it.
         if hasattr(self.base_field, 'from_db_value'):

+ 4 - 3
django/core/handlers/wsgi.py

@@ -143,9 +143,10 @@ class WSGIHandler(base.BaseHandler):
         response._handler_class = self.__class__
 
         status = '%d %s' % (response.status_code, response.reason_phrase)
-        response_headers = list(response.items())
-        for c in response.cookies.values():
-            response_headers.append(('Set-Cookie', c.output(header='')))
+        response_headers = [
+            *response.items(),
+            *(('Set-Cookie', c.output(header='')) for c in response.cookies.values()),
+        ]
         start_response(status, response_headers)
         if getattr(response, 'file_to_stream', None) is not None and environ.get('wsgi.file_wrapper'):
             response = environ['wsgi.file_wrapper'](response.file_to_stream)

+ 1 - 1
django/core/management/__init__.py

@@ -257,7 +257,7 @@ class ManagementUtility:
         except IndexError:
             curr = ''
 
-        subcommands = list(get_commands()) + ['help']
+        subcommands = [*get_commands(), 'help']
         options = [('--help', False)]
 
         # subcommand

+ 2 - 6
django/db/migrations/operations/models.py

@@ -735,9 +735,7 @@ class AddIndex(IndexOperation):
 
     def state_forwards(self, app_label, state):
         model_state = state.models[app_label, self.model_name_lower]
-        indexes = list(model_state.options[self.option_name])
-        indexes.append(self.index.clone())
-        model_state.options[self.option_name] = indexes
+        model_state.options[self.option_name] = [*model_state.options[self.option_name], self.index.clone()]
         state.reload_model(app_label, self.model_name_lower, delay=True)
 
     def database_forwards(self, app_label, schema_editor, from_state, to_state):
@@ -820,9 +818,7 @@ class AddConstraint(IndexOperation):
 
     def state_forwards(self, app_label, state):
         model_state = state.models[app_label, self.model_name_lower]
-        constraints = list(model_state.options[self.option_name])
-        constraints.append(self.constraint)
-        model_state.options[self.option_name] = constraints
+        model_state.options[self.option_name] = [*model_state.options[self.option_name], self.constraint]
 
     def database_forwards(self, app_label, schema_editor, from_state, to_state):
         model = to_state.apps.get_model(app_label, self.model_name)

+ 2 - 2
django/db/migrations/state.py

@@ -261,14 +261,14 @@ class StateApps(Apps):
                 self.real_models.append(ModelState.from_model(model, exclude_rels=True))
         # Populate the app registry with a stub for each application.
         app_labels = {model_state.app_label for model_state in models.values()}
-        app_configs = [AppConfigStub(label) for label in sorted(real_apps + list(app_labels))]
+        app_configs = [AppConfigStub(label) for label in sorted([*real_apps, *app_labels])]
         super().__init__(app_configs)
 
         # The lock gets in the way of copying as implemented in clone(), which
         # is called whenever Django duplicates a StateApps before updating it.
         self._lock = None
 
-        self.render_multiple(list(models.values()) + self.real_models)
+        self.render_multiple([*models.values(), *self.real_models])
 
         # There shouldn't be any operations pending at this point.
         from django.core.checks.model_checks import _check_lazy_references

+ 1 - 2
django/db/models/expressions.py

@@ -947,8 +947,7 @@ class Case(Expression):
         return self.cases + [self.default]
 
     def set_source_expressions(self, exprs):
-        self.cases = exprs[:-1]
-        self.default = exprs[-1]
+        *self.cases, self.default = exprs
 
     def resolve_expression(self, query=None, allow_joins=True, reuse=None, summarize=False, for_save=False):
         c = self.copy()

+ 12 - 14
django/db/models/query.py

@@ -96,13 +96,12 @@ class ValuesIterable(BaseIterable):
         query = queryset.query
         compiler = query.get_compiler(queryset.db)
 
-        field_names = list(query.values_select)
-        extra_names = list(query.extra_select)
-        annotation_names = list(query.annotation_select)
-
         # extra(select=...) cols are always at the start of the row.
-        names = extra_names + field_names + annotation_names
-
+        names = [
+            *query.extra_select,
+            *query.values_select,
+            *query.annotation_select,
+        ]
         indexes = range(len(names))
         for row in compiler.results_iter(chunked_fetch=self.chunked_fetch, chunk_size=self.chunk_size):
             yield {names[i]: row[i] for i in indexes}
@@ -120,14 +119,13 @@ class ValuesListIterable(BaseIterable):
         compiler = query.get_compiler(queryset.db)
 
         if queryset._fields:
-            field_names = list(query.values_select)
-            extra_names = list(query.extra_select)
-            annotation_names = list(query.annotation_select)
-
             # extra(select=...) cols are always at the start of the row.
-            names = extra_names + field_names + annotation_names
-
-            fields = list(queryset._fields) + [f for f in annotation_names if f not in queryset._fields]
+            names = [
+                *query.extra_select,
+                *query.values_select,
+                *query.annotation_select,
+            ]
+            fields = [*queryset._fields, *(f for f in query.annotation_select if f not in queryset._fields)]
             if fields != names:
                 # Reorder according to fields.
                 index_map = {name: idx for idx, name in enumerate(names)}
@@ -352,7 +350,7 @@ class QuerySet:
         """
         if self.query.distinct_fields:
             raise NotImplementedError("aggregate() + distinct(fields) not implemented.")
-        self._validate_values_are_expressions(args + tuple(kwargs.values()), method_name='aggregate')
+        self._validate_values_are_expressions((*args, *kwargs.values()), method_name='aggregate')
         for arg in args:
             # The default_alias property raises TypeError if default_alias
             # can't be set automatically or AttributeError if it isn't an

+ 1 - 1
django/db/models/query_utils.py

@@ -58,7 +58,7 @@ class Q(tree.Node):
     def __init__(self, *args, **kwargs):
         connector = kwargs.pop('_connector', None)
         negated = kwargs.pop('_negated', False)
-        super().__init__(children=list(args) + sorted(kwargs.items()), connector=connector, negated=negated)
+        super().__init__(children=[*args, *sorted(kwargs.items())], connector=connector, negated=negated)
 
     def _combine(self, other, conn):
         if not isinstance(other, Q):

+ 11 - 12
django/db/models/sql/query.py

@@ -1096,12 +1096,11 @@ class Query:
         and get_transform().
         """
         # __exact is the default lookup if one isn't given.
-        lookups = lookups or ['exact']
-        for name in lookups[:-1]:
+        *transforms, lookup_name = lookups or ['exact']
+        for name in transforms:
             lhs = self.try_transform(lhs, name)
         # First try get_lookup() so that the lookup takes precedence if the lhs
         # supports both transform and lookup for the name.
-        lookup_name = lookups[-1]
         lookup_class = lhs.get_lookup(lookup_name)
         if not lookup_class:
             if lhs.field.is_relation:
@@ -1406,11 +1405,11 @@ class Query:
                 # one step.
                 pos -= 1
                 if pos == -1 or fail_on_missing:
-                    field_names = list(get_field_names_from_opts(opts))
-                    available = sorted(
-                        field_names + list(self.annotation_select) +
-                        list(self._filtered_relations)
-                    )
+                    available = sorted([
+                        *get_field_names_from_opts(opts),
+                        *self.annotation_select,
+                        *self._filtered_relations,
+                    ])
                     raise FieldError("Cannot resolve keyword '%s' into field. "
                                      "Choices are: %s" % (name, ", ".join(available)))
                 break
@@ -1776,10 +1775,10 @@ class Query:
                 # from the model on which the lookup failed.
                 raise
             else:
-                names = sorted(
-                    list(get_field_names_from_opts(opts)) + list(self.extra) +
-                    list(self.annotation_select) + list(self._filtered_relations)
-                )
+                names = sorted([
+                    *get_field_names_from_opts(opts), *self.extra,
+                    *self.annotation_select, *self._filtered_relations
+                ])
                 raise FieldError("Cannot resolve keyword %r into field. "
                                  "Choices are: %s" % (name, ", ".join(names)))
 

+ 1 - 2
django/template/engine.py

@@ -107,8 +107,7 @@ class Engine:
 
     def find_template_loader(self, loader):
         if isinstance(loader, (tuple, list)):
-            args = list(loader[1:])
-            loader = loader[0]
+            loader, *args = loader
         else:
             args = []
 

+ 1 - 1
django/test/html.py

@@ -72,7 +72,7 @@ class Element:
         return self.children == element.children
 
     def __hash__(self):
-        return hash((self.name,) + tuple(a for a in self.attributes))
+        return hash((self.name, *(a for a in self.attributes)))
 
     def _count(self, element, count=True):
         if not isinstance(element, str):

+ 1 - 2
django/test/testcases.py

@@ -614,8 +614,7 @@ class SimpleTestCase(unittest.TestCase):
     def _assertFooMessage(self, func, cm_attr, expected_exception, expected_message, *args, **kwargs):
         callable_obj = None
         if args:
-            callable_obj = args[0]
-            args = args[1:]
+            callable_obj, *args = args
         cm = self._assert_raises_or_warns_cm(func, cm_attr, expected_exception, expected_message)
         # Assertion used in context manager fashion.
         if callable_obj is None:

+ 1 - 1
django/test/utils.py

@@ -120,7 +120,7 @@ def setup_test_environment(debug=None):
 
     saved_data.allowed_hosts = settings.ALLOWED_HOSTS
     # Add the default host of the test client.
-    settings.ALLOWED_HOSTS = list(settings.ALLOWED_HOSTS) + ['testserver']
+    settings.ALLOWED_HOSTS = [*settings.ALLOWED_HOSTS, 'testserver']
 
     saved_data.debug = settings.DEBUG
     settings.DEBUG = debug

+ 3 - 2
django/utils/html.py

@@ -133,8 +133,9 @@ def format_html_join(sep, format_string, args_generator):
                                                   for u in users))
     """
     return mark_safe(conditional_escape(sep).join(
-        format_html(format_string, *tuple(args))
-        for args in args_generator))
+        format_html(format_string, *args)
+        for args in args_generator
+    ))
 
 
 @keep_lazy_text

+ 1 - 1
django/utils/translation/trans_real.py

@@ -360,7 +360,7 @@ def all_locale_paths():
         locale_path = os.path.join(app_config.path, 'locale')
         if os.path.exists(locale_path):
             app_paths.append(locale_path)
-    return [globalpath] + list(settings.LOCALE_PATHS) + app_paths
+    return [globalpath, *settings.LOCALE_PATHS, *app_paths]
 
 
 @functools.lru_cache(maxsize=1000)

+ 1 - 1
django/utils/tree.py

@@ -71,7 +71,7 @@ class Node:
         )
 
     def __hash__(self):
-        return hash((self.__class__, self.connector, self.negated) + tuple([
+        return hash((self.__class__, self.connector, self.negated, *[
             tuple(child) if isinstance(child, list) else child
             for child in self.children
         ]))

+ 1 - 1
docs/topics/serialization.txt

@@ -99,7 +99,7 @@ attribute. The ``name`` attribute of the base class will be ignored.
 In order to fully serialize your ``Restaurant`` instances, you will need to
 serialize the ``Place`` models as well::
 
-    all_objects = list(Restaurant.objects.all()) + list(Place.objects.all())
+    all_objects = [*Restaurant.objects.all(), *Place.objects.all()]
     data = serializers.serialize('xml', all_objects)
 
 Deserializing data

+ 1 - 2
tests/file_storage/tests.py

@@ -544,8 +544,7 @@ class CustomStorage(FileSystemStorage):
         """
         Append numbers to duplicate files rather than underscores, like Trac.
         """
-        parts = name.split('.')
-        basename, ext = parts[0], parts[1:]
+        basename, *ext = name.split('.')
         number = 2
         while self.exists(name):
             name = '.'.join([basename, str(number)] + ext)

+ 1 - 1
tests/forms_tests/tests/test_forms.py

@@ -1566,7 +1566,7 @@ value="Should escape < & > and <script>alert('xss')</
         p = TestForm()
         self.assertEqual(list(p.fields), TestFormMissing.field_order)
         p = TestFormInit()
-        order = list(TestForm.field_order) + ['field1']
+        order = [*TestForm.field_order, 'field1']
         self.assertEqual(list(p.fields), order)
         TestForm.field_order = ['unknown']
         p = TestForm()

+ 2 - 2
tests/gis_tests/geos_tests/test_geos.py

@@ -476,8 +476,8 @@ class GEOSTest(SimpleTestCase, TestDataMixin):
                 Polygon('foo')
 
             # Polygon(shell, (hole1, ... holeN))
-            rings = tuple(r for r in poly)
-            self.assertEqual(poly, Polygon(rings[0], rings[1:]))
+            ext_ring, *int_rings = poly
+            self.assertEqual(poly, Polygon(ext_ring, int_rings))
 
             # Polygon(shell_tuple, hole_tuple1, ... , hole_tupleN)
             ring_tuples = tuple(r.tuple for r in poly)

+ 4 - 4
tests/gis_tests/geos_tests/test_mutable_list.py

@@ -72,7 +72,7 @@ class ListMixinTest(unittest.TestCase):
         return range(-self.limit - b, self.limit + b)
 
     def step_range(self):
-        return list(range(-1 - self.limit, 0)) + list(range(1, 1 + self.limit))
+        return [*range(-1 - self.limit, 0), *range(1, 1 + self.limit)]
 
     def test01_getslice(self):
         'Slice retrieval'
@@ -172,13 +172,13 @@ class ListMixinTest(unittest.TestCase):
                     del pl[i:j]
                     del ul[i:j]
                     self.assertEqual(pl[:], ul[:], 'del slice [%d:%d]' % (i, j))
-                    for k in list(range(-Len - 1, 0)) + list(range(1, Len)):
+                    for k in [*range(-Len - 1, 0), *range(1, Len)]:
                         pl, ul = self.lists_of_len(Len)
                         del pl[i:j:k]
                         del ul[i:j:k]
                         self.assertEqual(pl[:], ul[:], 'del slice [%d:%d:%d]' % (i, j, k))
 
-                for k in list(range(-Len - 1, 0)) + list(range(1, Len)):
+                for k in [*range(-Len - 1, 0), *range(1, Len)]:
                     pl, ul = self.lists_of_len(Len)
                     del pl[:i:k]
                     del ul[:i:k]
@@ -189,7 +189,7 @@ class ListMixinTest(unittest.TestCase):
                     del ul[i::k]
                     self.assertEqual(pl[:], ul[:], 'del slice [%d::%d]' % (i, k))
 
-            for k in list(range(-Len - 1, 0)) + list(range(1, Len)):
+            for k in [*range(-Len - 1, 0), *range(1, Len)]:
                 pl, ul = self.lists_of_len(Len)
                 del pl[::k]
                 del ul[::k]

+ 13 - 13
tests/model_fields/test_field_flags.py

@@ -76,21 +76,21 @@ class FieldFlagsTests(test.SimpleTestCase):
     @classmethod
     def setUpClass(cls):
         super().setUpClass()
-        cls.fields = (
-            list(AllFieldsModel._meta.fields) +
-            list(AllFieldsModel._meta.private_fields)
-        )
+        cls.fields = [
+            *AllFieldsModel._meta.fields,
+            *AllFieldsModel._meta.private_fields,
+        ]
 
-        cls.all_fields = (
-            cls.fields +
-            list(AllFieldsModel._meta.many_to_many) +
-            list(AllFieldsModel._meta.private_fields)
-        )
+        cls.all_fields = [
+            *cls.fields,
+            *AllFieldsModel._meta.many_to_many,
+            *AllFieldsModel._meta.private_fields,
+        ]
 
-        cls.fields_and_reverse_objects = (
-            cls.all_fields +
-            list(AllFieldsModel._meta.related_objects)
-        )
+        cls.fields_and_reverse_objects = [
+            *cls.all_fields,
+            *AllFieldsModel._meta.related_objects,
+        ]
 
     def test_each_field_should_have_a_concrete_attribute(self):
         self.assertTrue(all(f.concrete.__class__ == bool for f in self.fields))

+ 2 - 2
tests/template_tests/templatetags/custom.py

@@ -111,7 +111,7 @@ simple_one_default.anything = "Expected simple_one_default __dict__"
 def simple_unlimited_args(one, two='hi', *args):
     """Expected simple_unlimited_args __doc__"""
     return "simple_unlimited_args - Expected result: %s" % (
-        ', '.join(str(arg) for arg in [one, two] + list(args))
+        ', '.join(str(arg) for arg in [one, two, *args])
     )
 
 
@@ -133,7 +133,7 @@ def simple_unlimited_args_kwargs(one, two='hi', *args, **kwargs):
     # Sort the dictionary by key to guarantee the order for testing.
     sorted_kwarg = sorted(kwargs.items(), key=operator.itemgetter(0))
     return "simple_unlimited_args_kwargs - Expected result: %s / %s" % (
-        ', '.join(str(arg) for arg in [one, two] + list(args)),
+        ', '.join(str(arg) for arg in [one, two, *args]),
         ', '.join('%s=%s' % (k, v) for (k, v) in sorted_kwarg)
     )
 

+ 3 - 3
tests/template_tests/templatetags/inclusion.py

@@ -151,7 +151,7 @@ def inclusion_unlimited_args(one, two='hi', *args):
     return {
         "result": (
             "inclusion_unlimited_args - Expected result: %s" % (
-                ', '.join(str(arg) for arg in [one, two] + list(args))
+                ', '.join(str(arg) for arg in [one, two, *args])
             )
         )
     }
@@ -166,7 +166,7 @@ def inclusion_unlimited_args_from_template(one, two='hi', *args):
     return {
         "result": (
             "inclusion_unlimited_args_from_template - Expected result: %s" % (
-                ', '.join(str(arg) for arg in [one, two] + list(args))
+                ', '.join(str(arg) for arg in [one, two, *args])
             )
         )
     }
@@ -216,7 +216,7 @@ def inclusion_unlimited_args_kwargs(one, two='hi', *args, **kwargs):
     # Sort the dictionary by key to guarantee the order for testing.
     sorted_kwarg = sorted(kwargs.items(), key=operator.itemgetter(0))
     return {"result": "inclusion_unlimited_args_kwargs - Expected result: %s / %s" % (
-        ', '.join(str(arg) for arg in [one, two] + list(args)),
+        ', '.join(str(arg) for arg in [one, two, *args]),
         ', '.join('%s=%s' % (k, v) for (k, v) in sorted_kwarg)
     )}
 

+ 1 - 1
tests/utils_tests/test_baseconv.py

@@ -8,7 +8,7 @@ from django.utils.baseconv import (
 class TestBaseConv(TestCase):
 
     def test_baseconv(self):
-        nums = [-10 ** 10, 10 ** 10] + list(range(-100, 100))
+        nums = [-10 ** 10, 10 ** 10, *range(-100, 100)]
         for converter in [base2, base16, base36, base56, base62, base64]:
             for i in nums:
                 self.assertEqual(i, converter.decode(converter.encode(i)))