# Viết docstring

Tham chiếu API của LeRobot được tạo trực tiếp từ các docstring trong `src/lerobot/`. Docstring không phải là chú thích — nó là tài liệu công bố cho đối tượng đó, và định dạng bên dưới là thứ mà trình render và các kiểm tra CI sẽ phân tích.

Trang này là bản cam kết. Nếu bạn thêm hoặc chỉnh sửa bất kỳ thành phần công khai nào trong `src/lerobot/`, hãy tuân theo nó.

> [!IMPORTANT]
> **Một phương thức công khai không được tài liệu hóa là một phương thức vô hình.** `[[autodoc]]` sẽ bỏ qua một cách im lặng các thành viên không có docstring — không có cảnh báo, không có lỗi, chúng đơn giản là không xuất hiện trên trang được render. Độ bao phủ và tính đầy đủ của tham chiếu API là cùng một vấn đề.

## Định dạng trong một ví dụ

Tiêu đề phần của Google, định dạng kiểu của Hugging Face. Cả hai, không phải một trong hai.

````python
def send_action(self, action: RobotAction, rate_hz: float = 30.0) -> RobotAction:
    """Command the robot to move to a target joint configuration.

    Values are clipped by the configured maximum relative target before reaching the motors, so the
    returned action may differ from the requested one.

    Args:
        action (`dict[str, float]`):
            Target values keyed by motor name, e.g. `{"shoulder_pan.pos": 0.0}`. Keys must match the
            robot's action features.
        rate_hz (`float`, *optional*, defaults to `30.0`):
            Control loop frequency.

    Returns:
        `dict[str, float]`: The action actually written to the motors after safety clipping.

    Raises:
        DeviceNotConnectedError: If the robot has not been connected.

    Example:
        ```python
        >>> from lerobot.robots.so_follower import SO101Follower, SO101FollowerConfig
        >>> robot = SO101Follower(SO101FollowerConfig(port="/dev/ttyACM0"))  # doctest: +SKIP
        >>> robot.connect()  # doctest: +SKIP
        >>> robot.send_action({"shoulder_pan.pos": 0.0})  # doctest: +SKIP
        ```
    """
````

