diff options
-rw-r--r-- | sandbox/py-rest-doc/sphinx/environment.py | 26 | ||||
-rw-r--r-- | sandbox/py-rest-doc/sphinx/templates/not_found.html | 11 | ||||
-rw-r--r-- | sandbox/py-rest-doc/sphinx/web/application.py | 26 | ||||
-rw-r--r-- | sandbox/py-rest-doc/sphinx/web/util.py | 11 |
4 files changed, 63 insertions, 11 deletions
diff --git a/sandbox/py-rest-doc/sphinx/environment.py b/sandbox/py-rest-doc/sphinx/environment.py index 221f27822..03d2ea6fd 100644 --- a/sandbox/py-rest-doc/sphinx/environment.py +++ b/sandbox/py-rest-doc/sphinx/environment.py @@ -9,7 +9,9 @@ :license: Python license. """ +import difflib import itertools +import heapq import cPickle as pickle from os import path from string import uppercase @@ -454,6 +456,30 @@ class BuildEnvironment: if newnode: node.replace_self(newnode) + def get_close_matches(self, searchstring, n=20): + """ + Return a list of tuples in the form ``(type, filename, title)`` with + close matches for the given search string. + """ + cutoff = 0.6 + s = difflib.SequenceMatcher() + s.set_seq2(searchstring) + + possibilities = [('module', fn, title) for (title, (fn, _, _)) in + self.modules.iteritems()] + \ + [('ref', fn, title) for (title, (fn, _)) in + self.descrefs.iteritems()] + + result = [] + for type, filename, title in possibilities: + s.set_seq1(title) + if s.real_quick_ratio() >= cutoff and \ + s.quick_ratio() >= cutoff and \ + s.ratio() >= cutoff: + result.append((s.ratio(), type, filename, title)) + + return [item[1:] for item in heapq.nlargest(n, result)] + def resolve_toctrees(self, documents): # determine which files (containing a toc) must be rebuilt for each # target file (basically all "parent" files) diff --git a/sandbox/py-rest-doc/sphinx/templates/not_found.html b/sandbox/py-rest-doc/sphinx/templates/not_found.html index ccc91e154..c54cc522e 100644 --- a/sandbox/py-rest-doc/sphinx/templates/not_found.html +++ b/sandbox/py-rest-doc/sphinx/templates/not_found.html @@ -8,6 +8,17 @@ are easier to guess. Some of the old URLs still work and redirect to the new location, others do not because they were way too generic. </p> + {% if close_matches %} + <h3>Similar Pages</h3> + <p> + Here a list of {{ close_matches|length }} pages with a similar page name: + </p> + <ul> + {% for href, title in close_matches %} + <li><a href="{{ href }}">{{ title|e }}</a></li> + {% endfor %} + </ul> + {% endif %} <h3>You can</h3> <ul> <li><a href="{{ pathto("index.rst") }}">Click here</a> to go to the index.</li> diff --git a/sandbox/py-rest-doc/sphinx/web/application.py b/sandbox/py-rest-doc/sphinx/web/application.py index 81af09b9f..48f18ef49 100644 --- a/sandbox/py-rest-doc/sphinx/web/application.py +++ b/sandbox/py-rest-doc/sphinx/web/application.py @@ -100,20 +100,30 @@ class DocumentationApplication(object): Lookup close matches. If there is an exact match (for example http://docs.python.org/os.path.exists would automatically redirect to http://docs.python.org/modules/os.path/#os.path.exists. + + Module references are processed first so that "os.path" is + handled as module and not as member of os. """ + # module references + if url in self.environment.modules: + filename, title, system = self.environment.modules[url] + url = get_target_uri(filename) + return RedirectResponse(url) # direct references if url in self.environment.descrefs: filename, ref_type = self.environment.descrefs[url] url = get_target_uri(filename) + '#' + url return RedirectResponse(url) - # module references - # XXX: should those have a higher priority? - if url in self.environment.modules: - filename, title, arg = self.environment.modules[url] - url = get_target_uri(filename) - return RedirectResponse(url) - # XXX: do a difflib match test here - return Response(render_template(req, 'not_found.html'), status=404) + # get some close matches + close_matches = [] + for type, filename, title in self.environment.get_close_matches(url): + link = get_target_uri(filename) + if type == 'ref': + link += '#' + title + close_matches.append((relative_uri(url + '/', link), title)) + return Response(render_template(req, 'not_found.html', { + 'close_matches': close_matches + }), status=404) def __call__(self, environ, start_response): """ diff --git a/sandbox/py-rest-doc/sphinx/web/util.py b/sandbox/py-rest-doc/sphinx/web/util.py index c143487ba..d924d675f 100644 --- a/sandbox/py-rest-doc/sphinx/web/util.py +++ b/sandbox/py-rest-doc/sphinx/web/util.py @@ -74,7 +74,12 @@ HTTP_STATUS_CODES = { templates_path = path.join(path.dirname(__file__), '..', 'templates') jinja_env = Environment(loader=FileSystemLoader(templates_path, use_memcache=True), - friendly_traceback=False) + friendly_traceback=True) + + +def render_template(template_name, context): + tmpl = jinja_env.get_template(template_name) + return tmpl.render(context) class lazy_property(object): @@ -98,7 +103,7 @@ class lazy_property(object): class _StorageHelper(cgi.FieldStorage): """ - Helper class used by `BaseRequest` to parse submitted file and + Helper class used by `Request` to parse submitted file and form data. Don't use this class directly. """ @@ -379,7 +384,7 @@ class Headers(object): class Request(object): - charset = 'ascii' + charset = 'utf-8' def __init__(self, environ): self.environ = environ |