generate_docs.py 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  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. {module}
  80. {underline}
  81. .. automodule:: {module}
  82. :members:
  83. :inherited-members:
  84. :undoc-members:
  85. """
  86. def find_modules():
  87. modules = []
  88. for module_path in SOURCE_DIR.glob("**/*.py"):
  89. package_posix = module_path.parent.as_posix()
  90. if any(ignored in package_posix for ignored in IGNORED_PACKAGES):
  91. continue
  92. if any(ignored in module_path.stem for ignored in IGNORED_MODULES):
  93. continue
  94. package_name = "google.protobuf{}".format(
  95. package_posix[len(SOURCE_POSIX) :].replace("/", ".")
  96. )
  97. if module_path.name == "__init__.py":
  98. modules.append(package_name)
  99. else:
  100. module_name = module_path.stem
  101. modules.append("{}.{}".format(package_name, module_name))
  102. return modules
  103. def write_automodule(module):
  104. contents = AUTOMODULE_TEMPLATE.format(module=module, underline="=" * len(module),)
  105. automodule_path = DOCS_DIR.joinpath(*module.split(".")).with_suffix(".rst")
  106. try:
  107. automodule_path.parent.mkdir(parents=True)
  108. except FileExistsError:
  109. pass
  110. with open(automodule_path, "w") as automodule_file:
  111. automodule_file.write(contents)
  112. def replace_toc(modules):
  113. toctree = [module.replace(".", "/") for module in modules]
  114. with open(DOCS_DIR / "index.rst", "r") as index_file:
  115. index_contents = index_file.read()
  116. toc = TOC_TEMPLATE.format(
  117. toctree="\n ".join(toctree)
  118. )
  119. index_contents = re.sub(TOC_REGEX, toc, index_contents)
  120. with open(DOCS_DIR / "index.rst", "w") as index_file:
  121. index_file.write(index_contents)
  122. def main():
  123. modules = list(sorted(find_modules()))
  124. for module in modules:
  125. print("Generating reference for {}".format(module))
  126. write_automodule(module)
  127. print("Generating index.rst")
  128. replace_toc(modules)
  129. if __name__ == "__main__":
  130. main()