Browse Source

Refs #34233 -- Used str.removeprefix()/removesuffix().

Mariusz Felisiak 2 years ago
parent
commit
23e8868862

+ 1 - 1
django/apps/registry.py

@@ -261,7 +261,7 @@ class Apps:
         candidates = []
         for app_config in self.app_configs.values():
             if object_name.startswith(app_config.name):
-                subpath = object_name[len(app_config.name) :]
+                subpath = object_name.removeprefix(app_config.name)
                 if subpath == "" or subpath[0] == ".":
                     candidates.append(app_config)
         if candidates:

+ 1 - 2
django/contrib/admin/checks.py

@@ -727,8 +727,7 @@ class BaseModelAdminChecks:
             # this format would be nice, but it's a little fiddly).
             return []
         else:
-            if field_name.startswith("-"):
-                field_name = field_name[1:]
+            field_name = field_name.removeprefix("-")
             if field_name == "pk":
                 return []
             try:

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

@@ -1109,11 +1109,11 @@ class ModelAdmin(BaseModelAdmin):
         # Apply keyword searches.
         def construct_search(field_name):
             if field_name.startswith("^"):
-                return "%s__istartswith" % field_name[1:]
+                return "%s__istartswith" % field_name.removeprefix("^")
             elif field_name.startswith("="):
-                return "%s__iexact" % field_name[1:]
+                return "%s__iexact" % field_name.removeprefix("=")
             elif field_name.startswith("@"):
-                return "%s__search" % field_name[1:]
+                return "%s__search" % field_name.removeprefix("@")
             # Use field_name if it includes a lookup.
             opts = queryset.model._meta
             lookup_fields = field_name.split(LOOKUP_SEP)

+ 1 - 2
django/contrib/admin/sites.py

@@ -1,4 +1,3 @@
-import re
 from functools import update_wrapper
 from weakref import WeakSet
 
@@ -126,7 +125,7 @@ class AdminSite:
                 msg = "The model %s is already registered " % model.__name__
                 if registered_admin.endswith(".ModelAdmin"):
                     # Most likely registered without a ModelAdmin subclass.
-                    msg += "in app %r." % re.sub(r"\.ModelAdmin$", "", registered_admin)
+                    msg += "in app %r." % registered_admin.removesuffix(".ModelAdmin")
                 else:
                     msg += "with %r." % registered_admin
                 raise AlreadyRegistered(msg)

+ 3 - 3
django/contrib/admin/views/main.py

@@ -375,8 +375,8 @@ class ChangeList:
                             order_field.desc() if pfx == "-" else order_field.asc()
                         )
                     # reverse order if order_field has already "-" as prefix
-                    elif order_field.startswith("-") and pfx == "-":
-                        ordering.append(order_field[1:])
+                    elif pfx == "-" and order_field.startswith(pfx):
+                        ordering.append(order_field.removeprefix(pfx))
                     else:
                         ordering.append(pfx + order_field)
                 except (IndexError, ValueError):
@@ -474,7 +474,7 @@ class ChangeList:
                     else:
                         continue
                 elif field.startswith("-"):
-                    field = field[1:]
+                    field = field.removeprefix("-")
                     order_type = "desc"
                 else:
                     order_type = "asc"

+ 2 - 2
django/contrib/auth/hashers.py

@@ -808,8 +808,8 @@ class UnsaltedMD5PasswordHasher(BasePasswordHasher):
         }
 
     def verify(self, password, encoded):
-        if len(encoded) == 37 and encoded.startswith("md5$$"):
-            encoded = encoded[5:]
+        if len(encoded) == 37:
+            encoded = encoded.removeprefix("md5$$")
         encoded_2 = self.encode(password, "")
         return constant_time_compare(encoded, encoded_2)
 

+ 1 - 1
django/contrib/sessions/backends/file.py

@@ -201,7 +201,7 @@ class SessionStore(SessionBase):
         for session_file in os.listdir(storage_path):
             if not session_file.startswith(file_prefix):
                 continue
-            session_key = session_file[len(file_prefix) :]
+            session_key = session_file.removeprefix(file_prefix)
             session = cls(session_key)
             # When an expired session is loaded, its file is removed, and a
             # new file is immediately created. Prevent this by disabling

