Coverage for /Users/davegaeddert/Development/dropseed/plain/plain/plain/preflight/urls.py: 22%
49 statements
« prev ^ index » next coverage.py v7.6.1, created at 2024-10-16 22:04 -0500
« prev ^ index » next coverage.py v7.6.1, created at 2024-10-16 22:04 -0500
1from collections import Counter
3from plain.runtime import settings
5from . import Error, Warning, register
8@register
9def check_url_config(package_configs, **kwargs):
10 if getattr(settings, "ROOT_URLCONF", None):
11 from plain.urls import get_resolver
13 resolver = get_resolver()
14 return check_resolver(resolver)
15 return []
18def check_resolver(resolver):
19 """
20 Recursively check the resolver.
21 """
22 check_method = getattr(resolver, "check", None)
23 if check_method is not None:
24 return check_method()
25 elif not hasattr(resolver, "resolve"):
26 return get_warning_for_invalid_pattern(resolver)
27 else:
28 return []
31@register
32def check_url_namespaces_unique(package_configs, **kwargs):
33 """
34 Warn if URL namespaces used in applications aren't unique.
35 """
36 if not getattr(settings, "ROOT_URLCONF", None):
37 return []
39 from plain.urls import get_resolver
41 resolver = get_resolver()
42 all_namespaces = _load_all_namespaces(resolver)
43 counter = Counter(all_namespaces)
44 non_unique_namespaces = [n for n, count in counter.items() if count > 1]
45 errors = []
46 for namespace in non_unique_namespaces:
47 errors.append(
48 Warning(
49 "URL namespace '{}' isn't unique. You may not be able to reverse "
50 "all URLs in this namespace".format(namespace),
51 id="urls.W005",
52 )
53 )
54 return errors
57def _load_all_namespaces(resolver, parents=()):
58 """
59 Recursively load all namespaces from URL patterns.
60 """
61 url_patterns = getattr(resolver, "url_patterns", [])
62 namespaces = [
63 ":".join(parents + (url.namespace,))
64 for url in url_patterns
65 if getattr(url, "namespace", None) is not None
66 ]
67 for pattern in url_patterns:
68 namespace = getattr(pattern, "namespace", None)
69 current = parents
70 if namespace is not None:
71 current += (namespace,)
72 namespaces.extend(_load_all_namespaces(pattern, current))
73 return namespaces
76def get_warning_for_invalid_pattern(pattern):
77 """
78 Return a list containing a warning that the pattern is invalid.
80 describe_pattern() cannot be used here, because we cannot rely on the
81 urlpattern having regex or name attributes.
82 """
83 if isinstance(pattern, str):
84 hint = (
85 f"Try removing the string '{pattern}'. The list of urlpatterns should not "
86 "have a prefix string as the first element."
87 )
88 elif isinstance(pattern, tuple):
89 hint = "Try using path() instead of a tuple."
90 else:
91 hint = None
93 return [
94 Error(
95 "Your URL pattern {!r} is invalid. Ensure that urlpatterns is a list "
96 "of path() and/or re_path() instances.".format(pattern),
97 hint=hint,
98 id="urls.E004",
99 )
100 ]
103def E006(name):
104 return Error(
105 f"The {name} setting must end with a slash.",
106 id="urls.E006",
107 )