File size: 4,504 Bytes
ef16689
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# generate_api_docs.py

import os


def generate_api_docs(base_path, output_dir, package_name, exclude_list=None):
    """
    Automatically generates .rst files for Sphinx API documentation.

    Args:
        base_path (str): The root directory of the Python package (e.g., 'biomni').
        output_dir (str): The directory where the .rst files will be generated (e.g., 'source/api').
        package_name (str): The name of the Python package.
        exclude_list (list): A list of paths (directories or files) to exclude from documentation.
                             Paths should be relative to the base_path.
    """
    if exclude_list is None:
        exclude_list = []

    if not os.path.exists(output_dir):
        os.makedirs(output_dir)

    # Walk through the package directory
    for root, dirs, files in os.walk(base_path):
        # Exclude directories if they are in the exclude list
        dirs[:] = [d for d in dirs if os.path.join(os.path.relpath(root, base_path), d) not in exclude_list]

        for file in files:
            file_path_relative = os.path.relpath(os.path.join(root, file), base_path)

            # Check if the file should be excluded
            if file_path_relative in exclude_list:
                print(f"Skipping excluded file: {file_path_relative}")
                continue

            if file.endswith(".py") and file != "__init__.py":
                # Construct the full module name (e.g., biomni.agent.a1)
                rel_path = os.path.relpath(root, base_path)
                module_name = f"{package_name}.{rel_path.replace(os.path.sep, '.')}.{os.path.splitext(file)[0]}"

                # Clean up the module name if it starts with the package name
                if module_name.startswith(f"{package_name}.{package_name}."):
                    module_name = f"{package_name}.{module_name[len(f'{package_name}.{package_name}.') :]}"

                # Create the directory structure in the output folder
                output_path_dir = os.path.join(output_dir, rel_path)
                if not os.path.exists(output_path_dir):
                    os.makedirs(output_path_dir)

                # Define the output .rst file path
                output_file = os.path.join(output_path_dir, f"{os.path.splitext(file)[0]}.rst")

                # Generate the RST content
                rst_content = f"""{module_name}
{"=" * len(module_name)}

.. automodule:: {module_name}
   :members:
   :undoc-members:
   :show-inheritance:
"""
                # Write the content to the .rst file
                with open(output_file, "w", encoding="utf-8") as f:
                    f.write(rst_content)
                print(f"Generated {output_file}")


def create_index_rst(output_dir, package_name):
    """
    Creates or updates the main index file that lists all generated .rst files.
    """
    output_dir = os.path.join(output_dir, "../")
    index_path = os.path.join(output_dir, "index.rst")
    rst_files = []

    # Find all generated rst files
    for root, _dirs, files in os.walk(output_dir):
        for file in files:
            if file.endswith(".rst") and file != "index.rst":
                rel_path = os.path.relpath(os.path.join(root, file), output_dir)
                rst_files.append(os.path.splitext(rel_path)[0])

    rst_files.sort()

    index_content = f"""{package_name} API Reference
{"=" * (len(package_name) + len(" API Reference"))}

.. toctree::
   :maxdepth: 2
   :caption: API Contents:

"""
    for file in rst_files:
        index_content += f"   {file}\n"

    with open(index_path, "w", encoding="utf-8") as f:
        f.write(index_content)
    print(f"Updated {index_path} with module links.")

    # update ../index.rst to include api/index
    # index_path = os.path.join(output_dir, '../index.rst')
    # with open(index_path, 'w', encoding='utf-8') as f:


if __name__ == "__main__":
    package_to_document = "../biomni"
    api_docs_path = "./source/api"
    package_name = "biomni"

    os.makedirs(api_docs_path, exist_ok=True)

    exclude_list = [
        "llm.py",
        "env_desc.py",
        "version.py",
        "tool/tool_description",
        "tool/example_mcp_tools",
    ]

    generate_api_docs(package_to_document, api_docs_path, package_name, exclude_list)
    create_index_rst(api_docs_path, package_name)

    print("\nAPI documentation source files have been generated.")
    print("Now run 'make html' from your project's root directory to build the documentation.")