docker setup
This commit is contained in:
		| @ -0,0 +1,53 @@ | ||||
| from .base import ( | ||||
|     clear_script_prefix, | ||||
|     clear_url_caches, | ||||
|     get_script_prefix, | ||||
|     get_urlconf, | ||||
|     is_valid_path, | ||||
|     resolve, | ||||
|     reverse, | ||||
|     reverse_lazy, | ||||
|     set_script_prefix, | ||||
|     set_urlconf, | ||||
|     translate_url, | ||||
| ) | ||||
| from .conf import include, path, re_path | ||||
| from .converters import register_converter | ||||
| from .exceptions import NoReverseMatch, Resolver404 | ||||
| from .resolvers import ( | ||||
|     LocalePrefixPattern, | ||||
|     ResolverMatch, | ||||
|     URLPattern, | ||||
|     URLResolver, | ||||
|     get_ns_resolver, | ||||
|     get_resolver, | ||||
| ) | ||||
| from .utils import get_callable, get_mod_func | ||||
|  | ||||
| __all__ = [ | ||||
|     "LocalePrefixPattern", | ||||
|     "NoReverseMatch", | ||||
|     "URLPattern", | ||||
|     "URLResolver", | ||||
|     "Resolver404", | ||||
|     "ResolverMatch", | ||||
|     "clear_script_prefix", | ||||
|     "clear_url_caches", | ||||
|     "get_callable", | ||||
|     "get_mod_func", | ||||
|     "get_ns_resolver", | ||||
|     "get_resolver", | ||||
|     "get_script_prefix", | ||||
|     "get_urlconf", | ||||
|     "include", | ||||
|     "is_valid_path", | ||||
|     "path", | ||||
|     "re_path", | ||||
|     "register_converter", | ||||
|     "resolve", | ||||
|     "reverse", | ||||
|     "reverse_lazy", | ||||
|     "set_script_prefix", | ||||
|     "set_urlconf", | ||||
|     "translate_url", | ||||
| ] | ||||
							
								
								
									
										187
									
								
								srcs/.venv/lib/python3.11/site-packages/django/urls/base.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										187
									
								
								srcs/.venv/lib/python3.11/site-packages/django/urls/base.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,187 @@ | ||||
| from urllib.parse import unquote, urlsplit, urlunsplit | ||||
|  | ||||
| from asgiref.local import Local | ||||
|  | ||||
| from django.utils.functional import lazy | ||||
| from django.utils.translation import override | ||||
|  | ||||
| from .exceptions import NoReverseMatch, Resolver404 | ||||
| from .resolvers import _get_cached_resolver, get_ns_resolver, get_resolver | ||||
| from .utils import get_callable | ||||
|  | ||||
| # SCRIPT_NAME prefixes for each thread are stored here. If there's no entry for | ||||
| # the current thread (which is the only one we ever access), it is assumed to | ||||
| # be empty. | ||||
| _prefixes = Local() | ||||
|  | ||||
| # Overridden URLconfs for each thread are stored here. | ||||
| _urlconfs = Local() | ||||
|  | ||||
|  | ||||
| def resolve(path, urlconf=None): | ||||
|     if urlconf is None: | ||||
|         urlconf = get_urlconf() | ||||
|     return get_resolver(urlconf).resolve(path) | ||||
|  | ||||
|  | ||||
| def reverse(viewname, urlconf=None, args=None, kwargs=None, current_app=None): | ||||
|     if urlconf is None: | ||||
|         urlconf = get_urlconf() | ||||
|     resolver = get_resolver(urlconf) | ||||
|     args = args or [] | ||||
|     kwargs = kwargs or {} | ||||
|  | ||||
|     prefix = get_script_prefix() | ||||
|  | ||||
|     if not isinstance(viewname, str): | ||||
|         view = viewname | ||||
|     else: | ||||
|         *path, view = viewname.split(":") | ||||
|  | ||||
|         if current_app: | ||||
|             current_path = current_app.split(":") | ||||
|             current_path.reverse() | ||||
|         else: | ||||
|             current_path = None | ||||
|  | ||||
|         resolved_path = [] | ||||
|         ns_pattern = "" | ||||
|         ns_converters = {} | ||||
|         for ns in path: | ||||
|             current_ns = current_path.pop() if current_path else None | ||||
|             # Lookup the name to see if it could be an app identifier. | ||||
|             try: | ||||
|                 app_list = resolver.app_dict[ns] | ||||
|                 # Yes! Path part matches an app in the current Resolver. | ||||
|                 if current_ns and current_ns in app_list: | ||||
|                     # If we are reversing for a particular app, use that | ||||
|                     # namespace. | ||||
|                     ns = current_ns | ||||
|                 elif ns not in app_list: | ||||
|                     # The name isn't shared by one of the instances (i.e., | ||||
|                     # the default) so pick the first instance as the default. | ||||
|                     ns = app_list[0] | ||||
|             except KeyError: | ||||
|                 pass | ||||
|  | ||||
|             if ns != current_ns: | ||||
|                 current_path = None | ||||
|  | ||||
|             try: | ||||
|                 extra, resolver = resolver.namespace_dict[ns] | ||||
|                 resolved_path.append(ns) | ||||
|                 ns_pattern += extra | ||||
|                 ns_converters.update(resolver.pattern.converters) | ||||
|             except KeyError as key: | ||||
|                 if resolved_path: | ||||
|                     raise NoReverseMatch( | ||||
|                         "%s is not a registered namespace inside '%s'" | ||||
|                         % (key, ":".join(resolved_path)) | ||||
|                     ) | ||||
|                 else: | ||||
|                     raise NoReverseMatch("%s is not a registered namespace" % key) | ||||
|         if ns_pattern: | ||||
|             resolver = get_ns_resolver( | ||||
|                 ns_pattern, resolver, tuple(ns_converters.items()) | ||||
|             ) | ||||
|  | ||||
|     return resolver._reverse_with_prefix(view, prefix, *args, **kwargs) | ||||
|  | ||||
|  | ||||
| reverse_lazy = lazy(reverse, str) | ||||
|  | ||||
|  | ||||
| def clear_url_caches(): | ||||
|     get_callable.cache_clear() | ||||
|     _get_cached_resolver.cache_clear() | ||||
|     get_ns_resolver.cache_clear() | ||||
|  | ||||
|  | ||||
| def set_script_prefix(prefix): | ||||
|     """ | ||||
|     Set the script prefix for the current thread. | ||||
|     """ | ||||
|     if not prefix.endswith("/"): | ||||
|         prefix += "/" | ||||
|     _prefixes.value = prefix | ||||
|  | ||||
|  | ||||
| def get_script_prefix(): | ||||
|     """ | ||||
|     Return the currently active script prefix. Useful for client code that | ||||
|     wishes to construct their own URLs manually (although accessing the request | ||||
|     instance is normally going to be a lot cleaner). | ||||
|     """ | ||||
|     return getattr(_prefixes, "value", "/") | ||||
|  | ||||
|  | ||||
| def clear_script_prefix(): | ||||
|     """ | ||||
|     Unset the script prefix for the current thread. | ||||
|     """ | ||||
|     try: | ||||
|         del _prefixes.value | ||||
|     except AttributeError: | ||||
|         pass | ||||
|  | ||||
|  | ||||
| def set_urlconf(urlconf_name): | ||||
|     """ | ||||
|     Set the URLconf for the current thread (overriding the default one in | ||||
|     settings). If urlconf_name is None, revert back to the default. | ||||
|     """ | ||||
|     if urlconf_name: | ||||
|         _urlconfs.value = urlconf_name | ||||
|     else: | ||||
|         if hasattr(_urlconfs, "value"): | ||||
|             del _urlconfs.value | ||||
|  | ||||
|  | ||||
| def get_urlconf(default=None): | ||||
|     """ | ||||
|     Return the root URLconf to use for the current thread if it has been | ||||
|     changed from the default one. | ||||
|     """ | ||||
|     return getattr(_urlconfs, "value", default) | ||||
|  | ||||
|  | ||||
| def is_valid_path(path, urlconf=None): | ||||
|     """ | ||||
|     Return the ResolverMatch if the given path resolves against the default URL | ||||
|     resolver, False otherwise. This is a convenience method to make working | ||||
|     with "is this a match?" cases easier, avoiding try...except blocks. | ||||
|     """ | ||||
|     try: | ||||
|         return resolve(path, urlconf) | ||||
|     except Resolver404: | ||||
|         return False | ||||
|  | ||||
|  | ||||
| def translate_url(url, lang_code): | ||||
|     """ | ||||
|     Given a URL (absolute or relative), try to get its translated version in | ||||
|     the `lang_code` language (either by i18n_patterns or by translated regex). | ||||
|     Return the original URL if no translated version is found. | ||||
|     """ | ||||
|     parsed = urlsplit(url) | ||||
|     try: | ||||
|         # URL may be encoded. | ||||
|         match = resolve(unquote(parsed.path)) | ||||
|     except Resolver404: | ||||
|         pass | ||||
|     else: | ||||
|         to_be_reversed = ( | ||||
|             "%s:%s" % (match.namespace, match.url_name) | ||||
|             if match.namespace | ||||
|             else match.url_name | ||||
|         ) | ||||
|         with override(lang_code): | ||||
|             try: | ||||
|                 url = reverse(to_be_reversed, args=match.args, kwargs=match.kwargs) | ||||
|             except NoReverseMatch: | ||||
|                 pass | ||||
|             else: | ||||
|                 url = urlunsplit( | ||||
|                     (parsed.scheme, parsed.netloc, url, parsed.query, parsed.fragment) | ||||
|                 ) | ||||
|     return url | ||||
							
								
								
									
										95
									
								
								srcs/.venv/lib/python3.11/site-packages/django/urls/conf.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								srcs/.venv/lib/python3.11/site-packages/django/urls/conf.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,95 @@ | ||||
