Sphinx autodoc không đủ tự động


149

Tôi đang cố gắng sử dụng Sphinx để ghi lại dự án hơn 5.000 dòng trong Python. Nó có khoảng 7 mô-đun cơ sở. Theo như tôi biết, để sử dụng autodoc, tôi cần viết mã như thế này cho mỗi tệp trong dự án của mình:

.. automodule:: mods.set.tests
    :members:
    :show-inheritance:

Đây là cách quá tẻ nhạt vì tôi có nhiều tập tin. Sẽ dễ dàng hơn nhiều nếu tôi có thể chỉ định rằng tôi muốn gói 'mod' được ghi lại. Sphinx sau đó có thể đệ quy đi qua gói và tạo một trang cho mỗi mô hình con.

Có một tính năng như thế này? Nếu không tôi có thể viết một tập lệnh để tạo tất cả các tệp .rst, nhưng điều đó sẽ tốn rất nhiều thời gian.


Có gì sai khi viết một tập lệnh nhỏ sử dụng "os.walk" và viết tất cả những điều này? BTW, tôi đã có một dự án hơn 40.000 và không rõ bạn đang nói về điều gì. Có bao nhiêu tập tin liên quan? Làm thế nào khó có thể định tuyến lsđến một tập tin và chỉnh sửa đó?
S.Lott

124
Không ai nói nó khó cả. OP nói rằng nó là tẻ nhạt , đó là. Cho rằng các hệ thống tài liệu khác có thể làm điều này, nó không phải là không hợp lý.
Gregg Lind

Chỉ cần sử dụng pdoc .
K3 --- rnc

Câu trả lời:


143

Bạn có thể kiểm tra tập lệnh này mà tôi đã thực hiện. Tôi nghĩ rằng nó có thể giúp bạn.

Kịch bản lệnh này phân tích một cây thư mục tìm kiếm các mô-đun và gói python và tạo các tệp ReST một cách thích hợp để tạo tài liệu mã với Sphinx. Nó cũng tạo ra một chỉ mục mô-đun.

CẬP NHẬT

Kịch bản này hiện là một phần của Sphinx 1.1 dưới dạng apidoc .


Bạn phải xuất các tập tin ở đâu? Tôi đã thử xuất chúng vào thư mục _build mặc định của Sphinx, nhưng chạy sphinx-build -b html . ./_buildkhông nhận được chúng.
Cerin

Bạn nên đặt chúng trong source directory(trong trường hợp của bạn). Thư mục _build là nơi các tệp HTML sẽ được tạo. Kiểm tra để biết thêm thông tin: sphinx.pocoo.org/tutorial.html#rucky-the-build
Etienne

1
@Erienne: kịch bản tuyệt vời! Chỉ cần những gì tôi đang tìm kiếm. Mong muốn nó tạo ra các tiêu đề cho các lớp riêng lẻ (giao diện nhân sư thông thường không đẹp cho các lớp. Chúng bị lạc trong các mô-đun lớn hơn)
jbenet

1
Ngay cả nhân sư-apidoc cũng khá thô sơ. Đối với một gói có một hoặc hai mô-đun, nó hoạt động ổn, nhưng chúng tôi đã có các mô-đun lồng nhau sâu sắc và sphinx-apidoc tạo ra một số đầu ra khá khó kiểm soát.
slacy

4
tự trả lời: thêm .. include:: modules.rstvào của bạnindex.rst
Ciro Santilli 冠状 病 六四 事件

39

Tôi không biết liệu Sphinx có autosummarymở rộng tại thời điểm câu hỏi ban đầu được hỏi hay không, nhưng bây giờ hoàn toàn có thể thiết lập thế hệ tự động của loại đó mà không cần sử dụng sphinx-apidochoặc tập lệnh tương tự. Dưới đây là các cài đặt hoạt động cho một trong các dự án của tôi.

  1. Bật autosummarytiện ích mở rộng (cũng như autodoc) trong conf.pytệp và đặt autosummary_generatetùy chọn của nó thành True. Điều này có thể là đủ nếu bạn không sử dụng các *.rstmẫu tùy chỉnh . Nếu không, thêm thư mục mẫu của bạn để loại trừ danh sách, hoặc autosummarysẽ cố coi chúng là các tệp đầu vào (có vẻ là một lỗi).

    extensions = ['sphinx.ext.autodoc', 'sphinx.ext.autosummary']
    autosummary_generate = True
    templates_path = [ '_templates' ]
    exclude_patterns = ['_build', '_templates']
    
  2. Sử dụng autosummary::trong cây TOC trong index.rsttập tin của bạn . Trong ví dụ này tài liệu cho các mô-đun project.module1project.module2sẽ được tạo tự động và được đặt vào _autosummarythư mục.

    PROJECT
    =======
    
    .. toctree::
    
    .. autosummary::
       :toctree: _autosummary
    
       project.module1
       project.module2
    
  3. Theo mặc định autosummarysẽ chỉ tạo ra các bản tóm tắt rất ngắn cho các mô-đun và chức năng của chúng. Để thay đổi, bạn có thể đặt tệp mẫu tùy chỉnh vào _templates/autosummary/module.rst(sẽ được phân tích cú pháp bằng Jinja2 ):

    {{ fullname }}
    {{ underline }}
    
    .. automodule:: {{ fullname }}
        :members:
    

