Commits

Georg Brandl committed e3ea500

Fix the serializing and changes builders, and really test them.

Comments (0)

Files changed (10)

sphinx/application.py

     that renders templates given a template name and a context.
     """
 
-    def init(self, builder):
+    def init(self, builder, theme=None, dirs=None):
         """
-        Called by the builder to initialize the template system.  *builder*
-        is the builder object; you'll probably want to look at the value of
-        ``builder.config.templates_path``.
+        Called by the builder to initialize the template system.
+
+        *builder* is the builder object; you'll probably want to look at the
+        value of ``builder.config.templates_path``.
+
+        *theme* is a :class:`sphinx.theming.Theme` object or None; in the latter
+        case, *dirs* can be list of fixed directories to look for templates.
         """
         raise NotImplementedError('must be implemented in subclasses')
 

sphinx/builders/__init__.py

         """
         pass
 
-    def init_templates(self):
+    def create_template_bridge(self):
         """
-        Initialize the theme and template system.
-
-        Call this method from init() if you need templates in your builder.
+        Return the template bridge configured.
         """
-        from sphinx.theming import Theme
-        Theme.init_themes(self)
-        self.theme = Theme(self.config.html_theme)
-
         if self.config.template_bridge:
             self.templates = self.app.import_object(
                 self.config.template_bridge, 'template_bridge setting')()
         else:
             from sphinx.jinja2glue import BuiltinTemplateLoader
             self.templates = BuiltinTemplateLoader()
