summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sandbox/py-rest-doc/sphinx/environment.py26
-rw-r--r--sandbox/py-rest-doc/sphinx/templates/not_found.html11
-rw-r--r--sandbox/py-rest-doc/sphinx/web/application.py26
-rw-r--r--sandbox/py-rest-doc/sphinx/web/util.py11
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