Để kết luận, không cần phải giữ _autosummarythư mục dưới sự kiểm soát phiên bản. Ngoài ra, bạn có thể đặt tên cho nó bất cứ thứ gì bạn muốn và đặt nó ở bất cứ đâu trong cây nguồn ( _buildmặc dù vậy, đặt nó bên dưới sẽ không hoạt động).


4
Đây là một sự giúp đỡ rất lớn. Trong điểm 2, nơi bạn có "project.module1" và "project.module2", có cách nào để tự động tạo danh sách đó cho mọi mô-đun trong một gói nhất định không? Để chỉ đặt "dự án" và phát hiện ra "module1" và "module2"?
Brown

Khá ngạc nhiên khi tôi không thể tìm thấy câu trả lời cho vấn đề này ở bất cứ đâu, bạn có bao giờ làm việc đó không @Brown?
Alitorair Robertson

3
@AlonomairRobertson Không, nhưng giải pháp tự động được cung cấp cuối cùng đã quá đủ cho nhu cầu của tôi. Điều khác duy nhất tôi nghĩ làm là viết một tập lệnh để tạo tệp index.rst và tự động phát hiện tên mô-đun. Tuy nhiên, trong thực tế, danh sách các mô-đun không thay đổi thường xuyên, do đó, chỉ cần chỉnh sửa một tệp một lần không phải là không hợp lý. Tôi chắc chắn rằng tôi đã dành nhiều thời gian hơn để tìm kiếm một giải pháp hơn là chỉ cần chỉnh sửa một tệp đó!
Brown

12

Trong mỗi gói, __init__.pytệp có thể có .. automodule:: package.modulecác thành phần cho từng phần của gói.

Sau đó, bạn có thể .. automodule:: packagevà nó chủ yếu làm những gì bạn muốn.


Tôi chỉ cần đặt chuỗi đó trong ba dấu ngoặc kép trong init .py?
Cory Walker

5
@Cory Walker: Đây không phải là "chuỗi". Bạn có thể - và nên - đưa các tài liệu được trích dẫn ba lần vào mỗi tệp. Tất cả mọi người. Điều đó bao gồm các __init__.pytập tin trong gói của bạn. Chuỗi doc có thể bao gồm bất kỳ chỉ thị tài liệu Sphinx nào, bao gồm .. automodule::các mô-đun trong gói.
S.Lott

2
autodoclà một lỗi đánh máy, nó nên được automodule. nhưng cảm ơn rất nhiều cho gợi ý!
mariotomo

9

Từ Sphinx phiên bản 3.1 (tháng 6 năm 2020), sphinx.ext.autosummary(cuối cùng!) Đã được đệ quy.

Vì vậy, không cần phải cứng tên mô-đun hoặc dựa vào các thư viện bên thứ 3 như Sphinx AutoAPI hoặc Sphinx AutoPackageSummary để phát hiện gói tự động của họ nữa.

Ví dụ gói Python 3.7 vào tài liệu ( xem mã trên Githubkết quả trên ReadTheDocs ):

mytoolbox
|-- mypackage
|   |-- __init__.py
|   |-- foo.py
|   |-- mysubpackage
|       |-- __init__.py
|       |-- bar.py
|-- doc
|   |-- source
|       |--index.rst
|       |--conf.py
|       |-- _templates
|           |-- custom-module-template.rst
|           |-- custom-class-template.rst

conf.py:

import os
import sys
sys.path.insert(0, os.path.abspath('../..'))  # Source code dir relative to this file

extensions = [
    'sphinx.ext.autodoc',  # Core library for html generation from docstrings
    'sphinx.ext.autosummary',  # Create neat summary tables
]
autosummary_generate = True  # Turn on sphinx.ext.autosummary

# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']

index.rst(lưu ý :recursive:tùy chọn mới ):

Welcome to My Toolbox
=====================

Some words.

.. autosummary::
   :toctree: _autosummary
   :template: custom-module-template.rst
   :recursive:

   mypackage