+ 1 - 1
django/contrib/staticfiles/finders.py

@@ -137,7 +137,7 @@ class FileSystemFinder(BaseFinder):
             prefix = "%s%s" % (prefix, os.sep)
             if not path.startswith(prefix):
                 return None
-            path = path[len(prefix) :]
+            path = path.removeprefix(prefix)
         path = safe_join(root, path)
         if os.path.exists(path):
             return path

+ 1 - 1
django/contrib/staticfiles/handlers.py

@@ -42,7 +42,7 @@ class StaticFilesHandlerMixin:
         """
         Return the relative path to the media file on disk for the given URL.
         """
-        relative_url = url[len(self.base_url[2]) :]
+        relative_url = url.removeprefix(self.base_url[2])
         return url2pathname(relative_url)
 
     def serve(self, request):

+ 1 - 1
django/contrib/staticfiles/storage.py

@@ -231,7 +231,7 @@ class HashedFilesMixin:
             if url_path.startswith("/"):
                 # Otherwise the condition above would have returned prematurely.
                 assert url_path.startswith(settings.STATIC_URL)
-                target_name = url_path[len(settings.STATIC_URL) :]
+                target_name = url_path.removeprefix(settings.STATIC_URL)
             else:
                 # We're using the posixpath module to mix paths and URLs conveniently.
                 source_name = name if os.sep == "/" else name.replace(os.sep, "/")

+ 1 - 1
django/core/cache/backends/memcached.py

@@ -155,7 +155,7 @@ class PyLibMCCache(BaseMemcachedCache):
     def client_servers(self):
         output = []
         for server in self._servers:
-            output.append(server[5:] if server.startswith("unix:") else server)
+            output.append(server.removeprefix("unix:"))
         return output
 
     def touch(self, key, timeout=DEFAULT_TIMEOUT, version=None):

+ 2 - 2
django/core/handlers/asgi.py

@@ -41,9 +41,9 @@ class ASGIRequest(HttpRequest):
         self._read_started = False
         self.resolver_match = None
         self.script_name = self.scope.get("root_path", "")
-        if self.script_name and scope["path"].startswith(self.script_name):
+        if self.script_name:
             # TODO: Better is-prefix checking, slash handling?
-            self.path_info = scope["path"][len(self.script_name) :]
+            self.path_info = scope["path"].removeprefix(self.script_name)
         else:
             self.path_info = scope["path"]
         # The Django path is different from ASGI scope path args, it should

+ 1 - 1
django/core/handlers/wsgi.py

@@ -187,7 +187,7 @@ def get_script_name(environ):
             # do the same with script_url before manipulating paths (#17133).
             script_url = _slashes_re.sub(b"/", script_url)
         path_info = get_bytes_from_wsgi(environ, "PATH_INFO", "")
-        script_name = script_url[: -len(path_info)] if path_info else script_url
+        script_name = script_url.removesuffix(path_info)
     else:
         script_name = get_bytes_from_wsgi(environ, "SCRIPT_NAME", "")
 

+ 1 - 1
django/core/management/commands/inspectdb.py

@@ -275,7 +275,7 @@ class Command(BaseCommand):
 
         if is_relation:
             if new_name.endswith("_id"):
-                new_name = new_name[:-3]
+                new_name = new_name.removesuffix("_id")
             else:
                 field_params["db_column"] = col_name
 

+ 2 - 3
django/core/management/templates.py

@@ -182,7 +182,7 @@ class TemplateCommand(BaseCommand):
                 )
                 for old_suffix, new_suffix in self.rewrite_template_suffixes:
                     if new_path.endswith(old_suffix):
-                        new_path = new_path[: -len(old_suffix)] + new_suffix
+                        new_path = new_path.removesuffix(old_suffix) + new_suffix
                         break  # Only rewrite once
 
                 if os.path.exists(new_path):
@@ -241,8 +241,7 @@ class TemplateCommand(BaseCommand):
         if template is None:
             return os.path.join(django.__path__[0], "conf", subdir)
         else:
-            if template.startswith("file://"):
-                template = template[7:]
+            template = template.removeprefix("file://")
             expanded_template = os.path.expanduser(template)
             expanded_template = os.path.normpath(expanded_template)
             if os.path.isdir(expanded_template):

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