| """Functions for use in URLsconfs.""" | ||||
| from functools import partial | ||||
| from importlib import import_module | ||||
|  | ||||
| from django.core.exceptions import ImproperlyConfigured | ||||
|  | ||||
| from .resolvers import ( | ||||
|     LocalePrefixPattern, | ||||
|     RegexPattern, | ||||
|     RoutePattern, | ||||
|     URLPattern, | ||||
|     URLResolver, | ||||
| ) | ||||
|  | ||||
|  | ||||
| def include(arg, namespace=None): | ||||
|     app_name = None | ||||
|     if isinstance(arg, tuple): | ||||
|         # Callable returning a namespace hint. | ||||
|         try: | ||||
|             urlconf_module, app_name = arg | ||||
|         except ValueError: | ||||
|             if namespace: | ||||
|                 raise ImproperlyConfigured( | ||||
|                     "Cannot override the namespace for a dynamic module that " | ||||
|                     "provides a namespace." | ||||
|                 ) | ||||
|             raise ImproperlyConfigured( | ||||
|                 "Passing a %d-tuple to include() is not supported. Pass a " | ||||
|                 "2-tuple containing the list of patterns and app_name, and " | ||||
|                 "provide the namespace argument to include() instead." % len(arg) | ||||
|             ) | ||||
|     else: | ||||
|         # No namespace hint - use manually provided namespace. | ||||
|         urlconf_module = arg | ||||
|  | ||||
|     if isinstance(urlconf_module, str): | ||||
|         urlconf_module = import_module(urlconf_module) | ||||
|     patterns = getattr(urlconf_module, "urlpatterns", urlconf_module) | ||||
|     app_name = getattr(urlconf_module, "app_name", app_name) | ||||
|     if namespace and not app_name: | ||||
|         raise ImproperlyConfigured( | ||||
|             "Specifying a namespace in include() without providing an app_name " | ||||
|             "is not supported. Set the app_name attribute in the included " | ||||
|             "module, or pass a 2-tuple containing the list of patterns and " | ||||
|             "app_name instead.", | ||||
|         ) | ||||
|     namespace = namespace or app_name | ||||
|     # Make sure the patterns can be iterated through (without this, some | ||||
|     # testcases will break). | ||||
|     if isinstance(patterns, (list, tuple)): | ||||
|         for url_pattern in patterns: | ||||
|             pattern = getattr(url_pattern, "pattern", None) | ||||
|             if isinstance(pattern, LocalePrefixPattern): | ||||
|                 raise ImproperlyConfigured( | ||||
|                     "Using i18n_patterns in an included URLconf is not allowed." | ||||
|                 ) | ||||
|     return (urlconf_module, app_name, namespace) | ||||
|  | ||||
|  | ||||
| def _path(route, view, kwargs=None, name=None, Pattern=None): | ||||
|     from django.views import View | ||||
|  | ||||
|     if kwargs is not None and not isinstance(kwargs, dict): | ||||
|         raise TypeError( | ||||
|             f"kwargs argument must be a dict, but got {kwargs.__class__.__name__}." | ||||
|         ) | ||||
|     if isinstance(view, (list, tuple)): | ||||
|         # For include(...) processing. | ||||
|         pattern = Pattern(route, is_endpoint=False) | ||||
|         urlconf_module, app_name, namespace = view | ||||
|         return URLResolver( | ||||
|             pattern, | ||||
|             urlconf_module, | ||||
|             kwargs, | ||||
|             app_name=app_name, | ||||
|             namespace=namespace, | ||||
|         ) | ||||
|     elif callable(view): | ||||
|         pattern = Pattern(route, name=name, is_endpoint=True) | ||||
|         return URLPattern(pattern, view, kwargs, name) | ||||
|     elif isinstance(view, View): | ||||
|         view_cls_name = view.__class__.__name__ | ||||
|         raise TypeError( | ||||
|             f"view must be a callable, pass {view_cls_name}.as_view(), not " | ||||
|             f"{view_cls_name}()." | ||||
|         ) | ||||
|     else: | ||||
|         raise TypeError( | ||||
|             "view must be a callable or a list/tuple in the case of include()." | ||||
|         ) | ||||
|  | ||||
|  | ||||
| path = partial(_path, Pattern=RoutePattern) | ||||
| re_path = partial(_path, Pattern=RegexPattern) | ||||
| @ -0,0 +1,66 @@ | ||||
| import uuid | ||||
| from functools import lru_cache | ||||
|  | ||||
|  | ||||
| class IntConverter: | ||||
|     regex = "[0-9]+" | ||||
|  | ||||
|     def to_python(self, value): | ||||
|         return int(value) | ||||
|  | ||||
|     def to_url(self, value): | ||||
|         return str(value) | ||||
|  | ||||
|  | ||||
| class StringConverter: | ||||
|     regex = "[^/]+" | ||||
|  | ||||
|     def to_python(self, value): | ||||
|         return value | ||||
|  | ||||
|     def to_url(self, value): | ||||
|         return value | ||||
|  | ||||
|  | ||||
| class UUIDConverter: | ||||
|     regex = "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}" | ||||
|  | ||||
|     def to_python(self, value): | ||||
|         return uuid.UUID(value) | ||||
|  | ||||
|     def to_url(self, value): | ||||
|         return str(value) | ||||
|  | ||||
|  | ||||
| class SlugConverter(StringConverter): | ||||
|     regex = "[-a-zA-Z0-9_]+" | ||||
|  | ||||
|  | ||||
| class PathConverter(StringConverter): | ||||
|     regex = ".+" | ||||
|  | ||||
|  | ||||
| DEFAULT_CONVERTERS = { | ||||
|     "int": IntConverter(), | ||||
|     "path": PathConverter(), | ||||
|     "slug": SlugConverter(), | ||||
|     "str": StringConverter(), | ||||
|     "uuid": UUIDConverter(), | ||||
| } | ||||
|  | ||||
|  | ||||
| REGISTERED_CONVERTERS = {} | ||||
|  | ||||
|  | ||||
| def register_converter(converter, type_name): | ||||
|     REGISTERED_CONVERTERS[type_name] = converter() | ||||
|     get_converters.cache_clear() | ||||
|  | ||||
|  | ||||
| @lru_cache(maxsize=None) | ||||
| def get_converters(): | ||||
|     return {**DEFAULT_CONVERTERS, **REGISTERED_CONVERTERS} | ||||
|  | ||||
|  | ||||
| def get_converter(raw_converter): | ||||
|     return get_converters()[raw_converter] | ||||
| @ -0,0 +1,9 @@ | ||||
| from django.http import Http404 | ||||
|  | ||||
|  | ||||
| class Resolver404(Http404): | ||||
|     pass | ||||
|  | ||||
|  | ||||
| class NoReverseMatch(Exception): | ||||
|     pass | ||||
							
								
								
									
										828
									
								
								srcs/.venv/lib/python3.11/site-packages/django/urls/resolvers.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										828
									
								
								srcs/.venv/lib/python3.11/site-packages/django/urls/resolvers.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,828 @@ | ||||
