Commits

Anonymous committed f43a59c Merge

Add file serving middle ware and better OpenID handling

  • Participants
  • Parent commits 8fa7239, 0aec415

Comments (0)

Files changed (13)

 62a2a4c22b6ebb89e1277c6f29ba8ce9f0d43edd 0.6b1
 24762d857a192097f813818c4ff462f3bb32015f 0.5.2
 20f4a9ab90daee8523e00476a5a222d3a2bfea15 0.6
-4d927a5c58ea0833953871811f3c683e37a329cf 0.6.1
-4d927a5c58ea0833953871811f3c683e37a329cf 0.6.1
 fd52839b069b7127862811d105e0469b1a0c6608 0.6.1
+4be5ab5141779a1193b4f4b98c13700bd39d1a8c 0.6.2
 * Added simplified Chinese locale.
 
 
-Release 0.6.2 (in development)
+Release 0.6.3 (in development)
 ==============================
 
+Release 0.6.2 (Jun 16, 2009)
+============================
+
+* #130: Fix obscure IndexError in doctest extension.
+
 * #167: Make glossary sorting case-independent.
 
 * #196: Add a warning if an extension module doesn't have a

File sphinx/__init__.py

File contents unchanged.

File sphinx/application.py

 from sphinx.builders import BUILTIN_BUILDERS
 from sphinx.directives import GenericDesc, Target, additional_xref_types
 from sphinx.environment import SphinxStandaloneReader
+from sphinx.util import pycompat
 from sphinx.util.tags import Tags
 from sphinx.util.compat import Directive, directive_dwim
 from sphinx.util.console import bold

File sphinx/builders/webapp/templates/html/openid.html

+<div id="OpenIdLogin">
+{% if not openid_url %}
+  <h3>OpenID login:</h3>
+  <form name="fopenid" action="/oid/" method="get">
+    <input type="text" name="openid_url" maxlength="255" value="Your OpenID URL" onfocus="if(this.value=='Your OpenID URL'){this.value='';}; $(this).addClass('normaltext');" size="18" />
+    <input type="submit" value="Go" />
+  </form>
+  {% else %}
+  Logged-in as <b>{{ openid_url }}</b>.
+{% endif %}
+</div>

File sphinx/builders/webapp/templates/server.py

 from wsgiref import simple_server
 from sphinx.web.middleware.OpenId import OpenIDWrapper
 from sphinx.web.middleware.Xapian import XapianSearch
-from paste.urlparser import StaticURLParser
+from sphinx.web.middleware.appserver import AppServer
 from webob import Request
 
 def main():
     host, port = '127.0.0.1', 8000
