comparison piecrust/serving/server.py @ 517:c7e8b4a5afe3

serve: Improve error reporting when pages are not found.
author Ludovic Chabant <ludovic@chabant.com>
date Mon, 27 Jul 2015 00:48:19 -0700
parents 16e705c58cae
children bab91fcef741
comparison
equal deleted inserted replaced
516:73bd408caebc 517:c7e8b4a5afe3
51 51
52 def __call__(self, environ, start_response): 52 def __call__(self, environ, start_response):
53 return self.server._run_request(environ, start_response) 53 return self.server._run_request(environ, start_response)
54 54
55 55
56 class MultipleNotFound(HTTPException):
57 code = 404
58
59 def __init__(self, description, nfes):
60 super(MultipleNotFound, self).__init__(description)
61 self._nfes = nfes
62
63 def get_description(self, environ=None):
64 from werkzeug.utils import escape
65 desc = '<p>' + self.description + '</p>'
66 desc += '<p>'
67 for nfe in self._nfes:
68 desc += '<li>' + escape(nfe.description) + '</li>'
69 desc += '</p>'
70 return desc
71
72
56 class Server(object): 73 class Server(object):
57 def __init__(self, root_dir, 74 def __init__(self, root_dir,
58 debug=False, sub_cache_dir=None, enable_debug_info=True, 75 debug=False, sub_cache_dir=None, enable_debug_info=True,
59 static_preview=True, run_sse_check=None): 76 static_preview=True, run_sse_check=None):
60 self.root_dir = root_dir 77 self.root_dir = root_dir
94 def _run_request(self, environ, start_response): 111 def _run_request(self, environ, start_response):
95 try: 112 try:
96 return self._try_run_request(environ, start_response) 113 return self._try_run_request(environ, start_response)
97 except Exception as ex: 114 except Exception as ex:
98 if self.debug: 115 if self.debug:
99 if isinstance(ex, HTTPException):
100 return ex
101 raise 116 raise
102 return self._handle_error(ex, environ, start_response) 117 return self._handle_error(ex, environ, start_response)
103 118
104 def _try_run_request(self, environ, start_response): 119 def _try_run_request(self, environ, start_response):
105 request = Request(environ) 120 request = Request(environ)
143 # Nope. Let's see if it's an actual page. 158 # Nope. Let's see if it's an actual page.
144 try: 159 try:
145 response = self._try_serve_page(app, environ, request) 160 response = self._try_serve_page(app, environ, request)
146 return response(environ, start_response) 161 return response(environ, start_response)
147 except (RouteNotFoundError, SourceNotFoundError) as ex: 162 except (RouteNotFoundError, SourceNotFoundError) as ex:
148 raise NotFound(str(ex)) from ex 163 raise NotFound() from ex
149 except HTTPException: 164 except HTTPException:
150 raise 165 raise
151 except Exception as ex: 166 except Exception as ex:
152 if app.debug: 167 if app.debug:
153 logger.exception(ex) 168 logger.exception(ex)
222 routes = find_routes(app.routes, req_path) 237 routes = find_routes(app.routes, req_path)
223 if len(routes) == 0: 238 if len(routes) == 0:
224 raise RouteNotFoundError("Can't find route for: %s" % req_path) 239 raise RouteNotFoundError("Can't find route for: %s" % req_path)
225 240
226 rendered_page = None 241 rendered_page = None
227 first_not_found = None 242 not_found_errors = []
228 for route, route_metadata in routes: 243 for route, route_metadata in routes:
229 try: 244 try:
230 logger.debug("Trying to render match from source '%s'." % 245 logger.debug("Trying to render match from source '%s'." %
231 route.source_name) 246 route.source_name)
232 rendered_page = self._try_render_page( 247 rendered_page = self._try_render_page(
233 app, route, route_metadata, page_num, req_path) 248 app, route, route_metadata, page_num, req_path)
234 if rendered_page is not None: 249 if rendered_page is not None:
235 break 250 break
236 except NotFound as nfe: 251 except NotFound as nfe:
237 if first_not_found is None: 252 not_found_errors.append(nfe)
238 first_not_found = nfe
239 else:
240 raise SourceNotFoundError(
241 "Can't find path for: %s (looked in: %s)" %
242 (req_path, [r.source_name for r, _ in routes]))
243 253
244 # If we haven't found any good match, raise whatever exception we 254 # If we haven't found any good match, raise whatever exception we
245 # first got. Otherwise, raise a generic exception. 255 # first got. Otherwise, raise a generic exception.
246 if rendered_page is None: 256 if rendered_page is None:
247 first_not_found = first_not_found or NotFound( 257 msg = ("Can't find path for '%s', looked in sources: %s" %
248 "This page couldn't be found.") 258 (req_path,
249 raise first_not_found 259 ', '.join([r.source_name for r, _ in routes])))
260 raise MultipleNotFound(msg, not_found_errors)
250 261
251 # Start doing stuff. 262 # Start doing stuff.
252 page = rendered_page.page 263 page = rendered_page.page
253 rp_content = rendered_page.content 264 rp_content = rendered_page.content
254 265
312 taxonomy_info = None 323 taxonomy_info = None
313 source = app.getSource(route.source_name) 324 source = app.getSource(route.source_name)
314 if route.taxonomy_name is None: 325 if route.taxonomy_name is None:
315 factory = source.findPageFactory(route_metadata, MODE_PARSING) 326 factory = source.findPageFactory(route_metadata, MODE_PARSING)
316 if factory is None: 327 if factory is None:
317 return None 328 raise NotFound("No path found for '%s' in source '%s'." %
329 (req_path, source.name))
318 else: 330 else:
319 taxonomy = app.getTaxonomy(route.taxonomy_name) 331 taxonomy = app.getTaxonomy(route.taxonomy_name)
320 route_terms = route_metadata.get(taxonomy.term_name)
321 if route_terms is None:
322 return None
323
324 tax_terms = route.getTaxonomyTerms(route_metadata) 332 tax_terms = route.getTaxonomyTerms(route_metadata)
325 taxonomy_info = (taxonomy, tax_terms) 333 taxonomy_info = (taxonomy, tax_terms)
326 334
327 tax_page_ref = taxonomy.getPageRef(source) 335 tax_page_ref = taxonomy.getPageRef(source)
328 factory = tax_page_ref.getFactory() 336 factory = tax_page_ref.getFactory()
399 code = 500 407 code = 500
400 if isinstance(exception, HTTPException): 408 if isinstance(exception, HTTPException):
401 code = exception.code 409 code = exception.code
402 410
403 path = 'error' 411 path = 'error'
404 if isinstance(exception, NotFound): 412 if isinstance(exception, (NotFound, MultipleNotFound)):
405 path += '404' 413 path += '404'
406 414
407 descriptions = self._get_exception_descriptions(exception) 415 descriptions = self._get_exception_descriptions(exception)
408 416
409 env = Environment(loader=ErrorMessageLoader()) 417 env = Environment(loader=ErrorMessageLoader())
414 return response(environ, start_response) 422 return response(environ, start_response)
415 423
416 def _get_exception_descriptions(self, exception): 424 def _get_exception_descriptions(self, exception):
417 desc = [] 425 desc = []
418 while exception is not None: 426 while exception is not None:
419 if isinstance(exception, HTTPException): 427 if isinstance(exception, MultipleNotFound):
428 desc += [e.description for e in exception._nfes]
429 elif isinstance(exception, HTTPException):
420 desc.append(exception.description) 430 desc.append(exception.description)
421 else: 431 else:
422 desc.append(str(exception)) 432 desc.append(str(exception))
423 433
424 inner_ex = exception.__cause__ 434 inner_ex = exception.__cause__