示例#1
0
  def test_generate_markdown_for_class(self):

    index = {
        'TestClass': TestClass,
        'TestClass.a_method': TestClass.a_method,
        'TestClass.a_property': TestClass.a_property,
        'TestClass.ChildClass': TestClass.ChildClass,
        'TestClass.CLASS_MEMBER': TestClass.CLASS_MEMBER
    }

    tree = {
        'TestClass': ['a_method', 'a_property', 'ChildClass', 'CLASS_MEMBER']
    }

    docs = parser.generate_markdown(
        full_name='TestClass', py_object=TestClass, duplicate_of={},
        duplicates={}, index=index, tree=tree, reverse_index={}, doc_index={},
        guide_index={}, base_dir='/')

    # Make sure all required docstrings are present.
    self.assertTrue(inspect.getdoc(TestClass) in docs)
    self.assertTrue(inspect.getdoc(TestClass.a_method) in docs)
    self.assertTrue(inspect.getdoc(TestClass.a_property) in docs)

    # Make sure that the signature is extracted properly and omits self.
    self.assertTrue('a_method(arg=\'default\')' in docs)

    # Make sure there is a link to the child class and it points the right way.
    self.assertTrue('[`class ChildClass`](./TestClass/ChildClass.md)' in docs)

    # Make sure CLASS_MEMBER is mentioned.
    self.assertTrue('CLASS_MEMBER' in docs)

    # Make sure this file is contained as the definition location.
    self.assertTrue(os.path.relpath(__file__, '/') in docs)
示例#2
0
  def test_generate_markdown_for_class(self):

    index = {
        'TestClass': TestClass,
        'TestClass.a_method': TestClass.a_method,
        'TestClass.a_property': TestClass.a_property,
        'TestClass.ChildClass': TestClass.ChildClass,
        'TestClass.CLASS_MEMBER': TestClass.CLASS_MEMBER
    }

    tree = {
        'TestClass': ['a_method', 'a_property', 'ChildClass', 'CLASS_MEMBER']
    }

    docs = parser.generate_markdown(full_name='TestClass', py_object=TestClass,
                                    duplicate_of={}, duplicates={},
                                    index=index, tree=tree, reverse_index={},
                                    guide_index={}, base_dir='/')

    # Make sure all required docstrings are present.
    self.assertTrue(inspect.getdoc(TestClass) in docs)
    self.assertTrue(inspect.getdoc(TestClass.a_method) in docs)
    self.assertTrue(inspect.getdoc(TestClass.a_property) in docs)

    # Make sure that the signature is extracted properly and omits self.
    self.assertTrue('a_method(arg=\'default\')' in docs)

    # Make sure there is a link to the child class and it points the right way.
    self.assertTrue('[`class ChildClass`](./TestClass/ChildClass.md)' in docs)

    # Make sure CLASS_MEMBER is mentioned.
    self.assertTrue('CLASS_MEMBER' in docs)

    # Make sure this file is contained as the definition location.
    self.assertTrue(os.path.relpath(__file__, '/') in docs)
示例#3
0
  def test_generate_markdown_for_module(self):
    module = sys.modules[__name__]

    index = {
        'TestModule': module,
        'TestModule.test_function': test_function,
        'TestModule.test_function_with_args_kwargs':
        test_function_with_args_kwargs,
        'TestModule.TestClass': TestClass,
    }

    tree = {
        'TestModule': ['TestClass', 'test_function',
                       'test_function_with_args_kwargs']
    }

    docs = parser.generate_markdown(full_name='TestModule', py_object=module,
                                    duplicate_of={}, duplicates={},
                                    index=index, tree=tree, reverse_index={},
                                    doc_index={}, guide_index={}, base_dir='/')

    # Make sure all required docstrings are present.
    self.assertTrue(inspect.getdoc(module) in docs)

    # Make sure that links to the members are there (not asserting on exact link
    # text for functions).
    self.assertTrue('./TestModule/test_function.md' in docs)
    self.assertTrue('./TestModule/test_function_with_args_kwargs.md' in docs)

    # Make sure there is a link to the child class and it points the right way.
    self.assertTrue('[`class TestClass`](./TestModule/TestClass.md)' in docs)

    # Make sure this file is contained as the definition location.
    self.assertTrue(os.path.relpath(__file__, '/') in docs)
