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
|
Changes in trunk
|
||||||
================
|
================
|
||||||
|
|
||||||
* sphinx.application: Support a new method, ``add_crossref_type``.
|
New features added
|
||||||
It works like ``add_description_unit`` but the directive will only
|
------------------
|
||||||
create a target and no output.
|
|
||||||
|
|
||||||
* sphinx.application: Support a new method, ``add_transform``.
|
* Extension API (Application object):
|
||||||
It takes a standard docutils ``Transform`` subclass which is then
|
|
||||||
applied by Sphinx' reader on parsing reST document trees.
|
|
||||||
|
|
||||||
* sphinx.directives: New directive, ``currentmodule``. It can be used
|
- Support a new method, ``add_crossref_type``. It works like
|
||||||
to indicate the module name of the following documented things without
|
``add_description_unit`` but the directive will only create a target
|
||||||
creating index entries.
|
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
|
* sphinx.ext.autodoc: Don't check ``__module__`` for explicitly given
|
||||||
members. Remove "self" in class constructor argument list.
|
members. Remove "self" in class constructor argument list.
|
||||||
|
|
||||||
* sphinx.environment: Don't swallow TOC entries when resolving subtrees.
|
* sphinx.htmlwriter: Don't use os.path for joining image HREFs.
|
||||||
|
|
||||||
* 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.roles: Fix referencing glossary terms with explicit targets.
|
* 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.
|
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)
|
Release 0.1.61950 (Mar 26, 2008)
|
||||||
================================
|
================================
|
||||||
|
@ -132,6 +132,14 @@ General configuration
|
|||||||
``'sphinx'``, which is a builtin style designed to match Sphinx' default
|
``'sphinx'``, which is a builtin style designed to match Sphinx' default
|
||||||
style.
|
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:
|
.. _html-options:
|
||||||
|
|
||||||
@ -211,6 +219,13 @@ that use Sphinx' HTMLWriter class.
|
|||||||
If true, the reST sources are included in the HTML build as
|
If true, the reST sources are included in the HTML build as
|
||||||
:file:`_sources/{name}`.
|
: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
|
.. confval:: htmlhelp_basename
|
||||||
|
|
||||||
Output file base name for HTML help builder. Default is ``'pydoc'``.
|
Output file base name for HTML help builder. Default is ``'pydoc'``.
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
Extension API
|
Extension API
|
||||||
=============
|
=============
|
||||||
|
|
||||||
|
.. currentmodule:: sphinx.application
|
||||||
|
|
||||||
Each Sphinx extension is a Python module with at least a :func:`setup` function.
|
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
|
This function is called at initialization time with one argument, the
|
||||||
application object representing the Sphinx process. This application object has
|
application object representing the Sphinx process. This application object has
|
||||||
@ -169,3 +171,11 @@ Event name Emitted when Arguments
|
|||||||
references and TOCs have been
|
references and TOCs have been
|
||||||
inserted
|
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:
|
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
|
* You can :ref:`write a custom builder <writing-builders>` that derives from
|
||||||
:class:`~sphinx.builder.StandaloneHTMLBuilder` and calls your template engine
|
:class:`~sphinx.builder.StandaloneHTMLBuilder` and calls your template engine
|
||||||
of choice.
|
of choice.
|
||||||
@ -36,4 +40,6 @@ Inheritance is done via two (Jinja) directives, ``extends`` and ``block``.
|
|||||||
blocks
|
blocks
|
||||||
extends !template
|
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.
|
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):
|
if sys.version_info < (2, 4):
|
||||||
print 'ERROR: Sphinx requires at least Python 2.4 to run.'
|
print 'ERROR: Sphinx requires at least Python 2.4 to run.'
|
||||||
|
@ -13,7 +13,8 @@ import sys
|
|||||||
import codecs
|
import codecs
|
||||||
from os import path
|
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 import Environment
|
||||||
from jinja.loaders import BaseLoader
|
from jinja.loaders import BaseLoader
|
||||||
@ -53,3 +54,27 @@ class SphinxFileSystemLoader(BaseLoader):
|
|||||||
return f.read()
|
return f.read()
|
||||||
finally:
|
finally:
|
||||||
f.close()
|
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):
|
def add_transform(self, transform):
|
||||||
SphinxStandaloneReader.transforms.append(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
|
raise NotImplementedError
|
||||||
|
|
||||||
def init_templates(self):
|
def init_templates(self):
|
||||||
"""Call if you need Jinja templates in the builder."""
|
# Call this from init() if you need templates.
|
||||||
# lazily import this, other builders won't need it
|
if self.config.template_bridge:
|
||||||
from sphinx._jinja import Environment, SphinxFileSystemLoader
|
self.templates = self.app.import_object(
|
||||||
|
self.config.template_bridge, 'template_bridge setting')()
|
||||||
# load templates
|
else:
|
||||||
self.templates = {}
|
from sphinx._jinja import BuiltinTemplates
|
||||||
base_templates_path = path.join(path.dirname(__file__), 'templates')
|
self.templates = BuiltinTemplates()
|
||||||
ext_templates_path = [path.join(self.srcdir, dir)
|
self.templates.init(self)
|
||||||
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
|
|
||||||
|
|
||||||
def get_target_uri(self, docname, typ=None):
|
def get_target_uri(self, docname, typ=None):
|
||||||
"""
|
"""
|
||||||
@ -514,8 +501,8 @@ class StandaloneHTMLBuilder(Builder):
|
|||||||
self.handle_finish()
|
self.handle_finish()
|
||||||
|
|
||||||
def get_outdated_docs(self):
|
def get_outdated_docs(self):
|
||||||
if self.templates_path:
|
if self.templates:
|
||||||
template_mtime = max(mtimes_of_files(self.templates_path, '.html'))
|
template_mtime = self.templates.newest_template_mtime()
|
||||||
else:
|
else:
|
||||||
template_mtime = 0
|
template_mtime = 0
|
||||||
for docname in self.env.found_docs:
|
for docname in self.env.found_docs:
|
||||||
@ -535,7 +522,7 @@ class StandaloneHTMLBuilder(Builder):
|
|||||||
except EnvironmentError:
|
except EnvironmentError:
|
||||||
# source doesn't exist anymore
|
# source doesn't exist anymore
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def load_indexer(self, docnames):
|
def load_indexer(self, docnames):
|
||||||
try:
|
try:
|
||||||
f = open(path.join(self.outdir, 'searchindex.'+self.indexer_format), 'r')
|
f = open(path.join(self.outdir, 'searchindex.'+self.indexer_format), 'r')
|
||||||
@ -574,7 +561,7 @@ class StandaloneHTMLBuilder(Builder):
|
|||||||
ctx['customsidebar'] = sidebarfile
|
ctx['customsidebar'] = sidebarfile
|
||||||
ctx.update(addctx)
|
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')
|
outfilename = path.join(self.outdir, os_path(pagename) + '.html')
|
||||||
ensuredir(path.dirname(outfilename)) # normally different from self.outdir
|
ensuredir(path.dirname(outfilename)) # normally different from self.outdir
|
||||||
try:
|
try:
|
||||||
@ -611,8 +598,7 @@ class PickleHTMLBuilder(StandaloneHTMLBuilder):
|
|||||||
|
|
||||||
def init(self):
|
def init(self):
|
||||||
self.init_translator_class()
|
self.init_translator_class()
|
||||||
# no templates used, but get_outdated_docs() needs this attribute
|
self.templates = None # no template bridge necessary
|
||||||
self.templates_path = []
|
|
||||||
|
|
||||||
def get_target_uri(self, docname, typ=None):
|
def get_target_uri(self, docname, typ=None):
|
||||||
if docname == 'index':
|
if docname == 'index':
|
||||||
@ -827,9 +813,6 @@ class ChangesBuilder(Builder):
|
|||||||
|
|
||||||
def init(self):
|
def init(self):
|
||||||
self.init_templates()
|
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):
|
def get_outdated_docs(self):
|
||||||
return self.outdir
|
return self.outdir
|
||||||
@ -885,12 +868,12 @@ class ChangesBuilder(Builder):
|
|||||||
}
|
}
|
||||||
f = open(path.join(self.outdir, 'index.html'), 'w')
|
f = open(path.join(self.outdir, 'index.html'), 'w')
|
||||||
try:
|
try:
|
||||||
f.write(self.ftemplate.render(ctx))
|
f.write(self.templates.render('changes/frameset.html', ctx))
|
||||||
finally:
|
finally:
|
||||||
f.close()
|
f.close()
|
||||||
f = open(path.join(self.outdir, 'changes.html'), 'w')
|
f = open(path.join(self.outdir, 'changes.html'), 'w')
|
||||||
try:
|
try:
|
||||||
f.write(self.vtemplate.render(ctx))
|
f.write(self.templates.render('changes/versionchanges.html', ctx))
|
||||||
finally:
|
finally:
|
||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
@ -916,7 +899,7 @@ class ChangesBuilder(Builder):
|
|||||||
try:
|
try:
|
||||||
text = ''.join(hl(i+1, line) for (i, line) in enumerate(lines))
|
text = ''.join(hl(i+1, line) for (i, line) in enumerate(lines))
|
||||||
ctx = {'filename': self.env.doc2path(docname, None), 'text': text}
|
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:
|
finally:
|
||||||
f.close()
|
f.close()
|
||||||
shutil.copyfile(path.join(path.dirname(__file__), 'static', 'default.css'),
|
shutil.copyfile(path.join(path.dirname(__file__), 'static', 'default.css'),
|
||||||
|
@ -42,6 +42,7 @@ class Config(object):
|
|||||||
add_module_names = (True, True),
|
add_module_names = (True, True),
|
||||||
show_authors = (False, True),
|
show_authors = (False, True),
|
||||||
pygments_style = ('sphinx', False),
|
pygments_style = ('sphinx', False),
|
||||||
|
template_bridge = (None, False),
|
||||||
|
|
||||||
# HTML options
|
# HTML options
|
||||||
html_style = ('default.css', False),
|
html_style = ('default.css', False),
|
||||||
|
Loading…
Reference in New Issue
Block a user