def resolve(self, path): path = force_text(path) tried = [] match = self.regex.search(path) if match: new_path = path[match.end():] for pattern in self.url_patterns: try: sub_match = pattern.resolve(new_path) except Resolver404 as e: sub_tried = e.args[0].get('tried') if sub_tried is not None: tried.extend([pattern] + t for t in sub_tried) else: tried.append([pattern]) else: if sub_match: sub_match_dict = dict(match.groupdict(), **self.default_kwargs) sub_match_dict.update(sub_match.kwargs) return ResolverMatch( self._decorate(sub_match.func), sub_match.args, sub_match_dict, sub_match.url_name, self.app_name or sub_match.app_name, [self.namespace] + sub_match.namespaces) tried.append([pattern]) raise Resolver404({'tried': tried, 'path': new_path}) raise Resolver404({'path': path})
def find_page_for_path(self, path): """ Resolve the path into the Page instance and return it with trailing subpage information. """ clean_path = path[:-1] # remove trailing / slugs = clean_path.split('/') if clean_path else [] ancestor_paths = [''] + [ '/'.join(slugs[:i + 1]) for i in range(len(slugs)) ] pages = self.page_model.objects.filter( path__in=ancestor_paths).order_by('-path') # Bail if we don't have a result if not pages.exists(): raise Resolver404({ 'tried': [], 'path': path }) # since we query, we don't really have a "tried" list page = pages[0] # this is our best candidate # Check which part of the url we are using used_slugs = page.path.split('/') if page.path else [] page_slug = used_slugs[-1] if used_slugs else '' subpage_slugs = slugs[len(used_slugs):] return page, page_slug, subpage_slugs
def resolve_page_id(self, path): """Resolves requested path similar way how resolve does, but instead of return callback,.. returns page_id to which was application assigned. """ tried = [] match = self.regex.search(path) if match: new_path = path[match.end():] for pattern in self.url_patterns: if isinstance(pattern, AppRegexURLResolver): try: return pattern.resolve_page_id(new_path) except Resolver404: pass else: try: sub_match = pattern.resolve(new_path) except Resolver404: exc = sys.exc_info()[0] if 'tried' in exc.args[0]: tried.extend([[pattern] + t for t in exc.args[0]['tried']]) elif 'path' in exc.args[0]: tried.extend([[pattern] + t for t in exc.args[0]['path']]) else: if sub_match: return pattern.page_id tried.append(pattern.regex.pattern) raise Resolver404({'tried': tried, 'path': new_path})
def resolve_pattern_name(self, resolver, path): tried = [] match = resolver.regex.search(path) if match: new_path = path[match.end():] for pattern in resolver.url_patterns: try: sub_match = pattern.resolve(new_path) except Resolver404, e: sub_tried = e.args[0].get('tried') if sub_tried is not None: tried.extend([(pattern.regex.pattern + \ ' ' + t) for t in sub_tried]) else: tried.append(pattern.regex.pattern) else: if sub_match: sub_match_dict = dict([(smart_str(k), v) for \ k, v in match.groupdict().items()]) sub_match_dict.update(resolver.default_kwargs) for k, v in sub_match[2].iteritems(): sub_match_dict[smart_str(k)] = v try: return pattern.name except AttributeError: return self.resolve_pattern_name(pattern, new_path) tried.append(pattern.regex.pattern) raise Resolver404({'tried': tried, 'path': new_path})
def _resolver_resolve_to_name(resolver, path): tried = [] django1 = django.VERSION < (2, 0) if django1: match = resolver.regex.search(path) else: match = resolver.pattern.regex.search(path) if match: new_path = path[match.end():] for pattern in resolver.url_patterns: try: if isinstance(pattern, RegexURLPattern): name = _pattern_resolve_to_name(pattern, new_path) elif isinstance(pattern, RegexURLResolver): name = _resolver_resolve_to_name(pattern, new_path) except Resolver404 as e: if django1: tried.extend([(pattern.regex.pattern + ' ' + t) for t in e.args[0]['tried']]) else: tried.extend([(pattern.pattern.regex.pattern + ' ' + t) for t in e.args[0]['tried']]) else: if name: return name if django1: tried.append(pattern.regex.pattern) else: tried.append(pattern.pattern.regex.pattern) raise Resolver404({'tried': tried, 'path': new_path})
def resolve_page_id(self, path): """Resolves requested path similar way how resolve does, but instead of return callback,.. returns page_id to which was application assigned. """ tried = [] match = self.regex.search(path) if match: new_path = path[match.end():] for pattern in self.url_patterns: if isinstance(pattern, AppRegexURLResolver): try: return pattern.resolve_page_id(new_path) except Resolver404: pass else: try: sub_match = pattern.resolve(new_path) except Resolver404 as e: tried_match = e.args[0].get('tried') if tried_match is not None: tried.extend([[pattern] + t for t in tried_match]) else: tried.extend([pattern]) else: if sub_match: return getattr(pattern, 'page_id', None) tried.append(pattern.regex.pattern) raise Resolver404({'tried': tried, 'path': new_path})
def resolve(self, path): from django.core.urlresolvers import Resolver404 for v in SymResolver.symdjango.viewmap: s = SymURL(SymResolver.symdjango, v) r = s.resolve(path) if r is not None: return r raise Resolver404({'path': path})
def resolve(self, *args, **kwargs): result = super(ModuleURLResolver, self).resolve(*args, **kwargs) if result and not getattr(self._module, 'installed', True): raise Resolver404({'message': 'Module not installed'}) result.kwargs['module'] = self._module return result
def resolve(self, path): """ Match path to Page object and return its registered view """ # Clean up and check path path = force_text(path) # path may be a reverse_lazy object if path and not path.endswith('/'): # If we don't have a / at the end, we bail. If APPEND_SLASH is set, # this will redirect it to the view with a / raise Resolver404({'tried': [], 'path': path}) # Get the associated page page, page_slug, subpage_slugs = self.find_page_for_path(path) # Fetch the View class view_class = page.view_class # The view specifies if it allows subpages. We raise Resolver404 to # allow other patterns below this one in the urlconf if not view_class.allows_subpages and subpage_slugs: raise Resolver404({'tried': [], 'path': path}) # If we have an ApplicationView, we need to go deeper if issubclass(view_class, ApplicationView): resolver = self.get_subresolver(view_class, page.path) try: return resolver.resolve(path) except Resolver404 as e: # Add PageResolver as base to the tried patterns sub_tried = e.args[0].get('tried') or [] raise Resolver404({ 'path': path, 'tried': [[resolver] + t for t in sub_tried] }) else: kwargs = { 'page': page, 'slug': page_slug, 'subpage_slugs': subpage_slugs, } return ResolverMatch(view_class.as_view(), [], kwargs, app_name=self.app_name, namespaces=[self.namespace])
def resolve(self, path): func = APP2URL.get(self.app_name, self.empty_dict).get(path, None) if func: return ResolverMatch(func, (), {}, path) else: tried = [] for app, url2func in APP2URL.items(): for url, func in url2func.items(): tried.append([{'regex':{'pattern': '^{}:{}'.format(app, url)}}]) raise Resolver404({'tried': tried, 'path' : path})
def resolve(self, *args, **kwargs): # noqa D102 result = super(ModuleURLResolver, self).resolve(*args, **kwargs) if result and not getattr(self._module, 'installed', True): raise Resolver404({'message': 'Module not installed'}) result.url_name = ModuleMatchName(result.url_name) result.url_name.module = self._module return result
def resolve(self, path): ''' this is rewritten from django.core.urlresolvers because playing with URL patterns and resolvers in Django<=1.4 is weird. Probably because of the recursion. Really! Try it yourself. FIXME: As of Django 1.4 this shouldn't be necessary! ''' tried = [] match = self.regex.search(path) if match: new_path = path[match.end():] for pattern in self.url_patterns: try: sub_match = pattern.resolve(new_path) except Resolver404 as e: sub_tried = e.args[0].get('tried') if sub_tried is not None: tried.extend([[pattern] + t for t in sub_tried]) else: tried.append([pattern]) else: if sub_match: sub_match_dict = dict([ (smart_str(k), v) for k, v in match.groupdict().items() ]) sub_match_dict.update(self.default_kwargs) for k, v in sub_match.kwargs.items(): sub_match_dict[smart_str(k)] = v res_match = ResolverMatch( sub_match.func, sub_match.args, sub_match_dict, sub_match.url_name, self.app_name or sub_match.app_name, [self.namespace] + sub_match.namespaces) res_match.breadcrumb_verbose_name = getattr( sub_match, 'breadcrumb_verbose_name', None) return res_match tried.append([pattern]) raise Resolver404({'tried': tried, 'path': new_path}) raise Resolver404({'path': path})
def __raise_404(self, path): tried = [] valid_methods = self.valid_methods if len(resource_util.APPRESOURCE2CLASS) > 0: for app_resource, class_info in resource_util.APPRESOURCE2CLASS.items(): for key, value in class_info['cls'].__dict__.items(): if not key in valid_methods: continue tried.append([{'regex':{'pattern': '^{}:{}'.format(app_resource, key)}}]) else: tried.append([{'regex':{'pattern': 'None'}}]) raise Resolver404({'tried': tried, 'path' : path})
def test_handler404(self): # import the root urlconf like django does when it starts up root_urlconf = __import__(settings.ROOT_URLCONF, globals(), locals(), ['urls'], -1) # ...so that we can access the 'handler404' defined in there par, end = root_urlconf.handler404.rsplit('.', 1) # ...which is an importable reference to the real handler404 function views = __import__(par, globals(), locals(), [end], -1) # ...and finally we the handler404 function at hand handler404 = getattr(views, end) # to call this view function we need a mock request object fake_request = RequestFactory().request(**{'wsgi.input': None}) # the reason for first causing an exception to be raised is because # the handler404 function is only called by django when an exception # has been raised which means sys.exc_info() is something. try: raise Http404("something bad") except Http404: # mock the django_arecibo wrapper so it doesn't actually # call out on the network with patch('django_arecibo.wrapper') as m: # do this inside a frame that has a sys.exc_info() response = handler404(fake_request) eq_(response.status_code, 404) ok_('Page not found' in response.content) eq_(m.post.call_count, 1) try: # raise an error but this time withou a message raise Http404 except Http404: with patch('django_arecibo.wrapper') as m: response = handler404(fake_request) eq_(response.status_code, 404) ok_('Page not found' in response.content) eq_(m.post.call_count, 1) try: # Resolver404 is a subclass of Http404 that is raised by django # when it can't match a URL to a view raise Resolver404("/never/heard/of/") except Resolver404: with patch('django_arecibo.wrapper') as m: response = handler404(fake_request) eq_(response.status_code, 404) ok_('Page not found' in response.content) eq_(m.post.call_count, 0)
def process_response(self, request, response): url = request.path try: app_name = resolve(url).app_name app_ignored = app_name in TERMS_IGNORED_APPS except Resolver404: if TERMS_DEBUG: raise Resolver404("Could not find whether the application of " "'%s' is in TERMS_IGNORED_APPS" % url) app_ignored = True is_html = 'text/html' in response['Content-Type'] if not app_ignored and is_html and response.status_code == 200: response.content = replace_terms(response.content) return response
def resolve(self, path): self.regex.pattern = '{}/{}'.format(self.app_dir, path) if not self.is_func_loaded: self.__load_api_func() func = self.__get_api_func(path) if func: return ResolverMatch(func, (), {}, path) else: if self.__should_update_loaded_files(): self.is_func_loaded = False self.loaded_file_set = None self.name2func = {} return self.resolve(path) else: tried = [] for key in self.name2func: tried.append([{'regex': {'pattern': '^{}/$'.format(key)}}]) raise Resolver404({'tried': tried, 'path': path})
def _resolver_resolve_to_name(resolver, path): tried = [] match = resolver.pattern.regex.search(path) if match: new_path = path[match.end():] for pattern in resolver.url_patterns: try: if isinstance(pattern, URLPattern): name = _pattern_resolve_to_name(pattern, new_path) elif isinstance(pattern, URLResolver): name = _resolver_resolve_to_name(pattern, new_path) except Resolver404 as e: tried.extend([ "{} {}".format(pattern.pattern, t) for t in e.args[0]['tried'] ]) else: if name: return name tried.append(pattern.pattern) raise Resolver404({'tried': tried, 'path': new_path})
def get_via_uri(self, uri, request=None): prefix = get_script_prefix() chomped_uri = uri if prefix and chomped_uri.startswith(prefix): chomped_uri = chomped_uri[len(prefix) - 1:] split_chomped_uri_words = chomped_uri.split('/') found_at = 0 for word in split_chomped_uri_words: found_at = found_at + len(word) if word == self._meta.resource_name: break if found_at == len(chomped_uri): raise NotFound( "An incorrect URL was provided '%s' for the '%s' resource." % (uri, self.__class__.__name__)) chomped_uri = chomped_uri[found_at - 1:] try: for url_resolver in getattr(self, 'urls', []): result = url_resolver.resolve(chomped_uri) if result is not None: view, args, kwargs = result break else: raise Resolver404("URI not found in 'self.urls'.") except Resolver404: raise NotFound( "The URL provided '%s' was not a link to a valid resource." % uri) bundle = self.build_bundle(request=request) return self.obj_get(bundle=bundle, **self.remove_api_resource_names(kwargs))
def __raise_404(path, app_resource, method): tried = [] tried.append([{ 'regex': { 'pattern': 'target: path="{}", resource="{}:{}"'.format( path, app_resource, method) } }]) if len(resource_util.APPRESOURCE2CLASS) > 0: for app_resource, class_info in resource_util.APPRESOURCE2CLASS.items( ): for key, value in class_info['cls'].__dict__.items(): if not key in VALID_METHODS: continue tried.append([{ 'regex': { 'pattern': '^{}:{}'.format(app_resource, key) } }]) else: tried.append([{'regex': {'pattern': 'None'}}]) raise Resolver404({'tried': tried, 'path': path})
def process(self, request, **kw): page_url = self.parent.get_absolute_url() if "path_mapper" in self.app_config: path_mapper = get_object(self.app_config["path_mapper"]) path, page_url = path_mapper( request.path, page_url, appcontent_parameters=self.parameters ) else: path = request._feincms_extra_context['extra_path'] # Resolve the module holding the application urls. urlconf_path = self.app_config.get('urls', self.urlconf_path) try: fn, args, kwargs = resolve(path, urlconf_path) except (ValueError, Resolver404): raise Resolver404(str('Not found (resolving %r in %r failed)') % ( path, urlconf_path)) # Variables from the ApplicationContent parameters are added to request # so we can expose them to our templates via the appcontent_parameters # context_processor request._feincms_extra_context.update(self.parameters) request._feincms_extra_context.update({'widget': self}) # Save the application configuration for reuse elsewhere request._feincms_extra_context.update({ 'app_config': dict( self.app_config, urlconf_path=self.urlconf_path, ), }) view_wrapper = self.app_config.get("view_wrapper", None) if view_wrapper: fn = partial( get_object(view_wrapper), view=fn, appcontent_parameters=self.parameters ) output = fn(request, *args, **kwargs) # handle django rest framework as external application if hasattr(output, 'renderer_context'): output.context_data = output.renderer_context output.standalone = True if isinstance(output, HttpResponse): # update context if hasattr(output, 'context_data'): output.context_data['widget'] = self else: output.context_data = {'widget': self} if self.send_directly(request, output): return output elif output.status_code == 200: if self.unpack(request, output) and 'view' in kw: # Handling of @unpack and UnpackTemplateResponse kw['view'].template_name = output.template_name kw['view'].request._feincms_extra_context.update( output.context_data) else: # If the response supports deferred rendering, render the # response right now. We do not handle template response # middleware. if hasattr(output, 'render') and callable(output.render): output.render() self.rendered_result = mark_safe( output.content.decode('utf-8')) self.rendered_headers = {} # Copy relevant headers for later perusal for h in ('Cache-Control', 'Last-Modified', 'Expires'): if h in output: self.rendered_headers.setdefault( h, []).append(output[h]) elif isinstance(output, tuple) and 'view' in kw: kw['view'].template_name = output[0] kw['view'].request._feincms_extra_context.update(output[1]) # our hack # no template and view change and save content for our widget context = output[1] context['widget'] = self self.rendered_result = render_to_string( output[0], RequestContext(request, context)) else: self.rendered_result = mark_safe(output) # here is the magic ! # return renderered parent template ! context = RequestContext(request, {}) return render_to_response( self.parent.theme.template, context )
def process(self, request, **kw): page_url = self.parent.get_absolute_url() # Provide a way for appcontent items to customize URL processing by # altering the perceived path of the page: if "path_mapper" in self.app_config: path_mapper = get_object(self.app_config["path_mapper"]) path, page_url = path_mapper(request.path, page_url, appcontent_parameters=self.parameters) else: path = request._feincms_extra_context['extra_path'] # Resolve the module holding the application urls. urlconf_path = self.app_config.get('urls', self.urlconf_path) try: fn, args, kwargs = resolve(path, urlconf_path) except (ValueError, Resolver404): raise Resolver404( str('Not found (resolving %r in %r failed)') % (path, urlconf_path)) # Variables from the ApplicationContent parameters are added to request # so we can expose them to our templates via the appcontent_parameters # context_processor request._feincms_extra_context.update(self.parameters) # Save the application configuration for reuse elsewhere request._feincms_extra_context.update({ 'app_config': dict( self.app_config, urlconf_path=self.urlconf_path, ), }) view_wrapper = self.app_config.get("view_wrapper", None) if view_wrapper: fn = partial(get_object(view_wrapper), view=fn, appcontent_parameters=self.parameters) output = fn(request, *args, **kwargs) if isinstance(output, HttpResponse): if self.send_directly(request, output): return output elif output.status_code == 200: # If the response supports deferred rendering, render the # response right now. We do not handle template response # middleware. if hasattr(output, 'render') and callable(output.render): output.render() self.rendered_result = mark_safe( output.content.decode('utf-8')) self.rendered_headers = {} # Copy relevant headers for later perusal for h in ('Cache-Control', 'Last-Modified', 'Expires'): if h in output: self.rendered_headers.setdefault(h, []).append(output[h]) elif isinstance(output, tuple) and 'view' in kw: kw['view'].template_name = output[0] kw['view'].request._feincms_extra_context.update(output[1]) else: self.rendered_result = mark_safe(output) return True # successful
def test_returns_nothing_with_error(self, mock): """Test that when a resolve fails an empty context is returned""" mock.side_effect = Resolver404() context = add_active_url_name(self.request) self.assertNotIn('active_url_name', context) self.assertNotIn('app_name', context)