Coverage for /Users/davegaeddert/Developer/dropseed/plain/plain/plain/urls/conf.py: 67%

42 statements  

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

1"""Functions for use in URLsconfs.""" 

2 

3from functools import partial 

4 

5from plain.exceptions import ImproperlyConfigured 

6 

7from .resolvers import ( 

8 RegexPattern, 

9 RoutePattern, 

10 URLPattern, 

11 URLResolver, 

12) 

13 

14 

15def include(arg, namespace=None): 

16 default_namespace = None 

17 if isinstance(arg, tuple): 

18 # Callable returning a namespace hint. 

19 try: 

20 urlconf_module, default_namespace = arg 

21 except ValueError: 

22 if namespace: 

23 raise ImproperlyConfigured( 

24 "Cannot override the namespace for a dynamic module that " 

25 "provides a namespace." 

26 ) 

27 raise ImproperlyConfigured( 

28 "Passing a %d-tuple to include() is not supported. Pass a " 

29 "2-tuple containing the list of patterns and default_namespace, and " 

30 "provide the namespace argument to include() instead." % len(arg) 

31 ) 

32 else: 

33 # No namespace hint - use manually provided namespace. 

34 urlconf_module = arg 

35 

36 patterns = getattr(urlconf_module, "urlpatterns", urlconf_module) 

37 default_namespace = getattr(urlconf_module, "default_namespace", default_namespace) 

38 if namespace and not default_namespace: 

39 raise ImproperlyConfigured( 

40 "Specifying a namespace in include() without providing an default_namespace " 

41 "is not supported. Set the default_namespace attribute in the included " 

42 "module, or pass a 2-tuple containing the list of patterns and " 

43 "default_namespace instead.", 

44 ) 

45 namespace = namespace or default_namespace 

46 # Make sure the patterns can be iterated through (without this, some 

47 # testcases will break). 

48 if isinstance(patterns, list | tuple): 

49 for url_pattern in patterns: 

50 getattr(url_pattern, "pattern", None) 

51 return (urlconf_module, default_namespace, namespace) 

52 

53 

54def _path(route, view, kwargs=None, name=None, Pattern=None): 

55 from plain.views import View 

56 

57 if kwargs is not None and not isinstance(kwargs, dict): 

58 raise TypeError( 

59 f"kwargs argument must be a dict, but got {kwargs.__class__.__name__}." 

60 ) 

61 

62 if isinstance(view, list | tuple): 

63 # For include(...) processing. 

64 pattern = Pattern(route, is_endpoint=False) 

65 urlconf_module, default_namespace, namespace = view 

66 return URLResolver( 

67 pattern, 

68 urlconf_module, 

69 kwargs, 

70 default_namespace=default_namespace, 

71 namespace=namespace, 

72 ) 

73 

74 if isinstance(view, View): 

75 view_cls_name = view.__class__.__name__ 

76 raise TypeError( 

77 f"view must be a callable, pass {view_cls_name} or {view_cls_name}.as_view(*args, **kwargs), not " 

78 f"{view_cls_name}()." 

79 ) 

80 

81 # Automatically call view.as_view() for class-based views 

82 if as_view := getattr(view, "as_view", None): 

83 pattern = Pattern(route, name=name, is_endpoint=True) 

84 return URLPattern(pattern, as_view(), kwargs, name) 

85 

86 # Function-based views or view_class.as_view() usage 

87 if callable(view): 

88 pattern = Pattern(route, name=name, is_endpoint=True) 

89 return URLPattern(pattern, view, kwargs, name) 

90 

91 raise TypeError("view must be a callable or a list/tuple in the case of include().") 

92 

93 

94path = partial(_path, Pattern=RoutePattern) 

95re_path = partial(_path, Pattern=RegexPattern)