From 23e886886249ebe8f80a48b0d25fbb5308eeb06f Mon Sep 17 00:00:00 2001 From: Mariusz Felisiak Date: Wed, 18 Jan 2023 19:11:18 +0100 Subject: [PATCH] Refs #34233 -- Used str.removeprefix()/removesuffix(). --- django/apps/registry.py | 2 +- django/contrib/admin/checks.py | 3 +-- django/contrib/admin/options.py | 6 +++--- django/contrib/admin/sites.py | 3 +-- django/contrib/admin/views/main.py | 6 +++--- django/contrib/auth/hashers.py | 4 ++-- django/contrib/sessions/backends/file.py | 2 +- django/contrib/staticfiles/finders.py | 2 +- django/contrib/staticfiles/handlers.py | 2 +- django/contrib/staticfiles/storage.py | 2 +- django/core/cache/backends/memcached.py | 2 +- django/core/handlers/asgi.py | 4 ++-- django/core/handlers/wsgi.py | 2 +- django/core/management/commands/inspectdb.py | 2 +- django/core/management/templates.py | 5 ++--- django/core/management/utils.py | 2 +- django/core/serializers/json.py | 2 +- django/db/models/base.py | 2 +- django/db/models/indexes.py | 2 +- django/db/models/sql/query.py | 3 +-- django/http/request.py | 8 +++----- django/template/backends/django.py | 2 +- django/templatetags/cache.py | 2 +- django/test/testcases.py | 2 +- django/urls/resolvers.py | 8 +++----- django/utils/datastructures.py | 3 +-- django/utils/html.py | 4 ++-- django/utils/http.py | 2 +- docs/howto/custom-lookups.txt | 2 +- tests/forms_tests/field_tests/test_filepathfield.py | 4 +--- 30 files changed, 42 insertions(+), 53 deletions(-) diff --git a/django/apps/registry.py b/django/apps/registry.py index 4abf828ca1c..1cdb33b7f0a 100644 --- a/django/apps/registry.py +++ b/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: diff --git a/django/contrib/admin/checks.py b/django/contrib/admin/checks.py index dbbeb7fe9ce..27537d96145 100644 --- a/django/contrib/admin/checks.py +++ b/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: diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py index 6c6ee8cee77..4761144c7b5 100644 --- a/django/contrib/admin/options.py +++ b/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) diff --git a/django/contrib/admin/sites.py b/django/contrib/admin/sites.py index 47a25608fe0..34477900f12 100644 --- a/django/contrib/admin/sites.py +++ b/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) diff --git a/django/contrib/admin/views/main.py b/django/contrib/admin/views/main.py index ace4b34ce59..3323de1f1cb 100644 --- a/django/contrib/admin/views/main.py +++ b/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" diff --git a/django/contrib/auth/hashers.py b/django/contrib/auth/hashers.py index 31f8a309d49..c1de2597ad6 100644 --- a/django/contrib/auth/hashers.py +++ b/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) diff --git a/django/contrib/sessions/backends/file.py b/django/contrib/sessions/backends/file.py index b7a13d6d175..d3ba8b11ddd 100644 --- a/django/contrib/sessions/backends/file.py +++ b/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 diff --git a/django/contrib/staticfiles/finders.py b/django/contrib/staticfiles/finders.py index 184d297568e..8ea5a98777c 100644 --- a/django/contrib/staticfiles/finders.py +++ b/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 diff --git a/django/contrib/staticfiles/handlers.py b/django/contrib/staticfiles/handlers.py index b7d9b5c18dc..cd1cde1fc68 100644 --- a/django/contrib/staticfiles/handlers.py +++ b/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): diff --git a/django/contrib/staticfiles/storage.py b/django/contrib/staticfiles/storage.py index b3ba21f2b2b..b3ee32e665c 100644 --- a/django/contrib/staticfiles/storage.py +++ b/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, "/") diff --git a/django/core/cache/backends/memcached.py b/django/core/cache/backends/memcached.py index c970505b480..6e2c7615118 100644 --- a/django/core/cache/backends/memcached.py +++ b/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): diff --git a/django/core/handlers/asgi.py b/django/core/handlers/asgi.py index 2aede079b94..39e2abe5a98 100644 --- a/django/core/handlers/asgi.py +++ b/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 diff --git a/django/core/handlers/wsgi.py b/django/core/handlers/wsgi.py index c071b5ca8c3..c2b7cc2b6f3 100644 --- a/django/core/handlers/wsgi.py +++ b/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", "") diff --git a/django/core/management/commands/inspectdb.py b/django/core/management/commands/inspectdb.py index 992c523a8ed..3194aecacb5 100644 --- a/django/core/management/commands/inspectdb.py +++ b/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 diff --git a/django/core/management/templates.py b/django/core/management/templates.py index dd83668bca2..16f3b4442ce 100644 --- a/django/core/management/templates.py +++ b/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): diff --git a/django/core/management/utils.py b/django/core/management/utils.py index a308763d9d1..fca61f2c234 100644 --- a/django/core/management/utils.py +++ b/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) diff --git a/django/core/serializers/json.py b/django/core/serializers/json.py index 59d73184094..afac821465a 100644 --- a/django/core/serializers/json.py +++ b/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() diff --git a/django/db/models/base.py b/django/db/models/base.py index 8c8a74158d9..06bab385a3d 100644 --- a/django/db/models/base.py +++ b/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 = [] diff --git a/django/db/models/indexes.py b/django/db/models/indexes.py index a5bddb83252..b5451f9e241 100644 --- a/django/db/models/indexes.py +++ b/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 "" diff --git a/django/db/models/sql/query.py b/django/db/models/sql/query.py index 3fe00002bd5..0aa07e0b99e 100644 --- a/django/db/models/sql/query.py +++ b/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: diff --git a/django/http/request.py b/django/http/request.py index 6b51d23e975..d451147bc10 100644 --- a/django/http/request.py +++ b/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 diff --git a/django/template/backends/django.py b/django/template/backends/django.py index 218e5e0bc19..98abf7ddb5c 100644 --- a/django/template/backends/django.py +++ b/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(): diff --git a/django/templatetags/cache.py b/django/templatetags/cache.py index 4a60cd8afd9..1c48db7ce9f 100644 --- a/django/templatetags/cache.py +++ b/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 diff --git a/django/test/testcases.py b/django/test/testcases.py index 017c6eefd0d..ea63ac550e0 100644 --- a/django/test/testcases.py +++ b/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): diff --git a/django/urls/resolvers.py b/django/urls/resolvers.py index 9a22b0d87d8..107d640f23e 100644 --- a/django/urls/resolvers.py +++ b/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): diff --git a/django/utils/datastructures.py b/django/utils/datastructures.py index 51a586d1528..ded606d02a9 100644 --- a/django/utils/datastructures.py +++ b/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) diff --git a/django/utils/html.py b/django/utils/html.py index fdb88d67098..c32a36fa93c 100644 --- a/django/utils/html.py +++ b/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, diff --git a/django/utils/http.py b/django/utils/http.py index 8fd40c27af8..cfd982fc016 100644 --- a/django/utils/http.py +++ b/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 diff --git a/docs/howto/custom-lookups.txt b/docs/howto/custom-lookups.txt index 2a7ae4a5e56..59f3d30e2d8 100644 --- a/docs/howto/custom-lookups.txt +++ b/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: diff --git a/tests/forms_tests/field_tests/test_filepathfield.py b/tests/forms_tests/field_tests/test_filepathfield.py index ca0f6f3a7af..092001b4537 100644 --- a/tests/forms_tests/field_tests/test_filepathfield.py +++ b/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):