-        self.templates.init(self)
 
     def get_target_uri(self, docname, typ=None):
         """

sphinx/builders/changes.py

 from cgi import escape
 
 from sphinx import package_dir
-from sphinx.util import ensuredir, os_path
+from sphinx.util import ensuredir, os_path, copy_static_entry
+from sphinx.theming import Theme
 from sphinx.builders import Builder
 from sphinx.util.console import bold
 
     name = 'changes'
 
     def init(self):
-        self.init_templates()
+        self.create_template_bridge()
+        Theme.init_themes(self)
+        self.theme = Theme('default')
+        self.templates.init(self, self.theme)
 
     def get_outdated_docs(self):
         return self.outdir
         apichanges = []
         otherchanges = {}
         if version not in self.env.versionchanges:
-            self.info(bold('no changes in this version.'))
+            self.info(bold('no changes in version %s.' % version))
             return
         self.info(bold('writing summary file...'))
         for type, docname, lineno, module, descname, content in \
                 self.env.versionchanges[version]:
+            if isinstance(descname, tuple):
+                descname = descname[0]
             ttext = self.typemap[type]
             context = content.replace('\n', ' ')
             if descname and docname.startswith('c-api'):
                 f.write(self.templates.render('changes/rstsource.html', ctx))
             finally:
                 f.close()
-        shutil.copyfile(path.join(package_dir, 'themes', 'default',
-                                  'static', 'default.css'),
-                        path.join(self.outdir, 'default.css'))
-        shutil.copyfile(path.join(package_dir, 'themes', 'basic',
-                                  'static', 'basic.css'),
-                        path.join(self.outdir, 'basic.css'))
+        themectx = dict(('theme_' + key, val) for (key, val) in
+                        self.theme.get_options({}).iteritems())
+        copy_static_entry(path.join(package_dir, 'themes', 'default',
+                                    'static', 'default.css_t'),
+                          path.join(self.outdir, 'default.css_t'),
+                          self, themectx)
+        copy_static_entry(path.join(package_dir, 'themes', 'basic',
+                                    'static', 'basic.css'),
+                          path.join(self.outdir, 'basic.css'), self)
 
     def hl(self, text, version):
         text = escape(text)

sphinx/builders/html.py

 
 from sphinx import package_dir, __version__
 from sphinx.util import SEP, os_path, relative_uri, ensuredir, \
-    movefile, ustrftime
+    movefile, ustrftime, copy_static_entry
 from sphinx.search import js_index
+from sphinx.theming import Theme
 from sphinx.builders import Builder, ENV_PICKLE_FILENAME
 from sphinx.application import SphinxError
 from sphinx.highlighting import PygmentsBridge
             if path.isfile(jsfile):
                 self.script_files.append('_static/translations.js')
 
+    def init_templates(self):
+        Theme.init_themes(self)
+        self.theme = Theme(self.config.html_theme)
+        self.create_template_bridge()
+        self.templates.init(self, self.theme)
+
     def init_highlighter(self):
         # determine Pygments style and create the highlighter
         if self.config.pygments_style is not None:
             style = self.config.pygments_style
+        elif self.theme:
+            style = self.theme.get_confstr('theme', 'pygments_style', 'none')
         else:
-            style = self.theme.get_confstr('theme', 'pygments_style', 'none')
+            style = 'sphinx'
         self.highlighter = PygmentsBridge('html', style)
 
     def init_translator_class(self):
 
         if self.config.html_style is not None:
             stylename = self.config.html_style
+        elif self.theme:
+            stylename = self.theme.get_confstr('theme', 'stylesheet')
         else:
-            stylename = self.theme.get_confstr('theme', 'stylesheet')
+            stylename = 'default.css'
 
         self.globalcontext = dict(
             embedded = self.embedded,
             logo = logo,
             favicon = favicon,
         )
-        self.globalcontext.update(
-            ('theme_' + key, val) for (key, val) in
-            self.theme.get_options(self.config.html_theme_options).iteritems())
+        if self.theme:
+            self.globalcontext.update(
+                ('theme_' + key, val) for (key, val) in
+                self.theme.get_options(
+                self.config.html_theme_options).iteritems())
         self.globalcontext.update(self.config.html_context)
 
     def get_doc_context(self, docname, body, metatags):
                 shutil.copyfile(jsfile, path.join(self.outdir, '_static',
                                                   'translations.js'))
         # then, copy over all user-supplied static files
-        staticdirnames = [path.join(themepath, 'static')
-                          for themepath in self.theme.get_dirchain()[::-1]] + \
-                         [path.join(self.confdir, spath)
-                          for spath in self.config.html_static_path]
+        if self.theme:
+            staticdirnames = [path.join(themepath, 'static')
+                              for themepath in self.theme.get_dirchain()[::-1]]
+        else:
+            staticdirnames = []
+        staticdirnames += [path.join(self.confdir, spath)
+                           for spath in self.config.html_static_path]
         for staticdirname in staticdirnames:
             if not path.isdir(staticdirname):
                 self.warn('static directory %r does not exist' % staticdirname)
                     continue
                 fullname = path.join(staticdirname, filename)
                 targetname = path.join(self.outdir, '_static', filename)
-                if path.isfile(fullname):
-                    if fullname.lower().endswith('_t'):
-                        # templated!
-                        fsrc = open(fullname, 'rb')
-                        fdst = open(targetname[:-2], 'wb')
-                        fdst.write(self.templates.render_string(
-                            fsrc.read(), self.globalcontext))
-                        fsrc.close()
-                        fdst.close()
-                    else:
-                        shutil.copyfile(fullname, targetname)
-                elif path.isdir(fullname):
-                    if filename in self.config.exclude_dirnames:
-                        continue
-                    if path.exists(targetname):
-                        shutil.rmtree(targetname)
-                    shutil.copytree(fullname, targetname)
+                copy_static_entry(fullname, targetname, self,
+                                  self.globalcontext)
         # last, copy logo file (handled differently)
         if self.config.html_logo:
             logobase = path.basename(self.config.html_logo)
 
     def cleanup(self):
         # clean up theme stuff
-        self.theme.cleanup()
+        if self.theme:
+            self.theme.cleanup()
 
     def post_process_images(self, doctree):
         """
                              'image/gif', 'image/jpeg']
 
     def init(self):
