Coverage for /Users/davegaeddert/Developer/dropseed/plain/plain/plain/urls/base.py: 18%

65 statements  

« prev     ^ index     » next       coverage.py v7.6.9, created at 2024-12-23 11:16 -0600

1from threading import local 

2 

3from plain.utils.functional import lazy 

4 

5from .exceptions import NoReverseMatch, Resolver404 

6from .resolvers import _get_cached_resolver, get_ns_resolver, get_resolver 

7 

8# Overridden URLconfs for each thread are stored here. 

9_urlconfs = local() 

10 

11 

12def resolve(path, urlconf=None): 

13 if urlconf is None: 

14 urlconf = get_urlconf() 

15 return get_resolver(urlconf).resolve(path) 

16 

17 

18def reverse(viewname, urlconf=None, args=None, kwargs=None, using_namespace=None): 

19 if urlconf is None: 

20 urlconf = get_urlconf() 

21 resolver = get_resolver(urlconf) 

22 args = args or [] 

23 kwargs = kwargs or {} 

24 

25 if not isinstance(viewname, str): 

26 view = viewname 

27 else: 

28 *path, view = viewname.split(":") 

29 

30 if using_namespace: 

31 current_path = using_namespace.split(":") 

32 current_path.reverse() 

33 else: 

34 current_path = None 

35 

36 resolved_path = [] 

37 ns_pattern = "" 

38 ns_converters = {} 

39 for ns in path: 

40 current_ns = current_path.pop() if current_path else None 

41 # Lookup the name to see if it could be an app identifier. 

42 try: 

43 app_list = resolver.app_dict[ns] 

44 # Yes! Path part matches an app in the current Resolver. 

45 if current_ns and current_ns in app_list: 

46 # If we are reversing for a particular app, use that 

47 # namespace. 

48 ns = current_ns 

49 elif ns not in app_list: 

50 # The name isn't shared by one of the instances (i.e., 

51 # the default) so pick the first instance as the default. 

52 ns = app_list[0] 

53 except KeyError: 

54 pass 

55 

56 if ns != current_ns: 

57 current_path = None 

58 

59 try: 

60 extra, resolver = resolver.namespace_dict[ns] 

61 resolved_path.append(ns) 

62 ns_pattern += extra 

63 ns_converters.update(resolver.pattern.converters) 

64 except KeyError as key: 

65 if resolved_path: 

66 raise NoReverseMatch( 

67 "{} is not a registered namespace inside '{}'".format( 

68 key, ":".join(resolved_path) 

69 ) 

70 ) 

71 else: 

72 raise NoReverseMatch(f"{key} is not a registered namespace") 

73 if ns_pattern: 

74 resolver = get_ns_resolver( 

75 ns_pattern, resolver, tuple(ns_converters.items()) 

76 ) 

77 

78 return resolver.reverse(view, *args, **kwargs) 

79 

80 

81reverse_lazy = lazy(reverse, str) 

82 

83 

84def clear_url_caches(): 

85 _get_cached_resolver.cache_clear() 

86 get_ns_resolver.cache_clear() 

87 

88 

89def set_urlconf(urlconf_name): 

90 """ 

91 Set the URLconf for the current thread (overriding the default one in 

92 settings). If urlconf_name is None, revert back to the default. 

93 """ 

94 if urlconf_name: 

95 _urlconfs.value = urlconf_name 

96 else: 

97 if hasattr(_urlconfs, "value"): 

98 del _urlconfs.value 

99 

100 

101def get_urlconf(default=None): 

102 """ 

103 Return the root URLconf to use for the current thread if it has been 

104 changed from the default one. 

105 """ 

106 return getattr(_urlconfs, "value", default) 

107 

108 

109def is_valid_path(path, urlconf=None): 

110 """ 

111 Return the ResolverMatch if the given path resolves against the default URL 

112 resolver, False otherwise. This is a convenience method to make working 

113 with "is this a match?" cases easier, avoiding try...except blocks. 

114 """ 

115 try: 

116 return resolve(path, urlconf) 

117 except Resolver404: 

118 return False