-    app = StaticURLParser('public/')
+    app = AppServer('public/')
     app = OpenIDWrapper(app)
     app = XapianSearch(app)
     httpd = simple_server.WSGIServer((host, port),

File sphinx/builders/webapp/webapp.py

         Copy the files (defined in 'files' tuple) from sphinx/webapp/templates/
         to self.outdir.
         """
-        files = ('server.py', )
+        files = ('server.py', 'html/openid.html')
         templates_dir = path.join(path.dirname(__file__), 'templates')
         os.mkdir(path.join(self.outdir, 'html'))
         for f in files:

File sphinx/ext/doctest.py

         out(io.getvalue())
         return res
 
+    def _DocTestRunner__patched_linecache_getlines(self, filename,
+                                                   module_globals=None):
+        # this is overridden from DocTestRunner adding the try-except below
+        m = self._DocTestRunner__LINECACHE_FILENAME_RE.match(filename)
+        if m and m.group('name') == self.test.name:
+            try:
+                example = self.test.examples[int(m.group('examplenum'))]
+            # because we compile multiple doctest blocks with the same name
+            # (viz. the group name) this might, for outer stack frames in a
+            # traceback, get the wrong test which might not have enough examples
+            except IndexError:
+                pass
+            else:
+                return example.source.splitlines(True)
+        return self.save_linecache_getlines(filename, module_globals)
+
+
 # the new builder -- use sphinx-build.py -b doctest to run
 
 class DocTestBuilder(Builder):
 
     def test_group(self, group, filename):
         ns = {}
-        examples = []
+        setup_examples = []
         for setup in group.setup:
-            examples.append(doctest.Example(setup.code, '',
-                                            lineno=setup.lineno))
-        if examples:
+            setup_examples.append(doctest.Example(setup.code, '',
+                                                  lineno=setup.lineno))
+        if setup_examples:
             # simulate a doctest with the setup code
-            setup_doctest = doctest.DocTest(examples, {},
+            setup_doctest = doctest.DocTest(setup_examples, {},
                                             '%s (setup code)' % group.name,
                                             filename, 0, None)
             setup_doctest.globs = ns
                 return
         for code in group.tests:
             if len(code) == 1:
-                test = parser.get_doctest(code[0].code, {},
-                                          group.name, filename, code[0].lineno)
+                # ordinary doctests (code/output interleaved)
+                test = parser.get_doctest(code[0].code, {}, group.name,
+                                          filename, code[0].lineno)
                 if not test.examples:
                     continue
                 for example in test.examples:
                     new_opt = code[0].options.copy()
                     new_opt.update(example.options)
                     example.options = new_opt
-                self.type = 'single' # ordinary doctests
+                self.type = 'single' # as for ordinary doctests
             else:
+                # testcode and output separate
                 output = code[1] and code[1].code or ''
                 options = code[1] and code[1].options or {}
                 # disable <BLANKLINE> processing as it is not needed

File sphinx/themes/basic/layout.html

             </form>
           </div>
           {%- endblock %}
-          {%- block openid %}
-          <div id="OpenIdLogin">
-          <h3>{{ _('OpenID login:') }}</h3>
-          <form name="fopenid" action="/oid/" method="get">
-            <input type="text" name="openid_url" maxlength="255" value="Your OpenID URL" onfocus="if(this.value=='Your OpenID URL'){this.value='';}; $(this).addClass('normaltext');" size="18" />
-            <!--<input name="bsignin" type="submit" value="&raquo;" style="display: none;" />-->
-            <input type="submit" value="{{ _('Go') }}" />
-          </form>
-          </div>
-          {%- endblock %}
+          {%- block openid_login %}
+          {% raw %}
+          {{ openid_html }}
+          {% endraw %}
+          {% endblock %}
         </div>
       </div>
       {%- endif %}{% endif %}
     <title>{{ title|striptags }}{{ titlesuffix }}</title>
     <link rel="stylesheet" href="{{ pathto('_static/' + style, 1) }}" type="text/css" />
     <link rel="stylesheet" href="{{ pathto('_static/pygments.css', 1) }}" type="text/css" />
-<<<<<<< local
-    <script language="javascript" type="text/javascript" src="http://code.jquery.com/jquery-latest.js"></script>
-    <script language="javascript" type="text/javascript" src="_static/comments.js"></script>
-=======
-    {%- for cssfile in css_files %}
-    <link rel="stylesheet" href="{{ pathto('_static/' + cssfile, 1) }}" type="text/css" />
-    {%- endfor %}
->>>>>>> other
     {%- if not embedded %}
     <script type="text/javascript">
       var DOCUMENTATION_OPTIONS = {

File sphinx/util/pycompat.py

+# -*- coding: utf-8 -*-
+"""
+    sphinx.util.pycompat
+    ~~~~~~~~~~~~~~~~~~~~
+
+    Stuff for Python version compatibility.
+
+    :copyright: Copyright 2007-2009 by the Sphinx team, see AUTHORS.
+    :license: BSD, see LICENSE for details.
+"""
+
+import sys
+import codecs
+import encodings
+
+if sys.version_info < (2, 5):
+    # Python 2.4 doesn't know the utf-8-sig encoding, so deliver it here
+
+    def my_search_function(encoding):
+        norm_encoding = encodings.normalize_encoding(encoding)
+        if norm_encoding != 'utf_8_sig':
+            return None
+        return (encode, decode, StreamReader, StreamWriter)
+
+    codecs.register(my_search_function)
+
+    # begin code copied from utf_8_sig.py in Python 2.6
+
+    def encode(input, errors='strict'):
+        return (codecs.BOM_UTF8 + codecs.utf_8_encode(input, errors)[0], len(input))
+
+    def decode(input, errors='strict'):
+        prefix = 0
+        if input[:3] == codecs.BOM_UTF8:
+            input = input[3:]
+            prefix = 3
+        (output, consumed) = codecs.utf_8_decode(input, errors, True)
+        return (output, consumed+prefix)
+
+    class StreamWriter(codecs.StreamWriter):
+        def reset(self):
+            codecs.StreamWriter.reset(self)
+            try:
+                del self.encode
+            except AttributeError:
+                pass
+
+        def encode(self, input, errors='strict'):
+            self.encode = codecs.utf_8_encode
+            return encode(input, errors)
+
+    class StreamReader(codecs.StreamReader):
+        def reset(self):
+            codecs.StreamReader.reset(self)
+            try:
+                del self.decode
+            except AttributeError:
+                pass
+
+        def decode(self, input, errors='strict'):
+            if len(input) < 3:
+                if codecs.BOM_UTF8.startswith(input):
+                    # not enough data to decide if this is a BOM
+                    # => try again on the next call
+                    return (u"", 0)
+            elif input[:3] == codecs.BOM_UTF8:
+                self.decode = codecs.utf_8_decode
+                (output, consumed) = codecs.utf_8_decode(input[3:],errors)
+                return (output, consumed+3)
+            # (else) no BOM present
+            self.decode = codecs.utf_8_decode
+            return codecs.utf_8_decode(input, errors)
+
+    # end code copied from utf_8_sig.py

File sphinx/web/middleware/OpenId.py

 #!/usr/bin/env python
 # -*- coding: utf-8 -*-
+"""
+    sphinx.web.middleware.OpenId
+    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+    A middleware for OpenID logging.
+
+    :copyright: Copyright 2007-2009 by the Sphinx team, see AUTHORS.
+    :license: BSD, see LICENSE for details.
+"""
 
 import re
+import locale
 import urlparse
+
+from jinja2 import Environment, FileSystemLoader
 from openid.store import filestore
 from openid.consumer import consumer
 from openid.oidutil import appendArgs
 from webob import Request, Response
 from webob.exc import HTTPTemporaryRedirect
- 
+
 def get_consumer(session, store):
     """Create a Consumer object to perform OpenID authentication."""
     return consumer.Consumer(session, store)
 class OpenIDWrapper(object):
     def __init__(self, app):
         self.app = app
+        self.env = None
         self.store = filestore.FileOpenIDStore('./openidstore')
         self.session = {}
         self.oid_url = None
         self.oid_username = None
-        self.logged_in = False
+        self.init_templates()
 
     def __call__(self, environ, start_response):
+        environ['webapp.OPENID_URL'] = self.oid_url
+        req = Request(environ)
+        self.trust_root = req.host_url # base url
+        self.referer = '/'
+
+        # OpenID logging
+        if req.path == '/oid/':
+            resp = self.doVerify(environ, start_response)
+        elif req.path == '/process':
+            resp, self.logged_in = self.doProcess(environ, start_response)
+        # Regular HTML file
+        elif req.path.endswith('.html') or req.path == '/':
+            resp = self.doHTMLFile(environ, start_response)
+        # non-HTML files
+        else:
+            req = Request(environ)
+            resp = req.get_response(self.app)
+        return resp(environ, start_response)
+
+    def doVerify(self, environ, start_response): #req, resp):
+        """Initiate OpenId verification"""
         req = Request(environ)
         r = Response(content_type='text/html', charset='utf8')
         resp = req.get_response(r)
-        self.referer = '/'
-        self.trust_root = req.host_url # base url
+        user_url = req.GET['openid_url']
+        self.c = get_consumer(self.session, self.store)
 
-        if req.path == '/oid/':
-            resp = self.doVerify(req, resp)
-        elif req.path == '/process':
-            resp = self.doProcess(req, resp)
-        else:
-            # show static page
-            return self.app(environ, start_response)
-        return resp(environ, start_response)
-
-    def doVerify(self, req, resp):
-        """Initiate OpenId verification"""
-
-        user_url = req.GET['openid_url']
-        resp.charset = 'utf8'
-        resp.status_int = 200
-        self.c = get_consumer(self.session, self.store)
         try:
             auth_request = self.c.begin(user_url)
         except DiscoveryFailure, e:
 
         if auth_request.shouldSendRedirect():
             url = auth_request.redirectURL(self.trust_root, return_to)
-            print url, type(url), dir(url)
             exc = HTTPTemporaryRedirect(location=url)
             resp = req.get_response(exc)
         else:
             resp.body = form_html
         return resp
 
-    def doProcess(self, req, resp):
+    def doProcess(self, environ, start_response):
         """Handle the redirect from the OpenId server"""
+        req = Request(environ)
+        r = Response(content_type='text/html', charset='utf8')
+        resp = req.get_response(r)
+
         self.c = get_consumer(self.session, self.store)
         request_args = dict(req.GET)
         return_to = build_URL(self.trust_root, req.path_qs)
         response = self.c.complete(request_args, return_to)
-        identifier = response.getDisplayIdentifier()
-            
-        # Map different consumer status codes to template contexts.
+ 
         results = {
-           consumer.CANCEL:
-           {'message': 'OpenID authentication cancelled.'},
-
-           consumer.FAILURE:
-           {'error': 'OpenID authentication failed.'},
-
-           consumer.SUCCESS:
-           {'url': response.getDisplayIdentifier(), }
+           consumer.CANCEL:  'OpenID authentication cancelled.',
+           consumer.FAILURE: 'OpenID authentication failed.',
+           consumer.SUCCESS: response.getDisplayIdentifier(),
         }
 
         result = results[response.status]
+        # XXX: after logging-in we go to '/index.html' (self.referer),
+        # but we should rather go back to the site from which we were logging in
+        exc = HTTPTemporaryRedirect(location=self.referer)
+        resp = req.get_response(exc)
 
         if response.status == consumer.SUCCESS:
-            self.oid_url = result['url']
+            self.oid_url = result
             user_re = re.compile('http\:\/\/(\w+?)\.')
             self.oid_username = re.match(user_re, self.oid_url).groups()[0]
-            # at the moment, even if you logged in, the form for logging
-            # in will be visible on the page
-            self.logged_in = True
-        else:
-            self.logged_in = False
-            
-        exc = HTTPTemporaryRedirect(location=self.referer)
-        return req.get_response(exc)
+        return resp, self.oid_url
+
+    def doHTMLFile(self, environ, start_response):
+        req = Request(environ)
+        resp = req.get_response(self.app)
+        resp.charset = 'utf8'
+        openid_template = self.env.get_template('openid.html')
+        openid_html = openid_template.render({ 'openid_url': self.oid_url })
+        html_code = unicode(resp.body, locale.getpreferredencoding(), 'replace')
+        rendered = self.env.from_string(html_code).render(
+                                    {'openid_html': openid_html.encode('utf8')})
+        resp.body = rendered.encode('utf8')
+        return resp
+
+    def init_templates(self):
+        self.env = Environment(loader=FileSystemLoader('html/'),
+                               extensions=['jinja2.ext.i18n'])

File sphinx/web/middleware/Xapian.py

 #!/usr/bin/env python
 # -*- coding: utf-8 -*-
 """
-    sphinx.web.middleware.xapian
+    sphinx.web.middleware.Xapian
     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
     A middleware for Xapian search engine.

File sphinx/web/middleware/appserver.py

+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+    sphinx.web.middleware.appserver
+    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+    A middleware for Xapian search engine.
+
+    :copyright: Copyright 2007-2009 by the Sphinx team, see AUTHORS.
+    :license: BSD, see LICENSE for details.
+"""
+
+from webob import Request, Response
+from os import path
+import os
+
+class AppServer(object):
+    def __init__(self, www_dir):
+        self.www_dir = www_dir
+
+    def __call__(self, environ, start_response):
+        req = Request(environ)
+        resp = Response(content_type='text/html', charset='utf8')
+        resp.status = 404
+
+        if req.path == '/':
+            rel_file = 'index.html'
+        else:
+            rel_file = req.path[1:]
+
+        file_path = path.join(self.www_dir, rel_file)
+
+        if path.isfile(file_path):
+            resp.status = 200
+            file_contents = ''.join(open(file_path).read())
+            resp.body = file_contents
+        else:
+            resp.body = '<html><body>404!</body></html>'
+
+        return resp(environ, start_response)