@@ -135,7 +135,7 @@ def normalize_path_patterns(patterns):
     for pattern in patterns:
         for dir_suffix in dir_suffixes:
             if pattern.endswith(dir_suffix):
-                norm_patterns.append(pattern[: -len(dir_suffix)])
+                norm_patterns.append(pattern.removesuffix(dir_suffix))
                 break
         else:
             norm_patterns.append(pattern)

+ 1 - 1
django/core/serializers/json.py

@@ -87,7 +87,7 @@ class DjangoJSONEncoder(json.JSONEncoder):
             if o.microsecond:
                 r = r[:23] + r[26:]
             if r.endswith("+00:00"):
-                r = r[:-6] + "Z"
+                r = r.removesuffix("+00:00") + "Z"
             return r
         elif isinstance(o, datetime.date):
             return o.isoformat()

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

@@ -2109,7 +2109,7 @@ class Model(AltersData, metaclass=ModelBase):
         fields = (f for f in fields if isinstance(f, str) and f != "?")
 
         # Convert "-field" to "field".
-        fields = ((f[1:] if f.startswith("-") else f) for f in fields)
+        fields = (f.removeprefix("-") for f in fields)
 
         # Separate related fields and non-related fields.
         _fields = []

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

@@ -65,7 +65,7 @@ class Index:
         self.fields = list(fields)
         # A list of 2-tuple with the field name and ordering ('' or 'DESC').
         self.fields_orders = [
-            (field_name[1:], "DESC") if field_name.startswith("-") else (field_name, "")
+            (field_name.removeprefix("-"), "DESC" if field_name.startswith("-") else "")
             for field_name in self.fields
         ]
         self.name = name or ""

+ 1 - 2
django/db/models/sql/query.py

@@ -2163,8 +2163,7 @@ class Query(BaseExpression):
             if isinstance(item, str):
                 if item == "?":
                     continue
-                if item.startswith("-"):
-                    item = item[1:]
+                item = item.removeprefix("-")
                 if item in self.annotations:
                     continue
                 if self.extra and item in self.extra:

+ 3 - 5
django/http/request.py

@@ -242,9 +242,7 @@ class HttpRequest:
                 # If location starts with '//' but has no netloc, reuse the
                 # schema and netloc from the current request. Strip the double
                 # slashes and continue as if it wasn't specified.
-                if location.startswith("//"):
-                    location = location[2:]
-                location = self._current_scheme_host + location
+                location = self._current_scheme_host + location.removeprefix("//")
             else:
                 # Join the constructed URL with the provided location, which
                 # allows the provided location to apply query strings to the
@@ -456,7 +454,7 @@ class HttpHeaders(CaseInsensitiveMapping):
     @classmethod
     def parse_header_name(cls, header):
         if header.startswith(cls.HTTP_PREFIX):
-            header = header[len(cls.HTTP_PREFIX) :]
+            header = header.removeprefix(cls.HTTP_PREFIX)
         elif header not in cls.UNPREFIXED_HEADERS:
             return None
         return header.replace("_", "-").title()
@@ -724,7 +722,7 @@ def split_domain_port(host):
     bits = host.rsplit(":", 1)
     domain, port = bits if len(bits) == 2 else (bits[0], "")
     # Remove a trailing dot (if present) from the domain.
-    domain = domain[:-1] if domain.endswith(".") else domain
+    domain = domain.removesuffix(".")
     return domain, port
 
 

+ 1 - 1
django/template/backends/django.py

@@ -104,7 +104,7 @@ def get_template_tag_modules():
 
         if hasattr(pkg, "__path__"):
             for name in get_package_libraries(pkg):
-                yield name[len(candidate) + 1 :], name
+                yield name.removeprefix(candidate).lstrip("."), name
 
 
 def get_installed_libraries():

+ 1 - 1
django/templatetags/cache.py

@@ -87,7 +87,7 @@ def do_cache(parser, token):
     if len(tokens) < 3:
         raise TemplateSyntaxError("'%r' tag requires at least 2 arguments." % tokens[0])
     if len(tokens) > 3 and tokens[-1].startswith("using="):
