generate_docs.py 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. #!/usr/bin/env python
  2. # Protocol Buffers - Google's data interchange format
  3. # Copyright 2008 Google Inc. All rights reserved.
  4. # https://developers.google.com/protocol-buffers/
  5. #
  6. # Redistribution and use in source and binary forms, with or without
  7. # modification, are permitted provided that the following conditions are
  8. # met:
  9. #
  10. # * Redistributions of source code must retain the above copyright
  11. # notice, this list of conditions and the following disclaimer.
  12. # * Redistributions in binary form must reproduce the above
  13. # copyright notice, this list of conditions and the following disclaimer
  14. # in the documentation and/or other materials provided with the
  15. # distribution.
  16. # * Neither the name of Google Inc. nor the names of its
  17. # contributors may be used to endorse or promote products derived from
  18. # this software without specific prior written permission.
  19. #
  20. # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  21. # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  22. # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  23. # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  24. # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  25. # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  26. # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  27. # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  28. # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  29. # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  30. # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  31. """Script to generate a list of all modules to use in autosummary.
  32. This script creates a ReStructured Text file for each public module in the
  33. protobuf Python package. The script also updates the table of contents in
  34. ``docs/index.rst`` to point to these module references.
  35. To build the docs with Sphinx:
  36. 1. Install the needed packages (``sphinx``, ``sphinxcontrib-napoleon`` for
  37. Google-style docstring support). I've created a conda environment file to
  38. make this easier:
  39. .. code:: bash
  40. conda env create -f python/docs/environment.yml
  41. 2. (Optional) Generate reference docs files and regenerate index:
  42. .. code:: bash
  43. cd python/docs
  44. python generate_docs.py
  45. 3. Run Sphinx.
  46. .. code:: bash
  47. make html
  48. """
  49. import pathlib
  50. import re
  51. DOCS_DIR = pathlib.Path(__file__).parent.resolve()
  52. PYTHON_DIR = DOCS_DIR.parent
  53. SOURCE_DIR = PYTHON_DIR / "google" / "protobuf"
  54. SOURCE_POSIX = SOURCE_DIR.as_posix()
  55. IGNORED_PACKAGES = (
  56. "compiler",
  57. "internal",
  58. "pyext",
  59. "util",
  60. )
  61. IGNORED_MODULES = (
  62. "any_test_pb2",
  63. "api_pb2",
  64. "unittest",
  65. "source_context_pb2",
  66. "test_messages_proto3_pb2",
  67. "test_messages_proto2",
  68. )
  69. TOC_REGEX = re.compile(
  70. r"\.\. START REFTOC.*\.\. END REFTOC\.\n",
  71. flags=re.DOTALL,
  72. )
  73. TOC_TEMPLATE = """.. START REFTOC, generated by generate_docs.py.
  74. .. toctree::
  75. {toctree}
  76. .. END REFTOC.
  77. """
  78. AUTOMODULE_TEMPLATE = """.. DO NOT EDIT, generated by generate_docs.py.
  79. .. ifconfig:: build_env == 'readthedocs'
  80. .. warning::
  81. You are reading the documentation for the `latest committed changes
  82. <https://github.com/protocolbuffers/protobuf/tree/master/python>`_ of
  83. the `Protocol Buffers package for Python
  84. <https://developers.google.com/protocol-buffers/docs/pythontutorial>`_.
  85. Some features may not yet be released. Read the documentation for the
  86. latest released package at `googleapis.dev
  87. <https://googleapis.dev/python/protobuf/latest/>`_.
  88. {module}
  89. {underline}
  90. .. automodule:: {module}
  91. :members:
  92. :inherited-members:
  93. :undoc-members:
  94. """
  95. def find_modules():
  96. modules = []
  97. for module_path in SOURCE_DIR.glob("**/*.py"):
  98. package_posix = module_path.parent.as_posix()
  99. if any(ignored in package_posix for ignored in IGNORED_PACKAGES):
  100. continue
  101. if any(ignored in module_path.stem for ignored in IGNORED_MODULES):
  102. continue
  103. package_name = "google.protobuf{}".format(
  104. package_posix[len(SOURCE_POSIX) :].replace("/", ".")
  105. )
  106. if module_path.name == "__init__.py":
  107. modules.append(package_name)
  108. else:
  109. module_name = module_path.stem
  110. modules.append("{}.{}".format(package_name, module_name))
  111. return modules
  112. def write_automodule(module):
  113. contents = AUTOMODULE_TEMPLATE.format(module=module, underline="=" * len(module),)
  114. automodule_path = DOCS_DIR.joinpath(*module.split(".")).with_suffix(".rst")
  115. try:
  116. automodule_path.parent.mkdir(parents=True)
  117. except FileExistsError:
  118. pass
  119. with open(automodule_path, "w") as automodule_file:
  120. automodule_file.write(contents)
  121. def replace_toc(modules):
  122. toctree = [module.replace(".", "/") for module in modules]
  123. with open(DOCS_DIR / "index.rst", "r") as index_file:
  124. index_contents = index_file.read()
  125. toc = TOC_TEMPLATE.format(
  126. toctree="\n ".join(toctree)
  127. )
  128. index_contents = re.sub(TOC_REGEX, toc, index_contents)
  129. with open(DOCS_DIR / "index.rst", "w") as index_file:
  130. index_file.write(index_contents)
  131. def main():
  132. modules = list(sorted(find_modules()))
  133. for module in modules:
  134. print("Generating reference for {}".format(module))
  135. write_automodule(module)
  136. print("Generating index.rst")
  137. replace_toc(modules)
  138. if __name__ == "__main__":
  139. main()