示例#4
0
    def test_docstring_special_section(self):
        index = {'test_function': test_function_with_fancy_docstring}
        reference_resolver = parser.ReferenceResolver(duplicate_of={},
                                                      doc_index={},
                                                      index=index)

        tree = {'': 'test_function'}

        docs = parser.generate_markdown(
            full_name='test_function',
            py_object=test_function_with_fancy_docstring,
            reference_resolver=reference_resolver,
            duplicates={},
            tree=tree,
            reverse_index={},
            guide_index={},
            base_dir='/')
        expected = '\n'.join([
            'Function with a fancy docstring.', '', '#### Args:', '',
            '* <b>`arg`</b>: An argument.', '', '', '#### Returns:', '',
            '* <b>`arg`</b>: the input, and',
            '* <b>`arg`</b>: the input, again.', '', '', '', '', '',
            '#### numpy compatibility',
            'NumPy has nothing as awesome as this function.', '', '', '',
            '#### theano compatibility',
            'Theano has nothing as awesome as this function.', '',
            'Check it out.', '', '', ''
        ])
        self.assertTrue(expected in docs)
示例#5
0
    def test_generate_markdown_for_function_with_kwargs(self):
        index = {
            'test_function_with_args_kwargs': test_function_with_args_kwargs
        }
        reference_resolver = parser.ReferenceResolver(duplicate_of={},
                                                      doc_index={},
                                                      index=index)

        tree = {'': ['test_function_with_args_kwargs']}

        docs = parser.generate_markdown(
            full_name='test_function_with_args_kwargs',
            py_object=test_function_with_args_kwargs,
            reference_resolver=reference_resolver,
            duplicates={},
            tree=tree,
            reverse_index={},
            guide_index={},
            base_dir='/')

        # Make sure docstring shows up.
        self.assertTrue(inspect.getdoc(test_function_with_args_kwargs) in docs)

        # Make sure the extracted signature is good.
        self.assertTrue('test_function_with_args_kwargs(unused_arg,'
                        ' *unused_args, **unused_kwargs)' in docs)
示例#6
0
    def test_references_replaced_in_generated_markdown(self):
        index = {
            'test_function_for_markdown_reference':
            test_function_for_markdown_reference
        }
        reference_resolver = parser.ReferenceResolver(duplicate_of={},
                                                      doc_index={},
                                                      index=index)

        tree = {'': ['test_function_for_markdown_reference']}

        docs = parser.generate_markdown(
            full_name='test_function_for_markdown_reference',
            py_object=test_function_for_markdown_reference,
            reference_resolver=reference_resolver,
            duplicates={},
            tree=tree,
            reverse_index={},
            guide_index={},
            base_dir='/')

        # Make sure docstring shows up and is properly processed.
        expected_docs = reference_resolver.replace_references(
            inspect.getdoc(test_function_for_markdown_reference),
            relative_path_to_root='.')

        self.assertTrue(expected_docs in docs)
示例#7
0
    def test_generate_markdown_for_function(self):
        index = {'test_function': test_function}
        reference_resolver = parser.ReferenceResolver(duplicate_of={},
                                                      doc_index={},
                                                      index=index)

        tree = {'': ['test_function']}

        docs = parser.generate_markdown(full_name='test_function',
                                        py_object=test_function,
                                        reference_resolver=reference_resolver,
                                        duplicates={},
                                        tree=tree,
                                        reverse_index={},
                                        guide_index={},
                                        base_dir='/')

        # Make sure docstring shows up.
        self.assertTrue(inspect.getdoc(test_function) in docs)
        # Make sure the extracted signature is good.
        self.assertTrue(
            'test_function(unused_arg, unused_kwarg=\'default\')' in docs)

        # Make sure this file is contained as the definition location.
        self.assertTrue(os.path.relpath(__file__, '/') in docs)