| """ | ||||
| This module converts requested URLs to callback view functions. | ||||
|  | ||||
| URLResolver is the main class here. Its resolve() method takes a URL (as | ||||
| a string) and returns a ResolverMatch object which provides access to all | ||||
| attributes of the resolved URL match. | ||||
| """ | ||||
| import functools | ||||
| import inspect | ||||
| import re | ||||
| import string | ||||
| from importlib import import_module | ||||
| from pickle import PicklingError | ||||
| from urllib.parse import quote | ||||
|  | ||||
| from asgiref.local import Local | ||||
|  | ||||
| from django.conf import settings | ||||
| from django.core.checks import Error, Warning | ||||
| from django.core.checks.urls import check_resolver | ||||
| from django.core.exceptions import ImproperlyConfigured, ViewDoesNotExist | ||||
| from django.utils.datastructures import MultiValueDict | ||||
| from django.utils.functional import cached_property | ||||
| from django.utils.http import RFC3986_SUBDELIMS, escape_leading_slashes | ||||
| from django.utils.regex_helper import _lazy_re_compile, normalize | ||||
| from django.utils.translation import get_language | ||||
|  | ||||
| from .converters import get_converter | ||||
| from .exceptions import NoReverseMatch, Resolver404 | ||||
| from .utils import get_callable | ||||
|  | ||||
|  | ||||
| class ResolverMatch: | ||||
|     def __init__( | ||||
|         self, | ||||
|         func, | ||||
|         args, | ||||
|         kwargs, | ||||
|         url_name=None, | ||||
|         app_names=None, | ||||
|         namespaces=None, | ||||
|         route=None, | ||||
|         tried=None, | ||||
|         captured_kwargs=None, | ||||
|         extra_kwargs=None, | ||||
|     ): | ||||
|         self.func = func | ||||
|         self.args = args | ||||
|         self.kwargs = kwargs | ||||
|         self.url_name = url_name | ||||
|         self.route = route | ||||
|         self.tried = tried | ||||
|         self.captured_kwargs = captured_kwargs | ||||
|         self.extra_kwargs = extra_kwargs | ||||
|  | ||||
|         # If a URLRegexResolver doesn't have a namespace or app_name, it passes | ||||
|         # in an empty value. | ||||
|         self.app_names = [x for x in app_names if x] if app_names else [] | ||||
|         self.app_name = ":".join(self.app_names) | ||||
|         self.namespaces = [x for x in namespaces if x] if namespaces else [] | ||||
|         self.namespace = ":".join(self.namespaces) | ||||
|  | ||||
|         if hasattr(func, "view_class"): | ||||
|             func = func.view_class | ||||
|         if not hasattr(func, "__name__"): | ||||
|             # A class-based view | ||||
|             self._func_path = func.__class__.__module__ + "." + func.__class__.__name__ | ||||
|         else: | ||||
|             # A function-based view | ||||
|             self._func_path = func.__module__ + "." + func.__name__ | ||||
|  | ||||
|         view_path = url_name or self._func_path | ||||
|         self.view_name = ":".join(self.namespaces + [view_path]) | ||||
|  | ||||
|     def __getitem__(self, index): | ||||
|         return (self.func, self.args, self.kwargs)[index] | ||||
|  | ||||
|     def __repr__(self): | ||||
|         if isinstance(self.func, functools.partial): | ||||
|             func = repr(self.func) | ||||
|         else: | ||||
|             func = self._func_path | ||||
|         return ( | ||||
|             "ResolverMatch(func=%s, args=%r, kwargs=%r, url_name=%r, " | ||||
|             "app_names=%r, namespaces=%r, route=%r%s%s)" | ||||
|             % ( | ||||
|                 func, | ||||
|                 self.args, | ||||
|                 self.kwargs, | ||||
|                 self.url_name, | ||||
|                 self.app_names, | ||||
|                 self.namespaces, | ||||
|                 self.route, | ||||
|                 f", captured_kwargs={self.captured_kwargs!r}" | ||||
|                 if self.captured_kwargs | ||||
|                 else "", | ||||
|                 f", extra_kwargs={self.extra_kwargs!r}" if self.extra_kwargs else "", | ||||
|             ) | ||||
|         ) | ||||
|  | ||||
|     def __reduce_ex__(self, protocol): | ||||
|         raise PicklingError(f"Cannot pickle {self.__class__.__qualname__}.") | ||||
|  | ||||
|  | ||||
| def get_resolver(urlconf=None): | ||||
|     if urlconf is None: | ||||
|         urlconf = settings.ROOT_URLCONF | ||||
|     return _get_cached_resolver(urlconf) | ||||
|  | ||||
|  | ||||
| @functools.lru_cache(maxsize=None) | ||||
| def _get_cached_resolver(urlconf=None): | ||||
|     return URLResolver(RegexPattern(r"^/"), urlconf) | ||||
|  | ||||
|  | ||||
| @functools.lru_cache(maxsize=None) | ||||
| def get_ns_resolver(ns_pattern, resolver, converters): | ||||
|     # Build a namespaced resolver for the given parent URLconf pattern. | ||||
|     # This makes it possible to have captured parameters in the parent | ||||
|     # URLconf pattern. | ||||
|     pattern = RegexPattern(ns_pattern) | ||||
|     pattern.converters = dict(converters) | ||||
|     ns_resolver = URLResolver(pattern, resolver.url_patterns) | ||||
|     return URLResolver(RegexPattern(r"^/"), [ns_resolver]) | ||||
|  | ||||
|  | ||||
| class LocaleRegexDescriptor: | ||||
|     def __init__(self, attr): | ||||
|         self.attr = attr | ||||
|  | ||||
|     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 regex string is a regular | ||||
|         # string (not a lazily-translated string proxy), compile it once and | ||||
|         # avoid per-language compilation. | ||||
|         pattern = getattr(instance, self.attr) | ||||
|         if isinstance(pattern, str): | ||||
|             instance.__dict__["regex"] = instance._compile(pattern) | ||||
|             return instance.__dict__["regex"] | ||||
|         language_code = get_language() | ||||
|         if language_code not in instance._regex_dict: | ||||
|             instance._regex_dict[language_code] = instance._compile(str(pattern)) | ||||
|         return instance._regex_dict[language_code] | ||||
|  | ||||
|  | ||||
| class CheckURLMixin: | ||||
|     def describe(self): | ||||
|         """ | ||||
|         Format the URL pattern for display in warning messages. | ||||
|         """ | ||||
|         description = "'{}'".format(self) | ||||
|         if self.name: | ||||
|             description += " [name='{}']".format(self.name) | ||||
|         return description | ||||
|  | ||||
|     def _check_pattern_startswith_slash(self): | ||||
|         """ | ||||
|         Check that the pattern does not begin with a forward slash. | ||||
|         """ | ||||
|         regex_pattern = self.regex.pattern | ||||
|         if not settings.APPEND_SLASH: | ||||
|             # Skip check as it can be useful to start a URL pattern with a slash | ||||
|             # when APPEND_SLASH=False. | ||||
|             return [] | ||||
|         if regex_pattern.startswith(("/", "^/", "^\\/")) and not regex_pattern.endswith( | ||||
|             "/" | ||||
|         ): | ||||
|             warning = Warning( | ||||
|                 "Your URL pattern {} has a route beginning with a '/'. Remove this " | ||||
|                 "slash as it is unnecessary. If this pattern is targeted in an " | ||||
|                 "include(), ensure the include() pattern has a trailing '/'.".format( | ||||
|                     self.describe() | ||||
|                 ), | ||||
|                 id="urls.W002", | ||||
|             ) | ||||
|             return [warning] | ||||
|         else: | ||||
|             return [] | ||||
|  | ||||
|  | ||||
| class RegexPattern(CheckURLMixin): | ||||
|     regex = LocaleRegexDescriptor("_regex") | ||||
|  | ||||
|     def __init__(self, regex, name=None, is_endpoint=False): | ||||
|         self._regex = regex | ||||
|         self._regex_dict = {} | ||||
|         self._is_endpoint = is_endpoint | ||||
|         self.name = name | ||||
|         self.converters = {} | ||||
|  | ||||
|     def match(self, path): | ||||
|         match = ( | ||||
|             self.regex.fullmatch(path) | ||||
|             if self._is_endpoint and self.regex.pattern.endswith("$") | ||||
|             else self.regex.search(path) | ||||
|         ) | ||||
|         if match: | ||||
|             # If there are any named groups, use those as kwargs, ignoring | ||||
|             # non-named groups. Otherwise, pass all non-named arguments as | ||||
|             # positional arguments. | ||||
|             kwargs = match.groupdict() | ||||
|             args = () if kwargs else match.groups() | ||||
|             kwargs = {k: v for k, v in kwargs.items() if v is not None} | ||||
|             return path[match.end() :], args, kwargs | ||||
|         return None | ||||
|  | ||||
|     def check(self): | ||||
|         warnings = [] | ||||
|         warnings.extend(self._check_pattern_startswith_slash()) | ||||
|         if not self._is_endpoint: | ||||
|             warnings.extend(self._check_include_trailing_dollar()) | ||||
|         return warnings | ||||
|  | ||||
|     def _check_include_trailing_dollar(self): | ||||
|         regex_pattern = self.regex.pattern | ||||
|         if regex_pattern.endswith("$") and not regex_pattern.endswith(r"\$"): | ||||
|             return [ | ||||
|                 Warning( | ||||
|                     "Your URL pattern {} uses include with a route ending with a '$'. " | ||||
|                     "Remove the dollar from the route to avoid problems including " | ||||
|                     "URLs.".format(self.describe()), | ||||
|                     id="urls.W001", | ||||
|                 ) | ||||
|             ] | ||||
|         else: | ||||
|             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): | ||||
|         return str(self._regex) | ||||
|  | ||||
|  | ||||
| _PATH_PARAMETER_COMPONENT_RE = _lazy_re_compile( | ||||
|     r"<(?:(?P<converter>[^>:]+):)?(?P<parameter>[^>]+)>" | ||||
| ) | ||||
|  | ||||
|  | ||||
| def _route_to_regex(route, is_endpoint=False): | ||||
|     """ | ||||
|     Convert a path pattern into a regular expression. Return the regular | ||||
|     expression and a dictionary mapping the capture names to the converters. | ||||
|     For example, 'foo/<int:pk>' returns '^foo\\/(?P<pk>[0-9]+)' | ||||
|     and {'pk': <django.urls.converters.IntConverter>}. | ||||
|     """ | ||||
|     original_route = route | ||||
|     parts = ["^"] | ||||
|     converters = {} | ||||
|     while True: | ||||
|         match = _PATH_PARAMETER_COMPONENT_RE.search(route) | ||||
|         if not match: | ||||
|             parts.append(re.escape(route)) | ||||
|             break | ||||
|         elif not set(match.group()).isdisjoint(string.whitespace): | ||||
|             raise ImproperlyConfigured( | ||||
|                 "URL route '%s' cannot contain whitespace in angle brackets " | ||||
|                 "<…>." % original_route | ||||
|             ) | ||||
|         parts.append(re.escape(route[: match.start()])) | ||||
|         route = route[match.end() :] | ||||
|         parameter = match["parameter"] | ||||
|         if not parameter.isidentifier(): | ||||
|             raise ImproperlyConfigured( | ||||
|                 "URL route '%s' uses parameter name %r which isn't a valid " | ||||
|                 "Python identifier." % (original_route, parameter) | ||||
|             ) | ||||
|         raw_converter = match["converter"] | ||||
|         if raw_converter is None: | ||||
|             # If a converter isn't specified, the default is `str`. | ||||
|             raw_converter = "str" | ||||
|         try: | ||||
|             converter = get_converter(raw_converter) | ||||
|         except KeyError as e: | ||||
|             raise ImproperlyConfigured( | ||||
|                 "URL route %r uses invalid converter %r." | ||||
|                 % (original_route, raw_converter) | ||||
|             ) from e | ||||
|         converters[parameter] = converter | ||||
|         parts.append("(?P<" + parameter + ">" + converter.regex + ")") | ||||
|     if is_endpoint: | ||||
|         parts.append(r"\Z") | ||||
|     return "".join(parts), converters | ||||
|  | ||||
|  | ||||
| class RoutePattern(CheckURLMixin): | ||||
|     regex = LocaleRegexDescriptor("_route") | ||||
|  | ||||
|     def __init__(self, route, name=None, is_endpoint=False): | ||||
|         self._route = route | ||||
|         self._regex_dict = {} | ||||
|         self._is_endpoint = is_endpoint | ||||
|         self.name = name | ||||
|         self.converters = _route_to_regex(str(route), is_endpoint)[1] | ||||
|  | ||||
|     def match(self, path): | ||||
|         match = self.regex.search(path) | ||||
|         if match: | ||||
|             # RoutePattern doesn't allow non-named groups so args are ignored. | ||||
|             kwargs = match.groupdict() | ||||
|             for key, value in kwargs.items(): | ||||
|                 converter = self.converters[key] | ||||
|                 try: | ||||
|                     kwargs[key] = converter.to_python(value) | ||||
|                 except ValueError: | ||||
|                     return None | ||||
|             return path[match.end() :], (), kwargs | ||||
|         return None | ||||
|  | ||||
|     def check(self): | ||||
|         warnings = self._check_pattern_startswith_slash() | ||||
|         route = self._route | ||||
|         if "(?P<" in route or route.startswith("^") or route.endswith("$"): | ||||
|             warnings.append( | ||||
|                 Warning( | ||||
|                     "Your URL pattern {} has a route that contains '(?P<', begins " | ||||
|                     "with a '^', or ends with a '$'. This was likely an oversight " | ||||
|                     "when migrating to django.urls.path().".format(self.describe()), | ||||
|                     id="2_0.W001", | ||||
|                 ) | ||||
|             ) | ||||
|         return warnings | ||||
|  | ||||
|     def _compile(self, route): | ||||
|         return re.compile(_route_to_regex(route, self._is_endpoint)[0]) | ||||
|  | ||||
|     def __str__(self): | ||||
|         return str(self._route) | ||||
|  | ||||
|  | ||||
| class LocalePrefixPattern: | ||||
|     def __init__(self, prefix_default_language=True): | ||||
|         self.prefix_default_language = prefix_default_language | ||||
|         self.converters = {} | ||||
|  | ||||
|     @property | ||||
|     def regex(self): | ||||
|         # This is only used by reverse() and cached in _reverse_dict. | ||||
|         return re.compile(re.escape(self.language_prefix)) | ||||
|  | ||||
|     @property | ||||
|     def language_prefix(self): | ||||
|         language_code = get_language() or settings.LANGUAGE_CODE | ||||
|         if language_code == settings.LANGUAGE_CODE and not self.prefix_default_language: | ||||
|             return "" | ||||
|         else: | ||||
|             return "%s/" % language_code | ||||
|  | ||||
|     def match(self, path): | ||||
|         language_prefix = self.language_prefix | ||||
|         if path.startswith(language_prefix): | ||||
|             return path[len(language_prefix) :], (), {} | ||||
|         return None | ||||
|  | ||||
|     def check(self): | ||||
|         return [] | ||||
|  | ||||
|     def describe(self): | ||||
|         return "'{}'".format(self) | ||||
|  | ||||
|     def __str__(self): | ||||
|         return self.language_prefix | ||||
|  | ||||
|  | ||||
| class URLPattern: | ||||
|     def __init__(self, pattern, callback, default_args=None, name=None): | ||||
|         self.pattern = pattern | ||||
|         self.callback = callback  # the view | ||||
|         self.default_args = default_args or {} | ||||
|         self.name = name | ||||
|  | ||||
|     def __repr__(self): | ||||
|         return "<%s %s>" % (self.__class__.__name__, self.pattern.describe()) | ||||
|  | ||||
|     def check(self): | ||||
|         warnings = self._check_pattern_name() | ||||
|         warnings.extend(self.pattern.check()) | ||||
|         warnings.extend(self._check_callback()) | ||||
|         return warnings | ||||
|  | ||||
|     def _check_pattern_name(self): | ||||
|         """ | ||||
|         Check that the pattern name does not contain a colon. | ||||
|         """ | ||||
|         if self.pattern.name is not None and ":" in self.pattern.name: | ||||
|             warning = Warning( | ||||
|                 "Your URL pattern {} has a name including a ':'. Remove the colon, to " | ||||
|                 "avoid ambiguous namespace references.".format(self.pattern.describe()), | ||||
|                 id="urls.W003", | ||||
|             ) | ||||
|             return [warning] | ||||
|         else: | ||||
|             return [] | ||||
|  | ||||
|     def _check_callback(self): | ||||
|         from django.views import View | ||||
|  | ||||
|         view = self.callback | ||||
|         if inspect.isclass(view) and issubclass(view, View): | ||||
|             return [ | ||||
|                 Error( | ||||
|                     "Your URL pattern %s has an invalid view, pass %s.as_view() " | ||||
|                     "instead of %s." | ||||
|                     % ( | ||||
|                         self.pattern.describe(), | ||||
|                         view.__name__, | ||||
|                         view.__name__, | ||||
|                     ), | ||||
|                     id="urls.E009", | ||||
|                 ) | ||||
|             ] | ||||
|         return [] | ||||
|  | ||||
|     def resolve(self, path): | ||||
|         match = self.pattern.match(path) | ||||
|         if match: | ||||
|             new_path, args, captured_kwargs = match | ||||
|             # Pass any default args as **kwargs. | ||||
|             kwargs = {**captured_kwargs, **self.default_args} | ||||
|             return ResolverMatch( | ||||
|                 self.callback, | ||||
|                 args, | ||||
|                 kwargs, | ||||
|                 self.pattern.name, | ||||
|                 route=str(self.pattern), | ||||
|                 captured_kwargs=captured_kwargs, | ||||
|                 extra_kwargs=self.default_args, | ||||
|             ) | ||||
|  | ||||
|     @cached_property | ||||
|     def lookup_str(self): | ||||
|         """ | ||||
|         A string that identifies the view (e.g. 'path.to.view_function' or | ||||
|         'path.to.ClassBasedView'). | ||||
|         """ | ||||
|         callback = self.callback | ||||
|         if isinstance(callback, functools.partial): | ||||
|             callback = callback.func | ||||
|         if hasattr(callback, "view_class"): | ||||
|             callback = callback.view_class | ||||
|         elif not hasattr(callback, "__name__"): | ||||
|             return callback.__module__ + "." + callback.__class__.__name__ | ||||
|         return callback.__module__ + "." + callback.__qualname__ | ||||
|  | ||||
|  | ||||
| class URLResolver: | ||||
|     def __init__( | ||||
|         self, pattern, urlconf_name, default_kwargs=None, app_name=None, namespace=None | ||||
|     ): | ||||
|         self.pattern = pattern | ||||
|         # urlconf_name is the dotted Python path to the module defining | ||||
|         # urlpatterns. It may also be an object with an urlpatterns attribute | ||||
|         # or urlpatterns itself. | ||||
|         self.urlconf_name = urlconf_name | ||||
|         self.callback = None | ||||
|         self.default_kwargs = default_kwargs or {} | ||||
|         self.namespace = namespace | ||||
|         self.app_name = app_name | ||||
|         self._reverse_dict = {} | ||||
|         self._namespace_dict = {} | ||||
|         self._app_dict = {} | ||||
|         # set of dotted paths to all functions and classes that are used in | ||||
|         # urlpatterns | ||||
|         self._callback_strs = set() | ||||
|         self._populated = False | ||||
|         self._local = Local() | ||||
|  | ||||
|     def __repr__(self): | ||||
|         if isinstance(self.urlconf_name, list) and self.urlconf_name: | ||||
|             # Don't bother to output the whole list, it can be huge | ||||
|             urlconf_repr = "<%s list>" % self.urlconf_name[0].__class__.__name__ | ||||
|         else: | ||||
|             urlconf_repr = repr(self.urlconf_name) | ||||
|         return "<%s %s (%s:%s) %s>" % ( | ||||
|             self.__class__.__name__, | ||||
|             urlconf_repr, | ||||
|             self.app_name, | ||||
|             self.namespace, | ||||
|             self.pattern.describe(), | ||||
|         ) | ||||
|  | ||||
|     def check(self): | ||||
|         messages = [] | ||||
|         for pattern in self.url_patterns: | ||||
|             messages.extend(check_resolver(pattern)) | ||||
|         messages.extend(self._check_custom_error_handlers()) | ||||
|         return messages or self.pattern.check() | ||||
|  | ||||
|     def _check_custom_error_handlers(self): | ||||
|         messages = [] | ||||
|         # All handlers take (request, exception) arguments except handler500 | ||||
|         # which takes (request). | ||||
|         for status_code, num_parameters in [(400, 2), (403, 2), (404, 2), (500, 1)]: | ||||
|             try: | ||||
|                 handler = self.resolve_error_handler(status_code) | ||||
|             except (ImportError, ViewDoesNotExist) as e: | ||||
|                 path = getattr(self.urlconf_module, "handler%s" % status_code) | ||||
|                 msg = ( | ||||
|                     "The custom handler{status_code} view '{path}' could not be " | ||||
|                     "imported." | ||||
|                 ).format(status_code=status_code, path=path) | ||||
|                 messages.append(Error(msg, hint=str(e), id="urls.E008")) | ||||
|                 continue | ||||
|             signature = inspect.signature(handler) | ||||
|             args = [None] * num_parameters | ||||
|             try: | ||||
|                 signature.bind(*args) | ||||
|             except TypeError: | ||||
|                 msg = ( | ||||
|                     "The custom handler{status_code} view '{path}' does not " | ||||
|                     "take the correct number of arguments ({args})." | ||||
|                 ).format( | ||||
|                     status_code=status_code, | ||||
|                     path=handler.__module__ + "." + handler.__qualname__, | ||||
|                     args="request, exception" if num_parameters == 2 else "request", | ||||
|                 ) | ||||
|                 messages.append(Error(msg, id="urls.E007")) | ||||
|         return messages | ||||
|  | ||||
|     def _populate(self): | ||||
|         # Short-circuit if called recursively in this thread to prevent | ||||
|         # infinite recursion. Concurrent threads may call this at the same | ||||
|         # time and will need to continue, so set 'populating' on a | ||||
|         # thread-local variable. | ||||
|         if getattr(self._local, "populating", False): | ||||
|             return | ||||
|         try: | ||||
|             self._local.populating = True | ||||
|             lookups = MultiValueDict() | ||||
|             namespaces = {} | ||||
|             apps = {} | ||||
|             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:] | ||||
|                 if isinstance(url_pattern, URLPattern): | ||||
|                     self._callback_strs.add(url_pattern.lookup_str) | ||||
|                     bits = normalize(url_pattern.pattern.regex.pattern) | ||||
|                     lookups.appendlist( | ||||
|                         url_pattern.callback, | ||||
|                         ( | ||||
|                             bits, | ||||
|                             p_pattern, | ||||
|                             url_pattern.default_args, | ||||
|                             url_pattern.pattern.converters, | ||||
|                         ), | ||||
|                     ) | ||||
|                     if url_pattern.name is not None: | ||||
|                         lookups.appendlist( | ||||
|                             url_pattern.name, | ||||
|                             ( | ||||
|                                 bits, | ||||
|                                 p_pattern, | ||||
|                                 url_pattern.default_args, | ||||
|                                 url_pattern.pattern.converters, | ||||
|                             ), | ||||
|                         ) | ||||
|                 else:  # url_pattern is a URLResolver. | ||||
|                     url_pattern._populate() | ||||
|                     if url_pattern.app_name: | ||||
|                         apps.setdefault(url_pattern.app_name, []).append( | ||||
|                             url_pattern.namespace | ||||
|                         ) | ||||
|                         namespaces[url_pattern.namespace] = (p_pattern, url_pattern) | ||||
|                     else: | ||||
|                         for name in url_pattern.reverse_dict: | ||||
|                             for ( | ||||
|                                 matches, | ||||
|                                 pat, | ||||
|                                 defaults, | ||||
|                                 converters, | ||||
|                             ) in url_pattern.reverse_dict.getlist(name): | ||||
|                                 new_matches = normalize(p_pattern + pat) | ||||
|                                 lookups.appendlist( | ||||
|                                     name, | ||||
|                                     ( | ||||
|                                         new_matches, | ||||
|                                         p_pattern + pat, | ||||
|                                         {**defaults, **url_pattern.default_kwargs}, | ||||
|                                         { | ||||
|                                             **self.pattern.converters, | ||||
|                                             **url_pattern.pattern.converters, | ||||
|                                             **converters, | ||||
|                                         }, | ||||
|                                     ), | ||||
|                                 ) | ||||
|                         for namespace, ( | ||||
|                             prefix, | ||||
|                             sub_pattern, | ||||
|                         ) in url_pattern.namespace_dict.items(): | ||||
|                             current_converters = url_pattern.pattern.converters | ||||
|                             sub_pattern.pattern.converters.update(current_converters) | ||||
|                             namespaces[namespace] = (p_pattern + prefix, sub_pattern) | ||||
|                         for app_name, namespace_list in url_pattern.app_dict.items(): | ||||
|                             apps.setdefault(app_name, []).extend(namespace_list) | ||||
|                     self._callback_strs.update(url_pattern._callback_strs) | ||||
|             self._namespace_dict[language_code] = namespaces | ||||
|             self._app_dict[language_code] = apps | ||||
|             self._reverse_dict[language_code] = lookups | ||||
|             self._populated = True | ||||
|         finally: | ||||
|             self._local.populating = False | ||||
|  | ||||
|     @property | ||||
|     def reverse_dict(self): | ||||
|         language_code = get_language() | ||||
|         if language_code not in self._reverse_dict: | ||||
|             self._populate() | ||||
|         return self._reverse_dict[language_code] | ||||
|  | ||||
|     @property | ||||
|     def namespace_dict(self): | ||||
|         language_code = get_language() | ||||
|         if language_code not in self._namespace_dict: | ||||
|             self._populate() | ||||
|         return self._namespace_dict[language_code] | ||||
|  | ||||
|     @property | ||||
|     def app_dict(self): | ||||
|         language_code = get_language() | ||||
|         if language_code not in self._app_dict: | ||||
|             self._populate() | ||||
|         return self._app_dict[language_code] | ||||
|  | ||||
|     @staticmethod | ||||
|     def _extend_tried(tried, pattern, sub_tried=None): | ||||
|         if sub_tried is None: | ||||
|             tried.append([pattern]) | ||||
|         else: | ||||
|             tried.extend([pattern, *t] for t in sub_tried) | ||||
|  | ||||
|     @staticmethod | ||||
|     def _join_route(route1, route2): | ||||
|         """Join two routes, without the starting ^ in the second route.""" | ||||
|         if not route1: | ||||
|             return route2 | ||||
|         if route2.startswith("^"): | ||||
|             route2 = route2[1:] | ||||
|         return route1 + route2 | ||||
|  | ||||
|     def _is_callback(self, name): | ||||
|         if not self._populated: | ||||
|             self._populate() | ||||
|         return name in self._callback_strs | ||||
|  | ||||
|     def resolve(self, path): | ||||
|         path = str(path)  # path may be a reverse_lazy object | ||||
|         tried = [] | ||||
|         match = self.pattern.match(path) | ||||
|         if match: | ||||
|             new_path, args, kwargs = match | ||||
|             for pattern in self.url_patterns: | ||||
|                 try: | ||||
|                     sub_match = pattern.resolve(new_path) | ||||
|                 except Resolver404 as e: | ||||
|                     self._extend_tried(tried, pattern, e.args[0].get("tried")) | ||||
|                 else: | ||||
|                     if sub_match: | ||||
|                         # Merge captured arguments in match with submatch | ||||
|                         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. | ||||
|                         # Otherwise, pass all non-named arguments as positional | ||||
|                         # arguments. | ||||
|                         sub_match_args = sub_match.args | ||||
|                         if not sub_match_dict: | ||||
|                             sub_match_args = args + sub_match.args | ||||
|                         current_route = ( | ||||
|                             "" | ||||
|                             if isinstance(pattern, URLPattern) | ||||
|                             else str(pattern.pattern) | ||||
|                         ) | ||||
|                         self._extend_tried(tried, pattern, sub_match.tried) | ||||
|                         return ResolverMatch( | ||||
|                             sub_match.func, | ||||
|                             sub_match_args, | ||||
|                             sub_match_dict, | ||||
|                             sub_match.url_name, | ||||
|                             [self.app_name] + sub_match.app_names, | ||||
|                             [self.namespace] + sub_match.namespaces, | ||||
|                             self._join_route(current_route, sub_match.route), | ||||
|                             tried, | ||||
|                             captured_kwargs=sub_match.captured_kwargs, | ||||
|                             extra_kwargs={ | ||||
|                                 **self.default_kwargs, | ||||
|                                 **sub_match.extra_kwargs, | ||||
|                             }, | ||||
|                         ) | ||||
|                     tried.append([pattern]) | ||||
|             raise Resolver404({"tried": tried, "path": new_path}) | ||||
|         raise Resolver404({"path": path}) | ||||
|  | ||||
|     @cached_property | ||||
|     def urlconf_module(self): | ||||
|         if isinstance(self.urlconf_name, str): | ||||
|             return import_module(self.urlconf_name) | ||||
|         else: | ||||
|             return self.urlconf_name | ||||
|  | ||||
|     @cached_property | ||||
|     def url_patterns(self): | ||||
|         # urlconf_module might be a valid set of patterns, so we default to it | ||||
|         patterns = getattr(self.urlconf_module, "urlpatterns", self.urlconf_module) | ||||
|         try: | ||||
|             iter(patterns) | ||||
|         except TypeError as e: | ||||
|             msg = ( | ||||
|                 "The included URLconf '{name}' does not appear to have " | ||||
|                 "any patterns in it. If you see the 'urlpatterns' variable " | ||||
|                 "with valid patterns in the file then the issue is probably " | ||||
|                 "caused by a circular import." | ||||
|             ) | ||||
|             raise ImproperlyConfigured(msg.format(name=self.urlconf_name)) from e | ||||
|         return patterns | ||||
|  | ||||
|     def resolve_error_handler(self, view_type): | ||||
|         callback = getattr(self.urlconf_module, "handler%s" % view_type, None) | ||||
|         if not callback: | ||||
|             # No handler specified in file; use lazy import, since | ||||
|             # django.conf.urls imports this file. | ||||
|             from django.conf import urls | ||||
|  | ||||
|             callback = getattr(urls, "handler%s" % view_type) | ||||
|         return get_callable(callback) | ||||
|  | ||||
|     def reverse(self, lookup_view, *args, **kwargs): | ||||
|         return self._reverse_with_prefix(lookup_view, "", *args, **kwargs) | ||||
|  | ||||
|     def _reverse_with_prefix(self, lookup_view, _prefix, *args, **kwargs): | ||||
|         if args and kwargs: | ||||
|             raise ValueError("Don't mix *args and **kwargs in call to reverse()!") | ||||
|  | ||||
|         if not self._populated: | ||||
|             self._populate() | ||||
|  | ||||
|         possibilities = self.reverse_dict.getlist(lookup_view) | ||||
|  | ||||
|         for possibility, pattern, defaults, converters in possibilities: | ||||
|             for result, params in possibility: | ||||
|                 if args: | ||||
|                     if len(args) != len(params): | ||||
|                         continue | ||||
|                     candidate_subs = dict(zip(params, args)) | ||||
|                 else: | ||||
|                     if set(kwargs).symmetric_difference(params).difference(defaults): | ||||
|                         continue | ||||
|                     matches = True | ||||
|                     for k, v in defaults.items(): | ||||
|                         if k in params: | ||||
|                             continue | ||||
|                         if kwargs.get(k, v) != v: | ||||
|                             matches = False | ||||
|                             break | ||||
|                     if not matches: | ||||
|                         continue | ||||
|                     candidate_subs = kwargs | ||||
|                 # Convert the candidate subs to text using Converter.to_url(). | ||||
|                 text_candidate_subs = {} | ||||
|                 match = True | ||||
|                 for k, v in candidate_subs.items(): | ||||
|                     if k in converters: | ||||
|                         try: | ||||
|                             text_candidate_subs[k] = converters[k].to_url(v) | ||||
|                         except ValueError: | ||||
|                             match = False | ||||
|                             break | ||||
|                     else: | ||||
|                         text_candidate_subs[k] = str(v) | ||||
|                 if not match: | ||||
|                     continue | ||||
|                 # WSGI provides decoded URLs, without %xx escapes, and the URL | ||||
|                 # resolver operates on such URLs. First substitute arguments | ||||
|                 # without quoting to build a decoded URL and look for a match. | ||||
|                 # Then, if we have a match, redo the substitution with quoted | ||||
|                 # arguments in order to return a properly encoded URL. | ||||
|                 candidate_pat = _prefix.replace("%", "%%") + result | ||||
|                 if re.search( | ||||
|                     "^%s%s" % (re.escape(_prefix), pattern), | ||||
|                     candidate_pat % text_candidate_subs, | ||||
|                 ): | ||||
|                     # safe characters from `pchar` definition of RFC 3986 | ||||
|                     url = quote( | ||||
|                         candidate_pat % text_candidate_subs, | ||||
|                         safe=RFC3986_SUBDELIMS + "/~:@", | ||||
|                     ) | ||||
|                     # Don't allow construction of scheme relative urls. | ||||
|                     return escape_leading_slashes(url) | ||||
|         # lookup_view can be URL name or callable, but callables are not | ||||
|         # friendly in error messages. | ||||
|         m = getattr(lookup_view, "__module__", None) | ||||
|         n = getattr(lookup_view, "__name__", None) | ||||
|         if m is not None and n is not None: | ||||
|             lookup_view_s = "%s.%s" % (m, n) | ||||
|         else: | ||||
|             lookup_view_s = lookup_view | ||||
|  | ||||
|         patterns = [pattern for (_, pattern, _, _) in possibilities] | ||||
|         if patterns: | ||||
|             if args: | ||||
|                 arg_msg = "arguments '%s'" % (args,) | ||||
|             elif kwargs: | ||||
|                 arg_msg = "keyword arguments '%s'" % kwargs | ||||
|             else: | ||||
|                 arg_msg = "no arguments" | ||||
|             msg = "Reverse for '%s' with %s not found. %d pattern(s) tried: %s" % ( | ||||
|                 lookup_view_s, | ||||
|                 arg_msg, | ||||
|                 len(patterns), | ||||
|                 patterns, | ||||
|             ) | ||||
|         else: | ||||
|             msg = ( | ||||
|                 "Reverse for '%(view)s' not found. '%(view)s' is not " | ||||
|                 "a valid view function or pattern name." % {"view": lookup_view_s} | ||||
|             ) | ||||
|         raise NoReverseMatch(msg) | ||||
							
								
								
									
										66
									
								
								srcs/.venv/lib/python3.11/site-packages/django/urls/utils.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								srcs/.venv/lib/python3.11/site-packages/django/urls/utils.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,66 @@ | ||||
