diff --git a/CHANGES b/CHANGES index d3c590c6b..77e03db29 100644 --- a/CHANGES +++ b/CHANGES @@ -13,6 +13,9 @@ Changes in trunk * sphinx.builder, sphinx.environment: Gracefully handle some exception cases. +* sphinx.config: The config file itself can be an extension (if it + provides a setup() function). + Release 0.1.61950 (Mar 26, 2008) ================================ diff --git a/doc/conf.py b/doc/conf.py index 8f282cc0d..74ec3d394 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -11,17 +11,17 @@ # All configuration values have a default value; values that are commented out # serve to show the default value. -import sys, os +import sys, os, re # 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 # --------------------- # Add any Sphinx extension module names here, as strings. They can be extensions # 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. templates_path = ['_templates'] @@ -125,3 +125,37 @@ latex_documents = [('contents', 'sphinx.tex', 'Sphinx Documentation', #latex_appendices = [] 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') diff --git a/doc/config.rst b/doc/config.rst index b00225ead..91dd8b064 100644 --- a/doc/config.rst +++ b/doc/config.rst @@ -50,6 +50,9 @@ General configuration That way, you can load an extension called ``extname`` from the documentation 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 A list of paths that contain extra templates (or templates that overwrite diff --git a/doc/ext.py b/doc/ext.py deleted file mode 100644 index 518271df0..000000000 --- a/doc/ext.py +++ /dev/null @@ -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') diff --git a/doc/extensions.rst b/doc/extensions.rst index 00470f769..5eaf1ab36 100644 --- a/doc/extensions.rst +++ b/doc/extensions.rst @@ -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, 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:: ext/appapi diff --git a/sphinx/application.py b/sphinx/application.py index 35db38eaf..0e9637224 100644 --- a/sphinx/application.py +++ b/sphinx/application.py @@ -79,6 +79,9 @@ class Sphinx(object): # load all extension modules for extension in getattr(self.config, 'extensions', ()): 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 # can add custom config values diff --git a/sphinx/config.py b/sphinx/config.py index 0cec4fe88..055cc61e6 100644 --- a/sphinx/config.py +++ b/sphinx/config.py @@ -10,7 +10,6 @@ """ import os -import types from os import path @@ -77,10 +76,6 @@ class Config(object): execfile(config['__file__'], config) finally: 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) def init_defaults(self): @@ -91,5 +86,11 @@ class Config(object): def __getitem__(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): return hasattr(self, name) diff --git a/sphinx/environment.py b/sphinx/environment.py index 992a0e4b7..78b05be37 100644 --- a/sphinx/environment.py +++ b/sphinx/environment.py @@ -13,6 +13,7 @@ import re import os import time import heapq +import types import difflib import itertools import cPickle as pickle @@ -179,6 +180,12 @@ class BuildEnvironment: warnfunc = self._warnfunc self.set_warnfunc(None) 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: pickle.dump(self, picklefile, pickle.HIGHEST_PROTOCOL) finally: