Coverage for /Users/davegaeddert/Development/dropseed/plain/plain/plain/urls/conf.py: 17%

42 statements  

« prev     ^ index     » next       coverage.py v7.6.1, created at 2024-10-16 22:04 -0500

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

2from functools import partial 

3 

4from plain.exceptions import ImproperlyConfigured 

5 

6from .resolvers import ( 

7 RegexPattern, 

8 RoutePattern, 

9 URLPattern, 

10 URLResolver, 

11) 

12 

13 

14def include(arg, namespace=None): 

15 default_namespace = None 

16 if isinstance(arg, tuple): 

17 # Callable returning a namespace hint. 

18 try: 

19 urlconf_module, default_namespace = arg 

20 except ValueError: 

21 if namespace: 

22 raise ImproperlyConfigured( 

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

24 "provides a namespace." 

25 ) 

26 raise ImproperlyConfigured( 

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

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

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

30 ) 

31 else: 

32 # No namespace hint - use manually provided namespace. 

33 urlconf_module = arg 

34 

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

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

37 if namespace and not default_namespace: 

38 raise ImproperlyConfigured( 

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

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

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

42 "default_namespace instead.", 

43 ) 

44 namespace = namespace or default_namespace 

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

46 # testcases will break). 

47 if isinstance(patterns, list | tuple): 

48 for url_pattern in patterns: 

49 getattr(url_pattern, "pattern", None) 

50 return (urlconf_module, default_namespace, namespace) 

51 

52 

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

54 from plain.views import View 

55 

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

57 raise TypeError( 

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

59 ) 

60 

61 if isinstance(view, list | tuple): 

62 # For include(...) processing. 

63 pattern = Pattern(route, is_endpoint=False) 

64 urlconf_module, default_namespace, namespace = view 

65 return URLResolver( 

66 pattern, 

67 urlconf_module, 

68 kwargs, 

69 default_namespace=default_namespace, 

70 namespace=namespace, 

71 ) 

72 

73 if isinstance(view, View): 

74 view_cls_name = view.__class__.__name__ 

75 raise TypeError( 

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

77 f"{view_cls_name}()." 

78 ) 

79 

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

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

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

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

84 

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

86 if callable(view): 

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

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

89 

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

91 

92 

93path = partial(_path, Pattern=RoutePattern) 

94re_path = partial(_path, Pattern=RegexPattern)