def url_patterns(self): # First, add our "positively" flagged URLs, where when the flag # matches the defined state, the view is served for the pattern # and not the fallback. url_patterns = [] for pattern in super(FlaggedURLResolver, self).url_patterns: # Get the fallback view, if there is one, and remove it from # the list of fallback patterns. fallback = self.fallback if isinstance(self.fallback, (list, tuple)): fallback = next( (p.callback for p in self.fallback_patterns if p.pattern.describe() == pattern.pattern.describe()), None, ) flag_decorator = flag_check(self.flag_name, self.state, fallback=fallback) route_pattern = pattern.pattern flagged_pattern = URLPattern( route_pattern, flag_decorator(pattern.callback), pattern.default_args, pattern.name, ) url_patterns.append(flagged_pattern) # Next, add "negatively" flagged URLs, where the flag does not match # the defined state, for any remaining fallback patterns that didn't # match other url patterns. described_patterns = [p.pattern.describe() for p in url_patterns] negative_patterns = (p for p in self.fallback_patterns if p.pattern.describe() not in described_patterns) for pattern in negative_patterns: flag_decorator = flag_check(self.flag_name, not self.state) route_pattern = pattern.pattern flagged_pattern = URLPattern( route_pattern, flag_decorator(pattern.callback), pattern.default_args, pattern.name, ) url_patterns.append(flagged_pattern) return url_patterns
def test_process_resolver_wraps_pattern_callbacks(wrap_fun): cb1 = Mock() pattern1 = URLPattern('', cb1) cb2 = Mock() pattern2 = URLPattern('', cb2) resolver = URLResolver(RegexPattern(r'^$'), [pattern1, pattern2]) injector = Mock() process_resolver(resolver, injector) wrap_fun.assert_has_calls([ call(cb1, injector), call(cb2, injector), ])
def _flagged_path(flag_name, route, view, kwargs=None, name=None, state=True, fallback=None, Pattern=None): """ Make a URL depend on the state of a feature flag """ if callable(view): flagged_view = flag_check(flag_name, state, fallback=fallback)(view) if Pattern: # pragma: no cover route_pattern = Pattern(route, name=name, is_endpoint=True) else: # pragma: no cover route_pattern = route return URLPattern(route_pattern, flagged_view, kwargs, name) elif isinstance(view, (list, tuple)): urlconf_module, app_name, namespace = view if Pattern: # pragma: no cover route_pattern = Pattern(route, name=name, is_endpoint=True) else: # pragma: no cover route_pattern = route return FlaggedURLResolver( flag_name, route_pattern, urlconf_module, kwargs, app_name=app_name, namespace=namespace, state=state, fallback=fallback) else: raise TypeError('view must be a callable')
def get_django_admin_dashboard_urls(site): import django_sql_dashboard.urls from django.urls.resolvers import URLPattern urlpatterns = [ URLPattern( pattern=pattern.pattern, callback=require_enabled_dashboard( site.admin_view(pattern.callback)), default_args=pattern.default_args, name=pattern.name, ) for pattern in django_sql_dashboard.urls.urlpatterns ] return (urlpatterns, "", "")
def recurse_patterns(path, pattern_list, page_id, default_args=None, nested=False): """ Recurse over a list of to-be-hooked patterns for a given path prefix """ newpatterns = [] for pattern in pattern_list: app_pat = getattr(pattern, 'pattern', pattern).regex.pattern # make sure we don't get patterns that start with more than one '^'! app_pat = app_pat.lstrip('^') path = path.lstrip('^') regex = r'^%s%s' % (path, app_pat) if not nested else r'^%s' % (app_pat) if isinstance(pattern, URLResolver): # include default_args args = pattern.default_kwargs if default_args: args.update(default_args) # see lines 243 and 236 of urlresolvers.py to understand the next line urlconf_module = recurse_patterns(regex, pattern.url_patterns, page_id, args, nested=True) # this is an 'include', recurse! regex_pattern = RegexPattern(regex) resolver = URLResolver(regex_pattern, urlconf_module, pattern.default_kwargs, pattern.app_name, pattern.namespace) else: # Re-do the URLPattern with the new regular expression args = pattern.default_args if default_args: args.update(default_args) regex_pattern = RegexPattern(regex, name=pattern.name, is_endpoint=True) resolver = URLPattern(regex_pattern, pattern.callback, args, pattern.name) resolver.page_id = page_id newpatterns.append(resolver) return newpatterns
def detype_pattern(pattern): """ return an equivalent pattern that accepts arbitrary values for path parameters. de-typing the path will ease determining a matching route without having properly formatted dummy values for all path parameters. """ if isinstance(pattern, URLResolver): return URLResolver( pattern=detype_pattern(pattern.pattern), urlconf_name=[detype_pattern(p) for p in pattern.url_patterns], default_kwargs=pattern.default_kwargs, app_name=pattern.app_name, namespace=pattern.namespace, ) elif isinstance(pattern, URLPattern): return URLPattern( pattern=detype_pattern(pattern.pattern), callback=pattern.callback, default_args=pattern.default_args, name=pattern.name, ) elif isinstance(pattern, RoutePattern): return RoutePattern( route=re.sub(r'<\w+:(\w+)>', r'<\1>', pattern._route), name=pattern.name, is_endpoint=pattern._is_endpoint ) elif isinstance(pattern, RegexPattern): detyped_regex = pattern._regex for name, regex in analyze_named_regex_pattern(pattern._regex).items(): detyped_regex = detyped_regex.replace( f'(?P<{name}>{regex})', f'(?P<{name}>[^/]+)', ) return RegexPattern( regex=detyped_regex, name=pattern.name, is_endpoint=pattern._is_endpoint ) else: warn(f'unexpected pattern "{pattern}" encountered while simplifying urlpatterns.') return pattern
def route(path: OpenAPIPath, view: ty.Callable, kwargs: ty.Optional[ty.Mapping[str, ty.Any]] = None, name: ty.Optional[str] = None) -> URLPattern: return URLPattern(PathPattern(path), view, default_args=kwargs, name=name)