示例#8
0
  def test_docstring_special_section(self):
    index = {
        'test_function': test_function_with_fancy_docstring
    }

    tree = {
        '': 'test_function'
    }

    docs = parser.generate_markdown(
        full_name='test_function',
        py_object=test_function_with_fancy_docstring,
        duplicate_of={}, duplicates={},
        index=index, tree=tree, reverse_index={}, base_dir='/')

    expected = '\n'.join([
        'Function with a fancy docstring.',
        '',
        '#### Args:',
        '',
        '* <b>`arg`</b>: An argument.',
        '',
        '',
        '#### Returns:',
        '',
        '* <b>`arg`</b>: the input, and',
        '* <b>`arg`</b>: the input, again.',
        ''])
    self.assertTrue(expected in docs)
示例#9
0
  def test_generate_markdown_for_module(self):
    module = sys.modules[__name__]

    index = {
        'TestModule': module,
        'TestModule.test_function': test_function,
        'TestModule.test_function_with_args_kwargs':
        test_function_with_args_kwargs,
        'TestModule.TestClass': TestClass,
    }

    tree = {
        'TestModule': ['TestClass', 'test_function',
                       'test_function_with_args_kwargs']
    }

    docs = parser.generate_markdown(full_name='TestModule', py_object=module,
                                    duplicate_of={}, duplicates={},
                                    index=index, tree=tree, reverse_index={},
                                    guide_index={}, base_dir='/')

    # Make sure all required docstrings are present.
    self.assertTrue(inspect.getdoc(module) in docs)

    # Make sure that links to the members are there (not asserting on exact link
    # text for functions).
    self.assertTrue('./TestModule/test_function.md' in docs)
    self.assertTrue('./TestModule/test_function_with_args_kwargs.md' in docs)

    # Make sure there is a link to the child class and it points the right way.
    self.assertTrue('[`class TestClass`](./TestModule/TestClass.md)' in docs)

    # Make sure this file is contained as the definition location.
    self.assertTrue(os.path.relpath(__file__, '/') in docs)
示例#10
0
  def test_generate_markdown_for_function(self):
    index = {
        'test_function': test_function
    }
    reference_resolver = parser.ReferenceResolver(
        duplicate_of={}, doc_index={}, index=index)

    tree = {
        '': ['test_function']
    }

    docs = parser.generate_markdown(full_name='test_function',
                                    py_object=test_function,
                                    reference_resolver=reference_resolver,
                                    duplicates={}, tree=tree, reverse_index={},
                                    guide_index={}, base_dir='/')

    # Make sure docstring shows up.
    self.assertTrue(inspect.getdoc(test_function) in docs)
    # Make sure the extracted signature is good.
    self.assertTrue(
        'test_function(unused_arg, unused_kwarg=\'default\')' in docs)

    # Make sure this file is contained as the definition location.
    self.assertTrue(os.path.relpath(__file__, '/') in docs)
示例#11
0
  def test_docstring_special_section(self):
    index = {
        'test_function': test_function_with_fancy_docstring
    }
    reference_resolver = parser.ReferenceResolver(
        duplicate_of={}, doc_index={}, index=index)

    tree = {
        '': 'test_function'
    }

    docs = parser.generate_markdown(
        full_name='test_function', py_object=test_function_with_fancy_docstring,
        reference_resolver=reference_resolver, duplicates={}, tree=tree,
        reverse_index={}, guide_index={}, base_dir='/')
    expected = '\n'.join([
        'Function with a fancy docstring.',
        '',
        '#### Args:',
        '',
        '* <b>`arg`</b>: An argument.',
        '',
        '',
        '#### Returns:',
        '',
        '* <b>`arg`</b>: the input, and',
        '* <b>`arg`</b>: the input, again.',
        '',
        '',
        '',
        '',
        '',
        '#### numpy compatibility',
        'NumPy has nothing as awesome as this function.',
        '',
        '',
        '',
        '#### theano compatibility',
        'Theano has nothing as awesome as this function.',
        '',
        'Check it out.',
        '',
        '',
        ''])
    self.assertTrue(expected in docs)
示例#12
0
  def test_generate_markdown_for_function_with_kwargs(self):
    index = {
        'test_function_with_args_kwargs': test_function_with_args_kwargs
    }

    tree = {
        '': ['test_function_with_args_kwargs']
    }

    docs = parser.generate_markdown(full_name='test_function_with_args_kwargs',
                                    py_object=test_function_with_args_kwargs,
                                    duplicate_of={}, duplicates={},
                                    index=index, tree=tree, base_dir='/')

    # Make sure docstring shows up.
    self.assertTrue(inspect.getdoc(test_function_with_args_kwargs) in docs)

    # Make sure the extracted signature is good.
    self.assertTrue(
        'test_function_with_args_kwargs(unused_arg,'
        ' *unused_args, **unused_kwargs)' in docs)
