Allow the config to act as an extension.

This commit is contained in:
Georg Brandl 2008-04-06 17:38:55 +00:00
parent b016896c1c
commit ea2f87fc03
8 changed files with 62 additions and 48 deletions

View File

@ -13,6 +13,9 @@ Changes in trunk
* sphinx.builder, sphinx.environment: Gracefully handle some exception * sphinx.builder, sphinx.environment: Gracefully handle some exception
cases. cases.
* sphinx.config: The config file itself can be an extension (if it
provides a setup() function).
Release 0.1.61950 (Mar 26, 2008) Release 0.1.61950 (Mar 26, 2008)
================================ ================================

View File

@ -11,17 +11,17 @@
# All configuration values have a default value; values that are commented out # All configuration values have a default value; values that are commented out
# serve to show the default value. # serve to show the default value.
import sys, os import sys, os, re
# If your extensions are in another directory, add it here. # If your extensions are in another directory, add it here.
sys.path.append(os.path.dirname(__file__)) #sys.path.append(os.path.dirname(__file__))
# General configuration # General configuration
# --------------------- # ---------------------
# Add any Sphinx extension module names here, as strings. They can be extensions # Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.addons.*') or your custom ones. # coming with Sphinx (named 'sphinx.addons.*') or your custom ones.
extensions = ['ext', 'sphinx.ext.autodoc', 'sphinx.ext.doctest'] extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest']
# Add any paths that contain templates here, relative to this directory. # Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates'] templates_path = ['_templates']
@ -125,3 +125,37 @@ latex_documents = [('contents', 'sphinx.tex', 'Sphinx Documentation',
#latex_appendices = [] #latex_appendices = []
automodule_skip_lines = 4 automodule_skip_lines = 4
# Extension interface
# -------------------
from sphinx import addnodes
dir_sig_re = re.compile(r'\.\. ([^:]+)::(.*)$')
def parse_directive(env, sig, signode):
if not sig.startswith('.'):
dec_sig = '.. %s::' % sig
signode += addnodes.desc_name(dec_sig, dec_sig)
return sig
m = dir_sig_re.match(sig)
if not m:
signode += addnodes.desc_name(sig, sig)
return sig
name, args = m.groups()
dec_name = '.. %s::' % name
signode += addnodes.desc_name(dec_name, dec_name)
signode += addnodes.desc_classname(args, args)
return name
def parse_role(env, sig, signode):
signode += addnodes.desc_name(':%s:' % sig, ':%s:' % sig)
return sig
def setup(app):
app.add_description_unit('directive', 'dir', 'pair: %s; directive', parse_directive)
app.add_description_unit('role', 'role', 'pair: %s; role', parse_role)
app.add_description_unit('confval', 'confval', 'pair: %s; configuration value')

View File

@ -50,6 +50,9 @@ General configuration
That way, you can load an extension called ``extname`` from the documentation That way, you can load an extension called ``extname`` from the documentation
root's subdirectory ``sphinxext``. root's subdirectory ``sphinxext``.
The configuration file itself can be an extension; for that, you only need to
provide a :func:`setup` function in it.
.. confval:: templates_path .. confval:: templates_path
A list of paths that contain extra templates (or templates that overwrite A list of paths that contain extra templates (or templates that overwrite

View File

@ -1,40 +0,0 @@
# -*- coding: utf-8 -*-
"""
ext.py -- Sphinx extension for the Sphinx documentation
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
:copyright: 2008 by Georg Brandl.
:license: BSD.
"""
import re
from sphinx import addnodes
dir_sig_re = re.compile(r'\.\. ([^:]+)::(.*)$')
def parse_directive(env, sig, signode):
if not sig.startswith('.'):
dec_sig = '.. %s::' % sig
signode += addnodes.desc_name(dec_sig, dec_sig)
return sig
m = dir_sig_re.match(sig)
if not m:
signode += addnodes.desc_name(sig, sig)
return sig
name, args = m.groups()
dec_name = '.. %s::' % name
signode += addnodes.desc_name(dec_name, dec_name)
signode += addnodes.desc_classname(args, args)
return name
def parse_role(env, sig, signode):
signode += addnodes.desc_name(':%s:' % sig, ':%s:' % sig)
return sig
def setup(app):
app.add_description_unit('directive', 'dir', 'pair: %s; directive', parse_directive)
app.add_description_unit('role', 'role', 'pair: %s; role', parse_role)
app.add_description_unit('confval', 'confval', 'pair: %s; configuration value')

View File

@ -15,6 +15,9 @@ reStructuredText roles and directives, extending the markup. And finally, there
are so-called "hook points" at strategic places throughout the build process, are so-called "hook points" at strategic places throughout the build process,
where an extension can register a hook and run specialized code. where an extension can register a hook and run specialized code.
The configuration file itself can be an extension, see the :confval:`extensions`
configuration value docs.
.. toctree:: .. toctree::
ext/appapi ext/appapi

View File

@ -79,6 +79,9 @@ class Sphinx(object):
# load all extension modules # load all extension modules
for extension in getattr(self.config, 'extensions', ()): for extension in getattr(self.config, 'extensions', ()):
self.setup_extension(extension) self.setup_extension(extension)
# the config file itself can be an extension
if hasattr(self.config, 'setup'):
self.config.setup(self)
# this must happen after loading extension modules, since they # this must happen after loading extension modules, since they
# can add custom config values # can add custom config values

View File

@ -10,7 +10,6 @@
""" """
import os import os
import types
from os import path from os import path
@ -77,10 +76,6 @@ class Config(object):
execfile(config['__file__'], config) execfile(config['__file__'], config)
finally: finally:
os.chdir(olddir) os.chdir(olddir)
# remove potentially pickling-problematic values
for key, val in config.items():
if key.startswith('_') or isinstance(val, types.ModuleType):
del config[key]
self.__dict__.update(config) self.__dict__.update(config)
def init_defaults(self): def init_defaults(self):
@ -91,5 +86,11 @@ class Config(object):
def __getitem__(self, name): def __getitem__(self, name):
return getattr(self, name) return getattr(self, name)
def __setitem__(self, name, value):
setattr(self, name, value)
def __delitem__(self, name):
delattr(self, name)
def __contains__(self, name): def __contains__(self, name):
return hasattr(self, name) return hasattr(self, name)

View File

@ -13,6 +13,7 @@ import re
import os import os
import time import time
import heapq import heapq
import types
import difflib import difflib
import itertools import itertools
import cPickle as pickle import cPickle as pickle
@ -179,6 +180,12 @@ class BuildEnvironment:
warnfunc = self._warnfunc warnfunc = self._warnfunc
self.set_warnfunc(None) self.set_warnfunc(None)
picklefile = open(filename, 'wb') picklefile = open(filename, 'wb')
# remove potentially pickling-problematic values from config
for key, val in vars(self.config).items():
if key.startswith('_') or \
isinstance(val, types.ModuleType) or \
isinstance(val, types.FunctionType):
del self.config[key]
try: try:
pickle.dump(self, picklefile, pickle.HIGHEST_PROTOCOL) pickle.dump(self, picklefile, pickle.HIGHEST_PROTOCOL)
finally: finally: