summaryrefslogtreecommitdiff
path: root/doc/development/tutorials
diff options
context:
space:
mode:
Diffstat (limited to 'doc/development/tutorials')
-rw-r--r--doc/development/tutorials/examples/README.rst11
-rw-r--r--doc/development/tutorials/examples/helloworld.py6
-rw-r--r--doc/development/tutorials/examples/recipe.py228
-rw-r--r--doc/development/tutorials/examples/todo.py6
-rw-r--r--doc/development/tutorials/helloworld.rst17
-rw-r--r--doc/development/tutorials/recipe.rst85
-rw-r--r--doc/development/tutorials/todo.rst43
7 files changed, 174 insertions, 222 deletions
diff --git a/doc/development/tutorials/examples/README.rst b/doc/development/tutorials/examples/README.rst
new file mode 100644
index 000000000..2b9c01b5e
--- /dev/null
+++ b/doc/development/tutorials/examples/README.rst
@@ -0,0 +1,11 @@
+:orphan:
+
+Tutorial examples
+=================
+
+This directory contains a number of examples used in the tutorials. These are
+intended to be increasingly complex to demonstrate the various features of
+Sphinx, but should aim to be as complicated as necessary but no more.
+Individual sections are referenced by line numbers, meaning if you make changes
+to the source files, you should update the references in the documentation
+accordingly.
diff --git a/doc/development/tutorials/examples/helloworld.py b/doc/development/tutorials/examples/helloworld.py
index 66ab3295d..d6d81fd4f 100644
--- a/doc/development/tutorials/examples/helloworld.py
+++ b/doc/development/tutorials/examples/helloworld.py
@@ -11,3 +11,9 @@ class HelloWorld(Directive):
def setup(app):
app.add_directive("helloworld", HelloWorld)
+
+ return {
+ 'version': '0.1',
+ 'parallel_read_safe': True,
+ 'parallel_write_safe': True,
+ }
diff --git a/doc/development/tutorials/examples/recipe.py b/doc/development/tutorials/examples/recipe.py
index 213d30ff6..9c54a93f0 100644
--- a/doc/development/tutorials/examples/recipe.py
+++ b/doc/development/tutorials/examples/recipe.py
@@ -1,3 +1,5 @@
+from collections import defaultdict
+
import docutils
from docutils import nodes
from docutils.parsers import rst
@@ -18,33 +20,27 @@ class RecipeDirective(ObjectDescription):
has_content = True
required_arguments = 1
option_spec = {
- 'contains': directives.unchanged_required
+ 'contains': directives.unchanged_required,
}
def handle_signature(self, sig, signode):
signode += addnodes.desc_name(text=sig)
- signode += addnodes.desc_type(text='Recipe')
return sig
def add_target_and_index(self, name_cls, sig, signode):
signode['ids'].append('recipe' + '-' + sig)
if 'noindex' not in self.options:
- name = '{}.{}.{}'.format('rcp', type(self).__name__, sig)
- imap = self.env.domaindata['rcp']['obj2ingredient']
- imap[name] = list(self.options.get('contains').split(' '))
- objs = self.env.domaindata['rcp']['objects']
- objs.append((name,
- sig,
- 'Recipe',
- self.env.docname,
- 'recipe' + '-' + sig,
- 0))
+ ingredients = [
+ x.strip() for x in self.options.get('contains').split(',')]
+
+ recipes = self.env.get_domain('recipe')
+ recipes.add_recipe(sig, ingredients)
class IngredientIndex(Index):
- """A custom directive that creates an ingredient matrix."""
+ """A custom index that creates an ingredient matrix."""
- name = 'ing'
+ name = 'ingredient'
localname = 'Ingredient Index'
shortname = 'Ingredient'
@@ -52,69 +48,39 @@ class IngredientIndex(Index):
super(IngredientIndex, self).__init__(*args, **kwargs)
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 by some builders, such as
- the LaTeX builder.
- """
-
- content = {}
-
- objs = {name: (dispname, typ, docname, anchor)
- for name, dispname, typ, docname, anchor, prio
- in self.domain.get_objects()}
-
- imap = {}
- ingr = self.domain.data['obj2ingredient']
- for name, ingr in ingr.items():
- for ig in ingr:
- imap.setdefault(ig,[])
- imap[ig].append(name)
-
- for ingredient in imap.keys():
- lis = content.setdefault(ingredient, [])
- objlis = imap[ingredient]
- for objname in objlis:
- dispname, typ, docname, anchor = objs[objname]
- lis.append((
- dispname, 0, docname,
- anchor,
- docname, '', typ
- ))
- re = [(k, v) for k, v in sorted(content.items())]
-
- return (re, True)
+ content = defaultdict(list)
+
+ recipes = {name: (dispname, typ, docname, anchor)
+ for name, dispname, typ, docname, anchor, _
+ in self.domain.get_objects()}
+ recipe_ingredients = self.domain.data['recipe_ingredients']
+ ingredient_recipes = defaultdict(list)
+
+ # flip from recipe_ingredients to ingredient_recipes
+ for recipe_name, ingredients in recipe_ingredients.items():
+ for ingredient in ingredients:
+ ingredient_recipes[ingredient].append(recipe_name)
+
+ # convert the mapping of ingredient to recipes to produce the expected
+ # output, shown below, using the ingredient name as a key to group
+ #
+ # name, subtype, docname, anchor, extra, qualifier, description
+ for ingredient, recipe_names in ingredient_recipes.items():
+ for recipe_name in recipe_names:
+ dispname, typ, docname, anchor = recipes[recipe_name]
+ content[ingredient].append(
+ (dispname, 0, docname, anchor, docname, '', typ))
+
+ # convert the dict to the sorted list of tuples expected
+ content = sorted(content.items())
+
+ return content, True
class RecipeIndex(Index):
- name = 'rcp'
+ """A custom index that creates an recipe matrix."""
+
+ name = 'recipe'
localname = 'Recipe Index'
shortname = 'Recipe'
@@ -122,92 +88,54 @@ class RecipeIndex(Index):
super(RecipeIndex, self).__init__(*args, **kwargs)
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 by some builders, such as
- the LaTeX builder.
- """
-
- content = {}
- items = ((name, dispname, typ, docname, anchor)
- for name, dispname, typ, docname, anchor, prio
- in self.domain.get_objects())
- items = sorted(items, key=lambda item: item[0])
- for name, dispname, typ, docname, anchor in items:
- lis = content.setdefault('Recipe', [])
- lis.append((
- dispname, 0, docname,
- anchor,
- docname, '', typ
- ))
- re = [(k, v) for k, v in sorted(content.items())]
-
- return (re, True)
+ content = defaultdict(list)
+
+ # sort the list of recipes in alphabetical order
+ recipes = self.domain.get_objects()
+ recipes = sorted(recipes, key=lambda recipe: recipe[0])
+
+ # generate the expected output, shown below, from the above using the
+ # first letter of the recipe as a key to group thing
+ #
+ # name, subtype, docname, anchor, extra, qualifier, description
+ for name, dispname, typ, docname, anchor, _ in recipes:
+ content[dispname[0].lower()].append(
+ (dispname, 0, docname, anchor, docname, '', typ))
+
+ # convert the dict to the sorted list of tuples expected
+ content = sorted(content.items())
+
+ return content, True
class RecipeDomain(Domain):
- name = 'rcp'
+ name = 'recipe'
label = 'Recipe Sample'
-
roles = {
- 'reref': XRefRole()
+ 'ref': XRefRole()
}
-
directives = {
'recipe': RecipeDirective,
}
-
indices = {
RecipeIndex,
IngredientIndex
}
-
initial_data = {
- 'objects': [], # object list
- 'obj2ingredient': {}, # name -> object
+ 'recipes': [], # object list
+ 'recipe_ingredients': {}, # name -> object
}
def get_full_qualified_name(self, node):
- """Return full qualified name for a given node"""
- return "{}.{}.{}".format('rcp',
- type(node).__name__,
- node.arguments[0])
+ return '{}.{}'.format('recipe', node.arguments[0])
def get_objects(self):
- for obj in self.data['objects']:
+ for obj in self.data['recipes']:
yield(obj)
def resolve_xref(self, env, fromdocname, builder, typ, target, node,
contnode):
-
match = [(docname, anchor)
for name, sig, typ, docname, anchor, prio
in self.get_objects() if sig == target]
@@ -219,21 +147,25 @@ class RecipeDomain(Domain):
return make_refnode(builder, fromdocname, todocname, targ,
contnode, targ)
else:
- print("Awww, found nothing")
+ print('Awww, found nothing')
return None
+ def add_recipe(self, signature, ingredients):
+ """Add a new recipe to the domain."""
+ name = '{}.{}'.format('recipe', signature)
+ anchor = 'recipe-{}'.format(signature)
-def setup(app):
- app.add_domain(RecipeDomain)
+ self.data['recipe_ingredients'][name] = ingredients
+ # name, dispname, type, docname, anchor, priority
+ self.data['recipes'].append(
+ (name, signature, 'Recipe', self.env.docname, anchor, 0))
- StandardDomain.initial_data['labels']['recipeindex'] = (
- 'rcp-rcp', '', 'Recipe Index')
- StandardDomain.initial_data['labels']['ingredientindex'] = (
- 'rcp-ing', '', 'Ingredient Index')
- StandardDomain.initial_data['anonlabels']['recipeindex'] = (
- 'rcp-rcp', '')
- StandardDomain.initial_data['anonlabels']['ingredientindex'] = (
- 'rcp-ing', '')
+def setup(app):
+ app.add_domain(RecipeDomain)
- return {'version': '0.1'} # identifies the version of our extension
+ return {
+ 'version': '0.1',
+ 'parallel_read_safe': True,
+ 'parallel_write_safe': True,
+ }
diff --git a/doc/development/tutorials/examples/todo.py b/doc/development/tutorials/examples/todo.py
index bd50ba54a..d46f90821 100644
--- a/doc/development/tutorials/examples/todo.py
+++ b/doc/development/tutorials/examples/todo.py
@@ -117,4 +117,8 @@ def setup(app):
app.connect('doctree-resolved', process_todo_nodes)
app.connect('env-purge-doc', purge_todos)
- return {'version': '0.1'} # identifies the version of our extension
+ return {
+ 'version': '0.1',
+ 'parallel_read_safe': True,
+ 'parallel_write_safe': True,
+ }
diff --git a/doc/development/tutorials/helloworld.rst b/doc/development/tutorials/helloworld.rst
index 857b86c9a..a042f7b05 100644
--- a/doc/development/tutorials/helloworld.rst
+++ b/doc/development/tutorials/helloworld.rst
@@ -2,12 +2,13 @@ Developing a "Hello world" extension
====================================
The objective of this tutorial is to create a very basic extension that adds a
-new directive. This directive will output a paragraph containing `hello world`.
+new directive. This directive will output a paragraph containing "hello world".
Only basic information is provided in this tutorial. For more information, refer
to the :doc:`other tutorials <index>` that go into more details.
.. warning::
+
For this extension, you will need some basic understanding of docutils_
and Python.
@@ -17,7 +18,7 @@ Overview
We want the extension to add the following to Sphinx:
-* A ``helloworld`` directive, that will simply output the text `hello world`.
+* A ``helloworld`` directive, that will simply output the text "hello world".
Prerequisites
@@ -104,10 +105,10 @@ Sphinx.
:linenos:
:lines: 12-
-The simplest thing you can do it call the :meth:`~Sphinx.add_directive`
-method, which is what we've done here. For this particular call, the first
-argument is the name of the directive itself as used in an rST file. In this
-case, we would use ``helloworld``. For example:
+The simplest thing you can do it call the :meth:`~Sphinx.add_directive` method,
+which is what we've done here. For this particular call, the first argument is
+the name of the directive itself as used in a reST file. In this case, we would
+use ``helloworld``. For example:
.. code-block:: rst
@@ -117,6 +118,10 @@ case, we would use ``helloworld``. For example:
Some more text here...
+We also return the :ref:`extension metadata <ext-metadata>` that indicates the
+version of our extension, along with the fact that it is safe to use the
+extension for both parallel reading and writing.
+
Using the extension
-------------------
diff --git a/doc/development/tutorials/recipe.rst b/doc/development/tutorials/recipe.rst
index 67841c3a9..25a2c0732 100644
--- a/doc/development/tutorials/recipe.rst
+++ b/doc/development/tutorials/recipe.rst
@@ -19,14 +19,14 @@ Overview
We want the extension to add the following to Sphinx:
* A ``recipe`` :term:`directive`, containing some content describing the recipe
- steps, along with a ``:contains:`` argument highlighting the main ingredients
+ steps, along with a ``:contains:`` option highlighting the main ingredients
of the recipe.
-* A ``reref`` :term:`role`, which provides a cross-reference to the recipe
+* A ``ref`` :term:`role`, which provides a cross-reference to the recipe
itself.
-* A ``rcp`` :term:`domain`, which allows us to tie together the above role and
- domain, along with things like indices.
+* A ``recipe`` :term:`domain`, which allows us to tie together the above role
+ and domain, along with things like indices.
For that, we will need to add the following elements to Sphinx:
@@ -34,24 +34,15 @@ For that, we will need to add the following elements to Sphinx:
* New indexes to allow us to reference ingredient and recipes
-* A new domain called ``rcp``, which will contain the ``recipe`` directive and
- ``reref`` role
+* A new domain called ``recipe``, which will contain the ``recipe`` directive
+ and ``ref`` role
Prerequisites
-------------
-As with :doc:`the previous extensions <todo>`, we will not be distributing this
-plugin via PyPI so once again we need a Sphinx project to call this from. You
-can use an existing project or create a new one using
-:program:`sphinx-quickstart`.
-
-We assume you are using separate source (:file:`source`) and build
-(:file:`build`) folders. Your extension file could be in any folder of your
-project. In our case, let's do the following:
-
-#. Create an :file:`_ext` folder in :file:`source`
-#. Create a new Python file in the :file:`_ext` folder called :file:`recipe.py`
+We need the same setup as in :doc:`the previous extensions <todo>`. This time,
+we will be putting out extension in a file called :file:`recipe.py`.
Here is an example of the folder structure you might obtain:
@@ -59,7 +50,7 @@ Here is an example of the folder structure you might obtain:
└── source
   ├── _ext