示例#13
0
  def test_references_replaced_in_generated_markdown(self):
    index = {
        'test_function_for_markdown_reference':
        test_function_for_markdown_reference
    }

    tree = {
        '': ['test_function_for_markdown_reference']
    }

    docs = parser.generate_markdown(
        full_name='test_function_for_markdown_reference',
        py_object=test_function_for_markdown_reference, duplicate_of={},
        duplicates={}, index=index, tree=tree, reverse_index={}, doc_index={},
        guide_index={}, base_dir='/')

    # Make sure docstring shows up and is properly processed.
    expected_docs = parser.replace_references(
        inspect.getdoc(test_function_for_markdown_reference),
        relative_path_to_root='.', duplicate_of={}, doc_index={}, index={})

    self.assertTrue(expected_docs in docs)
示例#14
0
def write_docs(output_dir, base_dir, duplicate_of, duplicates, index, tree,
               reverse_index, guide_index):
  """Write previously extracted docs to disk.

  Write a docs page for each symbol in `index` to a tree of docs at
  `output_dir`.

  Symbols with multiple aliases will have only one page written about them,
  which is referenced for all aliases. `duplicate_of` and `duplicates` are used
  to determine which docs pages to write.

  Args:
    output_dir: Directory to write documentation markdown files to. Will be
      created if it doesn't exist.
    base_dir: Base directory of the code being documented. This prefix is
      stripped from all file paths that are part of the documentation.
    duplicate_of: A `dict` mapping fully qualified names to "master" names. This
      is used to resolve "@{symbol}" references to the "master" name.
    duplicates: A `dict` mapping fully qualified names to a set of all
      aliases of this name. This is used to automatically generate a list of all
      aliases for each name.
    index: A `dict` mapping fully qualified names to the corresponding Python
      objects. Used to produce docs for child objects, and to check the validity
      of "@{symbol}" references.
    tree: A `dict` mapping a fully qualified name to the names of all its
      members. Used to populate the members section of a class or module page.
    reverse_index: A `dict` mapping object ids to fully qualified names.
    guide_index: A `dict` mapping symbol name strings to GuideRef.
  """
  # Make output_dir.
  try:
    if not os.path.exists(output_dir):
      os.makedirs(output_dir)
  except OSError as e:
    print('Creating output dir "%s" failed: %s' % (output_dir, e))
    raise

  # Parse and write Markdown pages, resolving cross-links (@{symbol}).
  for full_name, py_object in six.iteritems(index):

    if full_name in duplicate_of:
      print('Not writing docs for %s, duplicate of %s.' % (
          full_name, duplicate_of[full_name]))
      continue

    # Methods and some routines are documented only as part of their class.
    if not (inspect.ismodule(py_object) or
            inspect.isclass(py_object) or
            inspect.isfunction(py_object)):
      print('Not writing docs for %s, not a class, module, or function.' % (
          full_name))
      continue

    print('Writing docs for %s (%r).' % (full_name, py_object))

    # Generate docs for `py_object`, resolving references.
    markdown = parser.generate_markdown(full_name, py_object,
                                        duplicate_of=duplicate_of,
                                        duplicates=duplicates,
                                        index=index,
                                        tree=tree,
                                        reverse_index=reverse_index,
                                        guide_index=guide_index,
                                        base_dir=base_dir)

    # TODO(deannarubin): use _tree to generate sidebar information.

    path = os.path.join(output_dir, parser.documentation_path(full_name))
    directory = os.path.dirname(path)
    try:
      if not os.path.exists(directory):
        os.makedirs(directory)
      with open(path, 'w') as f:
        f.write(markdown)
    except OSError as e:
      print('Cannot write documentation for %s to %s: %s' % (full_name,
                                                             directory, e))
      raise
    # TODO(deannarubin): write sidebar file?

  # Write a global index containing all full names with links.
  with open(os.path.join(output_dir, 'index.md'), 'w') as f:
    f.write(parser.generate_global_index('TensorFlow', index, duplicate_of))
示例#15
0
def write_docs(output_dir, base_dir, duplicate_of, duplicates, index, tree,
               reverse_index, reference_resolver, guide_index):
  """Write previously extracted docs to disk.

  Write a docs page for each symbol in `index` to a tree of docs at
  `output_dir`.

  Symbols with multiple aliases will have only one page written about them,
  which is referenced for all aliases. `duplicate_of` and `duplicates` are used
  to determine which docs pages to write.

  Args:
    output_dir: Directory to write documentation markdown files to. Will be
      created if it doesn't exist.
    base_dir: Base directory of the code being documented. This prefix is
      stripped from all file paths that are part of the documentation.
    duplicate_of: A `dict` mapping fully qualified names to "master" names. This
      is used to resolve "@{symbol}" references to the "master" name.
    duplicates: A `dict` mapping fully qualified names to a set of all
      aliases of this name. This is used to automatically generate a list of all
      aliases for each name.
    index: A `dict` mapping fully qualified names to the corresponding Python
      objects. Used to produce docs for child objects, and to check the validity
      of "@{symbol}" references.
    tree: A `dict` mapping a fully qualified name to the names of all its
      members. Used to populate the members section of a class or module page.
    reverse_index: A `dict` mapping object ids to fully qualified names.
    reference_resolver: A parser.ReferenceResolver object.
    guide_index: A `dict` mapping symbol name strings to _GuideRef.
  """
  # Make output_dir.
  try:
    if not os.path.exists(output_dir):
      os.makedirs(output_dir)
  except OSError as e:
    print('Creating output dir "%s" failed: %s' % (output_dir, e))
    raise

  # These dictionaries are used for table-of-contents generation below
  # They will contain, after the for-loop below::
  #  - module name(string):classes and functions the module contains(list)
  module_children = {}
  #  - symbol name(string):pathname (string)
  symbol_to_file = {}

  # Parse and write Markdown pages, resolving cross-links (@{symbol}).
  for full_name, py_object in six.iteritems(index):

    if full_name in duplicate_of:
      continue

    # Methods and some routines are documented only as part of their class.
    if not (inspect.ismodule(py_object) or
            inspect.isclass(py_object) or
            inspect.isfunction(py_object)):
      continue

    sitepath = os.path.join('api_docs/python',
                            parser.documentation_path(full_name)[:-3])

    # For TOC, we need to store a mapping from full_name to the file
    # we're generating
    symbol_to_file[full_name] = sitepath

    # For a module, remember the module for the table-of-contents
    if inspect.ismodule(py_object):
      if full_name in tree:
        module_children.setdefault(full_name, [])

    # For something else that's documented,
    # figure out what module it lives in
    else:
      subname = str(full_name)
      while True:
        subname = subname[:subname.rindex('.')]
        if inspect.ismodule(index[subname]):
          module_children.setdefault(subname, []).append(full_name)
          break

    print('Writing docs for %s (%r).' % (full_name, py_object))

    # Generate docs for `py_object`, resolving references.
    markdown = parser.generate_markdown(full_name, py_object,
                                        reference_resolver=reference_resolver,
                                        duplicates=duplicates,
                                        tree=tree,
                                        reverse_index=reverse_index,
                                        guide_index=guide_index,
                                        base_dir=base_dir)

    path = os.path.join(output_dir, parser.documentation_path(full_name))
    directory = os.path.dirname(path)
    try:
      if not os.path.exists(directory):
        os.makedirs(directory)
      with open(path, 'w') as f:
        f.write(markdown)
    except OSError as e:
      print('Cannot write documentation for %s to %s: %s' % (full_name,
                                                             directory, e))
      raise

  # Generate table of contents

  # Put modules in alphabetical order, case-insensitive
  modules = sorted(module_children.keys(), key=lambda a: a.upper())

  leftnav_path = os.path.join(output_dir, '_toc.yaml')
  with open(leftnav_path, 'w') as f:

    # Generate header
    f.write('# Automatically generated file; please do not edit\ntoc:\n')
    for module in modules:
      f.write('  - title: ' + module + '\n'
              '    section:\n' +
              '    - title: Overview\n' +
              '      path: /TARGET_DOC_ROOT/' + symbol_to_file[module] + '\n')

      symbols_in_module = module_children.get(module, [])
      symbols_in_module.sort(key=lambda a: a.upper())

      for full_name in symbols_in_module:
        f.write('    - title: ' + full_name[len(module)+1:] + '\n'
                '      path: /TARGET_DOC_ROOT/' +
                symbol_to_file[full_name] + '\n')

  # Write a global index containing all full names with links.
  with open(os.path.join(output_dir, 'index.md'), 'w') as f:
    f.write(
        parser.generate_global_index('TensorFlow', index, reference_resolver))
