diff options
Diffstat (limited to 'doc/development/tutorials/examples')
-rw-r--r-- | doc/development/tutorials/examples/README.rst | 11 | ||||
-rw-r--r-- | doc/development/tutorials/examples/helloworld.py | 6 | ||||
-rw-r--r-- | doc/development/tutorials/examples/recipe.py | 228 | ||||
-rw-r--r-- | doc/development/tutorials/examples/todo.py | 6 |
4 files changed, 102 insertions, 149 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, + } |