- │   └── todo.py
+ │   └── recipe.py
   ├── conf.py
   └── index.rst
@@ -67,8 +58,8 @@ Here is an example of the folder structure you might obtain:
Writing the extension
---------------------
-Open :file:`receipe.py` and paste the following code in it, all of which we
-will explain in detail shortly:
+Open :file:`recipe.py` and paste the following code in it, all of which we will
+explain in detail shortly:
.. literalinclude:: examples/recipe.py
:language: python
@@ -79,12 +70,12 @@ on.
.. rubric:: The directive class
-The first thing to examine is the ``RecipeNode`` directive:
+The first thing to examine is the ``RecipeDirective`` directive:
.. literalinclude:: examples/recipe.py
:language: python
:linenos:
- :lines: 15-40
+ :lines: 17-37
Unlike :doc:`helloworld` and :doc:`todo`, this directive doesn't derive from
:class:`docutils.parsers.rst.Directive` and doesn't define a ``run`` method.
@@ -100,7 +91,7 @@ for this node.
We also see that this directive defines ``has_content``, ``required_arguments``
and ``option_spec``. Unlike the ``TodoDirective`` directive added in the
:doc:`previous tutorial <todo>`, this directive takes a single argument, the
-recipe name, and an optional argument, ``contains``, in addition to the nested
+recipe name, and an option, ``contains``, in addition to the nested
reStructuredText in the body.
.. rubric:: The index classes
@@ -112,11 +103,11 @@ reStructuredText in the body.
.. literalinclude:: examples/recipe.py
:language: python
:linenos:
- :lines: 44-172
+ :lines: 40-108
Both ``IngredientIndex`` and ``RecipeIndex`` are derived from :class:`Index`.
They implement custom logic to generate a tuple of values that define the
-index. Note that ``RecipeIndex`` is a degenerate index that has only one entry.
+index. Note that ``RecipeIndex`` is a simple index that has only one entry.
Extending it to cover more object types is not yet part of the code.
Both indices use the method :meth:`Index.generate` to do their work. This
@@ -135,9 +126,9 @@ creating here.
.. literalinclude:: examples/recipe.py
:language: python
:linenos:
- :lines: 175-223
+ :lines: 111-161
-There are some interesting things to note about this ``rcp`` domain and domains
+There are some interesting things to note about this ``recipe`` domain and domains
in general. Firstly, we actually register our directives, roles and indices
here, via the ``directives``, ``roles`` and ``indices`` attributes, rather than
via calls later on in ``setup``. We can also note that we aren't actually
@@ -146,19 +137,21 @@ defining a custom role and are instead reusing the
:class:`sphinx.domains.Domain.resolve_xref` method. This method takes two
arguments, ``typ`` and ``target``, which refer to the cross-reference type and
its target name. We'll use ``target`` to resolve our destination from our
-domain's ``objects`` because we currently have only one type of node.
-
-Moving on, we can see that we've defined two items in ``intitial_data``:
-``objects`` and ``obj2ingredient``. These contain a list of all objects defined
-(i.e. all recipes) and a hash that maps a canonical ingredient name to the list
-of objects. The way we name objects is common across our extension and is
-defined in the ``get_full_qualified_name`` method. For each object created, the
-canonical name is ``rcp.<typename>.<objectname>``, where ``<typename>`` is the
-Python type of the object, and ``<objectname>`` is the name the documentation
-writer gives the object. This enables the extension to use different object
-types that share the same name. Having a canonical name and central place for
-our objects is a huge advantage. Both our indices and our cross-referencing
-code use this feature.
+domain's ``recipes`` because we currently have only one type of node.
+
+Moving on, we can see that we've defined ``initial_data``. The values defined in
+``initial_data`` will be copied to ``env.domaindata[domain_name]`` as the
+initial data of the domain, and domain instances can access it via
+``self.data``. We see that we have defined two items in ``initial_data``:
+``recipes`` and ``recipe2ingredient``. These contain a list of all objects
+defined (i.e. all recipes) and a hash that maps a canonical ingredient name to
+the list of objects. The way we name objects is common across our extension and
+is defined in the ``get_full_qualified_name`` method. For each object created,
+the canonical name is ``recipe.<recipename>``, where ``<recipename>`` is the
+name the documentation writer gives the object (a recipe). This enables the
+extension to use different object types that share the same name. Having a
+canonical name and central place for our objects is a huge advantage. Both our
+indices and our cross-referencing code use this feature.
.. rubric:: The ``setup`` function
@@ -171,7 +164,7 @@ hook the various parts of our extension into Sphinx. Let's look at the
.. literalinclude:: examples/recipe.py
:language: python
:linenos:
- :lines: 226-
+ :lines: 164-
This looks a little different to what we're used to seeing. There are no calls
to :meth:`~Sphinx.add_directive` or even :meth:`~Sphinx.add_role`. Instead, we
@@ -192,8 +185,8 @@ You can now use the extension throughout your project. For example:
Joe's Recipes
=============
- Below are a collection of my favourite receipes. I highly recommend the
- :rcp:reref:`TomatoSoup` receipe in particular!
+ Below are a collection of my favourite recipes. I highly recommend the
+ :recipe:ref:`TomatoSoup` recipe in particular!
.. toctree::
@@ -204,15 +197,15 @@ You can now use the extension throughout your project. For example:
The recipe contains `tomato` and `cilantro`.
- .. rcp:recipe:: TomatoSoup
+ .. recipe:recipe:: TomatoSoup
:contains: tomato cilantro salt pepper
This recipe is a tasty tomato soup, combine all ingredients
and cook.
-The important things to note are the use of the ``:rcp:recipe:`` role to
+The important things to note are the use of the ``:recipe:ref:`` role to
cross-reference the recipe actually defined elsewhere (using the
-``:rcp:recipe:`` directive.
+``:recipe:recipe:`` directive.
Further reading
diff --git a/doc/development/tutorials/todo.rst b/doc/development/tutorials/todo.rst
index 8071bda68..c04e14e99 100644
--- a/doc/development/tutorials/todo.rst
+++ b/doc/development/tutorials/todo.rst
@@ -174,10 +174,10 @@ The node structure that the directive returns looks like this::
.. rubric:: The event handlers
-Event handlers are one of Sphinx's most powerful features, providing a way to do
-hook into any part of the documentation process. There are many hooks available,
-as detailed in :doc:`/extdev/appapi`, and we're going to use a subset of them
-here.
+Event handlers are one of Sphinx's most powerful features, providing a way to
+do hook into any part of the documentation process. There are many events
+provided by Sphinx itself, as detailed in :ref:`the API guide <events>`, and
+we're going to use a subset of them here.
Let's look at the event handlers used in the above example. First, the one for
the :event:`env-purge-doc` event:
@@ -203,18 +203,19 @@ The other handler belongs to the :event:`doctree-resolved` event:
:lines: 64-103
The :event:`doctree-resolved` event is emitted at the end of :ref:`phase 3
-<build-phases>` and allows custom resolving to be done. The handler we have
-written for this event is a bit more involved. If the ``todo_include_todos``
-config value (which we'll describe shortly) is false, all ``todo`` and
-``todolist`` nodes are removed from the documents. If not, ``todo`` nodes just
-stay where and how they are. ``todolist`` nodes are replaced by a list of todo
-entries, complete with backlinks to the location where they come from. The list
-items are composed of the nodes from the ``todo`` entry and docutils nodes
-created on the fly: a paragraph for each entry, containing text that gives the
-location, and a link (reference node containing an italic node) with the
-backreference. The reference URI is built by ``app.builder.get_relative_uri``
-which creates a suitable URI depending on the used builder, and appending the
-todo node's (the target's) ID as the anchor name.
+(resolving) <build-phases>` and allows custom resolving to be done. The handler
+we have written for this event is a bit more involved. If the
+``todo_include_todos`` config value (which we'll describe shortly) is false,
+all ``todo`` and ``todolist`` nodes are removed from the documents. If not,
+``todo`` nodes just stay where and how they are. ``todolist`` nodes are
+replaced by a list of todo entries, complete with backlinks to the location
+where they come from. The list items are composed of the nodes from the
+``todo`` entry and docutils nodes created on the fly: a paragraph for each
+entry, containing text that gives the location, and a link (reference node
+containing an italic node) with the backreference. The reference URI is built
+by :meth:`sphinx.builders.Builder.get_relative_uri`` which creates a suitable
+URI depending on the used builder, and appending the todo node's (the target's)
+ID as the anchor name.
.. rubric:: The ``setup`` function
@@ -238,13 +239,13 @@ What the individual calls do is the following:
If the third argument was ``'html'``, HTML documents would be full rebuild if the
config value changed its value. This is needed for config values that
- influence reading (build :ref:`phase 1 <build-phases>`).
+ influence reading (build :ref:`phase 1 (reading) <build-phases>`).
* :meth:`~Sphinx.add_node` adds a new *node class* to the build system. It also
can specify visitor functions for each supported output format. These visitor
- functions are needed when the new nodes stay until :ref:`phase 4 <build-phases>`
- -- since the ``todolist`` node is always replaced in :ref:`phase 3 <build-phases>`,
- it doesn't need any.
+ functions are needed when the new nodes stay until :ref:`phase 4 (writing)
+ <build-phases>`. Since the ``todolist`` node is always replaced in
+ :ref:`phase 3 (resolving) <build-phases>`, it doesn't need any.
* :meth:`~Sphinx.add_directive` adds a new *directive*, given by name and class.
@@ -279,7 +280,7 @@ For example:
sys.path.append(os.path.abspath("./_ext"))
- extensions = ['helloworld']
+ extensions = ['todo']
todo_include_todos = False