1"""Functions for use in URLsconfs."""
2
3from functools import partial
4from importlib import import_module
5
6from django.core.exceptions import ImproperlyConfigured
7
8from .resolvers import (
9 LocalePrefixPattern,
10 RegexPattern,
11 RoutePattern,
12 URLPattern,
13 URLResolver,
14)
15
16
17def include(arg, namespace=None):
18 app_name = None
19 if isinstance(arg, tuple):
20 # Callable returning a namespace hint.
21 try:
22 urlconf_module, app_name = arg
23 except ValueError:
24 if namespace:
25 raise ImproperlyConfigured(
26 "Cannot override the namespace for a dynamic module that "
27 "provides a namespace."
28 )
29 raise ImproperlyConfigured(
30 "Passing a %d-tuple to include() is not supported. Pass a "
31 "2-tuple containing the list of patterns and app_name, and "
32 "provide the namespace argument to include() instead." % len(arg)
33 )
34 else:
35 # No namespace hint - use manually provided namespace.
36 urlconf_module = arg
37
38 if isinstance(urlconf_module, str):
39 urlconf_module = import_module(urlconf_module)
40 patterns = getattr(urlconf_module, "urlpatterns", urlconf_module)
41 app_name = getattr(urlconf_module, "app_name", app_name)
42 if namespace and not app_name:
43 raise ImproperlyConfigured(
44 "Specifying a namespace in include() without providing an app_name "
45 "is not supported. Set the app_name attribute in the included "
46 "module, or pass a 2-tuple containing the list of patterns and "
47 "app_name instead.",
48 )
49 namespace = namespace or app_name
50 # Make sure the patterns can be iterated through (without this, some
51 # testcases will break).
52 if isinstance(patterns, (list, tuple)):
53 for url_pattern in patterns:
54 pattern = getattr(url_pattern, "pattern", None)
55 if isinstance(pattern, LocalePrefixPattern):
56 raise ImproperlyConfigured(
57 "Using i18n_patterns in an included URLconf is not allowed."
58 )
59 return (urlconf_module, app_name, namespace)
60
61
62def _path(route, view, kwargs=None, name=None, Pattern=None):
63 from django.views import View
64
65 if kwargs is not None and not isinstance(kwargs, dict):
66 raise TypeError(
67 f"kwargs argument must be a dict, but got {kwargs.__class__.__name__}."
68 )
69 if isinstance(view, (list, tuple)):
70 # For include(...) processing.
71 pattern = Pattern(route, is_endpoint=False)
72 urlconf_module, app_name, namespace = view
73 return URLResolver(
74 pattern,
75 urlconf_module,
76 kwargs,
77 app_name=app_name,
78 namespace=namespace,
79 )
80 elif callable(view):
81 pattern = Pattern(route, name=name, is_endpoint=True)
82 return URLPattern(pattern, view, kwargs, name)
83 elif isinstance(view, View):
84 view_cls_name = view.__class__.__name__
85 raise TypeError(
86 f"view must be a callable, pass {view_cls_name}.as_view(), not "
87 f"{view_cls_name}()."
88 )
89 else:
90 raise TypeError(
91 "view must be a callable or a list/tuple in the case of include()."
92 )
93
94
95path = partial(_path, Pattern=RoutePattern)
96re_path = partial(_path, Pattern=RegexPattern)