diff options
| author | Georg Brandl <georg@python.org> | 2010-02-28 14:45:43 +0100 |
|---|---|---|
| committer | Georg Brandl <georg@python.org> | 2010-02-28 14:45:43 +0100 |
| commit | 4d77d3d6fb8859f859ecd46a7aa3a03923b9cfa2 (patch) | |
| tree | a7053d260603179f7c9447a43a82243ab70112e3 /sphinx/domains | |
| parent | 06fd1678117bc2a1c61b4d2de130d2480160e91d (diff) | |
| download | sphinx-4d77d3d6fb8859f859ecd46a7aa3a03923b9cfa2.tar.gz | |
Change domain-index API: introduce a class.
Diffstat (limited to 'sphinx/domains')
| -rw-r--r-- | sphinx/domains/__init__.py | 137 | ||||
| -rw-r--r-- | sphinx/domains/python.py | 141 |
2 files changed, 144 insertions, 134 deletions
diff --git a/sphinx/domains/__init__.py b/sphinx/domains/__init__.py index a03a74db..f1e6e8af 100644 --- a/sphinx/domains/__init__.py +++ b/sphinx/domains/__init__.py @@ -10,6 +10,8 @@ :license: BSD, see LICENSE for details. """ +from sphinx.errors import SphinxError + class ObjType(object): """ @@ -23,7 +25,7 @@ class ObjType(object): - *roles*: all the roles that can refer to an object of this type - *attrs*: object attributes -- currently only "searchprio" is known, which defines the object's priority in the full-text search index, - see `Domain.get_objects`. + see :meth:`Domain.get_objects()`. """ known_attrs = { @@ -37,6 +39,63 @@ class ObjType(object): self.attrs.update(attrs) +class Index(object): + """ + An Index is the description for a domain-specific index. To add an index to + a domain, subclass Index, overriding the three name attributes: + + * `name` is an identifier used for generating file names. + * `localname` is the section title for the index. + * `shortname` is a short name for the index, for use in the relation bar in + HTML output. Can be empty to disable entries in the relation bar. + + and providing a :meth:`generate()` method. Then, add the index class to + your domain's `indices` list. Extensions can add indices to existing + domains using :meth:`~sphinx.application.Sphinx.add_index_to_domain()`. + """ + + name = None + localname = None + shortname = None + + def __init__(self, domain): + if self.name is None or self.localname is None: + raise SphinxError('Index subclass %s has no valid name or localname' + % self.__class__.__name__) + self.domain = domain + + def generate(self, docnames=None): + """ + Return entries for the index given by *name*. If *docnames* is given, + restrict to entries referring to these docnames. + + The return value is a tuple of ``(content, collapse)``, where *collapse* + is a boolean that determines if sub-entries should start collapsed (for + output formats that support collapsing sub-entries). + + *content* is a sequence of ``(letter, entries)`` tuples, where *letter* + is the "heading" for the given *entries*, usually the starting letter. + + *entries* is a sequence of single entries, where a single entry is a + sequence ``[name, subtype, docname, anchor, extra, qualifier, descr]``. + The items in this sequence have the following meaning: + + - `name` -- the name of the index entry to be displayed + - `subtype` -- sub-entry related type: + 0 -- normal entry + 1 -- entry with sub-entries + 2 -- sub-entry + - `docname` -- docname where the entry is located + - `anchor` -- anchor for the entry within `docname` + - `extra` -- extra info for the entry + - `qualifier` -- qualifier for the description + - `descr` -- description for the entry + + Qualifier and description are not rendered e.g. in LaTeX output. + """ + return [] + + class Domain(object): """ A Domain is meant to be a group of "object" description directives for @@ -45,9 +104,9 @@ class Domain(object): of a templating language, Sphinx roles and directives, etc. Each domain has a separate storage for information about existing objects - and how to reference them in `data`, which must be a dictionary. It also - must implement several functions that expose the object information in a - uniform way to parts of Sphinx that allow the user to reference or search + and how to reference them in `self.data`, which must be a dictionary. It + also must implement several functions that expose the object information in + a uniform way to parts of Sphinx that allow the user to reference or search for objects in a domain-agnostic way. About `self.data`: since all object and cross-referencing information is @@ -56,8 +115,8 @@ class Domain(object): build process starts, every active domain is instantiated and given the environment object; the `domaindata` dict must then either be nonexistent or a dictionary whose 'version' key is equal to the domain class' - `data_version` attribute. Otherwise, `IOError` is raised and the pickled - environment is discarded. + :attr:`data_version` attribute. Otherwise, `IOError` is raised and the + pickled environment is discarded. """ #: domain name: should be short, but unique @@ -70,12 +129,12 @@ class Domain(object): directives = {} #: role name -> role callable roles = {} - #: (index identifier, localized index name, localized short name) tuples + #: a list of Index subclasses indices = [] #: data value for a fresh environment initial_data = {} - #: data version + #: data version, bump this when the format of `self.data` changes data_version = 0 def __init__(self, env): @@ -153,8 +212,8 @@ class Domain(object): then given to the 'missing-reference' event, and if that yields no resolution, replaced by *contnode*. - The method can also raise `sphinx.environment.NoUri` to suppress the - 'missing-reference' event being emitted. + The method can also raise :exc:`sphinx.environment.NoUri` to suppress + the 'missing-reference' event being emitted. """ pass @@ -170,63 +229,13 @@ class Domain(object): * `priority` -- how "important" the object is (determines placement in search results) - 1: default priority (placed before full-text matches) - 0: object is important (placed before default-priority objects) - 2: object is unimportant (placed after full-text matches) - -1: object should not show up in search at all + - 1: default priority (placed before full-text matches) + - 0: object is important (placed before default-priority objects) + - 2: object is unimportant (placed after full-text matches) + - -1: object should not show up in search at all """ return [] - def has_index_entries(self, name, docnames=None): - """ - Return True if there are entries for the index given by *name*. If - *docnames* is given, restrict to entries referring to these docnames. - - Do not overwrite this method, add a method ``has_<name>_entries(self, - docnames=None)`` method for every index. - """ - func = getattr(self, 'has_%s_entries' % name, None) - if not func: - return bool(self.get_index(name, docnames)) - return func(docnames) - - def get_index(self, name, docnames=None): - """ - Return entries for the index given by *name*. If *docnames* is given, - restrict to entries referring to these docnames. - - The return value is a tuple of ``(content, collapse)``, where *collapse* - is a boolean that determines if sub-entries should start collapsed (for - output formats that support collapsing sub-entries). - - *content* is a sequence of ``(letter, entries)`` tuples, where *letter* - is the "heading" for the given *entries*, usually the starting letter. - - *entries* is a sequence of single entries, where a single entry is a - sequence ``[name, subtype, docname, anchor, extra, qualifier, descr]``. - The items in this sequence have the following meaning: - - - `name` -- the name of the index entry to be displayed - - `subtype` -- sub-entry related type: - 0 -- normal entry - 1 -- entry with sub-entries - 2 -- sub-entry - - `docname` -- docname where the entry is located - - `anchor` -- anchor for the entry within `docname` - - `extra` -- extra info for the entry - - `qualifier` -- qualifier for the description - - `descr` -- description for the entry - - Qualifier and description are not rendered e.g. in LaTeX output. - - Do not overwrite this method, add a method ``get_<name>_index(self, - docnames=None)`` method for every index. - """ - func = getattr(self, 'get_%s_index' % name, None) - if not func: - return [] - return func(docnames) - from sphinx.domains.c import CDomain from sphinx.domains.std import StandardDomain diff --git a/sphinx/domains/python.py b/sphinx/domains/python.py index af1392a6..af8b2eda 100644 --- a/sphinx/domains/python.py +++ b/sphinx/domains/python.py @@ -17,7 +17,7 @@ from docutils.parsers.rst import directives from sphinx import addnodes from sphinx.roles import XRefRole from sphinx.locale import l_, _ -from sphinx.domains import Domain, ObjType +from sphinx.domains import Domain, ObjType, Index from sphinx.directives import ObjectDescription from sphinx.util.nodes import make_refnode from sphinx.util.compat import Directive @@ -419,6 +419,75 @@ class PyXRefRole(XRefRole): return title, target +class PythonModuleIndex(Index): + """ + Index subclass to provide the Python module index. + """ + + name = 'modindex' + localname = l_('Python Module Index') + shortname = l_('modules') + + def generate(self, docnames=None): + content = {} + # list of prefixes to ignore + ignores = self.domain.env.config['modindex_common_prefix'] + ignores = sorted(ignores, key=len, reverse=True) + # list of all modules, sorted by module name + modules = sorted(self.domain.data['modules'].iteritems(), + key=lambda x: x[0].lower()) + # sort out collapsable modules + prev_modname = '' + num_toplevels = 0 + for modname, (docname, synopsis, platforms, deprecated) in modules: + if docnames and docname not in docnames: + continue + + for ignore in ignores: + if modname.startswith(ignore): + modname = modname[len(ignore):] + stripped = ignore + break + else: + stripped = '' + + # we stripped the whole module name? + if not modname: + modname, stripped = stripped, '' + + entries = content.setdefault(modname[0].lower(), []) + + package = modname.split('.')[0] + if package != modname: + # it's a submodule + if prev_modname == package: + # first submodule - make parent a group head + entries[-1][1] = 1 + elif not prev_modname.startswith(package): + # submodule without parent in list, add dummy entry + entries.append([stripped + package, 1, '', '', '', '', '']) + subtype = 2 + else: + num_toplevels += 1 + subtype = 0 + + qualifier = deprecated and _('Deprecated') or '' + entries.append([stripped + modname, subtype, docname, + 'module-' + stripped + modname, platforms, + qualifier, synopsis]) + prev_modname = modname + + # apply heuristics when to collapse modindex at page load: + # only collapse if number of toplevel modules is larger than + # number of submodules + collapse = len(modules) - num_toplevels < num_toplevels + + # sort by first letter + content = sorted(content.iteritems()) + + return content, collapse + + class PythonDomain(Domain): """Python language domain.""" name = 'py' @@ -463,7 +532,7 @@ class PythonDomain(Domain): 'modules': {}, # modname -> docname, synopsis, platform, deprecated } indices = [ - ('modindex', l_('Python Module Index'), l_('modules')), + PythonModuleIndex, ] def clear_doc(self, docname): @@ -548,71 +617,3 @@ class PythonDomain(Domain): yield (modname, 'module', info[0], 'module-' + modname, 0) for refname, (docname, type) in self.data['objects'].iteritems(): yield (refname, type, docname, refname, 1) - - def has_modindex_entries(self, docnames=None): - if not docnames: - return bool(self.data['modules']) - else: - for modname, info in self.data['modules'].iteritems(): - if info[0] in docnames: - return True - return False - - def get_modindex_index(self, docnames=None): - content = {} - # list of prefixes to ignore - ignores = self.env.config['modindex_common_prefix'] - ignores = sorted(ignores, key=len, reverse=True) - # list of all modules, sorted by module name - modules = sorted(self.data['modules'].iteritems(), - key=lambda x: x[0].lower()) - # sort out collapsable modules - prev_modname = '' - num_toplevels = 0 - for modname, (docname, synopsis, platforms, deprecated) in modules: - if docnames and docname not in docnames: - continue - - for ignore in ignores: - if modname.startswith(ignore): - modname = modname[len(ignore):] - stripped = ignore - break - else: - stripped = '' - - # we stripped the whole module name? - if not modname: - modname, stripped = stripped, '' - - entries = content.setdefault(modname[0].lower(), []) - - package = modname.split('.')[0] - if package != modname: - # it's a submodule - if prev_modname == package: - # first submodule - make parent a group head - entries[-1][1] = 1 - elif not prev_modname.startswith(package): - # submodule without parent in list, add dummy entry - entries.append([stripped + package, 1, '', '', '', '', '']) - subtype = 2 - else: - num_toplevels += 1 - subtype = 0 - - qualifier = deprecated and _('Deprecated') or '' - entries.append([stripped + modname, subtype, docname, - 'module-' + stripped + modname, platforms, - qualifier, synopsis]) - prev_modname = modname - - # apply heuristics when to collapse modindex at page load: - # only collapse if number of toplevel modules is larger than - # number of submodules - collapse = len(modules) - num_toplevels < num_toplevels - - # sort by first letter - content = sorted(content.iteritems()) - - return content, collapse |