| import functools | ||||
| from importlib import import_module | ||||
|  | ||||
| from django.core.exceptions import ViewDoesNotExist | ||||
| from django.utils.module_loading import module_has_submodule | ||||
|  | ||||
|  | ||||
| @functools.lru_cache(maxsize=None) | ||||
| def get_callable(lookup_view): | ||||
|     """ | ||||
|     Return a callable corresponding to lookup_view. | ||||
|     * If lookup_view is already a callable, return it. | ||||
|     * If lookup_view is a string import path that can be resolved to a callable, | ||||
|       import that callable and return it, otherwise raise an exception | ||||
|       (ImportError or ViewDoesNotExist). | ||||
|     """ | ||||
|     if callable(lookup_view): | ||||
|         return lookup_view | ||||
|  | ||||
|     if not isinstance(lookup_view, str): | ||||
|         raise ViewDoesNotExist( | ||||
|             "'%s' is not a callable or a dot-notation path" % lookup_view | ||||
|         ) | ||||
|  | ||||
|     mod_name, func_name = get_mod_func(lookup_view) | ||||
|     if not func_name:  # No '.' in lookup_view | ||||
|         raise ImportError( | ||||
|             "Could not import '%s'. The path must be fully qualified." % lookup_view | ||||
|         ) | ||||
|  | ||||
|     try: | ||||
|         mod = import_module(mod_name) | ||||
|     except ImportError: | ||||
|         parentmod, submod = get_mod_func(mod_name) | ||||
|         if submod and not module_has_submodule(import_module(parentmod), submod): | ||||
|             raise ViewDoesNotExist( | ||||
|                 "Could not import '%s'. Parent module %s does not exist." | ||||
|                 % (lookup_view, mod_name) | ||||
|             ) | ||||
|         else: | ||||
|             raise | ||||
|     else: | ||||
|         try: | ||||
|             view_func = getattr(mod, func_name) | ||||
|         except AttributeError: | ||||
|             raise ViewDoesNotExist( | ||||
|                 "Could not import '%s'. View does not exist in module %s." | ||||
|                 % (lookup_view, mod_name) | ||||
|             ) | ||||
|         else: | ||||
|             if not callable(view_func): | ||||
|                 raise ViewDoesNotExist( | ||||
|                     "Could not import '%s.%s'. View is not callable." | ||||
|                     % (mod_name, func_name) | ||||
|                 ) | ||||
|             return view_func | ||||
|  | ||||
|  | ||||
| def get_mod_func(callback): | ||||
|     # Convert 'django.views.news.stories.story_detail' to | ||||
|     # ['django.views.news.stories', 'story_detail'] | ||||
|     try: | ||||
|         dot = callback.rindex(".") | ||||
|     except ValueError: | ||||
|         return callback, "" | ||||
|     return callback[:dot], callback[dot + 1 :] | ||||
		Reference in New Issue
	
	Block a user