Refs #35250 -- Avoided double conversion in RoutePattern.

This commit is contained in:
Adam Johnson 2024-02-24 19:14:22 +00:00 committed by Mariusz Felisiak
parent 595738296f
commit 5dfcf343cd
1 changed files with 36 additions and 22 deletions

View File

@ -128,9 +128,6 @@ def get_ns_resolver(ns_pattern, resolver, converters):
class LocaleRegexDescriptor: class LocaleRegexDescriptor:
def __init__(self, attr):
self.attr = attr
def __get__(self, instance, cls=None): def __get__(self, instance, cls=None):
""" """
Return a compiled regular expression based on the active language. Return a compiled regular expression based on the active language.
@ -140,15 +137,23 @@ class LocaleRegexDescriptor:
# As a performance optimization, if the given regex string is a regular # As a performance optimization, if the given regex string is a regular
# string (not a lazily-translated string proxy), compile it once and # string (not a lazily-translated string proxy), compile it once and
# avoid per-language compilation. # avoid per-language compilation.
pattern = getattr(instance, self.attr) pattern = instance._regex
if isinstance(pattern, str): if isinstance(pattern, str):
instance.__dict__["regex"] = instance._compile(pattern) instance.__dict__["regex"] = self._compile(pattern)
return instance.__dict__["regex"] return instance.__dict__["regex"]
language_code = get_language() language_code = get_language()
if language_code not in instance._regex_dict: if language_code not in instance._regex_dict:
instance._regex_dict[language_code] = instance._compile(str(pattern)) instance._regex_dict[language_code] = self._compile(str(pattern))
return instance._regex_dict[language_code] return instance._regex_dict[language_code]
def _compile(self, regex):
try:
return re.compile(regex)
except re.error as e:
raise ImproperlyConfigured(
f'"{regex}" is not a valid regular expression: {e}'
) from e
class CheckURLMixin: class CheckURLMixin:
def describe(self): def describe(self):
@ -186,7 +191,7 @@ class CheckURLMixin:
class RegexPattern(CheckURLMixin): class RegexPattern(CheckURLMixin):
regex = LocaleRegexDescriptor("_regex") regex = LocaleRegexDescriptor()
def __init__(self, regex, name=None, is_endpoint=False): def __init__(self, regex, name=None, is_endpoint=False):
self._regex = regex self._regex = regex
@ -232,15 +237,6 @@ class RegexPattern(CheckURLMixin):
else: else:
return [] return []
def _compile(self, regex):
"""Compile and return the given regular expression."""
try:
return re.compile(regex)
except re.error as e:
raise ImproperlyConfigured(
'"%s" is not a valid regular expression: %s' % (regex, e)
) from e
def __str__(self): def __str__(self):
return str(self._regex) return str(self._regex)
@ -250,7 +246,7 @@ _PATH_PARAMETER_COMPONENT_RE = _lazy_re_compile(
) )
def _route_to_regex(route, is_endpoint=False): def _route_to_regex(route, is_endpoint):
""" """
Convert a path pattern into a regular expression. Return the regular Convert a path pattern into a regular expression. Return the regular
expression and a dictionary mapping the capture names to the converters. expression and a dictionary mapping the capture names to the converters.
@ -296,15 +292,36 @@ def _route_to_regex(route, is_endpoint=False):
return "".join(parts), converters return "".join(parts), converters
class LocaleRegexRouteDescriptor:
def __get__(self, instance, cls=None):
"""
Return a compiled regular expression based on the active language.
"""
if instance is None:
return self
# As a performance optimization, if the given route is a regular string
# (not a lazily-translated string proxy), compile it once and avoid
# per-language compilation.
if isinstance(instance._route, str):
instance.__dict__["regex"] = re.compile(instance._regex)
return instance.__dict__["regex"]
language_code = get_language()
if language_code not in instance._regex_dict:
instance._regex_dict[language_code] = re.compile(
_route_to_regex(str(instance._route), instance._is_endpoint)[0]
)
return instance._regex_dict[language_code]
class RoutePattern(CheckURLMixin): class RoutePattern(CheckURLMixin):
regex = LocaleRegexDescriptor("_route") regex = LocaleRegexRouteDescriptor()
def __init__(self, route, name=None, is_endpoint=False): def __init__(self, route, name=None, is_endpoint=False):
self._route = route self._route = route
self._regex, self.converters = _route_to_regex(str(route), is_endpoint)
self._regex_dict = {} self._regex_dict = {}
self._is_endpoint = is_endpoint self._is_endpoint = is_endpoint
self.name = name self.name = name
self.converters = _route_to_regex(str(route), is_endpoint)[1]
def match(self, path): def match(self, path):
match = self.regex.search(path) match = self.regex.search(path)
@ -356,9 +373,6 @@ class RoutePattern(CheckURLMixin):
warnings.append(Warning(msg % (self.describe(), "<"), id="urls.W010")) warnings.append(Warning(msg % (self.describe(), "<"), id="urls.W010"))
return warnings return warnings
def _compile(self, route):
return re.compile(_route_to_regex(route, self._is_endpoint)[0])
def __str__(self): def __str__(self):
return str(self._route) return str(self._route)