Điều này là đủ để tự động tóm tắt mọi mô-đun trong gói, tuy nhiên được lồng sâu. Đối với mỗi mô-đun, sau đó nó tóm tắt mọi thuộc tính, chức năng, lớp và ngoại lệ trong mô-đun đó.

Mặc dù, điều kỳ lạ là các sphinx.ext.autosummarymẫu mặc định không tiếp tục tạo các trang tài liệu riêng cho từng thuộc tính, chức năng, lớp và ngoại lệ và liên kết với chúng từ các bảng tóm tắt. Có thể mở rộng các mẫu để làm điều này, như được hiển thị bên dưới, nhưng tôi không thể hiểu tại sao đây không phải là hành vi mặc định - chắc chắn đó là điều mà hầu hết mọi người sẽ muốn ..? Tôi đã nêu nó như một yêu cầu tính năng .

Tôi đã phải sao chép các mẫu mặc định cục bộ và sau đó thêm chúng vào:

  • Sao chép site-packages/sphinx/ext/autosummary/templates/autosummary/module.rstvàomytoolbox/doc/source/_templates/custom-module-template.rst
  • Sao chép site-packages/sphinx/ext/autosummary/templates/autosummary/class.rstvàomytoolbox/doc/source/_templates/custom-class-template.rst

Móc vào custom-module-template.rstlà ở index.rsttrên, sử dụng :template:tùy chọn. (Xóa dòng đó để xem điều gì xảy ra bằng cách sử dụng các mẫu gói trang mặc định.)

custom-module-template.rst (dòng bổ sung ghi chú bên phải):

{{ fullname | escape | underline}}

.. automodule:: {{ fullname }}
  
   {% block attributes %}
   {% if attributes %}
   .. rubric:: Module Attributes

   .. autosummary::
      :toctree:                                          <-- add this line
   {% for item in attributes %}
      {{ item }}
   {%- endfor %}
   {% endif %}
   {% endblock %}

   {% block functions %}
   {% if functions %}
   .. rubric:: {{ _('Functions') }}

   .. autosummary::
      :toctree:                                          <-- add this line
   {% for item in functions %}
      {{ item }}
   {%- endfor %}
   {% endif %}
   {% endblock %}

   {% block classes %}
   {% if classes %}
   .. rubric:: {{ _('Classes') }}

   .. autosummary::
      :toctree:                                          <-- add this line
      :template: custom-class-template.rst               <-- add this line
   {% for item in classes %}
      {{ item }}
   {%- endfor %}
   {% endif %}
   {% endblock %}

   {% block exceptions %}
   {% if exceptions %}
   .. rubric:: {{ _('Exceptions') }}

   .. autosummary::
      :toctree:                                          <-- add this line
   {% for item in exceptions %}
      {{ item }}
   {%- endfor %}
   {% endif %}
   {% endblock %}

{% block modules %}
{% if modules %}
.. rubric:: Modules

.. autosummary::
   :toctree:
   :template: custom-module-template.rst                 <-- add this line
   :recursive:
{% for item in modules %}
   {{ item }}
{%- endfor %}
{% endif %}
{% endblock %}

custom-class-template.rst (dòng bổ sung ghi chú bên phải):

{{ fullname | escape | underline}}

.. currentmodule:: {{ module }}

.. autoclass:: {{ objname }}
   :members:                                    <-- add at least this line
   :show-inheritance:                           <-- plus I want to show inheritance...
   :inherited-members:                          <-- ...and inherited members too

   {% block methods %}
   .. automethod:: __init__

   {% if methods %}
   .. rubric:: {{ _('Methods') }}

   .. autosummary::
   {% for item in methods %}
      ~{{ name }}.{{ item }}
   {%- endfor %}
   {% endif %}
   {% endblock %}

   {% block attributes %}
   {% if attributes %}
   .. rubric:: {{ _('Attributes') }}

   .. autosummary::
   {% for item in attributes %}
      ~{{ name }}.{{ item }}
   {%- endfor %}
   {% endif %}
   {% endblock %}

6

Sphinx AutoAPI thực hiện chính xác điều này.


1
Ôi Chúa ơi! Điều này làm việc tốt hơn nhiều so với bất cứ điều gì khác. Lưu ý rằng đây KHÔNG phải là "autodoc" hoặc "apidoc", đây là một phần mở rộng hoàn toàn khác.
ropeladder

2
Như trên. Điều này đặt "auto" trong "autodoc" .... Đây là tất cả dự án của chúng tôi phải làm để chuyển đổi: Chuyển sang autoapi từ autodoc bằng nealmcb · Pull Request \ # 7 · gwexploratoryaudits / r2b2
nealmcb

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.