-        cache_name = parser.compile_filter(tokens[-1][len("using=") :])
+        cache_name = parser.compile_filter(tokens[-1].removeprefix("using="))
         tokens = tokens[:-1]
     else:
         cache_name = None

+ 1 - 1
django/test/testcases.py

@@ -1524,7 +1524,7 @@ class FSFilesHandler(WSGIHandler):
 
     def file_path(self, url):
         """Return the relative path to the file on disk for the given URL."""
-        relative_url = url[len(self.base_url[2]) :]
+        relative_url = url.removeprefix(self.base_url[2])
         return url2pathname(relative_url)
 
     def get_response(self, request):

+ 3 - 5
django/urls/resolvers.py

@@ -359,7 +359,7 @@ class LocalePrefixPattern:
     def match(self, path):
         language_prefix = self.language_prefix
         if path.startswith(language_prefix):
-            return path[len(language_prefix) :], (), {}
+            return path.removeprefix(language_prefix), (), {}
         return None
 
     def check(self):
@@ -542,8 +542,7 @@ class URLResolver:
             language_code = get_language()
             for url_pattern in reversed(self.url_patterns):
                 p_pattern = url_pattern.pattern.regex.pattern
-                if p_pattern.startswith("^"):
-                    p_pattern = p_pattern[1:]
+                p_pattern = p_pattern.removeprefix("^")
                 if isinstance(url_pattern, URLPattern):
                     self._callback_strs.add(url_pattern.lookup_str)
                     bits = normalize(url_pattern.pattern.regex.pattern)
@@ -645,8 +644,7 @@ class URLResolver:
         """Join two routes, without the starting ^ in the second route."""
         if not route1:
             return route2
-        if route2.startswith("^"):
-            route2 = route2[1:]
+        route2 = route2.removeprefix("^")
         return route1 + route2
 
     def _is_callback(self, name):

+ 1 - 2
django/utils/datastructures.py

@@ -276,8 +276,7 @@ class DictWrapper(dict):
         before returning, otherwise return the raw value.
         """
         use_func = key.startswith(self.prefix)
-        if use_func:
-            key = key[len(self.prefix) :]
+        key = key.removeprefix(self.prefix)
         value = super().__getitem__(key)
         if use_func:
             return self.func(value)

+ 2 - 2
django/utils/html.py

@@ -343,7 +343,7 @@ class Urlizer:
             # Trim wrapping punctuation.
             for opening, closing in self.wrapping_punctuation:
                 if middle.startswith(opening):
-                    middle = middle[len(opening) :]
+                    middle = middle.removeprefix(opening)
                     lead += opening
                     trimmed_something = True
                 # Keep parentheses at the end only if they're balanced.
@@ -351,7 +351,7 @@ class Urlizer:
                     middle.endswith(closing)
                     and middle.count(closing) == middle.count(opening) + 1
                 ):
-                    middle = middle[: -len(closing)]
+                    middle = middle.removesuffix(closing)
                     trail = closing + trail
                     trimmed_something = True
             # Trim trailing punctuation (after trimming wrapping punctuation,

+ 1 - 1
django/utils/http.py

@@ -307,7 +307,7 @@ def escape_leading_slashes(url):
     redirecting to another host.
     """
     if url.startswith("//"):
-        url = "/%2F{}".format(url[2:])
+        url = "/%2F{}".format(url.removeprefix("//"))
     return url
 
 

+ 1 - 1
docs/howto/custom-lookups.txt

@@ -312,7 +312,7 @@ would override ``get_lookup`` with something like::
         def get_lookup(self, lookup_name):
             if lookup_name.startswith('x'):
                 try:
-                    dimension = int(lookup_name[1:])
+                    dimension = int(lookup_name.removeprefix("x"))
                 except ValueError:
                     pass
                 else:

+ 1 - 3
tests/forms_tests/field_tests/test_filepathfield.py

@@ -9,9 +9,7 @@ PATH = os.path.dirname(os.path.abspath(__file__))
 
 def fix_os_paths(x):
     if isinstance(x, str):
-        if x.startswith(PATH):
-            x = x[len(PATH) :]
-        return x.replace("\\", "/")
+        return x.removeprefix(PATH).replace("\\", "/")
     elif isinstance(x, tuple):
         return tuple(fix_os_paths(list(x)))
     elif isinstance(x, list):