+        self.config_hash = ''
+        self.tags_hash = ''
+        self.theme = None       # no theme necessary
+        self.templates = None   # no template bridge necessary
         self.init_translator_class()
         self.init_highlighter()
-        self.templates = None   # no template bridge necessary
 
     def get_target_uri(self, docname, typ=None):
         if docname == 'index':

sphinx/jinja2glue.py

 
     # TemplateBridge interface
 
-    def init(self, builder):
-        self.theme = builder.theme
-        # create a chain of paths to search:
-        # the theme's own dir and its bases' dirs
-        chain = self.theme.get_dirchain()
-        # then the theme parent paths (XXX doc)
-        chain.extend(self.theme.themepath)
+    def init(self, builder, theme=None, dirs=None):
+        # create a chain of paths to search
+        if theme:
+            # the theme's own dir and its bases' dirs
+            chain = theme.get_dirchain()
+            # then the theme parent paths
+            chain.extend(theme.themepath)
+        elif dirs:
+            chain = list(dirs)
+        else:
+            chain = []
 
         # prepend explicit template paths
         self.templatepathlen = len(builder.config.templates_path)

sphinx/theming.py

     """
     Represents the theme chosen in the configuration.
     """
+    themes = {}
+
     @classmethod
     def init_themes(cls, builder):
         """Search all theme paths for available themes."""
-        cls.themes = {}
-
         cls.themepath = list(builder.config.html_theme_path)
         cls.themepath.append(
             path.join(path.abspath(path.dirname(__file__)), 'themes'))

sphinx/util/__init__.py

 import sys
 import time
 import types
+import shutil
 import fnmatch
 import tempfile
 import posixpath
     os.rename(source, dest)
 
 
+def copy_static_entry(source, target, builder, context={}):
+    if path.isfile(source):
+        if source.lower().endswith('_t'):
+            # templated!
+            fsrc = open(source, 'rb')
+            fdst = open(target[:-2], 'wb')
+            fdst.write(builder.templates.render_string(fsrc.read(), context))
+            fsrc.close()
+            fdst.close()
+        else:
+            shutil.copyfile(source, target)
+    elif path.isdir(source):
+        if filename in builder.config.exclude_dirnames:
+            return
+        if path.exists(target):
+            shutil.rmtree(target)
+        shutil.copytree(source, target)
+
+
 # monkey-patch Node.traverse to get more speed
 # traverse() is called so many times during a build that it saves
 # on average 20-25% overall build time!

tests/root/conf.py

 
 project = 'Sphinx <Tests>'
 copyright = '2008, Georg Brandl & Team'
+# If this is changed, remember to update the versionchanges!
 version = '0.6'
 release = '0.6alpha1'
 today_fmt = '%B %d, %Y'

tests/root/markup.txt

 Version markup
 --------------
 
-.. versionadded:: 0.5
+.. versionadded:: 0.6
    Some funny **stuff**.
 
-.. versionchanged:: 0.5
+.. versionchanged:: 0.6
    Even more funny stuff.
 
-.. deprecated:: 0.4
+.. deprecated:: 0.6
    Boring stuff.
 
 

tests/test_build.py

 
 # just let the remaining ones run for now
 
+@with_app(buildername='pickle')
+def test_pickle(app):
+    app.builder.build_all()
+
 @with_app(buildername='linkcheck')
 def test_linkcheck(app):
     app.builder.build_all()
 def test_text(app):
     app.builder.build_all()
 
-@with_app(buildername='changes', cleanenv=True)
+@with_app(buildername='htmlhelp')
+def test_htmlhelp(app):
+    app.builder.build_all()
+
+@with_app(buildername='qthelp')
+def test_qthelp(app):
+    app.builder.build_all()
+
+@with_app(buildername='changes')
 def test_changes(app):
     app.builder.build_all()
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.