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:03 -0500

1from collections import Counter 

2 

3from plain.runtime import settings 

4 

5from . import Error, Warning, register 

6 

7 

8@register 

9def check_url_config(package_configs, **kwargs): 

10 if getattr(settings, "ROOT_URLCONF", None): 

11 from plain.urls import get_resolver 

12 

13 resolver = get_resolver() 

14 return check_resolver(resolver) 

15 return [] 

16 

17 

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 [] 

29 

30 

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 [] 

38 

39 from plain.urls import get_resolver 

40 

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 

55 

56 

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 

74 

75 

76def get_warning_for_invalid_pattern(pattern): 

77 """ 

78 Return a list containing a warning that the pattern is invalid. 

79 

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 

92 

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 ] 

101 

102 

103def E006(name): 

104 return Error( 

105 f"The {name} setting must end with a slash.", 

106 id="urls.E006", 

107 )