示例#16
0
def write_docs(output_dir, base_dir, duplicate_of, duplicates, index, tree,
               reverse_index, doc_index, guide_index):
    """Write previously extracted docs to disk.

  Write a docs page for each symbol in `index` to a tree of docs at
  `output_dir`.

  Symbols with multiple aliases will have only one page written about them,
  which is referenced for all aliases. `duplicate_of` and `duplicates` are used
  to determine which docs pages to write.

  Args:
    output_dir: Directory to write documentation markdown files to. Will be
      created if it doesn't exist.
    base_dir: Base directory of the code being documented. This prefix is
      stripped from all file paths that are part of the documentation.
    duplicate_of: A `dict` mapping fully qualified names to "master" names. This
      is used to resolve "@{symbol}" references to the "master" name.
    duplicates: A `dict` mapping fully qualified names to a set of all
      aliases of this name. This is used to automatically generate a list of all
      aliases for each name.
    index: A `dict` mapping fully qualified names to the corresponding Python
      objects. Used to produce docs for child objects, and to check the validity
      of "@{symbol}" references.
    tree: A `dict` mapping a fully qualified name to the names of all its
      members. Used to populate the members section of a class or module page.
    reverse_index: A `dict` mapping object ids to fully qualified names.
    doc_index: A `dict` mapping a doc key to a DocInfo.
    guide_index: A `dict` mapping symbol name strings to GuideRef.
  """
    # Make output_dir.
    try:
        if not os.path.exists(output_dir):
            os.makedirs(output_dir)
    except OSError as e:
        print('Creating output dir "%s" failed: %s' % (output_dir, e))
        raise

    # Parse and write Markdown pages, resolving cross-links (@{symbol}).
    for full_name, py_object in six.iteritems(index):

        if full_name in duplicate_of:
            continue

        # Methods and some routines are documented only as part of their class.
        if not (inspect.ismodule(py_object) or inspect.isclass(py_object)
                or inspect.isfunction(py_object)):
            continue

        print('Writing docs for %s (%r).' % (full_name, py_object))

        # Generate docs for `py_object`, resolving references.
        markdown = parser.generate_markdown(full_name,
                                            py_object,
                                            duplicate_of=duplicate_of,
                                            duplicates=duplicates,
                                            index=index,
                                            tree=tree,
                                            reverse_index=reverse_index,
                                            doc_index=doc_index,
                                            guide_index=guide_index,
                                            base_dir=base_dir)

        # TODO(deannarubin): use _tree to generate sidebar information.

        path = os.path.join(output_dir, parser.documentation_path(full_name))
        directory = os.path.dirname(path)
        try:
            if not os.path.exists(directory):
                os.makedirs(directory)
            with open(path, 'w') as f:
                f.write(markdown)
        except OSError as e:
            print('Cannot write documentation for %s to %s: %s' %
                  (full_name, directory, e))
            raise
        # TODO(deannarubin): write sidebar file?

    # Write a global index containing all full names with links.
    with open(os.path.join(output_dir, 'index.md'), 'w') as f:
        f.write(parser.generate_global_index('TensorFlow', index,
                                             duplicate_of))
