mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Add new templating API, remove Jinja external and add it to setup.py dependencies.
This commit is contained in:
parent
9e485e078e
commit
ae8813c788
57
CHANGES
57
CHANGES
@ -1,42 +1,49 @@
|
||||
Changes in trunk
|
||||
================
|
||||
|
||||
* sphinx.application: Support a new method, ``add_crossref_type``.
|
||||
It works like ``add_description_unit`` but the directive will only
|
||||
create a target and no output.
|
||||
New features added
|
||||
------------------
|
||||
|
||||
* sphinx.application: Support a new method, ``add_transform``.
|
||||
It takes a standard docutils ``Transform`` subclass which is then
|
||||
applied by Sphinx' reader on parsing reST document trees.
|
||||
* Extension API (Application object):
|
||||
|
||||
* sphinx.directives: New directive, ``currentmodule``. It can be used
|
||||
to indicate the module name of the following documented things without
|
||||
creating index entries.
|
||||
- Support a new method, ``add_crossref_type``. It works like
|
||||
``add_description_unit`` but the directive will only create a target
|
||||
and no output.
|
||||
- Support a new method, ``add_transform``. It takes a standard docutils
|
||||
``Transform`` subclass which is then applied by Sphinx' reader on
|
||||
parsing reST document trees.
|
||||
- Add support for other template engines than Jinja, by adding an
|
||||
abstraction called a "template bridge". This class handles rendering
|
||||
of templates and can be changed using the new configuration value
|
||||
"template_bridge".
|
||||
- The config file itself can be an extension (if it provides a ``setup()``
|
||||
function).
|
||||
|
||||
* Markup:
|
||||
|
||||
- New directive, ``currentmodule``. It can be used to indicate the module
|
||||
name of the following documented things without creating index entries.
|
||||
- Allow giving a different title to documents in the toctree.
|
||||
- Allow giving multiple options in a ``cmdoption`` directive.
|
||||
- Fix display of class members without explicit class name given.
|
||||
|
||||
Thanks to Jacob Kaplan-Moss, Talin and Sebastian Wiesner for suggestions.
|
||||
|
||||
Bugs fixed
|
||||
----------
|
||||
|
||||
* sphinx.ext.autodoc: Don't check ``__module__`` for explicitly given
|
||||
members. Remove "self" in class constructor argument list.
|
||||
|
||||
* sphinx.environment: Don't swallow TOC entries when resolving subtrees.
|
||||
|
||||
* sphinx.directives: Allow giving a different title to documents
|
||||
in the toctree.
|
||||
|
||||
* sphinx.directives: Allow giving multiple options in a ``cmdoption``
|
||||
directive.
|
||||
|
||||
* sphinx.directives: Fix display of class members without explicit
|
||||
class name given.
|
||||
* sphinx.htmlwriter: Don't use os.path for joining image HREFs.
|
||||
|
||||
* sphinx.roles: Fix referencing glossary terms with explicit targets.
|
||||
|
||||
* sphinx.builder, sphinx.environment: Gracefully handle some exception
|
||||
* sphinx.environment: Don't swallow TOC entries when resolving subtrees.
|
||||
|
||||
* sphinx.builder, sphinx.environment: Gracefully handle some user error
|
||||
cases.
|
||||
|
||||
* sphinx.config: The config file itself can be an extension (if it
|
||||
provides a setup() function).
|
||||
|
||||
* sphinx.htmlwriter: Don't use os.path for joining image HREFs.
|
||||
|
||||
|
||||
Release 0.1.61950 (Mar 26, 2008)
|
||||
================================
|
||||
|
@ -132,6 +132,14 @@ General configuration
|
||||
``'sphinx'``, which is a builtin style designed to match Sphinx' default
|
||||
style.
|
||||
|
||||
.. confval:: template_bridge
|
||||
|
||||
A string with the fully-qualified (that is, including the module name) name
|
||||
of a callable (or simply a class) that returns an instance of
|
||||
:class:`~sphinx.application.TemplateBridge`. This instance is then used to
|
||||
render HTML documents, and possibly the output of other builders (currently
|
||||
the changes builder).
|
||||
|
||||
|
||||
.. _html-options:
|
||||
|
||||
@ -211,6 +219,13 @@ that use Sphinx' HTMLWriter class.
|
||||
If true, the reST sources are included in the HTML build as
|
||||
:file:`_sources/{name}`.
|
||||
|
||||
.. confval:: html_translator_class
|
||||
|
||||
A string with the fully-qualified (that is, including the module name) name
|
||||
of a HTML Translator class, that is, a subclass of Sphinx'
|
||||
:class:`~sphinx.htmlwriter.HTMLTranslator`, that is used to translate
|
||||
document trees to HTML. Default is ``None`` (use the builtin translator).
|
||||
|
||||
.. confval:: htmlhelp_basename
|
||||
|
||||
Output file base name for HTML help builder. Default is ``'pydoc'``.
|
||||
|
@ -3,6 +3,8 @@
|
||||
Extension API
|
||||
=============
|
||||
|
||||
.. currentmodule:: sphinx.application
|
||||
|
||||
Each Sphinx extension is a Python module with at least a :func:`setup` function.
|
||||
This function is called at initialization time with one argument, the
|
||||
application object representing the Sphinx process. This application object has
|
||||
@ -169,3 +171,11 @@ Event name Emitted when Arguments
|
||||
references and TOCs have been
|
||||
inserted
|
||||
====================== =================================== =========
|
||||
|
||||
.. _template-bridge:
|
||||
|
||||
The template bridge
|
||||
-------------------
|
||||
|
||||
.. autoclass:: TemplateBridge
|
||||
:members:
|
||||
|
@ -14,6 +14,10 @@ Do I need to use Sphinx' templates to produce HTML?
|
||||
|
||||
No. You have several other options:
|
||||
|
||||
* You can write a :class:`~sphinx.application.TemplateBridge` subclass that
|
||||
calls your template engine of choice, and set the :confval:`template_bridge`
|
||||
configuration value accordingly.
|
||||
|
||||
* You can :ref:`write a custom builder <writing-builders>` that derives from
|
||||
:class:`~sphinx.builder.StandaloneHTMLBuilder` and calls your template engine
|
||||
of choice.
|
||||
@ -36,4 +40,6 @@ Inheritance is done via two (Jinja) directives, ``extends`` and ``block``.
|
||||
blocks
|
||||
extends !template
|
||||
|
||||
XXX continue this
|
||||
template names for other template engines
|
||||
|
||||
.. XXX continue this
|
||||
|
2
setup.py
2
setup.py
@ -34,7 +34,7 @@ are already present, work fine and can be seen "in action" in the Python docs:
|
||||
and inclusion of appropriately formatted docstrings.
|
||||
'''
|
||||
|
||||
requires = ['Pygments>=0.8', 'docutils>=0.4']
|
||||
requires = ['Pygments>=0.8', 'Jinja>=1.1', 'docutils>=0.4']
|
||||
|
||||
if sys.version_info < (2, 4):
|
||||
print 'ERROR: Sphinx requires at least Python 2.4 to run.'
|
||||
|
@ -13,7 +13,8 @@ import sys
|
||||
import codecs
|
||||
from os import path
|
||||
|
||||
sys.path.insert(0, path.dirname(__file__))
|
||||
from sphinx.util import mtimes_of_files
|
||||
from sphinx.application import TemplateBridge
|
||||
|
||||
from jinja import Environment
|
||||
from jinja.loaders import BaseLoader
|
||||
@ -53,3 +54,27 @@ class SphinxFileSystemLoader(BaseLoader):
|
||||
return f.read()
|
||||
finally:
|
||||
f.close()
|
||||
|
||||
|
||||
class BuiltinTemplates(TemplateBridge):
|
||||
def init(self, builder):
|
||||
self.templates = {}
|
||||
base_templates_path = path.join(path.dirname(__file__), 'templates')
|
||||
ext_templates_path = [path.join(builder.srcdir, dir)
|
||||
for dir in builder.config.templates_path]
|
||||
self.templates_path = [base_templates_path] + ext_templates_path
|
||||
loader = SphinxFileSystemLoader(base_templates_path, ext_templates_path)
|
||||
self.jinja_env = Environment(loader=loader,
|
||||
# disable traceback, more likely that something
|
||||
# in the application is broken than in the templates
|
||||
friendly_traceback=False)
|
||||
|
||||
def newest_template_mtime(self):
|
||||
return max(mtimes_of_files(self.templates_path, '.html'))
|
||||
|
||||
def render(self, template, context):
|
||||
if template in self.templates:
|
||||
return self.templates[template].render(context)
|
||||
templateobj = self.templates[template] = \
|
||||
self.jinja_env.get_template(template)
|
||||
return templateobj.render(context)
|
||||
|
@ -217,3 +217,32 @@ class Sphinx(object):
|
||||
|
||||
def add_transform(self, transform):
|
||||
SphinxStandaloneReader.transforms.append(transform)
|
||||
|
||||
|
||||
class TemplateBridge(object):
|
||||
"""
|
||||
|
||||
"""
|
||||
|
||||
def init(self, builder):
|
||||
"""
|
||||
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``.
|
||||
"""
|
||||
raise NotImplementedError('must be implemented in subclasses')
|
||||
|
||||
def newest_template_mtime(self):
|
||||
"""
|
||||
Called by the builder to determine if output files are outdated
|
||||
because of template changes. Return the mtime of the newest template
|
||||
file that was changed. The default implementation returns ``0``.
|
||||
"""
|
||||
return 0
|
||||
|
||||
def render(self, template, context):
|
||||
"""
|
||||
Called by the builder to render a *template* with a specified
|
||||
context (a Python dictionary).
|
||||
"""
|
||||
raise NotImplementedError('must be implemented in subclasses')
|
||||
|
@ -74,27 +74,14 @@ class Builder(object):
|
||||
raise NotImplementedError
|
||||
|
||||
def init_templates(self):
|
||||
"""Call if you need Jinja templates in the builder."""
|
||||
# lazily import this, other builders won't need it
|
||||
from sphinx._jinja import Environment, SphinxFileSystemLoader
|
||||
|
||||
# load templates
|
||||
self.templates = {}
|
||||
base_templates_path = path.join(path.dirname(__file__), 'templates')
|
||||
ext_templates_path = [path.join(self.srcdir, dir)
|
||||
for dir in self.config.templates_path]
|
||||
self.templates_path = [base_templates_path] + ext_templates_path
|
||||
loader = SphinxFileSystemLoader(base_templates_path, ext_templates_path)
|
||||
self.jinja_env = Environment(loader=loader,
|
||||
# disable traceback, more likely that something
|
||||
# in the application is broken than in the templates
|
||||
friendly_traceback=False)
|
||||
|
||||
def get_template(self, name):
|
||||
if name in self.templates:
|
||||
return self.templates[name]
|
||||
template = self.templates[name] = self.jinja_env.get_template(name)
|
||||
return template
|
||||
# Call this from init() if you need templates.
|
||||
if self.config.template_bridge:
|
||||
self.templates = self.app.import_object(
|
||||
self.config.template_bridge, 'template_bridge setting')()
|
||||
else:
|
||||
from sphinx._jinja import BuiltinTemplates
|
||||
self.templates = BuiltinTemplates()
|
||||
self.templates.init(self)
|
||||
|
||||
def get_target_uri(self, docname, typ=None):
|
||||
"""
|
||||
@ -514,8 +501,8 @@ class StandaloneHTMLBuilder(Builder):
|
||||
self.handle_finish()
|
||||
|
||||
def get_outdated_docs(self):
|
||||
if self.templates_path:
|
||||
template_mtime = max(mtimes_of_files(self.templates_path, '.html'))
|
||||
if self.templates:
|
||||
template_mtime = self.templates.newest_template_mtime()
|
||||
else:
|
||||
template_mtime = 0
|
||||
for docname in self.env.found_docs:
|
||||
@ -535,7 +522,7 @@ class StandaloneHTMLBuilder(Builder):
|
||||
except EnvironmentError:
|
||||
# source doesn't exist anymore
|
||||
pass
|
||||
|
||||
|
||||
def load_indexer(self, docnames):
|
||||
try:
|
||||
f = open(path.join(self.outdir, 'searchindex.'+self.indexer_format), 'r')
|
||||
@ -574,7 +561,7 @@ class StandaloneHTMLBuilder(Builder):
|
||||
ctx['customsidebar'] = sidebarfile
|
||||
ctx.update(addctx)
|
||||
|
||||
output = self.get_template(templatename).render(ctx)
|
||||
output = self.templates.render(templatename, ctx)
|
||||
outfilename = path.join(self.outdir, os_path(pagename) + '.html')
|
||||
ensuredir(path.dirname(outfilename)) # normally different from self.outdir
|
||||
try:
|
||||
@ -611,8 +598,7 @@ class PickleHTMLBuilder(StandaloneHTMLBuilder):
|
||||
|
||||
def init(self):
|
||||
self.init_translator_class()
|
||||
# no templates used, but get_outdated_docs() needs this attribute
|
||||
self.templates_path = []
|
||||
self.templates = None # no template bridge necessary
|
||||
|
||||
def get_target_uri(self, docname, typ=None):
|
||||
if docname == 'index':
|
||||
@ -827,9 +813,6 @@ class ChangesBuilder(Builder):
|
||||
|
||||
def init(self):
|
||||
self.init_templates()
|
||||
self.ftemplate = self.get_template('changes/frameset.html')
|
||||
self.vtemplate = self.get_template('changes/versionchanges.html')
|
||||
self.stemplate = self.get_template('changes/rstsource.html')
|
||||
|
||||
def get_outdated_docs(self):
|
||||
return self.outdir
|
||||
@ -885,12 +868,12 @@ class ChangesBuilder(Builder):
|
||||
}
|
||||
f = open(path.join(self.outdir, 'index.html'), 'w')
|
||||
try:
|
||||
f.write(self.ftemplate.render(ctx))
|
||||
f.write(self.templates.render('changes/frameset.html', ctx))
|
||||
finally:
|
||||
f.close()
|
||||
f = open(path.join(self.outdir, 'changes.html'), 'w')
|
||||
try:
|
||||
f.write(self.vtemplate.render(ctx))
|
||||
f.write(self.templates.render('changes/versionchanges.html', ctx))
|
||||
finally:
|
||||
f.close()
|
||||
|
||||
@ -916,7 +899,7 @@ class ChangesBuilder(Builder):
|
||||
try:
|
||||
text = ''.join(hl(i+1, line) for (i, line) in enumerate(lines))
|
||||
ctx = {'filename': self.env.doc2path(docname, None), 'text': text}
|
||||
f.write(self.stemplate.render(ctx))
|
||||
f.write(self.templates.render('changes/rstsource.html', ctx))
|
||||
finally:
|
||||
f.close()
|
||||
shutil.copyfile(path.join(path.dirname(__file__), 'static', 'default.css'),
|
||||
|
@ -42,6 +42,7 @@ class Config(object):
|
||||
add_module_names = (True, True),
|
||||
show_authors = (False, True),
|
||||
pygments_style = ('sphinx', False),
|
||||
template_bridge = (None, False),
|
||||
|
||||
# HTML options
|
||||
html_style = ('default.css', False),
|
||||
|
Loading…
Reference in New Issue
Block a user