summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sphinx/application.py1
-rw-r--r--sphinx/builders/html.py20
-rw-r--r--sphinx/directives/desc.py6
-rw-r--r--sphinx/directives/other.py71
-rw-r--r--sphinx/domains.py170
-rw-r--r--sphinx/environment.py29
-rw-r--r--sphinx/ext/coverage.py14
-rw-r--r--sphinx/search.py4
-rw-r--r--tests/test_env.py9
9 files changed, 179 insertions, 145 deletions
diff --git a/sphinx/application.py b/sphinx/application.py
index 3566bc50..7d9ee49d 100644
--- a/sphinx/application.py
+++ b/sphinx/application.py
@@ -14,6 +14,7 @@
import sys
import types
import posixpath
+from os import path
from cStringIO import StringIO
from docutils import nodes
diff --git a/sphinx/builders/html.py b/sphinx/builders/html.py
index 20e84b41..de4c9a39 100644
--- a/sphinx/builders/html.py
+++ b/sphinx/builders/html.py
@@ -240,7 +240,9 @@ class StandaloneHTMLBuilder(Builder):
rellinks = []
if self.config.html_use_index:
rellinks.append(('genindex', _('General Index'), 'I', _('index')))
- if self.config.html_use_modindex and self.env.modules:
+ # XXX generalization of modindex?
+ if self.config.html_use_modindex and \
+ self.env.domains['py'].data['modules']:
rellinks.append(('modindex', _('Global Module Index'),
'M', _('modules')))
@@ -405,12 +407,13 @@ class StandaloneHTMLBuilder(Builder):
# the global module index
- if self.config.html_use_modindex and self.env.modules:
+ moduleindex = self.env.domains['py'].data['modules']
+ if self.config.html_use_modindex and moduleindex:
# the sorted list of all modules, for the global module index
modules = sorted(((mn, (self.get_relative_uri('modindex', fn) +
'#module-' + mn, sy, pl, dep))
for (mn, (fn, sy, pl, dep)) in
- self.env.modules.iteritems()),
+ moduleindex.iteritems()),
key=lambda x: x[0].lower())
# collect all platforms
platforms = set()
@@ -710,14 +713,15 @@ class StandaloneHTMLBuilder(Builder):
self.info(bold('dumping object inventory... '), nonl=True)
f = open(path.join(self.outdir, INVENTORY_FILENAME), 'w')
try:
+ # XXX inventory version 2
f.write('# Sphinx inventory version 1\n')
f.write('# Project: %s\n' % self.config.project.encode('utf-8'))
f.write('# Version: %s\n' % self.config.version)
- for modname, info in self.env.modules.iteritems():
- f.write('%s mod %s\n' % (modname, self.get_target_uri(info[0])))
- for refname, (docname, desctype) in self.env.descrefs.iteritems():
- f.write('%s %s %s\n' % (refname, desctype,
- self.get_target_uri(docname)))
+ #for modname, info in self.env.modules.iteritems():
+ # f.write('%s mod %s\n' % (modname, self.get_target_uri(info[0])))
+ #for refname, (docname, desctype) in self.env.descrefs.iteritems():
+ # f.write('%s %s %s\n' % (refname, desctype,
+ # self.get_target_uri(docname)))
finally:
f.close()
self.info('done')
diff --git a/sphinx/directives/desc.py b/sphinx/directives/desc.py
index e3018100..06fc4c98 100644
--- a/sphinx/directives/desc.py
+++ b/sphinx/directives/desc.py
@@ -204,7 +204,10 @@ class DescDirective(Directive):
pass
def run(self):
- self.desctype = self.name
+ if ':' in self.name:
+ self.domain, self.desctype = self.name.split(':', 1)
+ else:
+ self.domain, self.desctype = '', self.name
self.env = self.state.document.settings.env
self.indexnode = addnodes.index(entries=[])
@@ -366,7 +369,6 @@ class DefaultDomain(Directive):
def run(self):
env = self.state.document.settings.env
domain_name = arguments[0]
- # XXX won't work
env.default_domain = env.domains.get(domain_name)
diff --git a/sphinx/directives/other.py b/sphinx/directives/other.py
index d056f3dc..ee938cfd 100644
--- a/sphinx/directives/other.py
+++ b/sphinx/directives/other.py
@@ -103,75 +103,6 @@ class TocTree(Directive):
return ret
-class Module(Directive):
- """
- Directive to mark description of a new module.
- """
-
- has_content = False
- required_arguments = 1
- optional_arguments = 0
- final_argument_whitespace = False
- option_spec = {
- 'platform': lambda x: x,
- 'synopsis': lambda x: x,
- 'noindex': directives.flag,
- 'deprecated': directives.flag,
- }
-
- def run(self):
- env = self.state.document.settings.env
- modname = self.arguments[0].strip()
- noindex = 'noindex' in self.options
- env.currmodule = modname
- env.note_module(modname, self.options.get('synopsis', ''),
- self.options.get('platform', ''),
- 'deprecated' in self.options)
- modulenode = addnodes.module()
- modulenode['modname'] = modname
- modulenode['synopsis'] = self.options.get('synopsis', '')
- targetnode = nodes.target('', '', ids=['module-' + modname], ismod=True)
- self.state.document.note_explicit_target(targetnode)
- ret = [modulenode, targetnode]
- if 'platform' in self.options:
- platform = self.options['platform']
- modulenode['platform'] = platform
- node = nodes.paragraph()
- node += nodes.emphasis('', _('Platforms: '))
- node += nodes.Text(platform, platform)
- ret.append(node)
- # the synopsis isn't printed; in fact, it is only used in the
- # modindex currently
- if not noindex:
- indextext = _('%s (module)') % modname
- inode = addnodes.index(entries=[('single', indextext,
- 'module-' + modname, modname)])
- ret.insert(0, inode)
- return ret
-
-
-class CurrentModule(Directive):
- """
- This directive is just to tell Sphinx that we're documenting
- stuff in module foo, but links to module foo won't lead here.
- """
-
- has_content = False
- required_arguments = 1
- optional_arguments = 0
- final_argument_whitespace = False
- option_spec = {}
-
- def run(self):
- env = self.state.document.settings.env
- modname = self.arguments[0].strip()
- if modname == 'None':
- env.currmodule = None
- else:
- env.currmodule = modname
- return []
-
-
class Author(Directive):
"""
Directive to give the name of the author of the current document
@@ -559,8 +490,6 @@ class Only(Directive):
directives.register_directive('toctree', directive_dwim(TocTree))
-directives.register_directive('module', directive_dwim(Module))
-directives.register_directive('currentmodule', directive_dwim(CurrentModule))
directives.register_directive('sectionauthor', directive_dwim(Author))
directives.register_directive('moduleauthor', directive_dwim(Author))
directives.register_directive('program', directive_dwim(Program))
diff --git a/sphinx/domains.py b/sphinx/domains.py
index 66448111..3e5b22e8 100644
--- a/sphinx/domains.py
+++ b/sphinx/domains.py
@@ -14,11 +14,13 @@ import re
import string
from docutils import nodes
+from docutils.parsers.rst import directives
from sphinx import addnodes
from sphinx.roles import XRefRole
from sphinx.directives import DescDirective
from sphinx.util import make_refnode
+from sphinx.util.compat import Directive
class Domain(object):
@@ -28,28 +30,28 @@ class Domain(object):
label = ''
# data value for a fresh environment
- initial_data = {
-
- }
+ initial_data = {}
# data version
data_version = 0
def __init__(self, env):
self.env = env
- self.data = env.domaindata.get(self.name, self.initial_data)
- if 'version' in self.data and self.data['version'] < self.data_version:
- raise IOError('data of %r domain out of date' % self.label)
+ if self.name not in env.domaindata:
+ new_data = self.initial_data.copy()
+ new_data['version'] = self.data_version
+ self.data = env.domaindata[self.name] = new_data
+ else:
+ self.data = env.domaindata[self.name]
+ if self.data['version'] < self.data_version:
+ raise IOError('data of %r domain out of date' % self.label)
self._role_cache = {}
self._directive_cache = {}
- def __getstate__(self):
- # can't pickle the adapter caches
- state = self.__dict__.copy()
- state['_role_cache'] = {}
- state['_directive_cache'] = {}
- return state
-
- #def clear_doc
+ def clear_doc(self, docname):
+ """
+ Remove traces of a document in the domain-specific inventories.
+ """
+ pass
def role(self, name):
"""
@@ -212,7 +214,15 @@ class PythonDesc(DescDirective):
signode['ids'].append(fullname)
signode['first'] = (not self.names)
self.state.document.note_explicit_target(signode)
- self.env.note_descref(fullname, self.desctype, self.lineno)
+ objects = self.env.domains['py'].data['objects']
+ if fullname in objects:
+ self.env.warn(
+ self.env.docname,
+ 'duplicate object description of %s, ' % fullname +
+ 'other instance in ' +
+ self.env.doc2path(objects[fullname][0]),
+ self.lineno)
+ objects[fullname] = (self.env.docname, self.desctype)
indextext = self.get_index_text(modname, name_cls)
if indextext:
@@ -352,6 +362,75 @@ class ClassmemberDesc(PythonDesc):
self.clsname_set = True
+class PyModule(Directive):
+ """
+ Directive to mark description of a new module.
+ """
+
+ has_content = False
+ required_arguments = 1
+ optional_arguments = 0
+ final_argument_whitespace = False
+ option_spec = {
+ 'platform': lambda x: x,
+ 'synopsis': lambda x: x,
+ 'noindex': directives.flag,
+ 'deprecated': directives.flag,
+ }
+
+ def run(self):
+ env = self.state.document.settings.env
+ modname = self.arguments[0].strip()
+ noindex = 'noindex' in self.options
+ env.currmodule = modname
+ env.domains['py'].data['modules'][modname] = \
+ (env.docname, self.options.get('synopsis', ''),
+ self.options.get('platform', ''), 'deprecated' in self.options)
+ modulenode = addnodes.module()
+ modulenode['modname'] = modname
+ modulenode['synopsis'] = self.options.get('synopsis', '')
+ targetnode = nodes.target('', '', ids=['module-' + modname], ismod=True)
+ self.state.document.note_explicit_target(targetnode)
+ ret = [modulenode, targetnode]
+ if 'platform' in self.options:
+ platform = self.options['platform']
+ modulenode['platform'] = platform
+ node = nodes.paragraph()
+ node += nodes.emphasis('', _('Platforms: '))
+ node += nodes.Text(platform, platform)
+ ret.append(node)
+ # the synopsis isn't printed; in fact, it is only used in the
+ # modindex currently
+ if not noindex:
+ indextext = _('%s (module)') % modname
+ inode = addnodes.index(entries=[('single', indextext,
+ 'module-' + modname, modname)])
+ ret.insert(0, inode)
+ return ret
+
+
+class PyCurrentModule(Directive):
+ """
+ This directive is just to tell Sphinx that we're documenting
+ stuff in module foo, but links to module foo won't lead here.
+ """
+
+ has_content = False
+ required_arguments = 1
+ optional_arguments = 0
+ final_argument_whitespace = False
+ option_spec = {}
+
+ def run(self):
+ env = self.state.document.settings.env
+ modname = self.arguments[0].strip()
+ if modname == 'None':
+ env.currmodule = None
+ else:
+ env.currmodule = modname
+ return []
+
+
class PyXRefRole(XRefRole):
def process_link(self, env, pnode, has_explicit_title, title, target):
pnode['modname'] = env.currmodule
@@ -387,6 +466,8 @@ class PythonDomain(Domain):
'classmethod': ClassmemberDesc,
'staticmethod': ClassmemberDesc,
'attribute': ClassmemberDesc,
+ 'module': PyModule,
+ 'currentmodule': PyCurrentModule,
}
roles = {
'data': PyXRefRole(),
@@ -399,6 +480,18 @@ class PythonDomain(Domain):
'mod': PyXRefRole(),
'obj': PyXRefRole(),
}
+ initial_data = {
+ 'objects': {}, # fullname -> docname, desctype
+ 'modules': {}, # modname -> docname, synopsis, platform, deprecated
+ }
+
+ def clear_doc(self, docname):
+ for fullname, (fn, _) in self.data['objects'].items():
+ if fn == docname:
+ del self.data['objects'][fullname]
+ for modname, (fn, _, _, _) in self.data['modules'].items():
+ if fn == docname:
+ del self.data['modules'][modname]
def find_desc(self, env, modname, classname, name, type, searchorder=0):
"""
@@ -412,41 +505,43 @@ class PythonDomain(Domain):
if not name:
return None, None
+ objects = self.data['objects']
+
newname = None
if searchorder == 1:
if modname and classname and \
- modname + '.' + classname + '.' + name in env.descrefs:
+ modname + '.' + classname + '.' + name in objects:
newname = modname + '.' + classname + '.' + name
- elif modname and modname + '.' + name in env.descrefs:
+ elif modname and modname + '.' + name in objects:
newname = modname + '.' + name
- elif name in env.descrefs:
+ elif name in objects:
newname = name
else:
- if name in env.descrefs:
+ if name in objects:
newname = name
- elif modname and modname + '.' + name in env.descrefs:
+ elif modname and modname + '.' + name in objects:
newname = modname + '.' + name
elif modname and classname and \
- modname + '.' + classname + '.' + name in env.descrefs:
+ modname + '.' + classname + '.' + name in objects:
newname = modname + '.' + classname + '.' + name
# special case: builtin exceptions have module "exceptions" set
elif type == 'exc' and '.' not in name and \
- 'exceptions.' + name in env.descrefs:
+ 'exceptions.' + name in objects:
newname = 'exceptions.' + name
# special case: object methods
elif type in ('func', 'meth') and '.' not in name and \
- 'object.' + name in env.descrefs:
+ 'object.' + name in objects:
newname = 'object.' + name
if newname is None:
return None, None
- return newname, env.descrefs[newname]
+ return newname, objects[newname]
def resolve_xref(self, env, fromdocname, builder,
typ, target, node, contnode):
if (typ == 'mod' or
- typ == 'obj' and target in env.modules):
+ typ == 'obj' and target in self.data['modules']):
docname, synopsis, platform, deprecated = \
- env.modules.get(target, ('','','', ''))
+ self.data['modules'].get(target, ('','','', ''))
if not docname:
return None
elif docname == fromdocname:
@@ -459,7 +554,6 @@ class PythonDomain(Domain):
return make_refnode(builder, fromdocname, docname,
'module-' + target, contnode, title)
else:
- # "descrefs"
modname = node['modname']
clsname = node['classname']
searchorder = node.hasattr('refspecific') and 1 or 0
@@ -589,7 +683,14 @@ class CDesc(DescDirective):
signode['ids'].append(name)
signode['first'] = (not self.names)
self.state.document.note_explicit_target(signode)
- self.env.note_descref(name, self.desctype, self.lineno)
+ inv = self.env.domains['c'].data['objects']
+ if name in inv:
+ self.env.warn(
+ self.env.docname,
+ 'duplicate C object description of %s, ' % name +
+ 'other instance in ' + self.env.doc2path(inv[name][0]),
+ self.lineno)
+ inv[name] = (self.env.docname, self.desctype)
indextext = self.get_index_text(name)
if indextext:
@@ -614,15 +715,22 @@ class CDomain(Domain):
'data': XRefRole(),
'type': XRefRole(),
}
+ initial_data = {
+ 'objects': {}, # fullname -> docname, desctype
+ }
+
+ def clear_doc(self, docname):
+ for fullname, (fn, _) in self.data['objects'].items():
+ if fn == docname:
+ del self.data['objects'][fullname]
def resolve_xref(self, env, fromdocname, builder,
typ, target, node, contnode):
# strip pointer asterisk
target = target.rstrip(' *')
- # XXX descrefs
- if target not in env.descrefs:
+ if target not in self.data:
return None
- desc = env.descrefs[target]
+ desc = self.data[target]
return make_refnode(builder, fromdocname, desc[0], contnode, target)
diff --git a/sphinx/environment.py b/sphinx/environment.py
index 62d3875b..2f64b147 100644
--- a/sphinx/environment.py
+++ b/sphinx/environment.py
@@ -297,13 +297,10 @@ class BuildEnvironment:
self.glob_toctrees = set() # docnames that have :glob: toctrees
self.numbered_toctrees = set() # docnames that have :numbered: toctrees
- # domain-specific inventories
- self.domaindata = {} # domainname -> object
+ # domain-specific inventories, here to be pickled
+ self.domaindata = {} # domainname -> domain-specific object
# X-ref target inventory
- self.descrefs = {} # fullname -> docname, desctype
- self.modules = {} # modname -> docname, synopsis,
- # platform, deprecated
self.labels = {} # labelname -> docname, labelid, sectionname
self.anonlabels = {} # labelname -> docname, labelid
self.progoptions = {} # (program, name) -> docname, labelid
@@ -371,12 +368,6 @@ class BuildEnvironment:
fnset.discard(docname)
if not fnset:
del self.files_to_rebuild[subfn]
- for fullname, (fn, _) in self.descrefs.items():
- if fn == docname:
- del self.descrefs[fullname]
- for modname, (fn, _, _, _) in self.modules.items():
- if fn == docname:
- del self.modules[modname]
for labelname, (fn, _, _) in self.labels.items():
if fn == docname:
del self.labels[labelname]
@@ -390,6 +381,10 @@ class BuildEnvironment:
new = [change for change in changes if change[1] != docname]
changes[:] = new
+ # XXX why does this not work inside the if?
+ for domain in self.domains.values():
+ domain.clear_doc(docname)
+
def doc2path(self, docname, base=True, suffix=None):
"""
Return the filename for the document name.
@@ -1001,18 +996,6 @@ class BuildEnvironment:
# -------
# these are called from docutils directives and therefore use self.docname
#
- def note_descref(self, fullname, desctype, line):
- if fullname in self.descrefs:
- self.warn(self.docname,
- 'duplicate canonical description name %s, ' % fullname +
- 'other instance in ' +
- self.doc2path(self.descrefs[fullname][0]),
- line)
- self.descrefs[fullname] = (self.docname, desctype)
-
- def note_module(self, modname, synopsis, platform, deprecated):
- self.modules[modname] = (self.docname, synopsis, platform, deprecated)
-
def note_progoption(self, optname, labelid):
self.progoptions[self.currprogram, optname] = (self.docname, labelid)
diff --git a/sphinx/ext/coverage.py b/sphinx/ext/coverage.py
index 964e58ee..6eb9bc8b 100644
--- a/sphinx/ext/coverage.py
+++ b/sphinx/ext/coverage.py
@@ -79,6 +79,7 @@ class CoverageBuilder(Builder):
def build_c_coverage(self):
# Fetch all the info from the header files
+ c_objects = self.env.domains['c'].data['objects']
for filename in self.c_sourcefiles:
undoc = []
f = open(filename, 'r')
@@ -88,7 +89,7 @@ class CoverageBuilder(Builder):
match = regex.match(line)
if match:
name = match.groups()[0]
- if name not in self.env.descrefs:
+ if name not in c_objects:
for exp in self.c_ignorexps.get(key, ()):
if exp.match(name):
break
@@ -116,7 +117,10 @@ class CoverageBuilder(Builder):
op.close()
def build_py_coverage(self):
- for mod_name in self.env.modules:
+ objects = self.env.domains['py'].data['objects']
+ modules = self.env.domains['py'].data['modules']
+
+ for mod_name in modules:
ignore = False
for exp in self.mod_ignorexps:
if exp.match(mod_name):
@@ -151,7 +155,7 @@ class CoverageBuilder(Builder):
full_name = '%s.%s' % (mod_name, name)
if inspect.isfunction(obj):
- if full_name not in self.env.descrefs:
+ if full_name not in objects:
for exp in self.fun_ignorexps:
if exp.match(name):
break
@@ -162,7 +166,7 @@ class CoverageBuilder(Builder):
if exp.match(name):
break
else:
- if full_name not in self.env.descrefs:
+ if full_name not in objects:
# not documented at all
classes[name] = []
continue
@@ -176,7 +180,7 @@ class CoverageBuilder(Builder):
continue
full_attr_name = '%s.%s' % (full_name, attr_name)
- if full_attr_name not in self.env.descrefs:
+ if full_attr_name not in objects:
attrs.append(attr_name)
if attrs:
diff --git a/sphinx/search.py b/sphinx/search.py
index 499c4aa9..f283881f 100644
--- a/sphinx/search.py
+++ b/sphinx/search.py
@@ -149,6 +149,8 @@ class IndexBuilder(object):
def get_modules(self, fn2index):
rv = {}
+ # XXX implement search capability
+ return rv
for name, (doc, _, _, _) in self.env.modules.iteritems():
if doc in fn2index:
rv[name] = fn2index[doc]
@@ -157,6 +159,8 @@ class IndexBuilder(object):
def get_descrefs(self, fn2index):
rv = {}
dt = self._desctypes
+ # XXX implement search capability
+ return rv
for fullname, (doc, desctype) in self.env.descrefs.iteritems():
if doc not in fn2index:
continue
diff --git a/tests/test_env.py b/tests/test_env.py
index d5f40f8c..921d893c 100644
--- a/tests/test_env.py
+++ b/tests/test_env.py
@@ -20,9 +20,8 @@ warnings = []
def setup_module():
global app, env
- app = TestApp(srcdir='(temp)')
+ app = TestApp(srcdir='(temp)', freshenv=True)
env = app.env
- #env = BuildEnvironment(app.srcdir, app.doctreedir, app.config)
env.set_warnfunc(lambda *args: warnings.append(args))
def teardown_module():
@@ -93,7 +92,7 @@ def test_second_update():
assert 'autodoc' not in env.found_docs
def test_object_inventory():
- refs = env.descrefs
+ refs = env.domains['py'].data['objects']
assert 'func_without_module' in refs
assert refs['func_without_module'] == ('desc', 'function')
@@ -110,5 +109,5 @@ def test_object_inventory():
assert 'func_in_module' not in refs
assert 'func_noindex' not in refs
- assert 'mod' in env.modules
- assert env.modules['mod'] == ('desc', 'Module synopsis.', 'UNIX', False)
+ assert env.domains['py'].data['modules']['mod'] == \
+ ('desc', 'Module synopsis.', 'UNIX', False)