Các tham chiếu chéo được lược bỏ khỏi các ví dụ trên trang này — xem [Cross-references](#cross-references) để biết cú pháp của chúng và lý do tại sao chúng không thể hiển thị bên trong khối mã.

## Quy tắc

### Các phần

`Args:` · `Returns:` · `Raises:` · `Yields:` · `Example:` · `Note:`

Theo đúng thứ tự đó. Không có tiêu đề mục nào khác. Một dòng tóm tắt đứng đầu, sau đó là phần mô tả tự do tùy chọn, rồi đến các mục.

### Dòng `Args:` được máy phân tích

```
name (`type`, *optional*, defaults to `X`):
    Description, indented on its own line.
```

The `*optional*, defaults to` clause is **checked against the real signature default** by `make check-docstrings`. It is not decorative — if you write a default that has drifted from the code, CI fails. Omit the clause entirely for required parameters:

```python
    Args:
        port (`str`):
            Serial port the arm is connected to, e.g. `/dev/ttyACM0`.
        max_relative_target (`float | dict[str, float]`, *optional*):
            Caps the magnitude of the relative positional target vector. `None` disables clipping.
        use_degrees (`bool`, *optional*, defaults to `True`):
            Keep `True` for backward compatibility with existing policies and datasets.
```

Types go in backticks. Use `*optional*` with no `defaults to` when the default is `None` or is otherwise not worth restating.

### `Returns:` ưu tiên kiểu

Một dòng thụt lề, nhập loại trước, sau đó là dấu hai chấm, rồi đến mô tả:

```python
    Returns:
        `dict[str, float]`: The action actually written to the motors after safety clipping.
```

`Yields:` có cùng hình dạng.

### `**Attributes**:`, không bao giờ `Attributes:`

doc-builder phân tích `Attributes:` đơn thuần như một **đồng nghĩa với `Parameters:`**, do đó các thuộc tính của bạn sẽ được hiển thị như các đối số của hàm khởi tạo. Điều này diễn ra âm thầm và sai. Bất cứ khi nào các thuộc tính khác với các tham số của hàm khởi tạo, hãy dùng dạng in đậm với bộ phân tách `--`:

```python
class Robot(abc.ABC):
    """The base abstract class for all LeRobot-compatible robots.

    **Attributes**:
        - **config_class** (`type[RobotConfig]`) -- The expected configuration class for this robot.
        - **name** (`str`) -- The unique robot name used to identify this robot type.
    """
```

Lưu ý `--`, không phải `:`.

### Tham chiếu chéo

Sử dụng cú pháp ngoặc vuông của doc-builder: một đường dẫn được đặt trong dấu ngoặc vuông và bao bởi dấu backtick. **Các vai trò Sphinx (`:pymeth:`, `:pyattr:`) không được hỗ trợ** và sẽ hiển thị dưới dạng văn bản thô trên trang.

| Muốn                         | Viết                               |
| ---------------------------- | ----------------------------------- |
| Class trong gói chính    | &#91;`Robot`&#93;                   |
| Phương thức, hiển thị đường dẫn đầy đủ   | &#91;`Robot.connect`&#93;           |
| Phương thức, hiển thị tên gốc   | &#91;`~Robot.connect`&#93;          |
| Đường dẫn lồng nhau                  | &#91;`~robots.Robot.connect`&#93;   |
| Đối tượng trong thư viện HF khác | &#91;`~accelerate.Accelerator`&#93; |

`~` chỉ xóa phần đường dẫn khỏi **chữ liên kết**; liên kết vẫn trỏ đến đường dẫn đầy đủ.

> [!NOTE]
> doc-builder xử lý cú pháp này ở mọi vị trí trong trang — bao gồm cả bên trong các khối code có rào chắn. Đó là lý do tại sao các ví dụ trong docstring trên trang này sử dụng văn bản thông thường thay vì tham chiếu chéo: một khối code chứa tham chiếu chéo sẽ hiển thị liên kết đã được phân giải thay vì cú pháp mà bạn cần nhập. Trong các docstring của riêng bạn, hãy sử dụng tham chiếu chéo một cách tự do; hạn chế này chỉ ảnh hưởng đến tài liệu _về_ cú pháp.

### Ghi chú

Sử dụng trích dẫn khối kiểu GitHub:

```markdown
> [!TIP]
> Call this once at startup — it takes about two seconds.

> [!WARNING]
> Torque is disabled on disconnect. The arm will drop if it is holding a load.
```

Thành phần `<Tip>` đã lỗi thời theo doc-builder; không thêm các thành phần mới.

### Các ví dụ phải được đặt trong hàng rào

An example lives inside a fenced `  DOCBUILDER_CODE_7 `python Example:
        ```python
        >>> from lerobot.robots.so_follower import SO101FollowerConfig
        >>> cfg = SO101FollowerConfig(port="/dev/ttyACM0")
        >>> cfg.use_degrees
        True
        ```
````

> [!WARNING]
> An unfenced `>>>` is still collected — doctest finds prompts anywhere in a docstring. What you lose is the
> rendering, so it shows up as a wall of prose on the page. Every example needs the fence.

Every example either executes in CI or carries `# doctest: +SKIP`. Anything that touches hardware, a GPU, or
downloads from the Hub gets `+SKIP`:

````python
    Example:
        ```python
        >>> robot.connect()  # doctest: +SKIP
        >>> policy = ACTPolicy.from_pretrained("lerobot/act_aloha_sim_transfer_cube_human")  # doctest: +SKIP
        ```
````

Thêm các tệp chứa các ví dụ có thể chạy vào `utils/documentation_tests.txt`.

Đặt ví dụ ở ba đến năm điểm vào thực sự của một module. Ví dụ ở các bộ truy cập tầm thường chỉ là nhiễu.

## Ba mẫu bạn sẽ gặp liên tục

### Các dataclass cấu hình

Các trường cấu hình từ trước đến nay được tài liệu hóa bằng các chú thích `#` phía trên mỗi trường. **doc-builder không thể nhìn thấy các chú thích inline** — một lớp như vậy sẽ hiển thị với tất cả các trường được liệt kê mà không có bất kỳ mô tả nào. Hãy chuyển chúng vào khối `Args:` trong docstring của lớp:

```python
@dataclass
class SOFollowerConfig:
    """Configuration for SO-family follower arms.

    Args:
        port (`str`):
            Serial port the arm is connected to, e.g. `/dev/ttyACM0`.
        max_relative_target (`float | dict[str, float]`, *optional*):
            Caps the magnitude of the relative positional target vector. A scalar applies to all motors;
            a dict maps motor name to a per-motor cap. `None` disables clipping.
        use_degrees (`bool`, *optional*, defaults to `True`):
            Keep `True` for backward compatibility with existing policies and datasets.
    """

    port: str
    max_relative_target: float | dict[str, float] | None = None
    use_degrees: bool = True
```

> [!IMPORTANT]
> **doc-builder không kế thừa docstring từ các lớp cơ sở.** Các lớp cấu hình đã đăng ký của LeRobot thường là các shim kế thừa đa lớp mỏng:
>
> ```python
> @RobotConfig.register_subclass("so101_follower")
> @dataclass
> class SOFollowerRobotConfig(RobotConfig, SOFollowerConfig):
>     pass
> ```
>
> Lớp đó hiển thị **mọi** trường — bao gồm cả những trường kế thừa — mà không có bất kỳ mô tả nào, bất kể các lớp cơ sở được tài liệu hóa tốt đến đâu. Khối `Args:` phải nằm trên lớp cụ thể mà `[[autodoc]]` chỉ định, và nó phải bao gồm cả các trường kế thừa.

### Lớp cơ sở, sau đó là lớp con cụ thể

Lớp trừu tượng cơ sở mang theo hợp đồng chuẩn. Các lớp con chỉ tài liệu hóa những gì khác biệt — ngữ nghĩa cổng, các đặc điểm hiệu chuẩn, bố trí động cơ, các khóa tính năng được hỗ trợ. Không sao chép hợp đồng cơ sở vào mọi lớp con.

`Robot`, `Teleoperator`, `Camera`, `MotorsBusBase`, `ProcessorStep` và `PreTrainedPolicy` đều tuân theo cấu trúc này.

### Biến alias ở cấp module

Một số tên công khai là các alias thay vì các lớp riêng biệt:

```python
SO100FollowerConfig = SOFollowerRobotConfig
SO101FollowerConfig = SOFollowerRobotConfig
```

`[[autodoc]]` sẽ phân giải alias và hiển thị tên class **canonical**, do đó tiêu đề `## SO101FollowerConfig` sẽ hiển thị `class lerobot.robots.so_follower.SOFollowerRobotConfig` trong phần thân. Hãy tài liệu hóa class canonical một lần, và đề cập đến các alias trong phần văn bản của trang thay vì tạo một khối autodoc riêng cho từng alias.

## Những gì không nên tài liệu hóa

- **Các thành viên riêng.** Mọi thứ bắt đầu bằng `_` không thuộc về API công khai.
- **The type annotation restated as prose.** `port (`str`): A string.` adds nothing. Say what it is for.
- **Mã nguồn từ upstream được nhúng sẵn.** `src/lerobot/policies/molmoact2/molmoact2_hf_model/` được nhúng từ `transformers` và đã có sẵn các docstring theo phong cách upstream. Hãy giữ nguyên — việc định dạng lại chỉ tạo ra xung đột trong lần đồng bộ tiếp theo. Thư mục này bị loại khỏi tham chiếu API và khỏi các kiểm tra docstring.

## Cách thức thực thi

| Kiểm tra                     | Những gì nó phát hiện                                                                                            |
| ------------------------- | ---------------------------------------------------------------------------------------------------------- |
| `make check-docstrings`   | Một mục `Args:` không khớp với chữ ký; một giá trị mặc định được tài liệu hóa đã lệch khỏi giá trị thực |
| `make doctest`            | Các ví dụ không còn chạy được                                                                                |
| `make check-doctest-list` | Các mục cũ hoặc chưa được sắp xếp trong `utils/documentation_tests.txt`                                               |
| `ruff` (các quy tắc `D`)        | Vi phạm quy tắc theo quy ước của Google                                                                         |
| `interrogate`             | Phạm vi bao phủ docstring giảm xuống dưới ngưỡng hiện tại                                                     |
| doc-builder               | Đường dẫn `[[autodoc]]` trỏ đến một đối tượng không tồn tại — điều này sẽ làm hỏng quá trình build tài liệu              |

Chạy chúng cùng nhau trước khi mở PR:

```bash
make check-docstrings && make doctest && pre-commit run --all-files
```

Sau đó, render trang và thực sự xem nó:

```bash
doc-builder build lerobot docs/source/ --build_dir /tmp/doc-build
```

## Danh sách kiểm tra

- [ ] Mọi thành viên công khai mà bạn đã chỉnh sửa đều có docstring.
- [ ] Every `Args:` entry matches the signature, including the `*optional*, defaults to` clause.
- [ ] `Returns:` là kiểu-first trên một dòng thụt lề.
- [ ] Không có `Attributes:` trần — hãy dùng `**Attributes**:` với các dấu phân cách `--`.
- [ ] Không có vai Sphinx — các tham chiếu chéo sử dụng &#91;`~module.Class.method`&#93;.
- [ ] Các ví dụ nằm trong khối ` ```python ` có hàng rào, và được chạy trong CI hoặc có `# doctest: +SKIP`.
- Các trường của dataclass Config nằm trong khối `Args:` của lớp cụ thể, không phải là các chú thích `#`.
- [ ] Trang đã được hiển thị và kiểm tra bằng mắt.