示例#17
0
def write_docs(output_dir, base_dir, duplicate_of, duplicates, index, tree,
               reverse_index, doc_index, guide_index):
    """Write previously extracted docs to disk.

  Write a docs page for each symbol in `index` to a tree of docs at
  `output_dir`.

  Symbols with multiple aliases will have only one page written about them,
  which is referenced for all aliases. `duplicate_of` and `duplicates` are used
  to determine which docs pages to write.

  Args:
    output_dir: Directory to write documentation markdown files to. Will be
      created if it doesn't exist.
    base_dir: Base directory of the code being documented. This prefix is
      stripped from all file paths that are part of the documentation.
    duplicate_of: A `dict` mapping fully qualified names to "master" names. This
      is used to resolve "@{symbol}" references to the "master" name.
    duplicates: A `dict` mapping fully qualified names to a set of all
      aliases of this name. This is used to automatically generate a list of all
      aliases for each name.
    index: A `dict` mapping fully qualified names to the corresponding Python
      objects. Used to produce docs for child objects, and to check the validity
      of "@{symbol}" references.
    tree: A `dict` mapping a fully qualified name to the names of all its
      members. Used to populate the members section of a class or module page.
    reverse_index: A `dict` mapping object ids to fully qualified names.
    doc_index: A `dict` mapping a doc key to a DocInfo.
    guide_index: A `dict` mapping symbol name strings to GuideRef.
  """
    # Make output_dir.
    try:
        if not os.path.exists(output_dir):
            os.makedirs(output_dir)
    except OSError as e:
        print('Creating output dir "%s" failed: %s' % (output_dir, e))
        raise

    # These dictionaries are used for table-of-contents generation below
    # They will contain, after the for-loop below::
    #  - module name(string):classes and functions the module contains(list)
    module_children = {}
    #  - symbol name(string):pathname (string)
    symbol_to_file = {}

    # Parse and write Markdown pages, resolving cross-links (@{symbol}).
    for full_name, py_object in six.iteritems(index):

        if full_name in duplicate_of:
            continue

        # Methods and some routines are documented only as part of their class.
        if not (inspect.ismodule(py_object) or inspect.isclass(py_object)
                or inspect.isfunction(py_object)):
            continue

        sitepath = os.path.join('api_docs/python',
                                parser.documentation_path(full_name)[:-3])

        # For TOC, we need to store a mapping from full_name to the file
        # we're generating
        symbol_to_file[full_name] = sitepath

        # For a module, remember the module for the table-of-contents
        if inspect.ismodule(py_object):
            if full_name in tree:
                module_children.setdefault(full_name, [])

        # For something else that's documented,
        # figure out what module it lives in
        else:
            subname = str(full_name)
            while True:
                subname = subname[:subname.rindex('.')]
                if inspect.ismodule(index[subname]):
                    module_children.setdefault(subname, []).append(full_name)
                    break

        print('Writing docs for %s (%r).' % (full_name, py_object))

        # Generate docs for `py_object`, resolving references.
        markdown = parser.generate_markdown(full_name,
                                            py_object,
                                            duplicate_of=duplicate_of,
                                            duplicates=duplicates,
                                            index=index,
                                            tree=tree,
                                            reverse_index=reverse_index,
                                            doc_index=doc_index,
                                            guide_index=guide_index,
                                            base_dir=base_dir)

        path = os.path.join(output_dir, parser.documentation_path(full_name))
        directory = os.path.dirname(path)
        try:
            if not os.path.exists(directory):
                os.makedirs(directory)
            with open(path, 'w') as f:
                f.write(markdown)
        except OSError as e:
            print('Cannot write documentation for %s to %s: %s' %
                  (full_name, directory, e))
            raise

    # Generate table of contents

    # Put modules in alphabetical order, case-insensitive
    modules = sorted(module_children.keys(), key=lambda a: a.upper())

    leftnav_path = os.path.join(output_dir, '_toc.yaml')
    with open(leftnav_path, 'w') as f:

        # Generate header
        f.write('# Automatically generated file; please do not edit\ntoc:\n')
        for module in modules:
            f.write('  - title: ' + module + '\n'
                    '    section:\n' + '    - title: Overview\n' +
                    '      path: /TARGET_DOC_ROOT/' + symbol_to_file[module] +
                    '\n')

            symbols_in_module = module_children.get(module, [])
            symbols_in_module.sort(key=lambda a: a.upper())

            for full_name in symbols_in_module:
                f.write('    - title: ' + full_name[len(module) + 1:] + '\n'
                        '      path: /TARGET_DOC_ROOT/' +
                        symbol_to_file[full_name] + '\n')

    # Write a global index containing all full names with links.
    with open(os.path.join(output_dir, 'index.md'), 'w') as f:
        f.write(parser.generate_global_index('TensorFlow', index,
                                             duplicate_of))